diff --git a/.codecov.yml b/.codecov.yml new file mode 100644 index 000000000000..337b0b15e740 --- /dev/null +++ b/.codecov.yml @@ -0,0 +1,57 @@ +--- + +codecov: + notify: + after_n_builds: 9 # Number of test matrix+lint jobs uploading coverage + wait_for_ci: false + + require_ci_to_pass: false + + token: >- # repo-scoped, upload-only, needed for stability in PRs from forks + 2b8c7a7a-7293-4a00-bf02-19bd55a1389b + +comment: + require_changes: true + +coverage: + range: 100..100 + status: + patch: + default: + target: 100% + pytest: + target: 100% + flags: + - pytest + typing: + flags: + - MyPy + project: + default: + target: 75% + lib: + flags: + - pytest + paths: + - awx/ + target: 75% + tests: + flags: + - pytest + paths: + - tests/ + - >- + **/test/ + - >- + **/tests/ + - >- + **/test/** + - >- + **/tests/** + target: 95% + typing: + flags: + - MyPy + target: 100% + +... diff --git a/.coveragerc b/.coveragerc index f9ef3447bfec..14aa98d8f966 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,16 +1,6 @@ -[run] -source = awx -branch = True -omit = - awx/main/migrations/* - awx/lib/site-packages/* - [report] # Regexes for lines to exclude from consideration -exclude_lines = - # Have to re-enable the standard pragma - pragma: no cover - +exclude_also = # Don't complain about missing debug-only code: def __repr__ if self\.debug @@ -23,7 +13,35 @@ exclude_lines = if 0: if __name__ == .__main__.: -ignore_errors = True + ^\s*@pytest\.mark\.xfail + +[run] +branch = True +# NOTE: `disable_warnings` is needed when `pytest-cov` runs in tandem +# NOTE: with `pytest-xdist`. These warnings are false negative in this +# NOTE: context. +# +# NOTE: It's `coveragepy` that emits the warnings and previously they +# NOTE: wouldn't get on the radar of `pytest`'s `filterwarnings` +# NOTE: mechanism. This changed, however, with `pytest >= 8.4`. And +# NOTE: since we set `filterwarnings = error`, those warnings are being +# NOTE: raised as exceptions, cascading into `pytest`'s internals and +# NOTE: causing tracebacks and crashes of the test sessions. +# +# Ref: +# * https://github.com/pytest-dev/pytest-cov/issues/693 +# * https://github.com/pytest-dev/pytest-cov/pull/695 +# * https://github.com/pytest-dev/pytest-cov/pull/696 +disable_warnings = + module-not-measured +omit = + awx/main/migrations/* + awx/settings/defaults.py + awx/settings/*_defaults.py +source = + . +source_pkgs = + awx [xml] output = ./reports/coverage.xml diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md index 0164155b8102..31368dcb706b 100644 --- a/.github/CODE_OF_CONDUCT.md +++ b/.github/CODE_OF_CONDUCT.md @@ -1,3 +1,3 @@ # Community Code of Conduct -Please see the official [Ansible Community Code of Conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html). +Please see the official [Ansible Community Code of Conduct](https://docs.ansible.com/projects/ansible/latest/community/code_of_conduct.html). diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 9cca894822ff..144f4599eb84 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -13,12 +13,14 @@ body: attributes: label: Please confirm the following options: - - label: I agree to follow this project's [code of conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html). + - label: I agree to follow this project's [code of conduct](https://docs.ansible.com/projects/ansible/latest/community/code_of_conduct.html). required: true - label: I have checked the [current issues](https://github.com/ansible/awx/issues) for duplicates. required: true - label: I understand that AWX is open source software provided for free and that I might not receive a timely response. required: true + - label: I am **NOT** reporting a (potential) security vulnerability. (These should be emailed to `security@ansible.com` instead.) + required: true - type: textarea id: summary @@ -42,6 +44,7 @@ body: label: Select the relevant components options: - label: UI + - label: UI (tech preview) - label: API - label: Docs - label: Collection diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index b3e5d26591c8..88a8445f2789 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -5,7 +5,7 @@ contact_links: url: https://github.com/ansible/awx#get-involved about: For general debugging or technical support please see the Get Involved section of our readme. - name: 📝 Ansible Code of Conduct - url: https://docs.ansible.com/ansible/latest/community/code_of_conduct.html?utm_medium=github&utm_source=issue_template_chooser + url: https://docs.ansible.com/projects/ansible/latest/community/code_of_conduct.html?utm_medium=github&utm_source=issue_template_chooser about: AWX uses the Ansible Code of Conduct; ❤ Be nice to other members of the community. ☮ Behave. - name: 💼 For Enterprise url: https://www.ansible.com/products/engine?utm_medium=github&utm_source=issue_template_chooser diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index 53ba31b9f6d1..d1c81fef755f 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -13,7 +13,7 @@ body: attributes: label: Please confirm the following options: - - label: I agree to follow this project's [code of conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html). + - label: I agree to follow this project's [code of conduct](https://docs.ansible.com/projects/ansible/latest/community/code_of_conduct.html). required: true - label: I have checked the [current issues](https://github.com/ansible/awx/issues) for duplicates. required: true diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 07d23adf000b..99a30cb41125 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -4,7 +4,8 @@ ##### ISSUE TYPE @@ -16,20 +17,14 @@ the change does. ##### COMPONENT NAME - API - - UI - Collection - CLI - Docs - Other -##### AWX VERSION - -``` - -``` -##### ADDITIONAL INFORMATION +##### STEPS TO REPRODUCE AND EXTRA INFO ' reports/coverage.xml + echo "Injected PR number ${{ github.event.pull_request.number }} into coverage.xml" + fi + + - name: Upload test coverage to Codecov + if: >- + !cancelled() + && steps.make-run.outputs.cov-report-files != '' + uses: codecov/codecov-action@v4 + with: + fail_ci_if_error: >- + ${{ + toJSON(env.UPSTREAM_REPOSITORY_ID == github.repository_id) + }} + files: >- + ${{ steps.make-run.outputs.cov-report-files }} + flags: >- + CI-GHA, + pytest, + OS-${{ + runner.os + }} + token: ${{ secrets.CODECOV_TOKEN }} + - name: Upload test results to Codecov + if: >- + !cancelled() + && steps.make-run.outputs.test-result-files != '' + uses: codecov/test-results-action@v1 + with: + fail_ci_if_error: >- + ${{ + toJSON(env.UPSTREAM_REPOSITORY_ID == github.repository_id) + }} + files: >- + ${{ steps.make-run.outputs.test-result-files }} + flags: >- + CI-GHA, + pytest, + OS-${{ + runner.os + }} + token: ${{ secrets.CODECOV_TOKEN }} + + - name: Upload test artifacts + if: always() + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.tests.name }}-artifacts + path: reports/coverage.xml + retention-days: 5 + + - name: >- + Upload ${{ + matrix.tests.coverage-upload-name || 'awx' + }} jUnit test reports to the unified dashboard + if: >- + !cancelled() + && steps.make-run.outputs.test-result-files != '' + && github.event_name == 'push' + && env.UPSTREAM_REPOSITORY_ID == github.repository_id + && github.ref_name == github.event.repository.default_branch + uses: ansible/gh-action-record-test-results@cd5956ead39ec66351d0779470c8cff9638dd2b8 + with: + aggregation-server-url: ${{ vars.PDE_ORG_RESULTS_AGGREGATOR_UPLOAD_URL }} + http-auth-password: >- + ${{ secrets.PDE_ORG_RESULTS_UPLOAD_PASSWORD }} + http-auth-username: >- + ${{ vars.PDE_ORG_RESULTS_AGGREGATOR_UPLOAD_USER }} + project-component-name: >- + ${{ matrix.tests.coverage-upload-name || 'awx' }} + test-result-files: >- + ${{ steps.make-run.outputs.test-result-files }} dev-env: runs-on: ubuntu-latest + timeout-minutes: 60 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 + with: + show-progress: false + + - uses: ./.github/actions/setup-python + with: + python-version: '3.13' + + - uses: ./.github/actions/run_awx_devel + id: awx + with: + build-ui: false + github-token: ${{ secrets.GITHUB_TOKEN }} + private-github-key: ${{ secrets.PRIVATE_GITHUB_KEY }} + + - name: Run live dev env tests + run: docker exec tools_awx_1 /bin/bash -c "make live_test" - - name: Run smoke test - run: make github_ci_setup && ansible-playbook tools/docker-compose/ansible/smoke-test.yml -v + - uses: ./.github/actions/upload_awx_devel_logs + if: always() + with: + log-filename: live-tests.log awx-operator: runs-on: ubuntu-latest + timeout-minutes: 60 + env: + DEBUG_OUTPUT_DIR: /tmp/awx_operator_molecule_test steps: - name: Checkout awx - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: + show-progress: false path: awx + - uses: ./awx/.github/actions/setup-ssh-agent + with: + ssh-private-key: ${{ secrets.PRIVATE_GITHUB_KEY }} + - name: Checkout awx-operator - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: + show-progress: false\ repository: ansible/awx-operator path: awx-operator - - name: Get python version from Makefile - working-directory: awx - run: echo py_version=`make PYTHON_VERSION` >> $GITHUB_ENV - - - name: Install python ${{ env.py_version }} - uses: actions/setup-python@v2 + - name: Setup python, referencing action at awx relative path + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 with: - python-version: ${{ env.py_version }} + python-version: '3.12' - name: Install playbook dependencies run: | - python3 -m pip install docker + python -m pip install docker + - name: Check Python version + working-directory: awx + run: | + make print-PYTHON + - name: Build AWX image working-directory: awx run: | - ansible-playbook -v tools/ansible/build.yml \ - -e headless=yes \ - -e awx_image=awx \ - -e awx_image_tag=ci \ - -e ansible_python_interpreter=$(which python3) + VERSION=`make version-for-buildyml` make awx-kube-build + env: + COMPOSE_TAG: ci + DEV_DOCKER_TAG_BASE: local + HEADLESS: yes - name: Run test deployment with awx-operator working-directory: awx-operator + id: awx_operator_test + timeout-minutes: 60 + continue-on-error: true run: | - python3 -m pip install -r molecule/requirements.txt - ansible-galaxy collection install -r molecule/requirements.yml - sudo rm -f $(which kustomize) - make kustomize - KUSTOMIZE_PATH=$(readlink -f bin/kustomize) molecule -v test -s kind + set +e + timeout 15m bash -elc ' + python -m pip install -r molecule/requirements.txt + python -m pip install PyYAML # for awx/tools/scripts/rewrite-awx-operator-requirements.py + $(realpath ../awx/tools/scripts/rewrite-awx-operator-requirements.py) molecule/requirements.yml $(realpath ../awx) + ansible-galaxy collection install -r molecule/requirements.yml + sudo rm -f $(which kustomize) + make kustomize + KUSTOMIZE_PATH=$(readlink -f bin/kustomize) molecule -v test -s kind -- --skip-tags=replicas + ' + rc=$? + if [ $rc -eq 124 ]; then + echo "timed_out=true" >> "$GITHUB_OUTPUT" + fi + exit $rc env: - AWX_TEST_IMAGE: awx + AWX_TEST_IMAGE: local/awx AWX_TEST_VERSION: ci + AWX_EE_TEST_IMAGE: quay.io/ansible/awx-ee:latest + STORE_DEBUG_OUTPUT: true + + - name: Collect awx-operator logs on timeout + # Only run on timeout; normal failures should use molecule's built-in log collection. + if: steps.awx_operator_test.outputs.timed_out == 'true' + run: | + mkdir -p "$DEBUG_OUTPUT_DIR" + if command -v kind >/dev/null 2>&1; then + for cluster in $(kind get clusters 2>/dev/null); do + kind export logs "$DEBUG_OUTPUT_DIR/$cluster" --name "$cluster" || true + done + fi + if command -v kubectl >/dev/null 2>&1; then + kubectl get all -A -o wide > "$DEBUG_OUTPUT_DIR/kubectl-get-all.txt" || true + kubectl get pods -A -o wide > "$DEBUG_OUTPUT_DIR/kubectl-get-pods.txt" || true + kubectl describe pods -A > "$DEBUG_OUTPUT_DIR/kubectl-describe-pods.txt" || true + fi + docker ps -a > "$DEBUG_OUTPUT_DIR/docker-ps.txt" || true + + - name: Upload debug output + if: always() + uses: actions/upload-artifact@v4 + with: + name: awx-operator-debug-output + path: ${{ env.DEBUG_OUTPUT_DIR }} + + - name: Fail awx-operator check if test deployment failed + if: steps.awx_operator_test.outcome != 'success' + run: exit 1 collection-sanity: name: awx_collection sanity runs-on: ubuntu-latest + timeout-minutes: 30 strategy: fail-fast: false + matrix: + ansible: + - stable-2.17 + # - devel steps: - - uses: actions/checkout@v2 + - name: Perform sanity testing + uses: ansible-community/ansible-test-gh-action@release/v1 + with: + ansible-core-version: ${{ matrix.ansible }} + codecov-token: ${{ secrets.CODECOV_TOKEN }} + collection-root: awx_collection + pre-test-cmd: >- + ansible-playbook + -i localhost, + tools/template_galaxy.yml + -e collection_package=awx + -e collection_namespace=awx + -e collection_version=1.0.0 + -e '{"awx_template_version": false}' + testing-type: sanity - # The containers that GitHub Actions use have Ansible installed, so upgrade to make sure we have the latest version. - - name: Upgrade ansible-core - run: python3 -m pip install --upgrade ansible-core + - name: Upload awx jUnit test reports to the unified dashboard + if: >- + !cancelled() + && steps.make-run.outputs.test-result-files != '' + && github.event_name == 'push' + && env.UPSTREAM_REPOSITORY_ID == github.repository_id + && github.ref_name == github.event.repository.default_branch + uses: ansible/gh-action-record-test-results@cd5956ead39ec66351d0779470c8cff9638dd2b8 + with: + aggregation-server-url: ${{ vars.PDE_ORG_RESULTS_AGGREGATOR_UPLOAD_URL }} + http-auth-password: >- + ${{ secrets.PDE_ORG_RESULTS_UPLOAD_PASSWORD }} + http-auth-username: >- + ${{ vars.PDE_ORG_RESULTS_AGGREGATOR_UPLOAD_USER }} + project-component-name: awx + test-result-files: >- + ${{ steps.make-run.outputs.test-result-files }} + + collection-integration: + name: awx_collection integration + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + target-regex: + - name: a-h + regex: ^[a-h] + - name: i-p + regex: ^[i-p] + - name: r-z0-9 + regex: ^[r-z0-9] + steps: + - uses: actions/checkout@v4 + with: + show-progress: false - - name: Run sanity tests - run: make test_collection_sanity + - uses: ./.github/actions/setup-python + with: + python-version: '3.13' + + - name: Remove system ansible to avoid conflicts + run: | + python -m pip uninstall -y ansible ansible-core || true + + - uses: ./.github/actions/run_awx_devel + id: awx + with: + build-ui: false + github-token: ${{ secrets.GITHUB_TOKEN }} + private-github-key: ${{ secrets.PRIVATE_GITHUB_KEY }} + + - name: Install dependencies for running tests + run: | + python -m pip install -e ./awxkit/ + python -m pip install -r awx_collection/requirements.txt + hash -r # Rehash to pick up newly installed scripts + + - name: Run integration tests + id: make-run + run: | + echo "::remove-matcher owner=python::" # Disable annoying annotations from setup-python + echo '[general]' > ~/.tower_cli.cfg + echo 'host = https://${{ steps.awx.outputs.ip }}:8043' >> ~/.tower_cli.cfg + echo 'username = admin' >> ~/.tower_cli.cfg + echo 'password = password' >> ~/.tower_cli.cfg + echo 'verify_ssl = false' >> ~/.tower_cli.cfg + TARGETS="$(ls awx_collection/tests/integration/targets | grep '${{ matrix.target-regex.regex }}' | tr '\n' ' ')" + export PYTHONPATH="$(python -c 'import site; print(":".join(site.getsitepackages()))')${PYTHONPATH:+:$PYTHONPATH}" + make COLLECTION_VERSION=100.100.100-git COLLECTION_TEST_TARGET="--requirements $TARGETS" test_collection_integration env: - # needed due to cgroupsv2. This is fixed, but a stable release - # with the fix has not been made yet. ANSIBLE_TEST_PREFER_PODMAN: 1 + + - name: Upload test coverage to Codecov + if: >- + !cancelled() + && steps.make-run.outputs.cov-report-files != '' + uses: codecov/codecov-action@v4 + with: + fail_ci_if_error: >- + ${{ + toJSON(env.UPSTREAM_REPOSITORY_ID == github.repository_id) + }} + files: >- + ${{ steps.make-run.outputs.cov-report-files }} + flags: >- + CI-GHA, + ansible-test, + integration, + OS-${{ + runner.os + }} + token: ${{ secrets.CODECOV_TOKEN }} + + # Upload coverage report as artifact + - uses: actions/upload-artifact@v4 + if: always() + with: + name: coverage-${{ matrix.target-regex.name }} + path: ~/.ansible/collections/ansible_collections/awx/awx/tests/output/coverage/ + retention-days: 1 + + - uses: ./.github/actions/upload_awx_devel_logs + if: always() + with: + log-filename: collection-integration-${{ matrix.target-regex.name }}.log + + collection-integration-coverage-combine: + name: combine awx_collection integration coverage + runs-on: ubuntu-latest + timeout-minutes: 10 + needs: + - collection-integration + strategy: + fail-fast: false + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + show-progress: false + + - uses: ./.github/actions/setup-python + with: + python-version: '3.13' + + - name: Remove system ansible to avoid conflicts + run: | + python -m pip uninstall -y ansible ansible-core || true + + - name: Upgrade ansible-core + run: python -m pip install --upgrade ansible-core + + - name: Download coverage artifacts + uses: actions/download-artifact@v4 + with: + merge-multiple: true + path: coverage + pattern: coverage-* + + - name: Combine coverage + run: | + make COLLECTION_VERSION=100.100.100-git install_collection + mkdir -p ~/.ansible/collections/ansible_collections/awx/awx/tests/output/coverage + cp -rv coverage/* ~/.ansible/collections/ansible_collections/awx/awx/tests/output/coverage/ + cd ~/.ansible/collections/ansible_collections/awx/awx + hash -r # Rehash to pick up newly installed scripts + PATH="$(python -c 'import sys; import os; print(os.path.dirname(sys.executable))'):$PATH" ansible-test coverage combine --requirements + PATH="$(python -c 'import sys; import os; print(os.path.dirname(sys.executable))'):$PATH" ansible-test coverage html + echo '## AWX Collection Integration Coverage' >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + PATH="$(python -c 'import sys; import os; print(os.path.dirname(sys.executable))'):$PATH" ansible-test coverage report >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + echo >> $GITHUB_STEP_SUMMARY + echo '## AWX Collection Integration Coverage HTML' >> $GITHUB_STEP_SUMMARY + echo 'Download the HTML artifacts to view the coverage report.' >> $GITHUB_STEP_SUMMARY + + - name: Upload coverage report as artifact + uses: actions/upload-artifact@v4 + with: + name: awx-collection-integration-coverage-html + path: ~/.ansible/collections/ansible_collections/awx/awx/tests/output/reports/coverage diff --git a/.github/workflows/dab-release.yml b/.github/workflows/dab-release.yml new file mode 100644 index 000000000000..6ebbe05bcecf --- /dev/null +++ b/.github/workflows/dab-release.yml @@ -0,0 +1,57 @@ +--- +name: django-ansible-base requirements update +on: + workflow_dispatch: + schedule: + - cron: '0 6 * * *' # once an day @ 6 AM +permissions: + pull-requests: write + contents: write +jobs: + dab-pin-newest: + if: (github.repository_owner == 'ansible' && endsWith(github.repository, 'awx')) || github.event_name != 'schedule' + runs-on: ubuntu-latest + steps: + - id: dab-release + name: Get current django-ansible-base release version + uses: pozetroninc/github-action-get-latest-release@2a61c339ea7ef0a336d1daa35ef0cb1418e7676c # v0.8.0 + with: + owner: ansible + repo: django-ansible-base + excludes: prerelease, draft + + - name: Check out respository code + uses: actions/checkout@v4 + + - id: dab-pinned + name: Get current django-ansible-base pinned version + run: + echo "version=$(requirements/django-ansible-base-pinned-version.sh)" >> "$GITHUB_OUTPUT" + + - name: Update django-ansible-base pinned version to upstream release + run: + requirements/django-ansible-base-pinned-version.sh -s ${{ steps.dab-release.outputs.release }} + + - name: Create Pull Request + uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c # v6 + with: + base: devel + branch: bump-django-ansible-base + title: Bump django-ansible-base to ${{ steps.dab-release.outputs.release }} + body: | + ##### SUMMARY + Automated .github/workflows/dab-release.yml + + django-ansible-base upstream released version == ${{ steps.dab-release.outputs.release }} + requirements_git.txt django-ansible-base pinned version == ${{ steps.dab-pinned.outputs.version }} + + ##### ISSUE TYPE + - Bug, Docs Fix or other nominal change + + ##### COMPONENT NAME + - API + + commit-message: | + Update django-ansible-base version to ${{ steps.dab-pinned.outputs.version }} + add-paths: + requirements/requirements_git.txt diff --git a/.github/workflows/devel_images.yml b/.github/workflows/devel_images.yml index dbc1a4937bee..213d90b8eca9 100644 --- a/.github/workflows/devel_images.yml +++ b/.github/workflows/devel_images.yml @@ -2,44 +2,78 @@ name: Build/Push Development Images env: LC_ALL: "C.UTF-8" # prevent ERROR: Ansible could not initialize the preferred locale: unsupported locale setting + DOCKER_CACHE: "--no-cache" # using the cache will not rebuild git requirements and other things on: + workflow_dispatch: push: branches: - devel - release_* + - feature_* + - stable-* jobs: - push: - if: endsWith(github.repository, '/awx') || startsWith(github.ref, 'refs/heads/release_') + push-development-images: runs-on: ubuntu-latest + timeout-minutes: 120 permissions: packages: write contents: read + strategy: + fail-fast: false + matrix: + build-targets: + - image-name: awx_devel + make-target: docker-compose-buildx + - image-name: awx_kube_devel + make-target: awx-kube-dev-buildx + - image-name: awx + make-target: awx-kube-buildx steps: - - uses: actions/checkout@v2 - - name: Get python version from Makefile - run: echo py_version=`make PYTHON_VERSION` >> $GITHUB_ENV + - name: Skipping build of awx image for non-awx repository + run: | + echo "Skipping build of awx image for non-awx repository" + exit 0 + if: matrix.build-targets.image-name == 'awx' && !endsWith(github.repository, '/awx') - - name: Install python ${{ env.py_version }} - uses: actions/setup-python@v2 + - uses: actions/checkout@v4 with: - python-version: ${{ env.py_version }} + show-progress: false + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Set GITHUB_ENV variables + run: | + echo "DEV_DOCKER_TAG_BASE=ghcr.io/${OWNER,,}" >> $GITHUB_ENV + echo "COMPOSE_TAG=${GITHUB_REF##*/}" >> $GITHUB_ENV + env: + OWNER: '${{ github.repository_owner }}' + + - uses: ./.github/actions/setup-python - name: Log in to registry run: | echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin - - name: Pre-pull image to warm build cache - run: | - docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${GITHUB_REF##*/} || : - docker pull ghcr.io/${{ github.repository_owner }}/awx_kube_devel:${GITHUB_REF##*/} || : + - name: Setup node and npm for the new UI build + uses: actions/setup-node@v2 + with: + node-version: '18' + if: matrix.build-targets.image-name == 'awx' - - name: Build images + - name: Prebuild new UI for awx image (to speed up build process) run: | - DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${GITHUB_REF##*/} make docker-compose-build - DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${GITHUB_REF##*/} make awx-kube-dev-build + make ui + if: matrix.build-targets.image-name == 'awx' + + - uses: ./.github/actions/setup-ssh-agent + with: + ssh-private-key: ${{ secrets.PRIVATE_GITHUB_KEY }} - - name: Push image + - name: Build and push AWX devel images run: | - docker push ghcr.io/${{ github.repository_owner }}/awx_devel:${GITHUB_REF##*/} - docker push ghcr.io/${{ github.repository_owner }}/awx_kube_devel:${GITHUB_REF##*/} + make ${{ matrix.build-targets.make-target }} diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 000000000000..ec6c9f4a4f2f --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,23 @@ +--- +name: Docsite CI +on: + pull_request: +jobs: + docsite-build: + name: docsite test build + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v4 + with: + show-progress: false + + - uses: ./.github/actions/setup-python + with: + python-version: '3.x' + + - name: install tox + run: pip install tox + + - name: Assure docs can be built + run: tox -e docs diff --git a/.github/workflows/e2e_test.yml b/.github/workflows/e2e_test.yml deleted file mode 100644 index 788042baed97..000000000000 --- a/.github/workflows/e2e_test.yml +++ /dev/null @@ -1,109 +0,0 @@ ---- -name: E2E Tests -env: - LC_ALL: "C.UTF-8" # prevent ERROR: Ansible could not initialize the preferred locale: unsupported locale setting - -on: - pull_request_target: - types: [labeled] -jobs: - e2e-test: - if: contains(github.event.pull_request.labels.*.name, 'qe:e2e') - runs-on: ubuntu-latest - timeout-minutes: 40 - permissions: - packages: write - contents: read - strategy: - matrix: - job: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24] - - steps: - - uses: actions/checkout@v2 - - - name: Get python version from Makefile - run: echo py_version=`make PYTHON_VERSION` >> $GITHUB_ENV - - - name: Install python ${{ env.py_version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ env.py_version }} - - - name: Install system deps - run: sudo apt-get install -y gettext - - - name: Log in to registry - run: | - echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin - - - name: Pre-pull image to warm build cache - run: | - docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ github.base_ref }} - - - name: Build UI - run: | - DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ github.base_ref }} make ui-devel - - - name: Start AWX - run: | - DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ github.base_ref }} make docker-compose &> make-docker-compose-output.log & - - - name: Pull awx_cypress_base image - run: | - docker pull quay.io/awx/awx_cypress_base:latest - - - name: Checkout test project - uses: actions/checkout@v2 - with: - repository: ${{ github.repository_owner }}/tower-qa - ssh-key: ${{ secrets.QA_REPO_KEY }} - path: tower-qa - ref: devel - - - name: Build cypress - run: | - cd ${{ secrets.E2E_PROJECT }}/ui-tests/awx-pf-tests - docker build -t awx-pf-tests . - - - name: Update default AWX password - run: | - while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' -k https://localhost:8043/api/v2/ping/)" != "200" ]] - do - echo "Waiting for AWX..." - sleep 5; - done - echo "AWX is up, updating the password..." - docker exec -i tools_awx_1 sh <<-EOSH - awx-manage update_password --username=admin --password=password - EOSH - - - name: Run E2E tests - env: - CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} - run: | - export COMMIT_INFO_BRANCH=$GITHUB_HEAD_REF - export COMMIT_INFO_AUTHOR=$GITHUB_ACTOR - export COMMIT_INFO_SHA=$GITHUB_SHA - export COMMIT_INFO_REMOTE=$GITHUB_REPOSITORY_OWNER - cd ${{ secrets.E2E_PROJECT }}/ui-tests/awx-pf-tests - AWX_IP=$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' tools_awx_1) - printenv > .env - echo "Executing tests:" - docker run \ - --network '_sources_default' \ - --ipc=host \ - --env-file=.env \ - -e CYPRESS_baseUrl="https://$AWX_IP:8043" \ - -e CYPRESS_AWX_E2E_USERNAME=admin \ - -e CYPRESS_AWX_E2E_PASSWORD='password' \ - -e COMMAND="npm run cypress-concurrently-gha" \ - -v /dev/shm:/dev/shm \ - -v $PWD:/e2e \ - -w /e2e \ - awx-pf-tests run --project . - - - name: Save AWX logs - uses: actions/upload-artifact@v2 - with: - name: AWX-logs-${{ matrix.job }} - path: make-docker-compose-output.log diff --git a/.github/workflows/feature_branch_deletion.yml b/.github/workflows/feature_branch_deletion.yml index 3e574b211b80..0de807aaf4f8 100644 --- a/.github/workflows/feature_branch_deletion.yml +++ b/.github/workflows/feature_branch_deletion.yml @@ -2,13 +2,12 @@ name: Feature branch deletion cleanup env: LC_ALL: "C.UTF-8" # prevent ERROR: Ansible could not initialize the preferred locale: unsupported locale setting -on: - delete: - branches: - - feature_** +on: delete jobs: - push: + branch_delete: + if: ${{ github.event.ref_type == 'branch' && startsWith(github.event.ref, 'feature_') }} runs-on: ubuntu-latest + timeout-minutes: 20 permissions: packages: write contents: read @@ -21,6 +20,4 @@ jobs: run: | ansible localhost -c local, -m command -a "{{ ansible_python_interpreter + ' -m pip install boto3'}}" ansible localhost -c local -m aws_s3 \ - -a "bucket=awx-public-ci-files object=${GITHUB_REF##*/}/schema.json mode=delete permission=public-read" - - + -a "bucket=awx-public-ci-files object=${{ github.event.repository.name }}/${GITHUB_REF##*/}/schema.json mode=delobj permission=public-read" diff --git a/.github/workflows/label_issue.yml b/.github/workflows/label_issue.yml index ead15724bbc0..952685cd5476 100644 --- a/.github/workflows/label_issue.yml +++ b/.github/workflows/label_issue.yml @@ -6,14 +6,19 @@ on: - opened - reopened +permissions: + contents: write # to fetch code + issues: write # to label issues + jobs: triage: runs-on: ubuntu-latest + timeout-minutes: 20 name: Label Issue steps: - name: Label Issue - uses: github/issue-labeler@v2.4.1 + uses: github/issue-labeler@v3.1 with: repo-token: "${{ secrets.GITHUB_TOKEN }}" not-before: 2021-12-07T07:00:00Z @@ -22,12 +27,18 @@ jobs: community: runs-on: ubuntu-latest + timeout-minutes: 20 name: Label Issue - Community steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v4 + - uses: actions/checkout@v4 + with: + show-progress: false + + - uses: ./.github/actions/setup-python + - name: Install python requests run: pip install requests + - name: Check if user is a member of Ansible org uses: jannekem/run-python-script-action@v1 id: check_user diff --git a/.github/workflows/label_pr.yml b/.github/workflows/label_pr.yml index 8e3f8b81a210..43f1e3a2915c 100644 --- a/.github/workflows/label_pr.yml +++ b/.github/workflows/label_pr.yml @@ -7,9 +7,14 @@ on: - reopened - synchronize +permissions: + contents: write # to determine modified files (actions/labeler) + pull-requests: write # to add labels to PRs (actions/labeler) + jobs: triage: runs-on: ubuntu-latest + timeout-minutes: 20 name: Label PR steps: @@ -21,10 +26,17 @@ jobs: community: runs-on: ubuntu-latest + timeout-minutes: 20 name: Label PR - Community steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v4 + - uses: actions/checkout@v4 + with: + show-progress: false + + - uses: ./.github/actions/setup-python + with: + python-version: '3.x' + - name: Install python requests run: pip install requests - name: Check if user is a member of Ansible org diff --git a/.github/workflows/pr_body_check.yml b/.github/workflows/pr_body_check.yml index 7ddcabd3d64b..9532aa87ede1 100644 --- a/.github/workflows/pr_body_check.yml +++ b/.github/workflows/pr_body_check.yml @@ -7,8 +7,10 @@ on: types: [opened, edited, reopened, synchronize] jobs: pr-check: + if: github.repository_owner == 'ansible' && endsWith(github.repository, 'awx') name: Scan PR description for semantic versioning keywords runs-on: ubuntu-latest + timeout-minutes: 20 permissions: packages: write contents: read diff --git a/.github/workflows/promote.yml b/.github/workflows/promote.yml index 6bd36f010200..ba723c07f975 100644 --- a/.github/workflows/promote.yml +++ b/.github/workflows/promote.yml @@ -7,21 +7,36 @@ env: on: release: types: [published] + workflow_dispatch: + inputs: + tag_name: + description: 'Name for the tag of the release.' + required: true +permissions: + contents: read # to fetch code (actions/checkout) jobs: promote: + if: endsWith(github.repository, '/awx') runs-on: ubuntu-latest + timeout-minutes: 90 steps: - - name: Checkout awx - uses: actions/checkout@v2 + - name: Set GitHub Env vars for workflow_dispatch event + if: ${{ github.event_name == 'workflow_dispatch' }} + run: | + echo "TAG_NAME=${{ github.event.inputs.tag_name }}" >> $GITHUB_ENV - - name: Get python version from Makefile - run: echo py_version=`make PYTHON_VERSION` >> $GITHUB_ENV + - name: Set GitHub Env vars if release event + if: ${{ github.event_name == 'release' }} + run: | + echo "TAG_NAME=${{ github.event.release.tag_name }}" >> $GITHUB_ENV - - name: Install python ${{ env.py_version }} - uses: actions/setup-python@v2 + - name: Checkout awx + uses: actions/checkout@v4 with: - python-version: ${{ env.py_version }} + show-progress: false + + - uses: ./.github/actions/setup-python - name: Install dependencies run: | @@ -36,14 +51,23 @@ jobs: if: ${{ github.repository_owner != 'ansible' }} - name: Build collection and publish to galaxy + env: + COLLECTION_NAMESPACE: ${{ env.collection_namespace }} + COLLECTION_VERSION: ${{ env.TAG_NAME }} + COLLECTION_TEMPLATE_VERSION: true run: | - COLLECTION_TEMPLATE_VERSION=true COLLECTION_NAMESPACE=${{ env.collection_namespace }} make build_collection - if [ "$(curl --head -sw '%{http_code}' https://galaxy.ansible.com/download/${{ env.collection_namespace }}-awx-${{ github.event.release.tag_name }}.tar.gz | tail -1)" == "302" ] ; then \ - echo "Galaxy release already done"; \ - else \ + sudo apt-get install jq + make build_collection + count=$(curl -s https://galaxy.ansible.com/api/v3/plugin/ansible/search/collection-versions/\?namespace\=${COLLECTION_NAMESPACE}\&name\=awx\&version\=${COLLECTION_VERSION} | jq .meta.count) + if [[ "$count" == "1" ]]; then + echo "Galaxy release already done"; + elif [[ "$count" == "0" ]]; then ansible-galaxy collection publish \ --token=${{ secrets.GALAXY_TOKEN }} \ - awx_collection_build/${{ env.collection_namespace }}-awx-${{ github.event.release.tag_name }}.tar.gz; \ + awx_collection_build/${COLLECTION_NAMESPACE}-awx-${COLLECTION_VERSION}.tar.gz; + else + echo "Unexpected count from galaxy search: $count"; + exit 1; fi - name: Set official pypi info @@ -55,9 +79,11 @@ jobs: if: ${{ github.repository_owner != 'ansible' }} - name: Build awxkit and upload to pypi + env: + SETUPTOOLS_SCM_PRETEND_VERSION: ${{ env.TAG_NAME }} run: | git reset --hard - cd awxkit && python3 setup.py bdist_wheel + cd awxkit && python3 setup.py sdist bdist_wheel twine upload \ -r ${{ env.pypi_repo }} \ -u ${{ secrets.PYPI_USERNAME }} \ @@ -74,11 +100,15 @@ jobs: - name: Re-tag and promote awx image run: | - docker pull ghcr.io/${{ github.repository }}:${{ github.event.release.tag_name }} - docker tag ghcr.io/${{ github.repository }}:${{ github.event.release.tag_name }} quay.io/${{ github.repository }}:${{ github.event.release.tag_name }} - docker tag ghcr.io/${{ github.repository }}:${{ github.event.release.tag_name }} quay.io/${{ github.repository }}:latest - docker push quay.io/${{ github.repository }}:${{ github.event.release.tag_name }} - docker push quay.io/${{ github.repository }}:latest - docker pull ghcr.io/${{ github.repository_owner }}/awx-ee:${{ github.event.release.tag_name }} - docker tag ghcr.io/${{ github.repository_owner }}/awx-ee:${{ github.event.release.tag_name }} quay.io/${{ github.repository_owner }}/awx-ee:${{ github.event.release.tag_name }} - docker push quay.io/${{ github.repository_owner }}/awx-ee:${{ github.event.release.tag_name }} + docker buildx imagetools create \ + ghcr.io/${{ github.repository }}:${{ env.TAG_NAME }} \ + --tag quay.io/${{ github.repository }}:${{ env.TAG_NAME }} + docker buildx imagetools create \ + ghcr.io/${{ github.repository }}:${{ env.TAG_NAME }} \ + --tag quay.io/${{ github.repository }}:latest + + - name: Re-tag and promote awx-ee image + run: | + docker buildx imagetools create \ + ghcr.io/${{ github.repository_owner }}/awx-ee:${{ env.TAG_NAME }} \ + --tag quay.io/${{ github.repository_owner }}/awx-ee:${{ env.TAG_NAME }} diff --git a/.github/workflows/sonarcloud_pr.yml b/.github/workflows/sonarcloud_pr.yml new file mode 100644 index 000000000000..380118d7b5c4 --- /dev/null +++ b/.github/workflows/sonarcloud_pr.yml @@ -0,0 +1,248 @@ +# SonarCloud Analysis Workflow for awx +# +# This workflow runs SonarCloud analysis triggered by CI workflow completion. +# It is split into two separate jobs for clarity and maintainability: +# +# FLOW: CI completes → workflow_run triggers this workflow → appropriate job runs +# +# JOB 1: sonar-pr-analysis (for PRs) +# - Triggered by: workflow_run (CI on pull_request) +# - Steps: Download coverage → Get PR info → Get changed files → Run SonarCloud PR analysis +# - Scans: All changed files in the PR (Python, YAML, JSON, etc.) +# - Quality gate: Focuses on new/changed code in PR only +# +# JOB 2: sonar-branch-analysis (for long-lived branches) +# - Triggered by: workflow_run (CI on push to devel) +# - Steps: Download coverage → Run SonarCloud branch analysis +# - Scans: Full codebase +# - Quality gate: Focuses on overall project health +# +# This ensures coverage data is always available from CI before analysis runs. +# +# What files are scanned: +# - All files in the repository that SonarCloud can analyze +# - Excludes: tests, scripts, dev environments, external collections (see sonar-project.properties) + + +# With much help from: +# https://community.sonarsource.com/t/how-to-use-sonarcloud-with-a-forked-repository-on-github/7363/30 +# https://community.sonarsource.com/t/how-to-use-sonarcloud-with-a-forked-repository-on-github/7363/32 +name: SonarCloud +on: + workflow_run: # This is triggered by CI being completed. + workflows: + - CI + types: + - completed +permissions: read-all +jobs: + sonar-pr-analysis: + name: SonarCloud PR Analysis + runs-on: ubuntu-latest + if: | + github.event.workflow_run.conclusion == 'success' && + github.event.workflow_run.event == 'pull_request' && + github.repository == 'ansible/awx' + steps: + - uses: actions/checkout@v4 + + # Download all individual coverage artifacts from CI workflow + - name: Download coverage artifacts + uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + workflow: CI + run_id: ${{ github.event.workflow_run.id }} + pattern: api-test-artifacts + + # Extract PR metadata from workflow_run event + - name: Set PR metadata and prepare files for analysis + env: + COMMIT_SHA: ${{ github.event.workflow_run.head_sha }} + REPO_NAME: ${{ github.event.repository.full_name }} + HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + # Find all downloaded coverage XML files + coverage_files=$(find . -name "coverage.xml" -type f | tr '\n' ',' | sed 's/,$//') + echo "Found coverage files: $coverage_files" + echo "COVERAGE_PATHS=$coverage_files" >> $GITHUB_ENV + + # Extract PR number from first coverage.xml file found + first_coverage=$(find . -name "coverage.xml" -type f | head -1) + if [ -f "$first_coverage" ]; then + PR_NUMBER=$(grep -m 1 ' host_id + # so we can associate emitted events to Host objects + self.runner_callback.host_map[hostname] = hv.get('remote_tower_id', '') + file_content = '#! /usr/bin/env python3\n# -*- coding: utf-8 -*-\nprint(%r)\n' % json.dumps(script_data) + return self.write_private_data_file(private_data_dir, file_name, file_content, sub_dir='inventory', file_permissions=0o700) + def build_inventory(self, instance, private_data_dir): script_params = dict(hostvars=True, towervars=True) if hasattr(instance, 'job_slice_number'): script_params['slice_number'] = instance.job_slice_number script_params['slice_count'] = instance.job_slice_count - script_data = instance.inventory.get_script_data(**script_params) - # maintain a list of host_name --> host_id - # so we can associate emitted events to Host objects - self.runner_callback.host_map = {hostname: hv.pop('remote_tower_id', '') for hostname, hv in script_data.get('_meta', {}).get('hostvars', {}).items()} - file_content = '#! /usr/bin/env python3\n# -*- coding: utf-8 -*-\nprint(%r)\n' % json.dumps(script_data) - return self.write_private_data_file(private_data_dir, 'hosts', file_content, sub_dir='inventory', file_permissions=0o700) + + return self.write_inventory_file(instance.inventory, private_data_dir, 'hosts', script_params) def build_args(self, instance, private_data_dir, passwords): raise NotImplementedError @@ -399,7 +505,7 @@ def acquire_lock(self, project, unified_job_id=None): except IOError as e: if e.errno not in (errno.EAGAIN, errno.EACCES): os.close(self.lock_fd) - logger.error("I/O error({0}) while trying to aquire lock on file [{1}]: {2}".format(e.errno, lock_path, e.strerror)) + logger.error("I/O error({0}) while trying to acquire lock on file [{1}]: {2}".format(e.errno, lock_path, e.strerror)) raise else: if not emitted_lockfile_log: @@ -435,20 +541,40 @@ def final_run_hook(self, instance, status, private_data_dir): Hook for any steps to run after job/task is marked as complete. """ instance.log_lifecycle("finalize_run") - artifact_dir = os.path.join(private_data_dir, 'artifacts', str(self.instance.id)) - collections_info = os.path.join(artifact_dir, 'collections.json') - ansible_version_file = os.path.join(artifact_dir, 'ansible_version.txt') - - if os.path.exists(collections_info): - with open(collections_info) as ee_json_info: - ee_collections_info = json.loads(ee_json_info.read()) - instance.installed_collections = ee_collections_info - instance.save(update_fields=['installed_collections']) - if os.path.exists(ansible_version_file): - with open(ansible_version_file) as ee_ansible_info: - ansible_version_info = ee_ansible_info.readline() - instance.ansible_version = ansible_version_info - instance.save(update_fields=['ansible_version']) + + # Run task manager appropriately for speculative dependencies + if instance.unifiedjob_blocked_jobs.exists(): + ScheduleTaskManager().schedule() + if instance.spawned_by_workflow: + ScheduleWorkflowManager().schedule() + + def should_use_fact_cache(self): + return False + + def transition_status(self, pk: int) -> bool: + """Atomically transition status to running, if False returned, another process got it""" + with transaction.atomic(): + # Explanation of parts for the fetch: + # .values - avoid loading a full object, this is known to lead to deadlocks due to signals + # the signals load other related rows which another process may be locking, and happens in practice + # of=('self',) - keeps FK tables out of the lock list, another way deadlocks can happen + # .get - just load the single job + instance_data = UnifiedJob.objects.select_for_update(of=('self',)).values('status', 'cancel_flag').get(pk=pk) + + # If status is not waiting (obtained under lock) then this process does not have clearence to run + if instance_data['status'] == 'waiting': + if instance_data['cancel_flag']: + updated_status = 'canceled' + else: + updated_status = 'running' + # Explanation of the update: + # .filter - again, do not load the full object + # .update - a bulk update on just that one row, avoid loading unintended data + UnifiedJob.objects.filter(pk=pk).update(status=updated_status, start_args='') + elif instance_data['status'] == 'running': + logger.info(f'Job {pk} is being ran by another process, exiting') + return False + return True @with_path_cleanup @with_signal_handling @@ -456,21 +582,17 @@ def run(self, pk, **kwargs): """ Run the job/task and capture its output. """ - self.instance = self.model.objects.get(pk=pk) - if self.instance.status != 'canceled' and self.instance.cancel_flag: - self.instance = self.update_model(self.instance.pk, start_args='', status='canceled') - if self.instance.status not in ACTIVE_STATES: - # Prevent starting the job if it has been reaped or handled by another process. - raise RuntimeError(f'Not starting {self.instance.status} task pk={pk} because {self.instance.status} is not a valid active state') - - if self.instance.execution_environment_id is None: - from awx.main.signals import disable_activity_stream + if not self.instance: # Used to skip fetch for local runs + if not self.transition_status(pk): + logger.info(f'Job {pk} is being ran by another process, exiting') + return - with disable_activity_stream(): - self.instance = self.update_model(self.instance.pk, execution_environment=self.instance.resolve_execution_environment()) + # Load the instance + self.instance = self.update_model(pk) + if self.instance.status != 'running': + logger.error(f'Not starting {self.instance.status} task pk={pk} because its status "{self.instance.status}" is not expected') + return - # self.instance because of the update_model pattern and when it's used in callback handlers - self.instance = self.update_model(pk, status='running', start_args='') # blank field to remove encrypted passwords self.instance.websocket_emit_status("running") status, rc = 'error', None self.runner_callback.event_ct = 0 @@ -483,12 +605,20 @@ def run(self, pk, **kwargs): private_data_dir = None try: + if self.instance.execution_environment_id is None: + from awx.main.signals import disable_activity_stream + + with disable_activity_stream(): + self.instance = self.update_model(self.instance.pk, execution_environment=self.instance.resolve_execution_environment()) + self.instance.send_notification_templates("running") private_data_dir = self.build_private_data_dir(self.instance) self.pre_run_hook(self.instance, private_data_dir) + evaluate_policy(self.instance) self.build_project_dir(self.instance, private_data_dir) self.instance.log_lifecycle("preparing_playbook") if self.instance.cancel_flag or signal_callback(): + logger.debug(f'detected pre-run cancel flag for {self.instance.log_format}') self.instance = self.update_model(self.instance.pk, status='canceled') if self.instance.status != 'running': @@ -520,9 +650,13 @@ def run(self, pk, **kwargs): credentials = self.build_credentials_list(self.instance) + container_root = None + if settings.IS_K8S and isinstance(self.instance, ProjectUpdate): + container_root = private_data_dir + for credential in credentials: if credential: - credential.credential_type.inject_credential(credential, env, self.safe_cred_env, args, private_data_dir) + credential.credential_type.inject_credential(credential, env, self.safe_cred_env, args, private_data_dir, container_root=container_root) self.runner_callback.safe_env.update(self.safe_cred_env) @@ -548,7 +682,8 @@ def run(self, pk, **kwargs): params['module'] = self.build_module_name(self.instance) params['module_args'] = self.build_module_args(self.instance) - if getattr(self.instance, 'use_fact_cache', False): + # TODO: refactor into a better BasTask method + if self.should_use_fact_cache(): # Enable Ansible fact cache. params['fact_cache_type'] = 'jsonfile' else: @@ -606,12 +741,11 @@ def run(self, pk, **kwargs): elif status == 'canceled': self.instance = self.update_model(pk) cancel_flag_value = getattr(self.instance, 'cancel_flag', False) - if (cancel_flag_value is False) and signal_callback(): + if cancel_flag_value is False: self.runner_callback.delay_update(skip_if_already_set=True, job_explanation="Task was canceled due to receiving a shutdown signal.") status = 'failed' - elif cancel_flag_value is False: - self.runner_callback.delay_update(skip_if_already_set=True, job_explanation="The running ansible process received a shutdown signal.") - status = 'failed' + except PolicyEvaluationError as exc: + self.runner_callback.delay_update(job_explanation=str(exc), result_traceback=str(exc)) except ReceptorNodeNotFound as exc: self.runner_callback.delay_update(job_explanation=str(exc)) except Exception: @@ -637,8 +771,11 @@ def run(self, pk, **kwargs): # Field host_status_counts is used as a metric to check if event processing is finished # we send notifications if it is, if not, callback receiver will send them + if not self.instance: + logger.error(f'Unified job pk={pk} appears to be deleted while running') + return if (self.instance.host_status_counts is not None) or (not self.runner_callback.wrapup_event_dispatched): - self.instance.send_notification_templates('succeeded' if status == 'successful' else 'failed') + events_processed_hook(self.instance) try: self.final_run_hook(self.instance, status, private_data_dir) @@ -686,6 +823,7 @@ def get_sync_needs(self, project, scm_branch=None): logger.debug(f'Project not available locally, {self.instance.id} will sync with remote') sync_needs.append(source_update_tag) + # Determine whether or not this project sync needs to populate the cache for Ansible content, roles and collections has_cache = os.path.exists(os.path.join(project.get_cache_path(), project.cache_id)) # Galaxy requirements are not supported for manual projects if project.scm_type and ((not has_cache) or branch_override): @@ -732,6 +870,7 @@ def sync_and_copy_without_lock(self, project, private_data_dir, scm_branch=None) try: # the job private_data_dir is passed so sync can download roles and collections there sync_task = RunProjectUpdate(job_private_data_dir=private_data_dir) + sync_task.instance = local_project_sync # avoids "waiting" status check, performance sync_task.run(local_project_sync.id) local_project_sync.refresh_from_db() self.instance = self.update_model(self.instance.pk, scm_revision=local_project_sync.scm_revision) @@ -759,7 +898,7 @@ def sync_and_copy_without_lock(self, project, private_data_dir, scm_branch=None) def sync_and_copy(self, project, private_data_dir, scm_branch=None): self.acquire_lock(project, self.instance.id) - + is_commit = False try: original_branch = None failed_reason = project.get_reason_if_failed() @@ -771,6 +910,7 @@ def sync_and_copy(self, project, private_data_dir, scm_branch=None): if os.path.exists(project_path): git_repo = git.Repo(project_path) if git_repo.head.is_detached: + is_commit = True original_branch = git_repo.head.commit else: original_branch = git_repo.active_branch @@ -782,7 +922,11 @@ def sync_and_copy(self, project, private_data_dir, scm_branch=None): # for git project syncs, non-default branches can be problems # restore to branch the repo was on before this run try: - original_branch.checkout() + if is_commit: + git_repo.head.set_commit(original_branch) + git_repo.head.reset(index=True, working_tree=True) + else: + original_branch.checkout() except Exception: # this could have failed due to dirty tree, but difficult to predict all cases logger.exception(f'Failed to restore project repo to prior state after {self.instance.id}') @@ -790,7 +934,7 @@ def sync_and_copy(self, project, private_data_dir, scm_branch=None): self.release_lock(project) -@task(queue=get_local_queuename) +@task(queue=get_task_queuename) class RunJob(SourceControlMixin, BaseTask): """ Run a job using ansible-playbook. @@ -892,7 +1036,7 @@ def build_env(self, job, private_data_dir, private_data_files=None): cred_files = private_data_files.get('credentials', {}) for cloud_cred in job.cloud_credentials: if cloud_cred and cloud_cred.credential_type.namespace == 'openstack' and cred_files.get(cloud_cred, ''): - env['OS_CLIENT_CONFIG_FILE'] = to_container_path(cred_files.get(cloud_cred, ''), private_data_dir) + env['OS_CLIENT_CONFIG_FILE'] = get_incontainer_path(cred_files.get(cloud_cred, ''), private_data_dir) for network_cred in job.network_credentials: env['ANSIBLE_NET_USERNAME'] = network_cred.get_input('username', default='') @@ -907,10 +1051,15 @@ def build_env(self, job, private_data_dir, private_data_files=None): if authorize: env['ANSIBLE_NET_AUTH_PASS'] = network_cred.get_input('authorize_password', default='') - path_vars = ( - ('ANSIBLE_COLLECTIONS_PATHS', 'collections_paths', 'requirements_collections', '~/.ansible/collections:/usr/share/ansible/collections'), + path_vars = [ ('ANSIBLE_ROLES_PATH', 'roles_path', 'requirements_roles', '~/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles'), - ) + ('ANSIBLE_COLLECTIONS_PATH', 'collections_path', 'requirements_collections', '~/.ansible/collections:/usr/share/ansible/collections'), + ] + + if flag_enabled("FEATURE_INDIRECT_NODE_COUNTING_ENABLED"): + path_vars.append( + ('ANSIBLE_CALLBACK_PLUGINS', 'callback_plugins', 'plugins_path', '~/.ansible/plugins:/plugins/callback:/usr/share/ansible/plugins/callback'), + ) config_values = read_ansible_config(os.path.join(private_data_dir, 'project'), list(map(lambda x: x[1], path_vars))) @@ -927,6 +1076,11 @@ def build_env(self, job, private_data_dir, private_data_files=None): paths = [os.path.join(CONTAINER_ROOT, folder)] + paths env[env_key] = os.pathsep.join(paths) + if flag_enabled("FEATURE_INDIRECT_NODE_COUNTING_ENABLED"): + env['ANSIBLE_CALLBACKS_ENABLED'] = 'indirect_instance_count' + if 'callbacks_enabled' in config_values: + env['ANSIBLE_CALLBACKS_ENABLED'] += ':' + config_values['callbacks_enabled'] + return env def build_args(self, job, private_data_dir, passwords): @@ -998,6 +1152,9 @@ def build_args(self, job, private_data_dir, passwords): return args + def should_use_fact_cache(self): + return self.instance.use_fact_cache + def build_playbook_path_relative_to_cwd(self, job, private_data_dir): return job.playbook @@ -1063,8 +1220,11 @@ def pre_run_hook(self, job, private_data_dir): # Fetch "cached" fact data from prior runs and put on the disk # where ansible expects to find it - if job.use_fact_cache: - self.facts_write_time = self.instance.start_job_fact_cache(os.path.join(private_data_dir, 'artifacts', str(job.id), 'fact_cache')) + if self.should_use_fact_cache(): + job.log_lifecycle("start_job_fact_cache") + self.hosts_with_facts_cached = start_fact_cache( + job.get_hosts_for_fact_cache(), artifacts_dir=os.path.join(private_data_dir, 'artifacts', str(job.id)), inventory_id=job.inventory_id + ) def build_project_dir(self, job, private_data_dir): self.sync_and_copy(job.project, private_data_dir, scm_branch=job.scm_branch) @@ -1073,15 +1233,17 @@ def post_run_hook(self, job, status): super(RunJob, self).post_run_hook(job, status) job.refresh_from_db(fields=['job_env']) private_data_dir = job.job_env.get('AWX_PRIVATE_DATA_DIR') - if (not private_data_dir) or (not hasattr(self, 'facts_write_time')): + if not private_data_dir: # If there's no private data dir, that means we didn't get into the # actual `run()` call; this _usually_ means something failed in # the pre_run_hook method return - if job.use_fact_cache: - job.finish_job_fact_cache( - os.path.join(private_data_dir, 'artifacts', str(job.id), 'fact_cache'), - self.facts_write_time, + if self.should_use_fact_cache() and self.runner_callback.artifacts_processed: + job.log_lifecycle("finish_job_fact_cache") + finish_fact_cache( + artifacts_dir=os.path.join(private_data_dir, 'artifacts', str(job.id)), + job_id=job.id, + inventory_id=job.inventory_id, ) def final_run_hook(self, job, status, private_data_dir): @@ -1095,7 +1257,7 @@ def final_run_hook(self, job, status, private_data_dir): update_inventory_computed_fields.delay(inventory.id) -@task(queue=get_local_queuename) +@task(queue=get_task_queuename) class RunProjectUpdate(BaseTask): model = ProjectUpdate event_model = ProjectUpdateEvent @@ -1242,7 +1404,7 @@ def build_extra_vars_file(self, project_update, private_data_dir): galaxy_creds_are_defined = project_update.project.organization and project_update.project.organization.galaxy_credentials.exists() if not galaxy_creds_are_defined and (settings.AWX_ROLES_ENABLED or settings.AWX_COLLECTIONS_ENABLED): - logger.warning('Galaxy role/collection syncing is enabled, but no ' f'credentials are configured for {project_update.project.organization}.') + logger.warning(f'Galaxy role/collection syncing is enabled, but no credentials are configured for {project_update.project.organization}.') extra_vars.update( { @@ -1266,7 +1428,7 @@ def build_extra_vars_file(self, project_update, private_data_dir): extra_vars['scm_refspec'] = project_update.scm_refspec elif project_update.project.allow_override: # If branch is override-able, do extra fetch for all branches - extra_vars['scm_refspec'] = 'refs/heads/*:refs/remotes/origin/*' + extra_vars['scm_refspec'] = '+refs/heads/*:refs/remotes/origin/*' if project_update.scm_type == 'archive': # for raw archive, prevent error moving files between volumes @@ -1356,6 +1518,17 @@ def make_local_copy(project, job_private_data_dir): shutil.copytree(cache_subpath, dest_subpath, symlinks=True) logger.debug('{0} {1} prepared {2} from cache'.format(type(project).__name__, project.pk, dest_subpath)) + if flag_enabled("FEATURE_INDIRECT_NODE_COUNTING_ENABLED"): + # copy the special callback (not stdout type) plugin to get list of collections + pdd_plugins_path = os.path.join(job_private_data_dir, 'plugins_path') + if not os.path.exists(pdd_plugins_path): + os.mkdir(pdd_plugins_path) + from awx.playbooks import library + + plugin_file_source = os.path.join(library.__path__._path[0], 'indirect_instance_count.py') + plugin_file_dest = os.path.join(pdd_plugins_path, 'indirect_instance_count.py') + shutil.copyfile(plugin_file_source, plugin_file_dest) + def post_run_hook(self, instance, status): super(RunProjectUpdate, self).post_run_hook(instance, status) # To avoid hangs, very important to release lock even if errors happen here @@ -1416,8 +1589,13 @@ def build_execution_environment_params(self, instance, private_data_dir): ) return params + def build_credentials_list(self, project_update): + if project_update.scm_type == 'insights' and project_update.credential: + return [project_update.credential] + return [] + -@task(queue=get_local_queuename) +@task(queue=get_task_queuename) class RunInventoryUpdate(SourceControlMixin, BaseTask): model = InventoryUpdate event_model = InventoryUpdateEvent @@ -1464,8 +1642,6 @@ def build_env(self, inventory_update, private_data_dir, private_data_files=None) if injector is not None: env = injector.build_env(inventory_update, env, private_data_dir, private_data_files) - # All CLOUD_PROVIDERS sources implement as inventory plugin from collection - env['ANSIBLE_INVENTORY_ENABLED'] = 'auto' if inventory_update.source == 'scm': for env_k in inventory_update.source_vars_dict: @@ -1475,7 +1651,7 @@ def build_env(self, inventory_update, private_data_dir, private_data_files=None) raise NotImplementedError('Cannot update file sources through the task system.') if inventory_update.source == 'scm' and inventory_update.source_project_update: - env_key = 'ANSIBLE_COLLECTIONS_PATHS' + env_key = 'ANSIBLE_COLLECTIONS_PATH' config_setting = 'collections_paths' folder = 'requirements_collections' default = '~/.ansible/collections:/usr/share/ansible/collections' @@ -1493,12 +1669,12 @@ def build_env(self, inventory_update, private_data_dir, private_data_files=None) paths = [config_values[config_setting]] + paths paths = [os.path.join(CONTAINER_ROOT, folder)] + paths env[env_key] = os.pathsep.join(paths) - if 'ANSIBLE_COLLECTIONS_PATHS' in env: - paths = env['ANSIBLE_COLLECTIONS_PATHS'].split(':') + if 'ANSIBLE_COLLECTIONS_PATH' in env: + paths = env['ANSIBLE_COLLECTIONS_PATH'].split(':') else: paths = ['~/.ansible/collections', '/usr/share/ansible/collections'] paths.append('/usr/share/automation-controller/collections') - env['ANSIBLE_COLLECTIONS_PATHS'] = os.pathsep.join(paths) + env['ANSIBLE_COLLECTIONS_PATH'] = os.pathsep.join(paths) return env @@ -1518,6 +1694,22 @@ def build_args(self, inventory_update, private_data_dir, passwords): args = ['ansible-inventory', '--list', '--export'] + # special case for constructed inventories, we pass source inventories from database + # these must come in order, and in order _before_ the constructed inventory itself + if inventory_update.inventory.kind == 'constructed': + inventory_update.log_lifecycle("start_job_fact_cache") + for input_inventory in inventory_update.inventory.input_inventories.all(): + args.append('-i') + script_params = dict(hostvars=True, towervars=True) + source_inv_path = self.write_inventory_file(input_inventory, private_data_dir, f'hosts_{input_inventory.id}', script_params) + args.append(get_incontainer_path(source_inv_path, private_data_dir)) + # Include any facts from input inventories so they can be used in filters + start_fact_cache( + input_inventory.hosts.only(*HOST_FACTS_FIELDS), + artifacts_dir=os.path.join(private_data_dir, 'artifacts', str(inventory_update.id)), + inventory_id=input_inventory.id, + ) + # Add arguments for the source inventory file/script/thing rel_path = self.pseudo_build_inventory(inventory_update, private_data_dir) container_location = os.path.join(CONTAINER_ROOT, rel_path) @@ -1525,6 +1717,11 @@ def build_args(self, inventory_update, private_data_dir, passwords): args.append('-i') args.append(container_location) + # Added this in order to allow older versions of ansible-inventory https://github.com/ansible/ansible/pull/79596 + # limit should be usable in ansible-inventory 2.15+ + if inventory_update.limit: + args.append('--limit') + args.append(inventory_update.limit) args.append('--output') args.append(os.path.join(CONTAINER_ROOT, 'artifacts', str(inventory_update.id), 'output.json')) @@ -1540,6 +1737,9 @@ def build_args(self, inventory_update, private_data_dir, passwords): return args + def should_use_fact_cache(self): + return bool(self.instance.source == 'constructed') + def build_inventory(self, inventory_update, private_data_dir): return None # what runner expects in order to not deal with inventory @@ -1581,7 +1781,7 @@ def build_project_dir(self, inventory_update, private_data_dir): if inventory_update.source == 'scm': if not source_project: raise RuntimeError('Could not find project to run SCM inventory update from.') - self.sync_and_copy(source_project, private_data_dir) + self.sync_and_copy(source_project, private_data_dir, scm_branch=inventory_update.inventory_source.scm_branch) else: # If source is not SCM make an empty project directory, content is built inside inventory folder super(RunInventoryUpdate, self).build_project_dir(inventory_update, private_data_dir) @@ -1658,7 +1858,7 @@ def post_run_hook(self, inventory_update, status): raise PostRunError('Error occured while saving inventory data, see traceback or server logs', status='error', tb=traceback.format_exc()) -@task(queue=get_local_queuename) +@task(queue=get_task_queuename) class RunAdHocCommand(BaseTask): """ Run an ad hoc command using ansible. @@ -1811,7 +2011,7 @@ def get_password_prompts(self, passwords={}): return d -@task(queue=get_local_queuename) +@task(queue=get_task_queuename) class RunSystemJob(BaseTask): model = SystemJob event_model = SystemJobEvent @@ -1831,6 +2031,8 @@ def build_args(self, system_job, private_data_dir, passwords): if system_job.job_type in ('cleanup_jobs', 'cleanup_activitystream'): if 'days' in json_vars: args.extend(['--days', str(json_vars.get('days', 60))]) + if 'batch_size' in json_vars: + args.extend(['--batch-size', str(json_vars['batch_size'])]) if 'dry_run' in json_vars and json_vars['dry_run']: args.extend(['--dry-run']) if system_job.job_type == 'cleanup_jobs': diff --git a/awx/main/tasks/policy.py b/awx/main/tasks/policy.py new file mode 100644 index 000000000000..e629e919bbdb --- /dev/null +++ b/awx/main/tasks/policy.py @@ -0,0 +1,457 @@ +import json +import tempfile +import contextlib + +from pprint import pformat + +from typing import Optional, Union + +from django.conf import settings +from django.utils.translation import gettext_lazy as _ +from opa_client import OpaClient +from opa_client.base import BaseClient +from requests import HTTPError +from rest_framework import serializers +from rest_framework import fields + +from awx.main import models +from awx.main.exceptions import PolicyEvaluationError + +# Monkey patching opa_client.base.BaseClient to fix retries and timeout settings +_original_opa_base_client_init = BaseClient.__init__ + + +def _opa_base_client_init_fix( + self, + host: str = "localhost", + port: int = 8181, + version: str = "v1", + ssl: bool = False, + cert: Optional[Union[str, tuple]] = None, + headers: Optional[dict] = None, + retries: int = 2, + timeout: float = 1.5, +): + _original_opa_base_client_init(self, host, port, version, ssl, cert, headers) + self.retries = retries + self.timeout = timeout + + +BaseClient.__init__ = _opa_base_client_init_fix + + +class _TeamSerializer(serializers.ModelSerializer): + class Meta: + model = models.Team + fields = ('id', 'name') + + +class _UserSerializer(serializers.ModelSerializer): + teams = serializers.SerializerMethodField() + + class Meta: + model = models.User + fields = ('id', 'username', 'is_superuser', 'teams') + + def get_teams(self, user: models.User): + teams = models.Team.access_qs(user, 'member') + return _TeamSerializer(many=True).to_representation(teams) + + +class _ExecutionEnvironmentSerializer(serializers.ModelSerializer): + class Meta: + model = models.ExecutionEnvironment + fields = ( + 'id', + 'name', + 'image', + 'pull', + ) + + +class _InstanceGroupSerializer(serializers.ModelSerializer): + class Meta: + model = models.InstanceGroup + fields = ( + 'id', + 'name', + 'capacity', + 'jobs_running', + 'jobs_total', + 'max_concurrent_jobs', + 'max_forks', + ) + + +class _InventorySourceSerializer(serializers.ModelSerializer): + class Meta: + model = models.InventorySource + fields = ('id', 'name', 'source', 'status') + + +class _InventorySerializer(serializers.ModelSerializer): + inventory_sources = _InventorySourceSerializer(many=True) + + class Meta: + model = models.Inventory + fields = ( + 'id', + 'name', + 'description', + 'kind', + 'total_hosts', + 'total_groups', + 'has_inventory_sources', + 'total_inventory_sources', + 'has_active_failures', + 'hosts_with_active_failures', + 'inventory_sources', + ) + + +class _JobTemplateSerializer(serializers.ModelSerializer): + class Meta: + model = models.JobTemplate + fields = ( + 'id', + 'name', + 'job_type', + ) + + +class _WorkflowJobTemplateSerializer(serializers.ModelSerializer): + class Meta: + model = models.WorkflowJobTemplate + fields = ( + 'id', + 'name', + 'job_type', + ) + + +class _WorkflowJobSerializer(serializers.ModelSerializer): + class Meta: + model = models.WorkflowJob + fields = ( + 'id', + 'name', + ) + + +class _OrganizationSerializer(serializers.ModelSerializer): + class Meta: + model = models.Organization + fields = ( + 'id', + 'name', + ) + + +class _ProjectSerializer(serializers.ModelSerializer): + class Meta: + model = models.Project + fields = ( + 'id', + 'name', + 'status', + 'scm_type', + 'scm_url', + 'scm_branch', + 'scm_refspec', + 'scm_clean', + 'scm_track_submodules', + 'scm_delete_on_update', + ) + + +class _CredentialSerializer(serializers.ModelSerializer): + organization = _OrganizationSerializer() + + class Meta: + model = models.Credential + fields = ( + 'id', + 'name', + 'description', + 'organization', + 'credential_type', + 'managed', + 'kind', + 'cloud', + 'kubernetes', + ) + + +class _LabelSerializer(serializers.ModelSerializer): + organization = _OrganizationSerializer() + + class Meta: + model = models.Label + fields = ('id', 'name', 'organization') + + +class JobSerializer(serializers.ModelSerializer): + created_by = _UserSerializer() + credentials = _CredentialSerializer(many=True) + execution_environment = _ExecutionEnvironmentSerializer() + instance_group = _InstanceGroupSerializer() + inventory = _InventorySerializer() + job_template = _JobTemplateSerializer() + labels = _LabelSerializer(many=True) + organization = _OrganizationSerializer() + project = _ProjectSerializer() + extra_vars = fields.SerializerMethodField() + hosts_count = fields.SerializerMethodField() + workflow_job = fields.SerializerMethodField() + workflow_job_template = fields.SerializerMethodField() + + class Meta: + model = models.Job + fields = ( + 'id', + 'name', + 'created', + 'created_by', + 'credentials', + 'execution_environment', + 'extra_vars', + 'forks', + 'hosts_count', + 'instance_group', + 'inventory', + 'job_template', + 'job_type', + 'job_type_name', + 'labels', + 'launch_type', + 'limit', + 'launched_by', + 'organization', + 'playbook', + 'project', + 'scm_branch', + 'scm_revision', + 'workflow_job', + 'workflow_job_template', + ) + + def get_extra_vars(self, obj: models.Job): + return json.loads(obj.display_extra_vars()) + + def get_hosts_count(self, obj: models.Job): + return obj.hosts.count() + + def get_workflow_job(self, obj: models.Job): + workflow_job: models.WorkflowJob = obj.get_workflow_job() + if workflow_job is None: + return None + return _WorkflowJobSerializer().to_representation(workflow_job) + + def get_workflow_job_template(self, obj: models.Job): + workflow_job: models.WorkflowJob = obj.get_workflow_job() + if workflow_job is None: + return None + + workflow_job_template: models.WorkflowJobTemplate = workflow_job.workflow_job_template + if workflow_job_template is None: + return None + + return _WorkflowJobTemplateSerializer().to_representation(workflow_job_template) + + +class OPAResultSerializer(serializers.Serializer): + allowed = fields.BooleanField(required=True) + violations = fields.ListField(child=fields.CharField()) + + +class OPA_AUTH_TYPES: + NONE = 'None' + TOKEN = 'Token' + CERTIFICATE = 'Certificate' + + +@contextlib.contextmanager +def opa_cert_file(): + """ + Context manager that creates temporary certificate files for OPA authentication. + + For mTLS (mutual TLS), we need: + - Client certificate and key for client authentication + - CA certificate (optional) for server verification + + Returns: + tuple: (client_cert_path, verify_path) + - client_cert_path: Path to client cert file or None if not using client cert + - verify_path: Path to CA cert file, True to use system CA store, or False for no verification + """ + client_cert_temp = None + ca_temp = None + + try: + # Case 1: Full mTLS with client cert and optional CA cert + if settings.OPA_AUTH_TYPE == OPA_AUTH_TYPES.CERTIFICATE: + # Create client certificate file (required for mTLS) + client_cert_temp = tempfile.NamedTemporaryFile(delete=True, mode='w', suffix=".pem") + client_cert_temp.write(settings.OPA_AUTH_CLIENT_CERT) + client_cert_temp.write("\n") + client_cert_temp.write(settings.OPA_AUTH_CLIENT_KEY) + client_cert_temp.write("\n") + client_cert_temp.flush() + + # If CA cert is provided, use it for server verification + # Otherwise, use system CA store (True) + if settings.OPA_AUTH_CA_CERT: + ca_temp = tempfile.NamedTemporaryFile(delete=True, mode='w', suffix=".pem") + ca_temp.write(settings.OPA_AUTH_CA_CERT) + ca_temp.write("\n") + ca_temp.flush() + verify_path = ca_temp.name + else: + verify_path = True # Use system CA store + + yield (client_cert_temp.name, verify_path) + + # Case 2: TLS with only server verification (no client cert) + elif settings.OPA_SSL: + # If CA cert is provided, use it for server verification + # Otherwise, use system CA store (True) + if settings.OPA_AUTH_CA_CERT: + ca_temp = tempfile.NamedTemporaryFile(delete=True, mode='w', suffix=".pem") + ca_temp.write(settings.OPA_AUTH_CA_CERT) + ca_temp.write("\n") + ca_temp.flush() + verify_path = ca_temp.name + else: + verify_path = True # Use system CA store + + yield (None, verify_path) + + # Case 3: No TLS + else: + yield (None, False) + + finally: + # Clean up temporary files + if client_cert_temp: + client_cert_temp.close() + if ca_temp: + ca_temp.close() + + +@contextlib.contextmanager +def opa_client(headers=None): + with opa_cert_file() as cert_files: + cert, verify = cert_files + + with OpaClient( + host=settings.OPA_HOST, + port=settings.OPA_PORT, + headers=headers, + ssl=settings.OPA_SSL, + cert=cert, + timeout=settings.OPA_REQUEST_TIMEOUT, + retries=settings.OPA_REQUEST_RETRIES, + ) as client: + # Workaround for https://github.com/Turall/OPA-python-client/issues/32 + # by directly setting cert and verify on requests.session + client._session.cert = cert + client._session.verify = verify + + yield client + + +def evaluate_policy(instance): + # Policy evaluation for Policy as Code feature + if not settings.OPA_HOST: + return + + if not isinstance(instance, models.Job): + return + + instance.log_lifecycle("evaluate_policy") + + input_data = JobSerializer(instance=instance).data + + headers = settings.OPA_AUTH_CUSTOM_HEADERS + if settings.OPA_AUTH_TYPE == OPA_AUTH_TYPES.TOKEN: + headers.update({'Authorization': 'Bearer {}'.format(settings.OPA_AUTH_TOKEN)}) + + if settings.OPA_AUTH_TYPE == OPA_AUTH_TYPES.CERTIFICATE and not settings.OPA_SSL: + raise PolicyEvaluationError(_('OPA_AUTH_TYPE=Certificate requires OPA_SSL to be enabled.')) + + cert_settings_missing = [] + + if settings.OPA_AUTH_TYPE == OPA_AUTH_TYPES.CERTIFICATE: + if not settings.OPA_AUTH_CLIENT_CERT: + cert_settings_missing += ['OPA_AUTH_CLIENT_CERT'] + if not settings.OPA_AUTH_CLIENT_KEY: + cert_settings_missing += ['OPA_AUTH_CLIENT_KEY'] + if not settings.OPA_AUTH_CA_CERT: + cert_settings_missing += ['OPA_AUTH_CA_CERT'] + + if cert_settings_missing: + raise PolicyEvaluationError(_('Following certificate settings are missing for OPA_AUTH_TYPE=Certificate: {}').format(cert_settings_missing)) + + query_paths = [ + ('Organization', instance.organization.opa_query_path), + ('Inventory', instance.inventory.opa_query_path), + ('Job template', instance.job_template.opa_query_path), + ] + violations = dict() + errors = dict() + + try: + with opa_client(headers=headers) as client: + for path_type, query_path in query_paths: + response = dict() + try: + if not query_path: + continue + + response = client.query_rule(input_data=input_data, package_path=query_path) + + except HTTPError as e: + message = _('Call to OPA failed. Exception: {}').format(e) + try: + error_data = e.response.json() + except ValueError: + errors[path_type] = message + continue + + error_code = error_data.get("code") + error_message = error_data.get("message") + if error_code or error_message: + message = _('Call to OPA failed. Code: {}, Message: {}').format(error_code, error_message) + errors[path_type] = message + continue + + except Exception as e: + errors[path_type] = _('Call to OPA failed. Exception: {}').format(e) + continue + + result = response.get('result') + if result is None: + errors[path_type] = _('Call to OPA did not return a "result" property. The path refers to an undefined document.') + continue + + result_serializer = OPAResultSerializer(data=result) + if not result_serializer.is_valid(): + errors[path_type] = _('OPA policy returned invalid result.') + continue + + result_data = result_serializer.validated_data + if not result_data.get("allowed") and (result_violations := result_data.get("violations")): + violations[path_type] = result_violations + + format_results = dict() + if any(errors[e] for e in errors): + format_results["Errors"] = errors + + if any(violations[v] for v in violations): + format_results["Violations"] = violations + + if violations or errors: + raise PolicyEvaluationError(pformat(format_results, width=80)) + + except Exception as e: + raise PolicyEvaluationError(_('This job cannot be executed due to a policy violation or error. See the following details:\n{}').format(e)) diff --git a/awx/main/tasks/receptor.py b/awx/main/tasks/receptor.py index 006c805943c8..e1ccf4d7c440 100644 --- a/awx/main/tasks/receptor.py +++ b/awx/main/tasks/receptor.py @@ -17,6 +17,12 @@ # Runner import ansible_runner +# django-ansible-base +from ansible_base.lib.utils.db import advisory_lock + +# Dispatcherd +from dispatcherd.publish import task + # AWX from awx.main.utils.execution_environments import get_default_pod_spec from awx.main.exceptions import ReceptorNodeNotFound @@ -27,9 +33,8 @@ ) from awx.main.constants import MAX_ISOLATED_PATH_COLON_DELIMITER from awx.main.tasks.signals import signal_state, signal_callback, SignalExit -from awx.main.models import Instance, InstanceLink, UnifiedJob -from awx.main.dispatch import get_local_queuename -from awx.main.dispatch.publish import task +from awx.main.models import Instance, InstanceLink, UnifiedJob, ReceptorAddress +from awx.main.dispatch import get_task_queuename # Receptorctl from receptorctl.socket_interface import ReceptorControl @@ -48,6 +53,70 @@ class ReceptorConnectionType(Enum): STREAMTLS = 2 +""" +Translate receptorctl messages that come in over stdout into +structured messages. Currently, these are error messages. +""" + + +class ReceptorErrorBase: + _MESSAGE = 'Receptor Error' + + def __init__(self, node: str = 'N/A', state_name: str = 'N/A'): + self.node = node + self.state_name = state_name + + def __str__(self): + return f"{self.__class__.__name__} '{self._MESSAGE}' on node '{self.node}' with state '{self.state_name}'" + + +class WorkUnitError(ReceptorErrorBase): + _MESSAGE = 'unknown work unit ' + + def __init__(self, work_unit_id: str, *args, **kwargs): + super().__init__(*args, **kwargs) + self.work_unit_id = work_unit_id + + def __str__(self): + return f"{super().__str__()} work unit id '{self.work_unit_id}'" + + +class WorkUnitCancelError(WorkUnitError): + _MESSAGE = 'error cancelling remote unit: unknown work unit ' + + +class WorkUnitResultsError(WorkUnitError): + _MESSAGE = 'Failed to get results: unknown work unit ' + + +class UnknownError(ReceptorErrorBase): + _MESSAGE = 'Unknown receptor ctl error' + + def __init__(self, msg, *args, **kwargs): + super().__init__(*args, **kwargs) + self._MESSAGE = msg + + +class FuzzyError: + def __new__(self, e: RuntimeError, node: str, state_name: str): + """ + At the time of writing this comment all of the sub-classes detection + is centralized in this parent class. It's like a Router(). + Someone may find it better to push down the error detection logic into + each sub-class. + """ + msg = e.args[0] + + common_startswith = (WorkUnitCancelError, WorkUnitResultsError, WorkUnitError) + + for klass in common_startswith: + if msg.startswith(klass._MESSAGE): + work_unit_id = msg[len(klass._MESSAGE) :] + return klass(work_unit_id, node=node, state_name=state_name) + + return UnknownError(msg, node=node, state_name=state_name) + + def read_receptor_config(): # for K8S deployments, getting a lock is necessary as another process # may be re-writing the config at this time @@ -161,22 +230,24 @@ class RemoteJobError(RuntimeError): pass -def run_until_complete(node, timing_data=None, **kwargs): +def run_until_complete(node, timing_data=None, worktype='ansible-runner', ttl='20s', **kwargs): """ Runs an ansible-runner work_type on remote node, waits until it completes, then returns stdout. """ + config_data = read_receptor_config() receptor_ctl = get_receptor_ctl(config_data) use_stream_tls = getattr(get_conn_type(node, receptor_ctl), 'name', None) == "STREAMTLS" kwargs.setdefault('tlsclient', get_tls_client(config_data, use_stream_tls)) - kwargs.setdefault('ttl', '20s') + if ttl is not None: + kwargs['ttl'] = ttl kwargs.setdefault('payload', '') if work_signing_enabled(config_data): kwargs['signwork'] = True transmit_start = time.time() - result = receptor_ctl.submit_work(worktype='ansible-runner', node=node, **kwargs) + result = receptor_ctl.submit_work(worktype=worktype, node=node, **kwargs) unit_id = result['unitid'] run_start = time.time() @@ -184,6 +255,7 @@ def run_until_complete(node, timing_data=None, **kwargs): timing_data['transmit_timing'] = run_start - transmit_start run_timing = 0.0 stdout = '' + state_name = 'local var never set' try: resultfile = receptor_ctl.get_work_results(unit_id) @@ -204,13 +276,33 @@ def run_until_complete(node, timing_data=None, **kwargs): stdout = resultfile.read() stdout = str(stdout, encoding='utf-8') + except RuntimeError as e: + receptor_e = FuzzyError(e, node, state_name) + if type(receptor_e) in ( + WorkUnitError, + WorkUnitResultsError, + ): + logger.warning(f'While consuming job results: {receptor_e}') + else: + raise finally: if settings.RECEPTOR_RELEASE_WORK: - res = receptor_ctl.simple_command(f"work release {unit_id}") - if res != {'released': unit_id}: - logger.warning(f'Could not confirm release of receptor work unit id {unit_id} from {node}, data: {res}') - - receptor_ctl.close() + try: + res = receptor_ctl.simple_command(f"work release {unit_id}") + + if res != {'released': unit_id}: + logger.warning(f'Could not confirm release of receptor work unit id {unit_id} from {node}, data: {res}') + + receptor_ctl.close() + except RuntimeError as e: + receptor_e = FuzzyError(e, node, state_name) + if type(receptor_e) in ( + WorkUnitError, + WorkUnitCancelError, + ): + logger.warning(f"While releasing work: {receptor_e}") + else: + logger.error(f"While releasing work: {receptor_e}") if state_name.lower() == 'failed': work_detail = status.get('Detail', '') @@ -274,7 +366,7 @@ def _convert_args_to_cli(vargs): args = ['cleanup'] for option in ('exclude_strings', 'remove_images'): if vargs.get(option): - args.append('--{}={}'.format(option.replace('_', '-'), ' '.join(vargs.get(option)))) + args.append('--{} {}'.format(option.replace('_', '-'), ' '.join(f'"{item}"' for item in vargs.get(option)))) for option in ('file_pattern', 'image_prune', 'process_isolation_executable', 'grace_period'): if vargs.get(option) is True: args.append('--{}'.format(option.replace('_', '-'))) @@ -283,7 +375,7 @@ def _convert_args_to_cli(vargs): return args -def worker_cleanup(node_name, vargs, timeout=300.0): +def worker_cleanup(node_name, vargs): args = _convert_args_to_cli(vargs) remote_command = ' '.join(args) @@ -317,12 +409,40 @@ def run(self): res = self._run_internal(receptor_ctl) return res finally: - # Make sure to always release the work unit if we established it - if self.unit_id is not None and settings.RECEPTOR_RELEASE_WORK: - try: - receptor_ctl.simple_command(f"work release {self.unit_id}") - except Exception: - logger.exception(f"Error releasing work unit {self.unit_id}.") + status = getattr(res, 'status', 'error') + self._receptor_release_work(receptor_ctl, status) + + def _receptor_release_work(self, receptor_ctl: ReceptorControl, status: str) -> None: + """ + Releases the work unit from Receptor if certain conditions are met. + This method checks several conditions before attempting to release the work unit: + - If `self.unit_id` is `None`, the method returns immediately. + - If the `RECEPTOR_RELEASE_WORK` setting is `False`, the method returns immediately. + - If the `RECEPTOR_KEEP_WORK_ON_ERROR` setting is `True` and the status is 'error', the method returns immediately. + If none of the above conditions are met, the method attempts to release the work unit using the Receptor control command. + If an exception occurs during the release process, it logs an error message. + Args: + receptor_ctl (ReceptorControl): The Receptor control object used to issue commands. + status (str): The status of the work unit, which may affect whether it is released. + """ + + if self.unit_id is None: + logger.debug("No work unit ID to release.") + return + + if settings.RECEPTOR_RELEASE_WORK is False: + logger.debug(f"RECEPTOR_RELEASE_WORK is False, not releasing work unit {self.unit_id}.") + return + + if settings.RECEPTOR_KEEP_WORK_ON_ERROR and status == 'error': + logger.debug(f"RECEPTOR_KEEP_WORK_ON_ERROR is True and status is 'error', not releasing work unit {self.unit_id}.") + return + + try: + logger.debug(f"Released work unit {self.unit_id}.") + receptor_ctl.simple_command(f"work release {self.unit_id}") + except Exception: + logger.exception(f"Error releasing work unit {self.unit_id}.") def _run_internal(self, receptor_ctl): # Create a socketpair. Where the left side will be used for writing our payload @@ -431,16 +551,16 @@ def _run_internal(self, receptor_ctl): # massive, only ask for last 1000 bytes startpos = max(stdout_size - 1000, 0) resultsock, resultfile = receptor_ctl.get_work_results(self.unit_id, startpos=startpos, return_socket=True, return_sockfile=True) - resultsock.setblocking(False) # this makes resultfile reads non blocking lines = resultfile.readlines() receptor_output = b"".join(lines).decode() if receptor_output: - self.task.runner_callback.delay_update(result_traceback=receptor_output) + self.task.runner_callback.delay_update(result_traceback=f'Worker output:\n{receptor_output}') elif detail: - self.task.runner_callback.delay_update(result_traceback=detail) + self.task.runner_callback.delay_update(result_traceback=f'Receptor detail:\n{detail}') else: logger.warning(f'No result details or output from {self.task.instance.log_format}, status:\n{state_name}') except Exception: + logger.exception(f'Work results error from job id={self.task.instance.id} work_unit={self.task.instance.work_unit_id}') raise RuntimeError(detail) return res @@ -464,6 +584,7 @@ def processor(self, resultfile): event_handler=self.task.runner_callback.event_handler, finished_callback=self.task.runner_callback.finished_callback, status_handler=self.task.runner_callback.status_handler, + artifacts_handler=self.task.runner_callback.artifacts_handler, **self.runner_params, ) @@ -526,6 +647,10 @@ def pod_definition(self): pod_spec['spec']['containers'][0]['image'] = ee.image pod_spec['spec']['containers'][0]['args'] = ['ansible-runner', 'worker', '--private-data-dir=/runner'] + if settings.AWX_RUNNER_KEEPALIVE_SECONDS: + pod_spec['spec']['containers'][0].setdefault('env', []) + pod_spec['spec']['containers'][0]['env'].append({'name': 'ANSIBLE_RUNNER_KEEPALIVE_SECONDS', 'value': str(settings.AWX_RUNNER_KEEPALIVE_SECONDS)}) + # Enforce EE Pull Policy pull_options = {"always": "Always", "missing": "IfNotPresent", "never": "Never"} if self.task and self.task.instance.execution_environment: @@ -635,11 +760,11 @@ def kube_config(self): # RECEPTOR_CONFIG_STARTER = ( {'local-only': None}, - {'log-level': 'debug'}, + {'log-level': settings.RECEPTOR_LOG_LEVEL}, {'node': {'firewallrules': [{'action': 'reject', 'tonode': settings.CLUSTER_HOST_ID, 'toservice': 'control'}]}}, {'control-service': {'service': 'control', 'filename': '/var/run/receptor/receptor.sock', 'permissions': '0660'}}, {'work-command': {'worktype': 'local', 'command': 'ansible-runner', 'params': 'worker', 'allowruntimeparams': True}}, - {'work-signing': {'privatekey': '/etc/receptor/signing/work-private-key.pem', 'tokenexpiration': '1m'}}, + {'work-signing': {'privatekey': '/etc/receptor/work_private_key.pem', 'tokenexpiration': '1m'}}, { 'work-kubernetes': { 'worktype': 'kubernetes-runtime-auth', @@ -661,34 +786,58 @@ def kube_config(self): { 'tls-client': { 'name': 'tlsclient', - 'rootcas': '/etc/receptor/tls/ca/receptor-ca.crt', + 'rootcas': '/etc/receptor/tls/ca/mesh-CA.crt', 'cert': '/etc/receptor/tls/receptor.crt', 'key': '/etc/receptor/tls/receptor.key', + 'mintls13': False, } }, ) -@task() -def write_receptor_config(): - lock = FileLock(__RECEPTOR_CONF_LOCKFILE) - with lock: - receptor_config = list(RECEPTOR_CONFIG_STARTER) - - this_inst = Instance.objects.me() - instances = Instance.objects.filter(node_type=Instance.Types.EXECUTION) - existing_peers = {link.target_id for link in InstanceLink.objects.filter(source=this_inst)} - new_links = [] - for instance in instances: - peer = {'tcp-peer': {'address': f'{instance.hostname}:{instance.listener_port}', 'tls': 'tlsclient'}} +def should_update_config(new_config): + ''' + checks that the list of instances matches the list of + tcp-peers in the config + ''' + + current_config = read_receptor_config() # this gets receptor conf lock + for config_entry in current_config: + if config_entry not in new_config: + logger.warning(f"{config_entry} should not be in receptor config. Updating.") + return True + for config_entry in new_config: + if config_entry not in current_config: + logger.warning(f"{config_entry} missing from receptor config. Updating.") + return True + + return False + + +def generate_config_data(): + # returns two values + # receptor config - based on current database peers + # should_update - If True, receptor_config differs from the receptor conf file on disk + addresses = ReceptorAddress.objects.filter(peers_from_control_nodes=True) + + receptor_config = list(RECEPTOR_CONFIG_STARTER) + for address in addresses: + if address.get_peer_type(): + peer = { + f'{address.get_peer_type()}': { + 'address': f'{address.get_full_address()}', + 'tls': 'tlsclient', + } + } receptor_config.append(peer) - if instance.id not in existing_peers: - new_links.append(InstanceLink(source=this_inst, target=instance, link_state=InstanceLink.States.ADDING)) + else: + logger.warning(f"Receptor address {address} has unsupported peer type, skipping.") + should_update = should_update_config(receptor_config) + return receptor_config, should_update - InstanceLink.objects.bulk_create(new_links) - with open(__RECEPTOR_CONF, 'w') as file: - yaml.dump(receptor_config, file, default_flow_style=False) +def reload_receptor(): + logger.warning("Receptor config changed, reloading receptor") # This needs to be outside of the lock because this function itself will acquire the lock. receptor_ctl = get_receptor_ctl() @@ -704,14 +853,34 @@ def write_receptor_config(): else: raise RuntimeError("Receptor reload failed") - links = InstanceLink.objects.filter(source=this_inst, target__in=instances, link_state=InstanceLink.States.ADDING) - links.update(link_state=InstanceLink.States.ESTABLISHED) - -@task(queue=get_local_queuename) +@task(on_duplicate='queue_one') +def write_receptor_config(): + """ + This task runs async on each control node, K8S only. + It is triggered whenever remote is added or removed, or if peers_from_control_nodes + is flipped. + It is possible for write_receptor_config to be called multiple times. + For example, if new instances are added in quick succession. + To prevent that case, each control node first grabs a DB advisory lock, specific + to just that control node (i.e. multiple control nodes can run this function + at the same time, since it only writes the local receptor config file) + """ + with advisory_lock(f"{settings.CLUSTER_HOST_ID}_write_receptor_config", wait=True): + # Config file needs to be updated + receptor_config, should_update = generate_config_data() + if should_update: + lock = FileLock(__RECEPTOR_CONF_LOCKFILE) + with lock: + with open(__RECEPTOR_CONF, 'w') as file: + yaml.dump(receptor_config, file, default_flow_style=False) + reload_receptor() + + +@task(queue=get_task_queuename, on_duplicate='discard') def remove_deprovisioned_node(hostname): InstanceLink.objects.filter(source__hostname=hostname).update(link_state=InstanceLink.States.REMOVING) - InstanceLink.objects.filter(target__hostname=hostname).update(link_state=InstanceLink.States.REMOVING) + InstanceLink.objects.filter(target__instance__hostname=hostname).update(link_state=InstanceLink.States.REMOVING) node_jobs = UnifiedJob.objects.filter( execution_node=hostname, @@ -725,6 +894,3 @@ def remove_deprovisioned_node(hostname): # This will as a side effect also delete the InstanceLinks that are tied to it. Instance.objects.filter(hostname=hostname).delete() - - # Update the receptor configs for all of the control-plane. - write_receptor_config.apply_async(queue='tower_broadcast_all') diff --git a/awx/main/tasks/signals.py b/awx/main/tasks/signals.py index 95610548b991..a1607bfc9960 100644 --- a/awx/main/tasks/signals.py +++ b/awx/main/tasks/signals.py @@ -2,7 +2,6 @@ import functools import logging - logger = logging.getLogger('awx.main.tasks.signals') @@ -14,33 +13,50 @@ class SignalExit(Exception): class SignalState: + # SIGTERM: Sent by supervisord to process group on shutdown + # SIGUSR1: The dispatcherd cancel signal + signals = (signal.SIGTERM, signal.SIGINT, signal.SIGUSR1) + def reset(self): - self.sigterm_flag = False - self.is_active = False - self.original_sigterm = None - self.original_sigint = None + for for_signal in self.signals: + self.signal_flags[for_signal] = False + self.original_methods[for_signal] = None + + self.is_active = False # for nested context managers self.raise_exception = False def __init__(self): + self.signal_flags = {} + self.original_methods = {} self.reset() - def set_flag(self, *args): - """Method to pass into the python signal.signal method to receive signals""" - self.sigterm_flag = True + def raise_if_needed(self): if self.raise_exception: self.raise_exception = False # so it is not raised a second time in error handling raise SignalExit() + def set_signal_flag(self, *args, for_signal=None): + self.signal_flags[for_signal] = True + logger.info(f'Processed signal {for_signal}, set exit flag') + self.raise_if_needed() + def connect_signals(self): - self.original_sigterm = signal.getsignal(signal.SIGTERM) - self.original_sigint = signal.getsignal(signal.SIGINT) - signal.signal(signal.SIGTERM, self.set_flag) - signal.signal(signal.SIGINT, self.set_flag) + for for_signal in self.signals: + self.original_methods[for_signal] = signal.getsignal(for_signal) + signal.signal(for_signal, lambda *args, for_signal=for_signal: self.set_signal_flag(*args, for_signal=for_signal)) self.is_active = True def restore_signals(self): - signal.signal(signal.SIGTERM, self.original_sigterm) - signal.signal(signal.SIGINT, self.original_sigint) + for for_signal in self.signals: + original_method = self.original_methods[for_signal] + signal.signal(for_signal, original_method) + # if we got a signal while context manager was active, call parent methods. + if self.signal_flags[for_signal]: + if callable(original_method): + try: + original_method() + except Exception as exc: + logger.info(f'Error processing original {for_signal} signal, error: {str(exc)}') self.reset() @@ -48,12 +64,12 @@ def restore_signals(self): def signal_callback(): - return signal_state.sigterm_flag + return any(signal_state.signal_flags[for_signal] for for_signal in signal_state.signals) def with_signal_handling(f): """ - Change signal handling to make signal_callback return True in event of SIGTERM or SIGINT. + Change signal handling to make signal_callback return True in event of SIGTERM, SIGINT, or SIGUSR1. """ @functools.wraps(f) diff --git a/awx/main/tasks/system.py b/awx/main/tasks/system.py index 482c168af210..fda46b296849 100644 --- a/awx/main/tasks/system.py +++ b/awx/main/tasks/system.py @@ -1,74 +1,78 @@ # Python -from collections import namedtuple import functools import importlib +import itertools import json import logging import os -from io import StringIO -from contextlib import redirect_stdout import shutil import time -from distutils.version import LooseVersion as Version -from datetime import datetime +from collections import namedtuple +from contextlib import redirect_stdout +from packaging.version import Version +from io import StringIO + +# dispatcherd +from dispatcherd.factories import get_control_from_settings +from dispatcherd.publish import task + +# Runner +import ansible_runner.cleanup +import psycopg +from ansible_base.lib.utils.db import advisory_lock + +# django-ansible-base +from ansible_base.resource_registry.tasks.sync import SyncExecutor + +# Django-CRUM +from crum import impersonate + +# dateutil +from dateutil.parser import parse as parse_date # Django from django.conf import settings -from django.db import transaction, DatabaseError, IntegrityError +from django.contrib.auth.models import User +from django.core.cache import cache +from django.core.exceptions import ObjectDoesNotExist +from django.db import DatabaseError, IntegrityError, connection, transaction from django.db.models.fields.related import ForeignKey -from django.utils.timezone import now, timedelta +from django.db.models.query import QuerySet from django.utils.encoding import smart_str -from django.contrib.auth.models import User +from django.utils.timezone import now, timedelta from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_noop -from django.core.cache import cache -from django.core.exceptions import ObjectDoesNotExist - -# Django-CRUM -from crum import impersonate - -# Runner -import ansible_runner.cleanup - -# dateutil -from dateutil.parser import parse as parse_date +# Django flags +from flags.state import flag_enabled +from rest_framework.exceptions import PermissionDenied # AWX from awx import __version__ as awx_application_version +from awx.conf import settings_registry +from awx.main import analytics from awx.main.access import access_registry +from awx.main.analytics.subsystem_metrics import DispatcherMetrics +from awx.main.constants import ACTIVE_STATES, ERROR_STATES +from awx.main.consumers import emit_channel_notification +from awx.main.dispatch import get_task_queuename, reaper from awx.main.models import ( - Schedule, - TowerScheduleState, Instance, InstanceGroup, - UnifiedJob, - Notification, Inventory, - SmartInventoryMembership, Job, + Notification, + Schedule, + SmartInventoryMembership, + TowerScheduleState, + UnifiedJob, + convert_jsonfields, ) -from awx.main.constants import ACTIVE_STATES -from awx.main.dispatch.publish import task -from awx.main.dispatch import get_local_queuename, reaper -from awx.main.utils.common import ( - get_type_for_model, - ignore_inventory_computed_fields, - ignore_inventory_group_removal, - ScheduleWorkflowManager, - ScheduleTaskManager, -) - -from awx.main.utils.external_logging import reconfigure_rsyslog +from awx.main.tasks.helpers import is_run_threshold_reached +from awx.main.tasks.host_indirect import save_indirect_host_entries +from awx.main.tasks.receptor import administrative_workunit_reaper, get_receptor_ctl, worker_cleanup, worker_info, write_receptor_config +from awx.main.utils.common import ignore_inventory_computed_fields, ignore_inventory_group_removal from awx.main.utils.reload import stop_local_services -from awx.main.utils.pglock import advisory_lock -from awx.main.tasks.receptor import get_receptor_ctl, worker_info, worker_cleanup, administrative_workunit_reaper, write_receptor_config -from awx.main.consumers import emit_channel_notification -from awx.main import analytics -from awx.conf import settings_registry -from awx.main.analytics.subsystem_metrics import Metrics - -from rest_framework.exceptions import PermissionDenied logger = logging.getLogger('awx.main.tasks.system') @@ -79,19 +83,32 @@ ''' -def dispatch_startup(): +def _run_dispatch_startup_common(): + """ + Execute the common startup initialization steps. + This includes updating schedules, syncing instance membership, and starting + local reaping and resetting metrics. + """ startup_logger = logging.getLogger('awx.main.tasks') # TODO: Enable this on VM installs if settings.IS_K8S: - write_receptor_config() + try: + write_receptor_config() + except Exception: + logger.exception("Failed to write receptor config, skipping.") + + try: + convert_jsonfields() + except Exception: + logger.exception("Failed JSON field conversion, skipping.") - startup_logger.debug("Syncing Schedules") + startup_logger.debug("Syncing schedules") for sch in Schedule.objects.all(): try: sch.update_computed_fields() except Exception: - logger.exception("Failed to rebuild schedule {}.".format(sch)) + logger.exception("Failed to rebuild schedule %s.", sch) # # When the dispatcher starts, if the instance cannot be found in the database, @@ -109,30 +126,95 @@ def dispatch_startup(): # no-op. # apply_cluster_membership_policies() - cluster_node_heartbeat() + cluster_node_heartbeat(None) reaper.startup_reaping() - reaper.reap_waiting(grace_period=0) - m = Metrics() + m = DispatcherMetrics() m.reset_values() - # Update Tower's rsyslog.conf file based on loggins settings in the db - reconfigure_rsyslog() + +def _dispatcherd_dispatch_startup(): + """ + New dispatcherd branch for startup: uses the control API to re-submit waiting jobs. + """ + logger.debug("Dispatcherd enabled: dispatching waiting jobs via control channel") + from awx.main.tasks.jobs import dispatch_waiting_jobs + + dispatch_waiting_jobs.apply_async(queue=get_task_queuename()) + + +def dispatch_startup(): + """ + System initialization at startup. + First, execute the common logic. + Then, re-submit waiting jobs via the control API. + """ + _run_dispatch_startup_common() + _dispatcherd_dispatch_startup() def inform_cluster_of_shutdown(): + """ + Clean system shutdown that marks the current instance offline. + Relies on dispatcherd's built-in cleanup. + """ try: - this_inst = Instance.objects.get(hostname=settings.CLUSTER_HOST_ID) - this_inst.mark_offline(update_last_seen=True, errors=_('Instance received normal shutdown signal')) - try: - reaper.reap_waiting(this_inst, grace_period=0) - except Exception: - logger.exception('failed to reap waiting jobs for {}'.format(this_inst.hostname)) - logger.warning('Normal shutdown signal for instance {}, removed self from capacity pool.'.format(this_inst.hostname)) - except Exception: - logger.exception('Encountered problem with normal shutdown signal.') + inst = Instance.objects.get(hostname=settings.CLUSTER_HOST_ID) + inst.mark_offline(update_last_seen=True, errors=_('Instance received normal shutdown signal')) + except Instance.DoesNotExist: + logger.exception("Cluster host not found: %s", settings.CLUSTER_HOST_ID) + return + + logger.debug("No extra reaping required for instance %s", inst.hostname) + logger.warning("Normal shutdown processed for instance %s; instance removed from capacity pool.", inst.hostname) + + +@task(queue=get_task_queuename, timeout=3600 * 5) +def migrate_jsonfield(table, pkfield, columns): + batchsize = 10000 + with advisory_lock(f'json_migration_{table}', wait=False) as acquired: + if not acquired: + return + + from django.db.migrations.executor import MigrationExecutor + + # If Django is currently running migrations, wait until it is done. + while True: + executor = MigrationExecutor(connection) + if not executor.migration_plan(executor.loader.graph.leaf_nodes()): + break + time.sleep(120) + + logger.warning(f"Migrating json fields for {table}: {', '.join(columns)}") + + with connection.cursor() as cursor: + for i in itertools.count(0, batchsize): + # Are there even any rows in the table beyond this point? + cursor.execute(f"select count(1) from {table} where {pkfield} >= %s limit 1;", (i,)) + if not cursor.fetchone()[0]: + break + + column_expr = ', '.join(f"{colname} = {colname}_old::jsonb" for colname in columns) + # If any of the old columns have non-null values, the data needs to be cast and copied over. + empty_expr = ' or '.join(f"{colname}_old is not null" for colname in columns) + cursor.execute( # Only clobber the new fields if there is non-null data in the old ones. + f""" + update {table} + set {column_expr} + where {pkfield} >= %s and {pkfield} < %s + and {empty_expr}; + """, + (i, i + batchsize), + ) + rows = cursor.rowcount + logger.debug(f"Batch {i} to {i + batchsize} copied on {table}, {rows} rows affected.") + column_expr = ', '.join(f"DROP COLUMN {column}_old" for column in columns) + cursor.execute(f"ALTER TABLE {table} {column_expr};") -@task(queue=get_local_queuename) + logger.warning(f"Migration of {table} to jsonb is finished.") + + +@task(queue=get_task_queuename, timeout=3600, on_duplicate='queue_one') def apply_cluster_membership_policies(): from awx.main.signals import disable_activity_stream @@ -244,8 +326,10 @@ def apply_cluster_membership_policies(): logger.debug('Cluster policy computation finished in {} seconds'.format(time.time() - started_compute)) -@task(queue='tower_broadcast_all') -def handle_setting_changes(setting_keys): +@task(queue='tower_settings_change', timeout=600) +def clear_setting_cache(setting_keys): + # log that cache is being cleared + logger.info(f"clear_setting_cache of keys {setting_keys}") orig_len = len(setting_keys) for i in range(orig_len): for dependent_key in settings_registry.get_dependent_settings(setting_keys[i]): @@ -254,11 +338,13 @@ def handle_setting_changes(setting_keys): logger.debug('cache delete_many(%r)', cache_keys) cache.delete_many(cache_keys) - if any([setting.startswith('LOG_AGGREGATOR') for setting in setting_keys]): - reconfigure_rsyslog() + if 'LOG_AGGREGATOR_LEVEL' in setting_keys: + ctl = get_control_from_settings() + ctl.queuename = get_task_queuename() + ctl.control('set_log_level', data={'level': settings.LOG_AGGREGATOR_LEVEL}) -@task(queue='tower_broadcast_all') +@task(queue='tower_broadcast_all', timeout=600) def delete_project_files(project_path): # TODO: possibly implement some retry logic lock_file = project_path + '.lock' @@ -286,7 +372,7 @@ def profile_sql(threshold=1, minutes=1): logger.error('SQL QUERIES >={}s ENABLED FOR {} MINUTE(S)'.format(threshold, minutes)) -@task(queue=get_local_queuename) +@task(queue=get_task_queuename, timeout=1800) def send_notifications(notification_list, job_id=None): if not isinstance(notification_list, list): raise TypeError("notification_list should be of type list") @@ -317,20 +403,27 @@ def send_notifications(notification_list, job_id=None): logger.exception('Error saving notification {} result.'.format(notification.id)) -@task(queue=get_local_queuename) -def gather_analytics(): - from awx.conf.models import Setting - from rest_framework.fields import DateTimeField +def events_processed_hook(unified_job): + """This method is intended to be called for every unified job + after the playbook_on_stats/EOF event is processed and final status is saved + Either one of these events could happen before the other, or there may be no events""" + unified_job.send_notification_templates('succeeded' if unified_job.status == 'successful' else 'failed') + if isinstance(unified_job, Job) and flag_enabled("FEATURE_INDIRECT_NODE_COUNTING_ENABLED"): + if unified_job.event_queries_processed is True: + # If this is called from callback receiver, it likely does not have updated model data + # a refresh now is formally robust + unified_job.refresh_from_db(fields=['event_queries_processed']) + if unified_job.event_queries_processed is False: + save_indirect_host_entries.delay(unified_job.id) - last_gather = Setting.objects.filter(key='AUTOMATION_ANALYTICS_LAST_GATHER').first() - last_time = DateTimeField().to_internal_value(last_gather.value) if last_gather and last_gather.value else None - gather_time = now() - if not last_time or ((gather_time - last_time).total_seconds() > settings.AUTOMATION_ANALYTICS_GATHER_INTERVAL): +@task(queue=get_task_queuename, timeout=3600 * 5, on_duplicate='discard') +def gather_analytics(): + if is_run_threshold_reached(getattr(settings, 'AUTOMATION_ANALYTICS_LAST_GATHER', None), settings.AUTOMATION_ANALYTICS_GATHER_INTERVAL): analytics.gather() -@task(queue=get_local_queuename) +@task(queue=get_task_queuename, timeout=600, on_duplicate='queue_one') def purge_old_stdout_files(): nowtime = time.time() for f in os.listdir(settings.JOBOUTPUT_ROOT): @@ -339,70 +432,71 @@ def purge_old_stdout_files(): logger.debug("Removing {}".format(os.path.join(settings.JOBOUTPUT_ROOT, f))) -def _cleanup_images_and_files(**kwargs): - if settings.IS_K8S: - return - this_inst = Instance.objects.me() - runner_cleanup_kwargs = this_inst.get_cleanup_task_kwargs(**kwargs) - if runner_cleanup_kwargs: - stdout = '' - with StringIO() as buffer: - with redirect_stdout(buffer): - ansible_runner.cleanup.run_cleanup(runner_cleanup_kwargs) - stdout = buffer.getvalue() - if '(changed: True)' in stdout: - logger.info(f'Performed local cleanup with kwargs {kwargs}, output:\n{stdout}') - - # if we are the first instance alphabetically, then run cleanup on execution nodes - checker_instance = ( - Instance.objects.filter(node_type__in=['hybrid', 'control'], node_state=Instance.States.READY, enabled=True, capacity__gt=0) - .order_by('-hostname') - .first() - ) - if checker_instance and this_inst.hostname == checker_instance.hostname: - for inst in Instance.objects.filter(node_type='execution', node_state=Instance.States.READY, enabled=True, capacity__gt=0): - runner_cleanup_kwargs = inst.get_cleanup_task_kwargs(**kwargs) - if not runner_cleanup_kwargs: - continue - try: - stdout = worker_cleanup(inst.hostname, runner_cleanup_kwargs) - if '(changed: True)' in stdout: - logger.info(f'Performed cleanup on execution node {inst.hostname} with output:\n{stdout}') - except RuntimeError: - logger.exception(f'Error running cleanup on execution node {inst.hostname}') +class CleanupImagesAndFiles: + @classmethod + def get_first_control_instance(cls) -> Instance | None: + return ( + Instance.objects.filter(node_type__in=['hybrid', 'control'], node_state=Instance.States.READY, enabled=True, capacity__gt=0) + .order_by('-hostname') + .first() + ) + @classmethod + def get_execution_instances(cls) -> QuerySet[Instance]: + return Instance.objects.filter(node_type='execution', node_state=Instance.States.READY, enabled=True, capacity__gt=0) -@task(queue='tower_broadcast_all') + @classmethod + def run_local(cls, this_inst: Instance, **kwargs): + if settings.IS_K8S: + return + runner_cleanup_kwargs = this_inst.get_cleanup_task_kwargs(**kwargs) + if runner_cleanup_kwargs: + stdout = '' + with StringIO() as buffer: + with redirect_stdout(buffer): + ansible_runner.cleanup.run_cleanup(runner_cleanup_kwargs) + stdout = buffer.getvalue() + if '(changed: True)' in stdout: + logger.info(f'Performed local cleanup with kwargs {kwargs}, output:\n{stdout}') + + @classmethod + def run_remote(cls, this_inst: Instance, **kwargs): + # if we are the first instance alphabetically, then run cleanup on execution nodes + checker_instance = cls.get_first_control_instance() + + if checker_instance and this_inst.hostname == checker_instance.hostname: + for inst in cls.get_execution_instances(): + runner_cleanup_kwargs = inst.get_cleanup_task_kwargs(**kwargs) + if not runner_cleanup_kwargs: + continue + try: + stdout = worker_cleanup(inst.hostname, runner_cleanup_kwargs) + if '(changed: True)' in stdout: + logger.info(f'Performed cleanup on execution node {inst.hostname} with output:\n{stdout}') + except RuntimeError: + logger.exception(f'Error running cleanup on execution node {inst.hostname}') + + @classmethod + def run(cls, **kwargs): + if settings.IS_K8S: + return + this_inst = Instance.objects.me() + cls.run_local(this_inst, **kwargs) + cls.run_remote(this_inst, **kwargs) + + +@task(queue='tower_broadcast_all', timeout=3600) def handle_removed_image(remove_images=None): """Special broadcast invocation of this method to handle case of deleted EE""" - _cleanup_images_and_files(remove_images=remove_images, file_pattern='') + CleanupImagesAndFiles.run(remove_images=remove_images, file_pattern='') -@task(queue=get_local_queuename) +@task(queue=get_task_queuename, timeout=3600, on_duplicate='queue_one') def cleanup_images_and_files(): - _cleanup_images_and_files() - - -@task(queue=get_local_queuename) -def cluster_node_health_check(node): - """ - Used for the health check endpoint, refreshes the status of the instance, but must be ran on target node - """ - if node == '': - logger.warning('Local health check incorrectly called with blank string') - return - elif node != settings.CLUSTER_HOST_ID: - logger.warning(f'Local health check for {node} incorrectly sent to {settings.CLUSTER_HOST_ID}') - return - try: - this_inst = Instance.objects.me() - except Instance.DoesNotExist: - logger.warning(f'Instance record for {node} missing, could not check capacity.') - return - this_inst.local_health_check() + CleanupImagesAndFiles.run(image_prune=True) -@task(queue=get_local_queuename) +@task(queue=get_task_queuename, timeout=600, on_duplicate='queue_one') def execution_node_health_check(node): if node == '': logger.warning('Remote health check incorrectly called with blank string') @@ -424,7 +518,6 @@ def execution_node_health_check(node): data = worker_info(node) prior_capacity = instance.capacity - instance.save_health_data( version='ansible-runner-' + data.get('runner_version', '???'), cpu=data.get('cpu_count', 0), @@ -445,12 +538,44 @@ def execution_node_health_check(node): return data -def inspect_execution_nodes(instance_list): - with advisory_lock('inspect_execution_nodes_lock', wait=False): +def inspect_established_receptor_connections(mesh_status): + ''' + Flips link state from ADDING to ESTABLISHED + If the InstanceLink source and target match the entries + in Known Connection Costs, flip to Established. + ''' + from awx.main.models import InstanceLink + + all_links = InstanceLink.objects.filter(link_state=InstanceLink.States.ADDING) + if not all_links.exists(): + return + active_receptor_conns = mesh_status['KnownConnectionCosts'] + update_links = [] + for link in all_links: + if link.link_state != InstanceLink.States.REMOVING: + if link.target.instance.hostname in active_receptor_conns.get(link.source.hostname, {}): + if link.link_state is not InstanceLink.States.ESTABLISHED: + link.link_state = InstanceLink.States.ESTABLISHED + update_links.append(link) + + InstanceLink.objects.bulk_update(update_links, ['link_state']) + + +def inspect_execution_and_hop_nodes(instance_list): + with advisory_lock('inspect_execution_and_hop_nodes_lock', wait=False): node_lookup = {inst.hostname: inst for inst in instance_list} + try: + ctl = get_receptor_ctl() + except FileNotFoundError: + logger.error('Receptor daemon not running, skipping execution node check') + return + try: + mesh_status = ctl.simple_command('status') + except ValueError as exc: + logger.error(f'Error running receptorctl status command, error: {str(exc)}') + return - ctl = get_receptor_ctl() - mesh_status = ctl.simple_command('status') + inspect_established_receptor_connections(mesh_status) nowtime = now() workers = mesh_status['Advertisements'] @@ -496,8 +621,81 @@ def inspect_execution_nodes(instance_list): execution_node_health_check.apply_async([hostname]) -@task(queue=get_local_queuename, bind_kwargs=['dispatch_time', 'worker_tasks']) -def cluster_node_heartbeat(dispatch_time=None, worker_tasks=None): +@task(queue=get_task_queuename, bind=True) +def cluster_node_heartbeat(binder): + """ + Dispatcherd implementation. + Uses Control API to get running tasks. + """ + + # Run common instance management logic + this_inst, instance_list, lost_instances = _heartbeat_instance_management() + if this_inst is None: + return # Early return case from instance management + + # Check versions + _heartbeat_check_versions(this_inst, instance_list) + + # Handle lost instances + _heartbeat_handle_lost_instances(lost_instances, this_inst) + + # Get running tasks using dispatcherd API + if binder is None: + logger.debug("Heartbeat finished in startup.") + return + active_task_ids = _get_active_task_ids_from_dispatcherd(binder) + if active_task_ids is None: + logger.warning("No active task IDs retrieved from dispatcherd, skipping reaper") + return # Failed to get task IDs, don't attempt reaping + + # Run local reaper using tasks from dispatcherd + ref_time = now() # No dispatch_time in dispatcherd version + logger.debug(f"Running reaper with {len(active_task_ids)} excluded UUIDs") + reaper.reap(instance=this_inst, excluded_uuids=active_task_ids, ref_time=ref_time) + # If waiting jobs are hanging out, resubmit them + if UnifiedJob.objects.filter(controller_node=settings.CLUSTER_HOST_ID, status='waiting').exists(): + from awx.main.tasks.jobs import dispatch_waiting_jobs + + dispatch_waiting_jobs.apply_async(queue=get_task_queuename()) + + +def _get_active_task_ids_from_dispatcherd(binder): + """ + Retrieve active task IDs from the dispatcherd control API. + + Returns: + list: List of active task UUIDs + None: If there was an error retrieving the data + """ + active_task_ids = [] + try: + + logger.debug("Querying dispatcherd API for running tasks") + data = binder.control('running') + + # Extract UUIDs from the running data + # Process running data: first item is a dict with node_id and task entries + data.pop('node_id', None) + + # Extract task UUIDs from data structure + for task_key, task_value in data.items(): + if isinstance(task_value, dict) and 'uuid' in task_value: + active_task_ids.append(task_value['uuid']) + logger.debug(f"Found active task with UUID: {task_value['uuid']}") + elif isinstance(task_key, str): + # Handle case where UUID might be the key + active_task_ids.append(task_key) + logger.debug(f"Found active task with key: {task_key}") + + logger.debug(f"Retrieved {len(active_task_ids)} active task IDs from dispatcherd") + return active_task_ids + except Exception: + logger.exception("Failed to get running tasks from dispatcherd") + return None + + +def _heartbeat_instance_management(): + """Common logic for heartbeat instance management.""" logger.debug("Cluster node heartbeat task.") nowtime = now() instance_list = list(Instance.objects.filter(node_state__in=(Instance.States.READY, Instance.States.UNAVAILABLE, Instance.States.INSTALLED))) @@ -509,7 +707,7 @@ def cluster_node_heartbeat(dispatch_time=None, worker_tasks=None): this_inst = inst break - inspect_execution_nodes(instance_list) + inspect_execution_and_hop_nodes(instance_list) for inst in list(instance_list): if inst == this_inst: @@ -524,20 +722,26 @@ def cluster_node_heartbeat(dispatch_time=None, worker_tasks=None): this_inst.local_health_check() if startup_event and this_inst.capacity != 0: logger.warning(f'Rejoining the cluster as instance {this_inst.hostname}. Prior last_seen {last_last_seen}') - return + return None, None, None # Early return case elif not last_last_seen: logger.warning(f'Instance does not have recorded last_seen, updating to {nowtime}') elif (nowtime - last_last_seen) > timedelta(seconds=settings.CLUSTER_NODE_HEARTBEAT_PERIOD + 2): logger.warning(f'Heartbeat skew - interval={(nowtime - last_last_seen).total_seconds():.4f}, expected={settings.CLUSTER_NODE_HEARTBEAT_PERIOD}') else: if settings.AWX_AUTO_DEPROVISION_INSTANCES: - (changed, this_inst) = Instance.objects.register(ip_address=os.environ.get('MY_POD_IP'), node_type='control', uuid=settings.SYSTEM_UUID) + changed, this_inst = Instance.objects.register(ip_address=os.environ.get('MY_POD_IP'), node_type='control', node_uuid=settings.SYSTEM_UUID) if changed: logger.warning(f'Recreated instance record {this_inst.hostname} after unexpected removal') this_inst.local_health_check() else: - raise RuntimeError("Cluster Host Not Found: {}".format(settings.CLUSTER_HOST_ID)) - # IFF any node has a greater version than we do, then we'll shutdown services + logger.error("Cluster Host Not Found: {}".format(settings.CLUSTER_HOST_ID)) + return None, None, None + + return this_inst, instance_list, lost_instances + + +def _heartbeat_check_versions(this_inst, instance_list): + """Check versions across instances and determine if shutdown is needed.""" for other_inst in instance_list: if other_inst.node_type in ('execution', 'hop'): continue @@ -554,13 +758,18 @@ def cluster_node_heartbeat(dispatch_time=None, worker_tasks=None): stop_local_services(communicate=False) raise RuntimeError("Shutting down.") + +def _heartbeat_handle_lost_instances(lost_instances, this_inst): + """Handle lost instances by reaping their running jobs and marking them offline.""" for other_inst in lost_instances: try: + # Any jobs marked as running will be marked as error explanation = "Job reaped due to instance shutdown" reaper.reap(other_inst, job_explanation=explanation) - reaper.reap_waiting(other_inst, grace_period=0, job_explanation=explanation) + # Any jobs that were waiting to be processed by this node will be handed back to task manager + UnifiedJob.objects.filter(status='waiting', controller_node=other_inst.hostname).update(status='pending', controller_node='', execution_node='') except Exception: - logger.exception('failed to reap jobs for {}'.format(other_inst.hostname)) + logger.exception('failed to re-process jobs for lost instance {}'.format(other_inst.hostname)) try: if settings.AWX_AUTO_DEPROVISION_INSTANCES and other_inst.node_type == "control": deprovision_hostname = other_inst.hostname @@ -571,22 +780,21 @@ def cluster_node_heartbeat(dispatch_time=None, worker_tasks=None): logger.error("Host {} last checked in at {}, marked as lost.".format(other_inst.hostname, other_inst.last_seen)) except DatabaseError as e: - if 'did not affect any rows' in str(e): - logger.debug('Another instance has marked {} as lost'.format(other_inst.hostname)) + cause = e.__cause__ + if cause and hasattr(cause, 'sqlstate'): + sqlstate = cause.sqlstate + sqlstate_str = psycopg.errors.lookup(sqlstate) + logger.debug('SQL Error state: {} - {}'.format(sqlstate, sqlstate_str)) + + if sqlstate == psycopg.errors.NoData: + logger.debug('Another instance has marked {} as lost'.format(other_inst.hostname)) + else: + logger.exception("Error marking {} as lost.".format(other_inst.hostname)) else: - logger.exception('Error marking {} as lost'.format(other_inst.hostname)) - - # Run local reaper - if worker_tasks is not None: - active_task_ids = [] - for task_list in worker_tasks.values(): - active_task_ids.extend(task_list) - reaper.reap(instance=this_inst, excluded_uuids=active_task_ids) - if max(len(task_list) for task_list in worker_tasks.values()) <= 1: - reaper.reap_waiting(instance=this_inst, excluded_uuids=active_task_ids, ref_time=datetime.fromisoformat(dispatch_time)) + logger.exception('No SQL state available. Error marking {} as lost'.format(other_inst.hostname)) -@task(queue=get_local_queuename) +@task(queue=get_task_queuename, timeout=1800, on_duplicate='queue_one') def awx_receptor_workunit_reaper(): """ When an AWX job is launched via receptor, files such as status, stdin, and stdout are created @@ -609,11 +817,21 @@ def awx_receptor_workunit_reaper(): if not settings.RECEPTOR_RELEASE_WORK: return logger.debug("Checking for unreleased receptor work units") - receptor_ctl = get_receptor_ctl() - receptor_work_list = receptor_ctl.simple_command("work list") + try: + receptor_ctl = get_receptor_ctl() + except FileNotFoundError: + logger.info('Receptorctl sockfile not found for workunit reaper, doing nothing') + return + try: + receptor_work_list = receptor_ctl.simple_command("work list") + except ValueError as exc: + logger.info(f'Error getting work list for workunit reaper, error: {str(exc)}') + return unit_ids = [id for id in receptor_work_list] jobs_with_unreleased_receptor_units = UnifiedJob.objects.filter(work_unit_id__in=unit_ids).exclude(status__in=ACTIVE_STATES) + if settings.RECEPTOR_KEEP_WORK_ON_ERROR: + jobs_with_unreleased_receptor_units = jobs_with_unreleased_receptor_units.exclude(status__in=ERROR_STATES) for job in jobs_with_unreleased_receptor_units: logger.debug(f"{job.log_format} is not active, reaping receptor work unit {job.work_unit_id}") receptor_ctl.simple_command(f"work cancel {job.work_unit_id}") @@ -622,7 +840,7 @@ def awx_receptor_workunit_reaper(): administrative_workunit_reaper(receptor_work_list) -@task(queue=get_local_queuename) +@task(queue=get_task_queuename, timeout=1800, on_duplicate='queue_one') def awx_k8s_reaper(): if not settings.RECEPTOR_RELEASE_WORK: return @@ -633,7 +851,10 @@ def awx_k8s_reaper(): logger.debug("Checking for orphaned k8s pods for {}.".format(group)) pods = PodManager.list_active_jobs(group) time_cutoff = now() - timedelta(seconds=settings.K8S_POD_REAPER_GRACE_PERIOD) - for job in UnifiedJob.objects.filter(pk__in=pods.keys(), finished__lte=time_cutoff).exclude(status__in=ACTIVE_STATES): + reap_job_candidates = UnifiedJob.objects.filter(pk__in=pods.keys(), finished__lte=time_cutoff).exclude(status__in=ACTIVE_STATES) + if settings.RECEPTOR_KEEP_WORK_ON_ERROR: + reap_job_candidates = reap_job_candidates.exclude(status__in=ERROR_STATES) + for job in reap_job_candidates: logger.debug('{} is no longer active, reaping orphaned k8s pod'.format(job.log_format)) try: pm = PodManager(job) @@ -642,9 +863,10 @@ def awx_k8s_reaper(): logger.exception("Failed to delete orphaned pod {} from {}".format(job.log_format, group)) -@task(queue=get_local_queuename) +@task(queue=get_task_queuename, timeout=3600 * 5, on_duplicate='discard') def awx_periodic_scheduler(): - with advisory_lock('awx_periodic_scheduler_lock', wait=False) as acquired: + lock_session_timeout_milliseconds = settings.TASK_MANAGER_LOCK_TIMEOUT * 1000 + with advisory_lock('awx_periodic_scheduler_lock', lock_session_timeout_milliseconds=lock_session_timeout_milliseconds, wait=False) as acquired: if acquired is False: logger.debug("Not running periodic scheduler, another task holds lock") return @@ -691,76 +913,29 @@ def awx_periodic_scheduler(): continue if not can_start: new_unified_job.status = 'failed' - new_unified_job.job_explanation = gettext_noop( - "Scheduled job could not start because it \ - was not in the right state or required manual credentials" - ) + new_unified_job.job_explanation = gettext_noop("Scheduled job could not start because it \ + was not in the right state or required manual credentials") new_unified_job.save(update_fields=['status', 'job_explanation']) new_unified_job.websocket_emit_status("failed") emit_channel_notification('schedules-changed', dict(id=schedule.id, group_name="schedules")) - state.save() - - -def schedule_manager_success_or_error(instance): - if instance.unifiedjob_blocked_jobs.exists(): - ScheduleTaskManager().schedule() - if instance.spawned_by_workflow: - ScheduleWorkflowManager().schedule() - - -@task(queue=get_local_queuename) -def handle_work_success(task_actual): - try: - instance = UnifiedJob.get_instance_by_type(task_actual['type'], task_actual['id']) - except ObjectDoesNotExist: - logger.warning('Missing {} `{}` in success callback.'.format(task_actual['type'], task_actual['id'])) - return - if not instance: - return - schedule_manager_success_or_error(instance) -@task(queue=get_local_queuename) -def handle_work_error(task_actual): - try: - instance = UnifiedJob.get_instance_by_type(task_actual['type'], task_actual['id']) - except ObjectDoesNotExist: - logger.warning('Missing {} `{}` in error callback.'.format(task_actual['type'], task_actual['id'])) - return - if not instance: - return - - subtasks = instance.get_jobs_fail_chain() # reverse of dependent_jobs mostly - logger.debug(f'Executing error task id {task_actual["id"]}, subtasks: {[subtask.id for subtask in subtasks]}') - - deps_of_deps = {} - - for subtask in subtasks: - if subtask.celery_task_id != instance.celery_task_id and not subtask.cancel_flag and not subtask.status in ('successful', 'failed'): - # If there are multiple in the dependency chain, A->B->C, and this was called for A, blame B for clarity - blame_job = deps_of_deps.get(subtask.id, instance) - subtask.status = 'failed' - subtask.failed = True - if not subtask.job_explanation: - subtask.job_explanation = 'Previous Task Failed: {"job_type": "%s", "job_name": "%s", "job_id": "%s"}' % ( - get_type_for_model(type(blame_job)), - blame_job.name, - blame_job.id, - ) - subtask.save() - subtask.websocket_emit_status("failed") - - for sub_subtask in subtask.get_jobs_fail_chain(): - deps_of_deps[sub_subtask.id] = subtask - - # We only send 1 job complete message since all the job completion message - # handling does is trigger the scheduler. If we extend the functionality of - # what the job complete message handler does then we may want to send a - # completion event for each job here. - schedule_manager_success_or_error(instance) +@task(queue=get_task_queuename, timeout=3600) +def handle_failure_notifications(task_ids): + """A task-ified version of the method that sends notifications.""" + found_task_ids = set() + for instance in UnifiedJob.objects.filter(id__in=task_ids): + found_task_ids.add(instance.id) + try: + instance.send_notification_templates('failed') + except Exception: + logger.exception(f'Error preparing notifications for task {instance.id}') + deleted_tasks = set(task_ids) - found_task_ids + if deleted_tasks: + logger.warning(f'Could not send notifications for {deleted_tasks} because they were not found in the database') -@task(queue=get_local_queuename) +@task(queue=get_task_queuename, timeout=3600 * 5) def update_inventory_computed_fields(inventory_id): """ Signal handler and wrapper around inventory.update_computed_fields to @@ -774,10 +949,19 @@ def update_inventory_computed_fields(inventory_id): try: i.update_computed_fields() except DatabaseError as e: - if 'did not affect any rows' in str(e): - logger.debug('Exiting duplicate update_inventory_computed_fields task.') - return - raise + # https://github.com/django/django/blob/eff21d8e7a1cb297aedf1c702668b590a1b618f3/django/db/models/base.py#L1105 + # django raises DatabaseError("Forced update did not affect any rows.") + + # if sqlstate is set then there was a database error and otherwise will re-raise that error + cause = e.__cause__ + if cause and hasattr(cause, 'sqlstate'): + sqlstate = cause.sqlstate + sqlstate_str = psycopg.errors.lookup(sqlstate) + logger.error('SQL Error state: {} - {}'.format(sqlstate, sqlstate_str)) + raise + + # otherwise + logger.debug('Exiting duplicate update_inventory_computed_fields task.') def update_smart_memberships_for_inventory(smart_inventory): @@ -801,7 +985,7 @@ def update_smart_memberships_for_inventory(smart_inventory): return False -@task(queue=get_local_queuename) +@task(queue=get_task_queuename, timeout=3600, on_duplicate='queue_one') def update_host_smart_inventory_memberships(): smart_inventories = Inventory.objects.filter(kind='smart', host_filter__isnull=False, pending_deletion=False) changed_inventories = set([]) @@ -817,7 +1001,7 @@ def update_host_smart_inventory_memberships(): smart_inventory.update_computed_fields() -@task(queue=get_local_queuename) +@task(queue=get_task_queuename, timeout=3600 * 5) def delete_inventory(inventory_id, user_id, retries=5): # Delete inventory as user if user_id is None: @@ -829,10 +1013,7 @@ def delete_inventory(inventory_id, user_id, retries=5): user = None with ignore_inventory_computed_fields(), ignore_inventory_group_removal(), impersonate(user): try: - i = Inventory.objects.get(id=inventory_id) - for host in i.hosts.iterator(): - host.job_events_as_primary_host.update(host=None) - i.delete() + Inventory.objects.get(id=inventory_id).delete() emit_channel_notification('inventories-status_changed', {'group_name': 'inventories', 'inventory_id': inventory_id, 'status': 'deleted'}) logger.debug('Deleted inventory {} as user {}.'.format(inventory_id, user_id)) except Inventory.DoesNotExist: @@ -882,16 +1063,9 @@ def _reconstruct_relationships(copy_mapping): new_obj.save() -@task(queue=get_local_queuename) -def deep_copy_model_obj(model_module, model_name, obj_pk, new_obj_pk, user_pk, uuid, permission_check_func=None): - sub_obj_list = cache.get(uuid) - if sub_obj_list is None: - logger.error('Deep copy {} from {} to {} failed unexpectedly.'.format(model_name, obj_pk, new_obj_pk)) - return - +@task(queue=get_task_queuename, timeout=600) +def deep_copy_model_obj(model_module, model_name, obj_pk, new_obj_pk, user_pk, permission_check_func=None): logger.debug('Deep copy {} from {} to {}.'.format(model_name, obj_pk, new_obj_pk)) - from awx.api.generics import CopyAPIView - from awx.main.signals import disable_activity_stream model = getattr(importlib.import_module(model_module), model_name, None) if model is None: @@ -903,6 +1077,28 @@ def deep_copy_model_obj(model_module, model_name, obj_pk, new_obj_pk, user_pk, u except ObjectDoesNotExist: logger.warning("Object or user no longer exists.") return + + o2m_to_preserve = {} + fields_to_preserve = set(getattr(model, 'FIELDS_TO_PRESERVE_AT_COPY', [])) + + for field in model._meta.get_fields(): + if field.name in fields_to_preserve: + if field.one_to_many: + try: + field_val = getattr(obj, field.name) + except AttributeError: + continue + o2m_to_preserve[field.name] = field_val + + sub_obj_list = [] + for o2m in o2m_to_preserve: + for sub_obj in o2m_to_preserve[o2m].all(): + sub_model = type(sub_obj) + sub_obj_list.append((sub_model.__module__, sub_model.__name__, sub_obj.pk)) + + from awx.api.generics import CopyAPIView + from awx.main.signals import disable_activity_stream + with transaction.atomic(), ignore_inventory_computed_fields(), disable_activity_stream(): copy_mapping = {} for sub_obj_setup in sub_obj_list: @@ -920,3 +1116,27 @@ def deep_copy_model_obj(model_module, model_name, obj_pk, new_obj_pk, user_pk, u permission_check_func(creater, copy_mapping.values()) if isinstance(new_obj, Inventory): update_inventory_computed_fields.delay(new_obj.id) + + +@task(queue=get_task_queuename, timeout=3600, on_duplicate='discard') +def periodic_resource_sync(): + if not getattr(settings, 'RESOURCE_SERVER', None): + logger.debug("Skipping periodic resource_sync, RESOURCE_SERVER not configured") + return + + with advisory_lock('periodic_resource_sync', wait=False) as acquired: + if acquired is False: + logger.debug("Not running periodic_resource_sync, another task holds lock") + return + logger.debug("Running periodic resource sync") + + executor = SyncExecutor() + executor.run() + for key, item_list in executor.results.items(): + if not item_list or key == 'noop': + continue + # Log creations and conflicts + if len(item_list) > 10 and settings.LOG_AGGREGATOR_LEVEL != 'DEBUG': + logger.info(f'Periodic resource sync {key}, first 10 items:\n{item_list[:10]}') + else: + logger.info(f'Periodic resource sync {key}:\n{item_list}') diff --git a/awx/main/tests/README.md b/awx/main/tests/README.md new file mode 100644 index 000000000000..f6aac6418eec --- /dev/null +++ b/awx/main/tests/README.md @@ -0,0 +1,42 @@ +## Test Environments + +Several of the subfolders of `awx/main/tests/` indicate a different required _environment_ +where you can run the tests. Those folders are: + + - `functional/` - requires a test database and no other services running + - `live/` - must run in `tools_awx_1` container launched by `make docker-compose` + - `unit/` - does not require a test database or any active services + +### Functional and unit test environment + +The functional and unit tests have an invocation in `make test`, +and this attaches several other things like schema that piggybacks on requests. +These tests are ran from the root AWX folder. + +#### Functional tests + +Only tests in the `functional/` folder should use the `@pytest.mark.django_db` decorator. +This is the only difference between the functional and unit folders, +the test environment is otherwise the same for both. + +Functional tests use a sqlite3 database, so the postgres service is not necessary. + +### Live tests + +The live tests have an invocation in `make live_test` which will change +directory before running, which is required to pick up a different pytest +configuration. + +This will use the postges container from `make docker-compose` for the database, +and will disable the pytest-django features of running with a test database +and running tests in transactions. +This means that any changes done in the course of the test could potentially +be seen in your browser via the API or UI, and anything the test fails +to clean up will remain in the database. + +### Folders that should not contain tests + + - `data/` - just files other tests use + - `docs/` - utilities for schema generation + - `factories/` - general utilities + - `manual/` - python files to be ran directly diff --git a/awx/main/tests/conftest.py b/awx/main/tests/conftest.py index 28565901b06a..71e9637ed9e8 100644 --- a/awx/main/tests/conftest.py +++ b/awx/main/tests/conftest.py @@ -140,11 +140,6 @@ def rf(persisted): return rf -@pytest.fixture -def job_with_secret_key_unit(job_with_secret_key_factory): - return job_with_secret_key_factory(persisted=False) - - @pytest.fixture def workflow_job_template_factory(): return create_workflow_job_template @@ -216,6 +211,25 @@ def event_qs(self): @pytest.fixture def mock_me(): + "Allows Instance.objects.me() to work without touching the database" me_mock = mock.MagicMock(return_value=Instance(id=1, hostname=settings.CLUSTER_HOST_ID, uuid='00000000-0000-0000-0000-000000000000')) with mock.patch.object(Instance.objects, 'me', me_mock): yield + + +@pytest.fixture +def me_inst(): + "Inserts an instance to the database for Instance.objects.me(), and goes ahead and mocks it in" + inst = Instance.objects.create(hostname='local_node', uuid='00000000-0000-0000-0000-000000000000') + me_mock = mock.MagicMock(return_value=inst) + with mock.patch.object(Instance.objects, 'me', me_mock): + yield inst + + +@pytest.fixture(scope="session", autouse=True) +def load_all_credentials(): + with mock.patch('awx.main.models.credential.detect_server_product_name', return_value='NOT_AWX'): + from awx.main.models.credential import load_credentials + + load_credentials() + yield diff --git a/awx/main/tests/data/ansible_utils/playbooks/valid/hello_world.yml b/awx/main/tests/data/ansible_utils/playbooks/valid/hello_world.yml index 80d56debc40a..7aff8dbf9ef4 100644 --- a/awx/main/tests/data/ansible_utils/playbooks/valid/hello_world.yml +++ b/awx/main/tests/data/ansible_utils/playbooks/valid/hello_world.yml @@ -3,5 +3,5 @@ hosts: all tasks: - name: Hello Message - debug: + ansible.builtin.debug: msg: "Hello World!" diff --git a/awx/main/tests/data/inventory/plugins/azure_rm/env.json b/awx/main/tests/data/inventory/plugins/azure_rm/env.json index 9ad6db311ec0..b2627d437d7c 100644 --- a/awx/main/tests/data/inventory/plugins/azure_rm/env.json +++ b/awx/main/tests/data/inventory/plugins/azure_rm/env.json @@ -1,9 +1,8 @@ { "ANSIBLE_JINJA2_NATIVE": "True", - "ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never", "AZURE_CLIENT_ID": "fooo", "AZURE_CLOUD_ENVIRONMENT": "fooo", "AZURE_SECRET": "fooo", "AZURE_SUBSCRIPTION_ID": "fooo", "AZURE_TENANT": "fooo" -} \ No newline at end of file +} diff --git a/awx/main/tests/data/inventory/plugins/controller/env.json b/awx/main/tests/data/inventory/plugins/controller/env.json index cc7a5d1ffa7d..8a13483b0462 100644 --- a/awx/main/tests/data/inventory/plugins/controller/env.json +++ b/awx/main/tests/data/inventory/plugins/controller/env.json @@ -1,5 +1,4 @@ { - "ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never", "TOWER_HOST": "https://foo.invalid", "TOWER_PASSWORD": "fooo", "TOWER_USERNAME": "fooo", @@ -9,5 +8,12 @@ "CONTROLLER_PASSWORD": "fooo", "CONTROLLER_USERNAME": "fooo", "CONTROLLER_OAUTH_TOKEN": "", - "CONTROLLER_VERIFY_SSL": "False" -} \ No newline at end of file + "CONTROLLER_VERIFY_SSL": "False", + "AAP_HOSTNAME": "https://foo.invalid", + "AAP_PASSWORD": "fooo", + "AAP_USERNAME": "fooo", + "AAP_VALIDATE_CERTS": "False", + "CONTROLLER_REQUEST_TIMEOUT": "fooo", + "AAP_REQUEST_TIMEOUT": "fooo", + "AAP_TOKEN": "" +} diff --git a/awx/main/tests/data/inventory/plugins/ec2/env.json b/awx/main/tests/data/inventory/plugins/ec2/env.json index 77cedd003eb2..2d1fea36ac12 100644 --- a/awx/main/tests/data/inventory/plugins/ec2/env.json +++ b/awx/main/tests/data/inventory/plugins/ec2/env.json @@ -1,8 +1,7 @@ { "ANSIBLE_JINJA2_NATIVE": "True", - "ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never", "AWS_ACCESS_KEY_ID": "fooo", "AWS_SECRET_ACCESS_KEY": "fooo", "AWS_SECURITY_TOKEN": "fooo", "AWS_SESSION_TOKEN": "fooo" -} \ No newline at end of file +} diff --git a/awx/main/tests/data/inventory/plugins/gce/env.json b/awx/main/tests/data/inventory/plugins/gce/env.json index 4c87c078eb88..13970e2356d2 100644 --- a/awx/main/tests/data/inventory/plugins/gce/env.json +++ b/awx/main/tests/data/inventory/plugins/gce/env.json @@ -1,6 +1,5 @@ { "ANSIBLE_JINJA2_NATIVE": "True", - "ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never", "GCE_CREDENTIALS_FILE_PATH": "{{ file_reference }}", "GOOGLE_APPLICATION_CREDENTIALS": "{{ file_reference }}", "GCP_AUTH_KIND": "serviceaccount", diff --git a/awx/main/tests/data/inventory/plugins/insights/env.json b/awx/main/tests/data/inventory/plugins/insights/env.json index 46eb0a34e7bb..bbece6a48fcf 100644 --- a/awx/main/tests/data/inventory/plugins/insights/env.json +++ b/awx/main/tests/data/inventory/plugins/insights/env.json @@ -1,5 +1,6 @@ { - "ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never", "INSIGHTS_USER": "fooo", - "INSIGHTS_PASSWORD": "fooo" -} \ No newline at end of file + "INSIGHTS_PASSWORD": "fooo", + "INSIGHTS_CLIENT_ID": "fooo", + "INSIGHTS_CLIENT_SECRET": "fooo" +} diff --git a/awx/main/tests/data/inventory/plugins/openshift_virtualization/env.json b/awx/main/tests/data/inventory/plugins/openshift_virtualization/env.json new file mode 100644 index 000000000000..a44de77b88cb --- /dev/null +++ b/awx/main/tests/data/inventory/plugins/openshift_virtualization/env.json @@ -0,0 +1,5 @@ +{ + "K8S_AUTH_HOST": "https://foo.invalid", + "K8S_AUTH_API_KEY": "fooo", + "K8S_AUTH_VERIFY_SSL": "False" +} diff --git a/awx/main/tests/data/inventory/plugins/openstack/env.json b/awx/main/tests/data/inventory/plugins/openstack/env.json index 88dfb239c373..21e151c38bb3 100644 --- a/awx/main/tests/data/inventory/plugins/openstack/env.json +++ b/awx/main/tests/data/inventory/plugins/openstack/env.json @@ -1,4 +1,3 @@ { - "ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never", "OS_CLIENT_CONFIG_FILE": "{{ file_reference }}" -} \ No newline at end of file +} diff --git a/awx/main/tests/data/inventory/plugins/rhv/env.json b/awx/main/tests/data/inventory/plugins/rhv/env.json index 08477df16913..1030a591bf47 100644 --- a/awx/main/tests/data/inventory/plugins/rhv/env.json +++ b/awx/main/tests/data/inventory/plugins/rhv/env.json @@ -1,7 +1,6 @@ { - "ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never", "OVIRT_INI_PATH": "{{ file_reference }}", "OVIRT_PASSWORD": "fooo", "OVIRT_URL": "https://foo.invalid", "OVIRT_USERNAME": "fooo" -} \ No newline at end of file +} diff --git a/awx/main/tests/data/inventory/plugins/satellite6/env.json b/awx/main/tests/data/inventory/plugins/satellite6/env.json index 102abee70b10..482d2ae5057c 100644 --- a/awx/main/tests/data/inventory/plugins/satellite6/env.json +++ b/awx/main/tests/data/inventory/plugins/satellite6/env.json @@ -1,6 +1,5 @@ { - "ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never", "FOREMAN_PASSWORD": "fooo", "FOREMAN_SERVER": "https://foo.invalid", "FOREMAN_USER": "fooo" -} \ No newline at end of file +} diff --git a/awx/main/tests/data/inventory/plugins/terraform/env.json b/awx/main/tests/data/inventory/plugins/terraform/env.json new file mode 100644 index 000000000000..49e8282433e8 --- /dev/null +++ b/awx/main/tests/data/inventory/plugins/terraform/env.json @@ -0,0 +1,3 @@ +{ + "GOOGLE_BACKEND_CREDENTIALS": "{{ file_reference }}" +} diff --git a/awx/main/tests/data/inventory/plugins/vmware/env.json b/awx/main/tests/data/inventory/plugins/vmware/env.json index 97563377c050..6321c24f2632 100644 --- a/awx/main/tests/data/inventory/plugins/vmware/env.json +++ b/awx/main/tests/data/inventory/plugins/vmware/env.json @@ -1,7 +1,6 @@ { - "ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never", "VMWARE_HOST": "https://foo.invalid", "VMWARE_PASSWORD": "fooo", "VMWARE_USER": "fooo", "VMWARE_VALIDATE_CERTS": "False" -} \ No newline at end of file +} diff --git a/awx/main/tests/data/projects/README.md b/awx/main/tests/data/projects/README.md new file mode 100644 index 000000000000..26be7e425c27 --- /dev/null +++ b/awx/main/tests/data/projects/README.md @@ -0,0 +1,41 @@ +# Project data for live tests + +Each folder in this directory is usable as source for a project or role or collection, +which is used in tests, particularly the "awx/main/tests/live" tests. + +Although these are not git repositories, test fixtures will make copies, +and in the coppied folders, run `git init` type commands, turning them into +git repos. This is done in the locations + + - `/var/lib/awx/projects` + - `/tmp/live_tests` + +These can then be referenced for manual projects or git via the `file://` protocol. + +## debug + +This is the simplest possible case with 1 playbook with 1 debug task. + +## with_requirements + +This has a playbook that runs a task that uses a role. + +The role project is referenced in the `roles/requirements.yml` file. + +### role_requirement + +This is the source for the role that the `with_requirements` project uses. + +## test_host_query + +This has a playbook that runs a task from a custom collection module which +is registered for the host query feature. + +The collection is referenced in its `collections/requirements.yml` file. + +### host_query + +This can act as source code for a collection that enables host/event querying. + +It has a `meta/event_query.yml` file, which may provide you an example of how +to implement this in your own collection. diff --git a/awx/main/tests/data/projects/debug/debug.yml b/awx/main/tests/data/projects/debug/debug.yml new file mode 100644 index 000000000000..f4fdcb2f0e51 --- /dev/null +++ b/awx/main/tests/data/projects/debug/debug.yml @@ -0,0 +1,6 @@ +--- +- hosts: all + gather_facts: false + connection: local + tasks: + - debug: msg='hello' diff --git a/awx/main/tests/data/projects/debug/sleep.yml b/awx/main/tests/data/projects/debug/sleep.yml new file mode 100644 index 000000000000..5ae223f29dc2 --- /dev/null +++ b/awx/main/tests/data/projects/debug/sleep.yml @@ -0,0 +1,9 @@ +--- +- hosts: all + gather_facts: false + connection: local + vars: + sleep_interval: 5 + tasks: + - name: sleep for a specified interval + command: sleep '{{ sleep_interval }}' diff --git a/awx/main/tests/data/projects/facts/clear.yml b/awx/main/tests/data/projects/facts/clear.yml new file mode 100644 index 000000000000..140463d6c8fc --- /dev/null +++ b/awx/main/tests/data/projects/facts/clear.yml @@ -0,0 +1,7 @@ +--- + +- hosts: all + gather_facts: false + connection: local + tasks: + - meta: clear_facts diff --git a/awx/main/tests/data/projects/facts/gather.yml b/awx/main/tests/data/projects/facts/gather.yml new file mode 100644 index 000000000000..4b5592dd8b3e --- /dev/null +++ b/awx/main/tests/data/projects/facts/gather.yml @@ -0,0 +1,17 @@ +--- + +- hosts: all + vars: + extra_value: "" + gather_facts: false + connection: local + tasks: + - name: set a custom fact + set_fact: + foo: "bar{{ extra_value }}" + bar: + a: + b: + - "c" + - "d" + cacheable: true diff --git a/awx/main/tests/data/projects/facts/no_op.yml b/awx/main/tests/data/projects/facts/no_op.yml new file mode 100644 index 000000000000..05e5b244d7d1 --- /dev/null +++ b/awx/main/tests/data/projects/facts/no_op.yml @@ -0,0 +1,9 @@ +--- + +- hosts: all + gather_facts: false + connection: local + vars: + msg: 'hello' + tasks: + - debug: var=msg diff --git a/awx/main/tests/data/projects/host_query/extensions/audit/event_query.yml b/awx/main/tests/data/projects/host_query/extensions/audit/event_query.yml new file mode 100644 index 000000000000..a10586b90e22 --- /dev/null +++ b/awx/main/tests/data/projects/host_query/extensions/audit/event_query.yml @@ -0,0 +1,4 @@ +--- +demo.query.example: + query: >- + {name: .name, canonical_facts: {host_name: .direct_host_name}, facts: {device_type: .device_type}} diff --git a/awx/main/tests/data/projects/host_query/galaxy.yml b/awx/main/tests/data/projects/host_query/galaxy.yml new file mode 100644 index 000000000000..a69203d41643 --- /dev/null +++ b/awx/main/tests/data/projects/host_query/galaxy.yml @@ -0,0 +1,19 @@ +--- +authors: + - AWX Project Contributors +dependencies: {} +description: Indirect host counting example repo. Not for use in production. +documentation: https://github.com/ansible/awx +homepage: https://github.com/ansible/awx +issues: https://github.com/ansible/awx +license: + - GPL-3.0-or-later +name: query +namespace: demo +readme: README.md +repository: https://github.com/ansible/awx +tags: + - demo + - testing + - host_counting +version: 0.0.1 diff --git a/awx/main/tests/data/projects/host_query/plugins/modules/example.py b/awx/main/tests/data/projects/host_query/plugins/modules/example.py new file mode 100644 index 000000000000..c1427c1d52bd --- /dev/null +++ b/awx/main/tests/data/projects/host_query/plugins/modules/example.py @@ -0,0 +1,78 @@ +#!/usr/bin/python + +# Same licensing as AWX +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = r''' +--- +module: example + +short_description: Module for specific live tests + +version_added: "2.0.0" + +description: This module is part of a test collection in local source. + +options: + host_name: + description: Name to return as the host name. + required: false + type: str + +author: + - AWX Live Tests +''' + +EXAMPLES = r''' +- name: Test with defaults + demo.query.example: + +- name: Test with custom host name + demo.query.example: + host_name: foo_host +''' + +RETURN = r''' +direct_host_name: + description: The name of the host, this will be collected with the feature. + type: str + returned: always + sample: 'foo_host' +''' + +from ansible.module_utils.basic import AnsibleModule + + +def run_module(): + module_args = dict( + host_name=dict(type='str', required=False, default='foo_host_default'), + ) + + result = dict( + changed=False, + other_data='sample_string', + ) + + module = AnsibleModule(argument_spec=module_args, supports_check_mode=True) + + if module.check_mode: + module.exit_json(**result) + + result['direct_host_name'] = module.params['host_name'] + result['nested_host_name'] = {'host_name': module.params['host_name']} + result['name'] = 'vm-foo' + + # non-cononical facts + result['device_type'] = 'Fake Host' + + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == '__main__': + main() diff --git a/awx/main/tests/data/projects/inventory_vars/inventory_var_deleted_in_source.ini b/awx/main/tests/data/projects/inventory_vars/inventory_var_deleted_in_source.ini new file mode 100644 index 000000000000..8dfebcd50291 --- /dev/null +++ b/awx/main/tests/data/projects/inventory_vars/inventory_var_deleted_in_source.ini @@ -0,0 +1,3 @@ +[all:vars] +a=value_a +b=value_b diff --git a/awx/main/tests/data/projects/role_requirement/meta/main.yml b/awx/main/tests/data/projects/role_requirement/meta/main.yml new file mode 100644 index 000000000000..25563e6d68c8 --- /dev/null +++ b/awx/main/tests/data/projects/role_requirement/meta/main.yml @@ -0,0 +1,19 @@ +--- +galaxy_info: + author: "For Test" + company: AWX + license: MIT + min_ansible_version: 1.4 + platforms: + - name: EL + versions: + - 8 + - 9 + - name: Fedora + versions: + - 39 + - 40 + - 41 + categories: + - stuff +dependencies: [] diff --git a/awx/main/tests/data/projects/role_requirement/tasks/main.yml b/awx/main/tests/data/projects/role_requirement/tasks/main.yml new file mode 100644 index 000000000000..2dbafc91cfb7 --- /dev/null +++ b/awx/main/tests/data/projects/role_requirement/tasks/main.yml @@ -0,0 +1,4 @@ +--- +- name: debug variable + debug: + msg: "1234567890" diff --git a/awx/main/tests/data/projects/test_host_query/collections/requirements.yml b/awx/main/tests/data/projects/test_host_query/collections/requirements.yml new file mode 100644 index 000000000000..17e176ae3991 --- /dev/null +++ b/awx/main/tests/data/projects/test_host_query/collections/requirements.yml @@ -0,0 +1,5 @@ +--- +collections: + - name: 'file:///tmp/live_tests/host_query' + type: git + version: devel diff --git a/awx/main/tests/data/projects/test_host_query/run_task.yml b/awx/main/tests/data/projects/test_host_query/run_task.yml new file mode 100644 index 000000000000..2d23555c6385 --- /dev/null +++ b/awx/main/tests/data/projects/test_host_query/run_task.yml @@ -0,0 +1,8 @@ +--- +- hosts: all + gather_facts: false + connection: local + tasks: + - demo.query.example: + register: result + - debug: var=result diff --git a/awx/main/tests/data/projects/with_requirements/roles/requirements.yml b/awx/main/tests/data/projects/with_requirements/roles/requirements.yml new file mode 100644 index 000000000000..b4eb43576f61 --- /dev/null +++ b/awx/main/tests/data/projects/with_requirements/roles/requirements.yml @@ -0,0 +1,3 @@ +--- +- name: role_requirement + src: git+file:///tmp/live_tests/role_requirement diff --git a/awx/main/tests/data/projects/with_requirements/use_requirement.yml b/awx/main/tests/data/projects/with_requirements/use_requirement.yml new file mode 100644 index 000000000000..7907d662d272 --- /dev/null +++ b/awx/main/tests/data/projects/with_requirements/use_requirement.yml @@ -0,0 +1,7 @@ +--- +- hosts: all + connection: local + gather_facts: false + tasks: + - include_role: + name: role_requirement diff --git a/awx/main/tests/data/sleep_task.py b/awx/main/tests/data/sleep_task.py new file mode 100644 index 000000000000..8582a73c794c --- /dev/null +++ b/awx/main/tests/data/sleep_task.py @@ -0,0 +1,55 @@ +import time +import logging + +from dispatcherd.publish import task + +from django.db import connection + +from awx.main.dispatch import get_task_queuename + +from ansible_base.lib.utils.db import advisory_lock + +logger = logging.getLogger(__name__) + + +@task(queue=get_task_queuename) +def sleep_task(seconds=10, log=False): + if log: + logger.info('starting sleep_task') + time.sleep(seconds) + if log: + logger.info('finished sleep_task') + + +@task() +def sleep_break_connection(seconds=0.2): + """ + Interact with the database in an intentionally breaking way. + After this finishes, queries made by this connection are expected to error + with "the connection is closed" + This is obviously a problem for any task that comes afterwards. + So this is used to break things so that the fixes may be demonstrated. + """ + with connection.cursor() as cursor: + cursor.execute(f"SET idle_session_timeout = '{seconds / 2}s';") + + logger.info(f'sleeping for {seconds}s > {seconds / 2}s session timeout') + time.sleep(seconds) + + for i in range(1, 3): + logger.info(f'\nRunning query number {i}') + try: + with connection.cursor() as cursor: + cursor.execute("SELECT 1;") + logger.info(' query worked, not expected') + except Exception as exc: + logger.info(f' query errored as expected\ntype: {type(exc)}\nstr: {str(exc)}') + + logger.info(f'Connection present: {bool(connection.connection)}, reports closed: {getattr(connection.connection, "closed", "not_found")}') + + +@task() +def advisory_lock_exception(): + time.sleep(0.2) # so it can fill up all the workers... hacky for now + with advisory_lock('advisory_lock_exception', lock_session_timeout_milliseconds=20): + raise RuntimeError('this is an intentional error') diff --git a/awx/main/tests/docs/conftest.py b/awx/main/tests/docs/conftest.py index bd0cf1c99ff2..7ec4273627e3 100644 --- a/awx/main/tests/docs/conftest.py +++ b/awx/main/tests/docs/conftest.py @@ -1,13 +1,8 @@ from awx.main.tests.functional.conftest import * # noqa +import os +import pytest -def pytest_addoption(parser): - parser.addoption("--release", action="store", help="a release version number, e.g., 3.3.0") - - -def pytest_generate_tests(metafunc): - # This is called for every test. Only get/set command line arguments - # if the argument is specified in the list of test "fixturenames". - option_value = metafunc.config.option.release - if 'release' in metafunc.fixturenames and option_value is not None: - metafunc.parametrize("release", [option_value]) +@pytest.fixture() +def release(): + return os.environ.get('VERSION_TARGET', '') diff --git a/awx/main/tests/docs/test_swagger_generation.py b/awx/main/tests/docs/test_swagger_generation.py index 658d8ad2d4b5..39b8b8408ae7 100644 --- a/awx/main/tests/docs/test_swagger_generation.py +++ b/awx/main/tests/docs/test_swagger_generation.py @@ -7,7 +7,6 @@ from django.utils.functional import Promise from django.utils.encoding import force_str -from openapi_codec.encode import generate_swagger_object import pytest from awx.api.versioning import drf_reverse @@ -43,12 +42,12 @@ class TestSwaggerGeneration: @pytest.fixture(autouse=True, scope='function') def _prepare(self, get, admin): if not self.__class__.JSON: - url = drf_reverse('api:swagger_view') + '?format=openapi' + # drf-spectacular returns OpenAPI schema directly from schema endpoint + url = drf_reverse('api:schema-json') + '?format=json' response = get(url, user=admin) - data = generate_swagger_object(response.data) + data = response.data if response.has_header('X-Deprecated-Paths'): data['deprecated_paths'] = json.loads(response['X-Deprecated-Paths']) - data.update(response.accepted_renderer.get_customizations() or {}) data['host'] = None data['schemes'] = ['https'] @@ -60,12 +59,21 @@ def _prepare(self, get, admin): # change {version} in paths to the actual default API version (e.g., v2) revised_paths[path.replace('{version}', settings.REST_FRAMEWORK['DEFAULT_VERSION'])] = node for method in node: + # Ignore any parameters methods, these cause issues because it can come as an array instead of a dict + # Which causes issues in the last for loop in here + if method == 'parameters': + continue + if path in deprecated_paths: node[method]['deprecated'] = True if 'description' in node[method]: # Pop off the first line and use that as the summary lines = node[method]['description'].splitlines() - node[method]['summary'] = lines.pop(0).strip('#:') + # If there was a description then set the summary as the description, otherwise make something up + if lines: + node[method]['summary'] = lines.pop(0).strip('#:') + else: + node[method]['summary'] = f'No Description for {method} on {path}' node[method]['description'] = '\n'.join(lines) # remove the required `version` parameter @@ -80,7 +88,7 @@ def test_sanity(self, release, request): JSON['info']['version'] = release if not request.config.getoption('--genschema'): - JSON['modified'] = datetime.datetime.utcnow().isoformat() + JSON['modified'] = datetime.datetime.now(datetime.UTC).isoformat() # Make some basic assertions about the rendered JSON so we can # be sure it doesn't break across DRF upgrades and view/serializer @@ -90,13 +98,13 @@ def test_sanity(self, release, request): # The number of API endpoints changes over time, but let's just check # for a reasonable number here; if this test starts failing, raise/lower the bounds paths = JSON['paths'] - assert 250 < len(paths) < 350 - assert list(paths['/api/'].keys()) == ['get'] - assert list(paths['/api/v2/'].keys()) == ['get'] - assert list(sorted(paths['/api/v2/credentials/'].keys())) == ['get', 'post'] - assert list(sorted(paths['/api/v2/credentials/{id}/'].keys())) == ['delete', 'get', 'patch', 'put'] - assert list(paths['/api/v2/settings/'].keys()) == ['get'] - assert list(paths['/api/v2/settings/{category_slug}/'].keys()) == ['get', 'put', 'patch', 'delete'] + assert 250 < len(paths) < 400 + assert set(list(paths['/api/'].keys())) == set(['get', 'parameters']) + assert set(list(paths['/api/v2/'].keys())) == set(['get', 'parameters']) + assert set(list(sorted(paths['/api/v2/credentials/'].keys()))) == set(['get', 'post', 'parameters']) + assert set(list(sorted(paths['/api/v2/credentials/{id}/'].keys()))) == set(['delete', 'get', 'patch', 'put', 'parameters']) + assert set(list(paths['/api/v2/settings/'].keys())) == set(['get', 'parameters']) + assert set(list(paths['/api/v2/settings/{category_slug}/'].keys())) == set(['get', 'put', 'patch', 'delete', 'parameters']) @pytest.mark.parametrize( 'path', @@ -162,4 +170,8 @@ def teardown_class(cls): data = re.sub(r'[0-9]{4}-[0-9]{2}-[0-9]{2}(T|\s)[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]+(Z|\+[0-9]{2}:[0-9]{2})?', r'2018-02-01T08:00:00.000000Z', data) data = re.sub(r'''(\s+"client_id": ")([a-zA-Z0-9]{40})("\,\s*)''', r'\1xxxx\3', data) data = re.sub(r'"action_node": "[^"]+"', '"action_node": "awx"', data) + + # replace uuids to prevent needless diffs + pattern = r'[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' + data = re.sub(pattern, r'00000000-0000-0000-0000-000000000000', data) f.write(data) diff --git a/awx/main/tests/factories/fixtures.py b/awx/main/tests/factories/fixtures.py index 27556d6efe47..6f9a3263ac7f 100644 --- a/awx/main/tests/factories/fixtures.py +++ b/awx/main/tests/factories/fixtures.py @@ -1,6 +1,9 @@ import json from django.contrib.auth.models import User +from django.core.exceptions import ValidationError + +from unittest import mock from awx.main.models import ( Organization, @@ -20,6 +23,7 @@ WorkflowJobNode, WorkflowJobTemplateNode, ) +from awx.main.models.inventory import HostMetric, HostMetricSummaryMonthly # mk methods should create only a single object of a single type. # they should also have the option of being persisted or not. @@ -95,11 +99,19 @@ def mk_user(name, is_superuser=False, organization=None, team=None, persisted=Tr def mk_project(name, organization=None, description=None, persisted=True): description = description or '{}-description'.format(name) - project = Project(name=name, description=description, playbook_files=['helloworld.yml', 'alt-helloworld.yml']) + project = Project( + name=name, + description=description, + playbook_files=['helloworld.yml', 'alt-helloworld.yml'], + scm_type='git', + scm_url='https://foo.invalid', + scm_revision='1234567890123456789012345678901234567890', + scm_update_on_launch=False, + ) if organization is not None: project.organization = organization if persisted: - project.save() + project.save(skip_update=True) return project @@ -248,3 +260,42 @@ def mk_workflow_job_node(unified_job_template=None, success_nodes=None, failure_ if persisted: workflow_node.save() return workflow_node + + +def mk_host_metric(hostname, first_automation, last_automation=None, last_deleted=None, deleted=False, persisted=True): + ok, idx = False, 1 + while not ok: + try: + with mock.patch("django.utils.timezone.now") as mock_now: + mock_now.return_value = first_automation + metric = HostMetric( + hostname=hostname or f"host-{first_automation}-{idx}", + first_automation=first_automation, + last_automation=last_automation or first_automation, + last_deleted=last_deleted, + deleted=deleted, + ) + metric.validate_unique() + if persisted: + metric.save() + ok = True + except ValidationError as e: + # Repeat create for auto-generated hostname + if not hostname and e.message_dict.get('hostname', None): + idx += 1 + else: + raise e + + +def mk_host_metric_summary(date, license_consumed=0, license_capacity=0, hosts_added=0, hosts_deleted=0, indirectly_managed_hosts=0, persisted=True): + summary = HostMetricSummaryMonthly( + date=date, + license_consumed=license_consumed, + license_capacity=license_capacity, + hosts_added=hosts_added, + hosts_deleted=hosts_deleted, + indirectly_managed_hosts=indirectly_managed_hosts, + ) + if persisted: + summary.save() + return summary diff --git a/awx/main/tests/functional/__init__.py b/awx/main/tests/functional/__init__.py index 07d89e97390b..3139dcf4e720 100644 --- a/awx/main/tests/functional/__init__.py +++ b/awx/main/tests/functional/__init__.py @@ -59,8 +59,7 @@ def app_post_migration(sender, app_config, **kwargs): elif tblname == 'main_systemjobevent': unique_columns = "system_job_id integer NOT NULL" - cur.execute( - f"""CREATE TABLE _unpartitioned_{tblname} ( + cur.execute(f"""CREATE TABLE _unpartitioned_{tblname} ( id bigint NOT NULL, created timestamp with time zone NOT NULL, modified timestamp with time zone NOT NULL, @@ -72,8 +71,7 @@ def app_post_migration(sender, app_config, **kwargs): uuid character varying(1024) NOT NULL, verbosity integer NOT NULL, {unique_columns}); - """ - ) + """) if settings.DATABASES['default']['ENGINE'] == 'django.db.backends.sqlite3': diff --git a/awx/main/tests/functional/analytics/test_collectors.py b/awx/main/tests/functional/analytics/test_collectors.py index 0fed6e9c156c..4dcb9cd3c3ec 100644 --- a/awx/main/tests/functional/analytics/test_collectors.py +++ b/awx/main/tests/functional/analytics/test_collectors.py @@ -2,8 +2,8 @@ import tempfile import os import re -import shutil import csv +from io import StringIO from django.utils.timezone import now from datetime import timedelta @@ -20,15 +20,16 @@ ) -@pytest.fixture -def sqlite_copy_expert(request): - # copy_expert is postgres-specific, and SQLite doesn't support it; mock its - # behavior to test that it writes a file that contains stdout from events - path = tempfile.mkdtemp(prefix="copied_tables") +class MockCopy: + headers = None + results = None + sent_data = False - def write_stdout(self, sql, fd): + def __init__(self, sql, parent_connection): # Would be cool if we instead properly disected the SQL query and verified # it that way. But instead, we just take the naive approach here. + self.results = None + self.headers = None sql = sql.strip() assert sql.startswith("COPY (") assert sql.endswith(") TO STDOUT WITH CSV HEADER") @@ -51,29 +52,49 @@ def write_stdout(self, sql, fd): elif not line.endswith(","): sql_new[-1] = sql_new[-1].rstrip(",") sql = "\n".join(sql_new) + parent_connection.execute(sql) + self.results = parent_connection.fetchall() + self.headers = [i[0] for i in parent_connection.description] + + def read(self): + if not self.sent_data: + mem_file = StringIO() + csv_handle = csv.writer( + mem_file, + delimiter=",", + quoting=csv.QUOTE_ALL, + escapechar="\\", + lineterminator="\n", + ) + if self.headers: + csv_handle.writerow(self.headers) + if self.results: + csv_handle.writerows(self.results) + self.sent_data = True + return memoryview((mem_file.getvalue()).encode()) + return None + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + pass + - self.execute(sql) - results = self.fetchall() - headers = [i[0] for i in self.description] +@pytest.fixture +def sqlite_copy(request, mocker): + # copy is postgres-specific, and SQLite doesn't support it; mock its + # behavior to test that it writes a file that contains stdout from events - csv_handle = csv.writer( - fd, - delimiter=",", - quoting=csv.QUOTE_ALL, - escapechar="\\", - lineterminator="\n", - ) - csv_handle.writerow(headers) - csv_handle.writerows(results) + def write_stdout(self, sql): + mock_copy = MockCopy(sql, self) + return mock_copy - setattr(SQLiteCursorWrapper, "copy_expert", write_stdout) - request.addfinalizer(lambda: shutil.rmtree(path)) - request.addfinalizer(lambda: delattr(SQLiteCursorWrapper, "copy_expert")) - return path + mocker.patch.object(SQLiteCursorWrapper, 'copy', write_stdout, create=True) @pytest.mark.django_db -def test_copy_tables_unified_job_query(sqlite_copy_expert, project, inventory, job_template): +def test_copy_tables_unified_job_query(sqlite_copy, project, inventory, job_template): """ Ensure that various unified job types are in the output of the query. """ @@ -127,7 +148,7 @@ def workflow_job(states=["new", "new", "new", "new", "new"]): @pytest.mark.django_db -def test_copy_tables_workflow_job_node_query(sqlite_copy_expert, workflow_job): +def test_copy_tables_workflow_job_node_query(sqlite_copy, workflow_job): time_start = now() - timedelta(hours=9) with tempfile.TemporaryDirectory() as tmpdir: diff --git a/awx/main/tests/functional/analytics/test_core.py b/awx/main/tests/functional/analytics/test_core.py index e37f30d26bf1..a2c525c83670 100644 --- a/awx/main/tests/functional/analytics/test_core.py +++ b/awx/main/tests/functional/analytics/test_core.py @@ -2,11 +2,13 @@ import json import os import tarfile +import tempfile from unittest import mock import pytest from django.conf import settings -from awx.main.analytics import gather, register +from django.test.utils import override_settings +from awx.main.analytics import gather, register, ship @register('example', '1.0') @@ -57,3 +59,115 @@ def test_gather(mock_valid_license): os.remove(tgz) except Exception: pass + + +@pytest.fixture +def temp_analytic_tar(): + # Create a temporary file and yield its path + with tempfile.NamedTemporaryFile(delete=False) as temp_file: + temp_file.write(b"data") + temp_file_path = temp_file.name + yield temp_file_path + # Clean up the temporary file after the test + os.remove(temp_file_path) + + +@pytest.fixture +def mock_analytic_post(): + # Patch the Session.post method to return a mock response with status_code 200 + with mock.patch('awx.main.analytics.core.requests.Session.post', return_value=mock.Mock(status_code=200)) as mock_post: + yield mock_post + + +@pytest.mark.parametrize( + "setting_map, expected_result, expected_auth", + [ + # Valid Red Hat credentials + ( + { + 'REDHAT_USERNAME': 'redhat_user', + 'REDHAT_PASSWORD': 'redhat_pass', # NOSONAR + 'SUBSCRIPTIONS_CLIENT_ID': '', + 'SUBSCRIPTIONS_CLIENT_SECRET': '', + }, + True, + ('redhat_user', 'redhat_pass'), + ), + # Valid Subscription credentials with no Red Hat credentials + ( + { + 'REDHAT_USERNAME': None, + 'REDHAT_PASSWORD': None, + 'SUBSCRIPTIONS_CLIENT_ID': 'subs_user', + 'SUBSCRIPTIONS_CLIENT_SECRET': 'subs_pass', # NOSONAR + }, + True, + ('subs_user', 'subs_pass'), + ), + # Valid Subscription credentials with empty Red Hat credentials + ( + { + 'REDHAT_USERNAME': '', + 'REDHAT_PASSWORD': '', + 'SUBSCRIPTIONS_CLIENT_ID': 'subs_user', + 'SUBSCRIPTIONS_CLIENT_SECRET': 'subs_pass', # NOSONAR + }, + True, + ('subs_user', 'subs_pass'), + ), + # No credentials + ( + { + 'REDHAT_USERNAME': '', + 'REDHAT_PASSWORD': '', + 'SUBSCRIPTIONS_CLIENT_ID': '', + 'SUBSCRIPTIONS_CLIENT_SECRET': '', + }, + False, + None, # No request should be made + ), + # Mixed credentials + ( + { + 'REDHAT_USERNAME': '', + 'REDHAT_PASSWORD': 'redhat_pass', # NOSONAR + 'SUBSCRIPTIONS_CLIENT_ID': 'subs_user', + 'SUBSCRIPTIONS_CLIENT_SECRET': '', + }, + False, + None, # Invalid, no request should be made + ), + ], +) +@pytest.mark.django_db +def test_ship_credential(setting_map, expected_result, expected_auth, temp_analytic_tar, mock_analytic_post): + with override_settings(**setting_map): + result = ship(temp_analytic_tar) + + assert result == expected_result + if expected_auth: + mock_analytic_post.assert_called_once() + assert mock_analytic_post.call_args[1]['auth'] == expected_auth + else: + mock_analytic_post.assert_not_called() + + +@pytest.mark.django_db +def test_gather_cleanup_on_auth_failure(mock_valid_license, temp_analytic_tar): + settings.INSIGHTS_TRACKING_STATE = True + settings.AUTOMATION_ANALYTICS_URL = 'https://example.com/api' + settings.REDHAT_USERNAME = 'test_user' + settings.REDHAT_PASSWORD = 'test_password' + + with tempfile.NamedTemporaryFile(delete=False, suffix='.tar.gz') as temp_file: + temp_file_path = temp_file.name + + try: + with mock.patch('awx.main.analytics.core.ship', return_value=False): + with mock.patch('awx.main.analytics.core.package', return_value=temp_file_path): + gather(module=importlib.import_module(__name__), collection_type='scheduled') + + assert not os.path.exists(temp_file_path), "Temp file was not cleaned up after ship failure" + finally: + if os.path.exists(temp_file_path): + os.remove(temp_file_path) diff --git a/awx/main/tests/functional/analytics/test_counts.py b/awx/main/tests/functional/analytics/test_counts.py index dd38c9ef3147..015467692d5b 100644 --- a/awx/main/tests/functional/analytics/test_counts.py +++ b/awx/main/tests/functional/analytics/test_counts.py @@ -66,7 +66,7 @@ def test_database_counts(organization_factory, job_template_factory, workflow_jo @pytest.mark.django_db def test_inventory_counts(organization_factory, inventory_factory): - (inv1, inv2, inv3) = [inventory_factory(f"inv-{i}") for i in range(3)] + inv1, inv2, inv3 = [inventory_factory(f"inv-{i}") for i in range(3)] s1 = inv1.inventory_sources.create(name="src1", source="ec2") s2 = inv1.inventory_sources.create(name="src2", source="file") diff --git a/awx/main/tests/functional/analytics/test_metrics.py b/awx/main/tests/functional/analytics/test_metrics.py index 6192d4e9bd94..2652db85b7c3 100644 --- a/awx/main/tests/functional/analytics/test_metrics.py +++ b/awx/main/tests/functional/analytics/test_metrics.py @@ -1,10 +1,12 @@ import pytest +from django.test import RequestFactory from prometheus_client.parser import text_string_to_metric_families +from rest_framework.request import Request from awx.main import models from awx.main.analytics.metrics import metrics +from awx.main.analytics.dispatcherd_metrics import get_dispatcherd_metrics from awx.api.versioning import reverse -from awx.main.models.rbac import Role EXPECTED_VALUES = { 'awx_system_info': 1.0, @@ -31,6 +33,7 @@ 'awx_license_instance_free': 0, 'awx_pending_jobs_total': 0, 'awx_database_connections_total': 1, + 'awx_license_expiry': 0, } @@ -49,7 +52,7 @@ def test_metrics_counts(organization_factory, job_template_factory, workflow_job for gauge in gauges: for sample in gauge.samples: # name, label, value, timestamp, exemplar - name, _, value, _, _ = sample + name, _, value, _, _, _ = sample assert EXPECTED_VALUES[name] == value @@ -66,7 +69,6 @@ def test_metrics_permissions(get, admin, org_admin, alice, bob, organization): organization.auditor_role.members.add(bob) assert get(get_metrics_view_db_only(), user=bob).status_code == 403 - Role.singleton('system_auditor').members.add(bob) bob.is_system_auditor = True assert get(get_metrics_view_db_only(), user=bob).status_code == 200 @@ -78,3 +80,55 @@ def test_metrics_http_methods(get, post, patch, put, options, admin): assert patch(get_metrics_view_db_only(), user=admin).status_code == 405 assert post(get_metrics_view_db_only(), user=admin).status_code == 405 assert options(get_metrics_view_db_only(), user=admin).status_code == 200 + + +class DummyMetricsResponse: + def __init__(self, payload): + self._payload = payload + + def read(self): + return self._payload + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc, tb): + return False + + +def test_dispatcherd_metrics_node_filter_match(mocker, settings): + settings.CLUSTER_HOST_ID = "awx-1" + payload = b'# HELP test_metric A test metric\n# TYPE test_metric gauge\ntest_metric 1\n' + + def fake_urlopen(url, timeout=1.0): + return DummyMetricsResponse(payload) + + mocker.patch('urllib.request.urlopen', fake_urlopen) + + request = Request(RequestFactory().get('/api/v2/metrics/', {'node': 'awx-1'})) + + assert get_dispatcherd_metrics(request) == payload.decode('utf-8') + + +def test_dispatcherd_metrics_node_filter_excludes_local(mocker, settings): + settings.CLUSTER_HOST_ID = "awx-1" + + def fake_urlopen(*args, **kwargs): + raise AssertionError("urlopen should not be called when node filter excludes local node") + + mocker.patch('urllib.request.urlopen', fake_urlopen) + + request = Request(RequestFactory().get('/api/v2/metrics/', {'node': 'awx-2'})) + + assert get_dispatcherd_metrics(request) == '' + + +def test_dispatcherd_metrics_metric_filter_excludes_unrelated(mocker): + def fake_urlopen(*args, **kwargs): + raise AssertionError("urlopen should not be called when metric filter excludes dispatcherd metrics") + + mocker.patch('urllib.request.urlopen', fake_urlopen) + + request = Request(RequestFactory().get('/api/v2/metrics/', {'metric': 'awx_system_info'})) + + assert get_dispatcherd_metrics(request) == '' diff --git a/awx/main/tests/functional/api/test_activity_streams.py b/awx/main/tests/functional/api/test_activity_streams.py index 961fd02f8004..e66276b3cbf9 100644 --- a/awx/main/tests/functional/api/test_activity_streams.py +++ b/awx/main/tests/functional/api/test_activity_streams.py @@ -109,7 +109,8 @@ def test_stream_queryset_hides_shows_items( settings.ACTIVITY_STREAM_ENABLED = True # this user is not in any organizations and should not see any resource activity no_access_user = user('no-access-user', False) - queryset = ActivityStreamAccess(no_access_user).get_queryset() + access = ActivityStreamAccess(no_access_user) + queryset = access.get_queryset() assert not queryset.filter(project__pk=project.pk) assert not queryset.filter(credential__pk=org_credential.pk) @@ -120,9 +121,11 @@ def test_stream_queryset_hides_shows_items( assert not queryset.filter(host__pk=host.pk) assert not queryset.filter(team__pk=team.pk) assert not queryset.filter(notification_template__pk=notification_template.pk) + assert not access.can_read(activity_stream_entry) # Organization admin should be able to see most things in the ActivityStream - queryset = ActivityStreamAccess(org_admin).get_queryset() + access = ActivityStreamAccess(org_admin) + queryset = access.get_queryset() assert queryset.filter(project__pk=project.pk, operation='create').count() == 1 assert queryset.filter(credential__pk=org_credential.pk, operation='create').count() == 1 @@ -133,6 +136,7 @@ def test_stream_queryset_hides_shows_items( assert queryset.filter(host__pk=host.pk, operation='create').count() == 1 assert queryset.filter(team__pk=team.pk, operation='create').count() == 1 assert queryset.filter(notification_template__pk=notification_template.pk, operation='create').count() == 1 + assert access.can_read(activity_stream_entry) @pytest.mark.django_db diff --git a/awx/main/tests/functional/api/test_adhoc.py b/awx/main/tests/functional/api/test_adhoc.py index 983e45029c40..b6b0b7c7470b 100644 --- a/awx/main/tests/functional/api/test_adhoc.py +++ b/awx/main/tests/functional/api/test_adhoc.py @@ -3,7 +3,6 @@ from awx.api.versioning import reverse - """ def run_test_ad_hoc_command(self, **kwargs): # Post to list to start a new ad hoc command. diff --git a/awx/main/tests/functional/api/test_analytics.py b/awx/main/tests/functional/api/test_analytics.py new file mode 100644 index 000000000000..52fdba74e376 --- /dev/null +++ b/awx/main/tests/functional/api/test_analytics.py @@ -0,0 +1,259 @@ +import pytest +import requests +from unittest import mock +from awx.api.views.analytics import AnalyticsGenericView, MissingSettings, AUTOMATION_ANALYTICS_API_URL_PATH, ERROR_MISSING_USER, ERROR_MISSING_PASSWORD +from django.test.utils import override_settings +from django.test import RequestFactory +from rest_framework import status + +from awx.main.utils import get_awx_version +from django.utils import translation + + +class TestAnalyticsGenericView: + @pytest.mark.parametrize( + "existing_headers,expected_headers", + [ + ({}, {}), + ({'Hey': 'There'}, {}), # We don't forward just any headers + ({'Content-Type': 'text/html', 'Content-Length': '12'}, {'Content-Type': 'text/html', 'Content-Length': '12'}), + # Requests will auto-add the following headers (so we don't need to test them): 'Accept-Encoding', 'User-Agent', 'Accept' + ], + ) + def test__request_headers(self, existing_headers, expected_headers): + expected_headers['X-Rh-Analytics-Source'] = 'controller' + expected_headers['X-Rh-Analytics-Source-Version'] = get_awx_version() + expected_headers['Accept-Language'] = translation.get_language() + + request = requests.session() + request.headers.update(existing_headers) + assert set(expected_headers.items()).issubset(set(AnalyticsGenericView._request_headers(request).items())) + + @pytest.mark.parametrize( + "path,expected_path", + [ + ('A/B', f'{AUTOMATION_ANALYTICS_API_URL_PATH}/A/B'), + ('B', f'{AUTOMATION_ANALYTICS_API_URL_PATH}/B'), + ('/a/b/c/analytics/reports/my_slug', f'{AUTOMATION_ANALYTICS_API_URL_PATH}/reports/my_slug'), + ('/a/b/c/analytics/', f'{AUTOMATION_ANALYTICS_API_URL_PATH}/'), + ('/a/b/c/analytics', f'{AUTOMATION_ANALYTICS_API_URL_PATH}//a/b/c/analytics'), # Because there is no ending / on analytics we get a weird condition + ('/a/b/c/analytics/', f'{AUTOMATION_ANALYTICS_API_URL_PATH}/'), + ], + ) + @pytest.mark.django_db + def test__get_analytics_path(self, path, expected_path): + assert AnalyticsGenericView._get_analytics_path(path) == expected_path + + @pytest.mark.django_db + def test__get_analytics_url_no_url(self): + with override_settings(AUTOMATION_ANALYTICS_URL=None): + with pytest.raises(MissingSettings): + agw = AnalyticsGenericView() + agw._get_analytics_url('A') + + @pytest.mark.parametrize( + "request_path,ending_url", + [ + ('A', 'A'), + ('A/B', 'A/B'), + ('A/B/analytics/', ''), # we split on analytics but because there is nothing after + ('A/B/analytics/report', 'report'), + ('A/B/analytics/report/slug', 'report/slug'), + ], + ) + @pytest.mark.django_db + def test__get_analytics_url(self, request_path, ending_url): + base_url = 'http://testing' + with override_settings(AUTOMATION_ANALYTICS_URL=base_url): + agw = AnalyticsGenericView() + assert agw._get_analytics_url(request_path) == f'{base_url}{AUTOMATION_ANALYTICS_API_URL_PATH}/{ending_url}' + + @pytest.mark.parametrize( + "setting_name,setting_value,raises", + [ + ('INSIGHTS_TRACKING_STATE', None, True), + ('INSIGHTS_TRACKING_STATE', False, True), + ('INSIGHTS_TRACKING_STATE', True, False), + ('INSIGHTS_TRACKING_STATE', 'Steve', False), + ('INSIGHTS_TRACKING_STATE', 1, False), + ('INSIGHTS_TRACKING_STATE', '', True), + ], + ) + @pytest.mark.django_db + def test__get_setting(self, setting_name, setting_value, raises): + with override_settings(**{setting_name: setting_value}): + if raises: + with pytest.raises(MissingSettings): + AnalyticsGenericView._get_setting(setting_name, False, None) + else: + assert AnalyticsGenericView._get_setting(setting_name, False, None) == setting_value + + @pytest.mark.parametrize( + "settings_map, expected_auth, expected_error_keyword", + [ + # Test case 1: Valid Red Hat credentials + ( + { + 'INSIGHTS_TRACKING_STATE': True, + 'REDHAT_USERNAME': 'redhat_user', + 'REDHAT_PASSWORD': 'redhat_pass', # NOSONAR + 'SUBSCRIPTIONS_CLIENT_ID': '', + 'SUBSCRIPTIONS_CLIENT_SECRET': '', + }, + ('redhat_user', 'redhat_pass'), + None, + ), + # Test case 2: Valid Subscription credentials + ( + { + 'INSIGHTS_TRACKING_STATE': True, + 'REDHAT_USERNAME': '', + 'REDHAT_PASSWORD': '', + 'SUBSCRIPTIONS_CLIENT_ID': 'subs_user', + 'SUBSCRIPTIONS_CLIENT_SECRET': 'subs_pass', # NOSONAR + }, + ('subs_user', 'subs_pass'), + None, + ), + # Test case 3: No credentials + ( + { + 'INSIGHTS_TRACKING_STATE': True, + 'REDHAT_USERNAME': '', + 'REDHAT_PASSWORD': '', + 'SUBSCRIPTIONS_CLIENT_ID': '', + 'SUBSCRIPTIONS_CLIENT_SECRET': '', + }, + None, + ERROR_MISSING_USER, + ), + # Test case 4: Both credentials + ( + { + 'INSIGHTS_TRACKING_STATE': True, + 'REDHAT_USERNAME': 'redhat_user', + 'REDHAT_PASSWORD': 'redhat_pass', # NOSONAR + 'SUBSCRIPTIONS_CLIENT_ID': 'subs_user', + 'SUBSCRIPTIONS_CLIENT_SECRET': 'subs_pass', # NOSONAR + }, + ('redhat_user', 'redhat_pass'), + None, + ), + # Test case 5: Missing password + ( + { + 'INSIGHTS_TRACKING_STATE': True, + 'REDHAT_USERNAME': '', + 'REDHAT_PASSWORD': '', + 'SUBSCRIPTIONS_CLIENT_ID': 'subs_user', # NOSONAR + 'SUBSCRIPTIONS_CLIENT_SECRET': '', + }, + None, + ERROR_MISSING_PASSWORD, + ), + ], + ) + @pytest.mark.django_db + def test__send_to_analytics_credentials(self, settings_map, expected_auth, expected_error_keyword): + """ + Test _send_to_analytics with various combinations of credentials. + """ + with override_settings(**settings_map): + request = RequestFactory().post('/some/path') + view = AnalyticsGenericView() + + if expected_auth: + with mock.patch('awx.api.views.analytics.OIDCClient') as mock_oidc_client: + # Configure the mock OIDCClient instance and its make_request method + mock_client_instance = mock.Mock() + mock_oidc_client.return_value = mock_client_instance + mock_client_instance.make_request.return_value = mock.Mock(status_code=200) + + analytic_url = view._get_analytics_url(request.path) + response = view._send_to_analytics(request, 'POST') + + # Assertions + # Assert OIDCClient instantiation + expected_client_id, expected_client_secret = expected_auth + mock_oidc_client.assert_called_once_with(expected_client_id, expected_client_secret) + + # Assert make_request call + mock_client_instance.make_request.assert_called_once_with( + 'POST', + analytic_url, + headers=mock.ANY, + verify=mock.ANY, + params=mock.ANY, + json=mock.ANY, + timeout=mock.ANY, + ) + assert response.status_code == 200 + else: + # Test when settings are missing and MissingSettings is raised + response = view._send_to_analytics(request, 'POST') + + # # Assert that _error_response is called when MissingSettings is raised + # mock_error_response.assert_called_once_with(expected_error_keyword, remote=False) + assert response.status_code == status.HTTP_403_FORBIDDEN + assert response.data['error']['keyword'] == expected_error_keyword + + @pytest.mark.django_db + @pytest.mark.parametrize( + "settings_map, expected_auth", + [ + # Test case 1: Username and password should be used for basic auth + ( + { + 'INSIGHTS_TRACKING_STATE': True, + 'REDHAT_USERNAME': 'redhat_user', + 'REDHAT_PASSWORD': 'redhat_pass', # NOSONAR + 'SUBSCRIPTIONS_CLIENT_ID': '', + 'SUBSCRIPTIONS_CLIENT_SECRET': '', + }, + ('redhat_user', 'redhat_pass'), + ), + # Test case 2: Client ID and secret should be used for basic auth + ( + { + 'INSIGHTS_TRACKING_STATE': True, + 'REDHAT_USERNAME': '', + 'REDHAT_PASSWORD': '', + 'SUBSCRIPTIONS_CLIENT_ID': 'subs_user', + 'SUBSCRIPTIONS_CLIENT_SECRET': 'subs_pass', # NOSONAR + }, + None, + ), + ], + ) + def test__send_to_analytics_fallback_to_basic_auth(self, settings_map, expected_auth): + """ + Test _send_to_analytics with basic auth fallback. + """ + with override_settings(**settings_map): + request = RequestFactory().post('/some/path') + view = AnalyticsGenericView() + + with mock.patch('awx.api.views.analytics.OIDCClient') as mock_oidc_client, mock.patch( + 'awx.api.views.analytics.AnalyticsGenericView._base_auth_request' + ) as mock_base_auth_request: + # Configure the mock OIDCClient instance and its make_request method + mock_client_instance = mock.Mock() + mock_oidc_client.return_value = mock_client_instance + mock_client_instance.make_request.side_effect = requests.RequestException("Incorrect credentials") + + analytic_url = view._get_analytics_url(request.path) + view._send_to_analytics(request, 'POST') + + if expected_auth: + # assert mock_base_auth_request called with expected_auth + mock_base_auth_request.assert_called_once_with( + request, + 'POST', + analytic_url, + expected_auth[0], + expected_auth[1], + mock.ANY, + ) + else: + # assert mock_base_auth_request not called + mock_base_auth_request.assert_not_called() diff --git a/awx/main/tests/functional/test_api_generics.py b/awx/main/tests/functional/api/test_api_generics.py similarity index 100% rename from awx/main/tests/functional/test_api_generics.py rename to awx/main/tests/functional/api/test_api_generics.py diff --git a/awx/main/tests/functional/api/test_application_name.py b/awx/main/tests/functional/api/test_application_name.py new file mode 100644 index 000000000000..da7cda210ca0 --- /dev/null +++ b/awx/main/tests/functional/api/test_application_name.py @@ -0,0 +1,23 @@ +import pytest +from awx.settings.application_name import get_service_name, set_application_name + + +@pytest.mark.parametrize( + 'argv,result', + ( + ([], None), + (['-m'], None), + (['-m', 'python'], None), + (['-m', 'python', 'manage'], None), + (['-m', 'python', 'manage', 'a'], 'a'), + (['-m', 'python', 'manage', 'b', 'a'], 'b'), + (['-m', 'python', 'manage', 'run_something', 'b', 'a'], 'something'), + ), +) +def test_get_service_name(argv, result): + assert get_service_name(argv) == result + + +@pytest.mark.parametrize('DATABASES,CLUSTER_ID,function', (({}, 12, ''), ({'default': {'ENGINE': 'sqllite3'}}, 12, ''))) +def test_set_application_name(DATABASES, CLUSTER_ID, function): + set_application_name(DATABASES, CLUSTER_ID, function) diff --git a/awx/main/tests/functional/api/test_auth.py b/awx/main/tests/functional/api/test_auth.py index d9ac588de323..49a9c7640df2 100644 --- a/awx/main/tests/functional/api/test_auth.py +++ b/awx/main/tests/functional/api/test_auth.py @@ -1,12 +1,16 @@ import pytest from django.contrib import auth +from django.http import JsonResponse + from django.test import Client from rest_framework.test import APIRequestFactory -from awx.api.generics import LoggedLoginView -from awx.api.versioning import drf_reverse +import awx.api.generics +from rest_framework.reverse import reverse as drf_reverse + +from pytest_mock import MockerFixture @pytest.mark.django_db @@ -21,6 +25,25 @@ def test_invalid_login(): request = factory.post(url, data) request.user = anon - response = LoggedLoginView.as_view()(request) + response = awx.api.generics.LoggedLoginView.as_view()(request) + + assert response.status_code == 401 + +@pytest.mark.django_db +def test_invalid_post(mocker: MockerFixture, monkeypatch: pytest.MonkeyPatch): + url = drf_reverse('api:login') + factory = APIRequestFactory() + request = factory.post(url) + + is_proxied_request_mock = mocker.Mock( + autospec=True, + name='is_proxied_request', + return_value=True, + ) + monkeypatch.setattr(awx.api.generics, 'is_proxied_request', is_proxied_request_mock) + response = awx.api.generics.LoggedLoginView.as_view()(request) + + assert isinstance(response, JsonResponse) + assert b'Please log in via Platform Authentication.' in response.content assert response.status_code == 401 diff --git a/awx/main/tests/functional/api/test_create_attach_views.py b/awx/main/tests/functional/api/test_create_attach_views.py index b22ec089122f..7b92f82f5076 100644 --- a/awx/main/tests/functional/api/test_create_attach_views.py +++ b/awx/main/tests/functional/api/test_create_attach_views.py @@ -9,8 +9,8 @@ def test_user_role_view_access(rando, inventory, mocker, post): role_pk = inventory.admin_role.pk data = {"id": role_pk} mock_access = mocker.MagicMock(can_attach=mocker.MagicMock(return_value=False)) - with mocker.patch('awx.main.access.RoleAccess', return_value=mock_access): - post(url=reverse('api:user_roles_list', kwargs={'pk': rando.pk}), data=data, user=rando, expect=403) + mocker.patch('awx.main.access.RoleAccess', return_value=mock_access) + post(url=reverse('api:user_roles_list', kwargs={'pk': rando.pk}), data=data, user=rando, expect=403) mock_access.can_attach.assert_called_once_with(inventory.admin_role, rando, 'members', data, skip_sub_obj_read_check=False) @@ -21,8 +21,8 @@ def test_team_role_view_access(rando, team, inventory, mocker, post): role_pk = inventory.admin_role.pk data = {"id": role_pk} mock_access = mocker.MagicMock(can_attach=mocker.MagicMock(return_value=False)) - with mocker.patch('awx.main.access.RoleAccess', return_value=mock_access): - post(url=reverse('api:team_roles_list', kwargs={'pk': team.pk}), data=data, user=rando, expect=403) + mocker.patch('awx.main.access.RoleAccess', return_value=mock_access) + post(url=reverse('api:team_roles_list', kwargs={'pk': team.pk}), data=data, user=rando, expect=403) mock_access.can_attach.assert_called_once_with(inventory.admin_role, team, 'member_role.parents', data, skip_sub_obj_read_check=False) @@ -33,8 +33,8 @@ def test_role_team_view_access(rando, team, inventory, mocker, post): role_pk = inventory.admin_role.pk data = {"id": team.pk} mock_access = mocker.MagicMock(return_value=False, __name__='mocked') - with mocker.patch('awx.main.access.RoleAccess.can_attach', mock_access): - post(url=reverse('api:role_teams_list', kwargs={'pk': role_pk}), data=data, user=rando, expect=403) + mocker.patch('awx.main.access.RoleAccess.can_attach', mock_access) + post(url=reverse('api:role_teams_list', kwargs={'pk': role_pk}), data=data, user=rando, expect=403) mock_access.assert_called_once_with(inventory.admin_role, team, 'member_role.parents', data, skip_sub_obj_read_check=False) diff --git a/awx/main/tests/functional/api/test_credential.py b/awx/main/tests/functional/api/test_credential.py index 52814f3655ea..7956ebed4fc1 100644 --- a/awx/main/tests/functional/api/test_credential.py +++ b/awx/main/tests/functional/api/test_credential.py @@ -12,25 +12,13 @@ EXAMPLE_PRIVATE_KEY = '-----BEGIN PRIVATE KEY-----\nxyz==\n-----END PRIVATE KEY-----' EXAMPLE_ENCRYPTED_PRIVATE_KEY = '-----BEGIN PRIVATE KEY-----\nProc-Type: 4,ENCRYPTED\nxyz==\n-----END PRIVATE KEY-----' - -@pytest.mark.django_db -def test_idempotent_credential_type_setup(): - assert CredentialType.objects.count() == 0 - CredentialType.setup_tower_managed_defaults() - total = CredentialType.objects.count() - assert total > 0 - - CredentialType.setup_tower_managed_defaults() - assert CredentialType.objects.count() == total - - # # user credential creation # @pytest.mark.django_db -def test_create_user_credential_via_credentials_list(post, get, alice, credentialtype_ssh): +def test_create_user_credential_via_credentials_list(post, get, alice, credentialtype_ssh, setup_managed_roles): params = { 'credential_type': 1, 'inputs': {'username': 'someusername'}, @@ -77,11 +65,11 @@ def test_credential_validation_error_with_multiple_owner_fields(post, admin, ali } response = post(reverse('api:credential_list'), params, admin) assert response.status_code == 400 - assert response.data['detail'][0] == ("Only one of 'user', 'team', or 'organization' should be provided, " "received organization, team, user fields.") + assert response.data['detail'][0] == ("Only one of 'user', 'team', or 'organization' should be provided, received organization, team, user fields.") @pytest.mark.django_db -def test_create_user_credential_via_user_credentials_list(post, get, alice, credentialtype_ssh): +def test_create_user_credential_via_user_credentials_list(post, get, alice, credentialtype_ssh, setup_managed_roles): params = { 'credential_type': 1, 'inputs': {'username': 'someusername'}, @@ -299,6 +287,72 @@ def test_sa_grant_private_credential_to_team_through_role_teams(post, credential assert response.status_code == 400 +@pytest.mark.django_db +def test_grant_credential_to_team_different_organization_through_role_teams(post, get, credential, organizations, admin, org_admin, team, team_member): + # # Test that credential from different org can be assigned to team by a superuser through role_teams_list endpoint + orgs = organizations(2) + credential.organization = orgs[0] + credential.save() + team.organization = orgs[1] + team.save() + + # Non-superuser (org_admin) trying cross-org assignment should be denied + response = post(reverse('api:role_teams_list', kwargs={'pk': credential.use_role.id}), {'id': team.id}, org_admin) + assert response.status_code == 400 + assert ( + "You cannot grant a team access to a credential in a different organization. Only superusers can grant cross-organization credential access to teams" + in response.data['msg'] + ) + + # Superuser (admin) can do cross-org assignment + response = post(reverse('api:role_teams_list', kwargs={'pk': credential.use_role.id}), {'id': team.id}, admin) + assert response.status_code == 204 + + assert credential.use_role in team.member_role.children.all() + assert team_member in credential.read_role + assert team_member in credential.use_role + assert team_member not in credential.admin_role + + +@pytest.mark.django_db +def test_grant_credential_to_team_different_organization(post, get, credential, organizations, admin, org_admin, team, team_member): + # Test that credential from different org can be assigned to team by a superuser + orgs = organizations(2) + credential.organization = orgs[0] + credential.save() + team.organization = orgs[1] + team.save() + + # Non-superuser (org_admin, ...) trying cross-org assignment should be denied + response = post(reverse('api:team_roles_list', kwargs={'pk': team.id}), {'id': credential.use_role.id}, org_admin) + assert response.status_code == 400 + assert ( + "You cannot grant a team access to a credential in a different organization. Only superusers can grant cross-organization credential access to teams" + in response.data['msg'] + ) + + # Superuser (system admin) can do cross-org assignment + response = post(reverse('api:team_roles_list', kwargs={'pk': team.id}), {'id': credential.use_role.id}, admin) + assert response.status_code == 204 + + assert credential.use_role in team.member_role.children.all() + + assert team_member in credential.read_role + assert team_member in credential.use_role + assert team_member not in credential.admin_role + + # Team member can see the credential in API + response = get(reverse('api:team_credentials_list', kwargs={'pk': team.id}), team_member) + assert response.status_code == 200 + assert response.data['count'] == 1 + assert response.data['results'][0]['id'] == credential.id + + # Team member can see the credential in general credentials API + response = get(reverse('api:credential_list'), team_member) + assert response.status_code == 200 + assert any(cred['id'] == credential.id for cred in response.data['results']) + + @pytest.mark.django_db def test_sa_grant_private_credential_to_team_through_team_roles(post, credential, admin, team): # not even a system admin can grant a private cred to a team though @@ -385,10 +439,9 @@ def test_list_created_org_credentials(post, get, organization, org_admin, org_me @pytest.mark.django_db def test_list_cannot_order_by_encrypted_field(post, get, organization, org_admin, credentialtype_ssh, order_by): for i, password in enumerate(('abc', 'def', 'xyz')): - response = post(reverse('api:credential_list'), {'organization': organization.id, 'name': 'C%d' % i, 'password': password}, org_admin) + post(reverse('api:credential_list'), {'organization': organization.id, 'name': 'C%d' % i, 'password': password}, org_admin, expect=400) - response = get(reverse('api:credential_list'), org_admin, QUERY_STRING='order_by=%s' % order_by, status=400) - assert response.status_code == 400 + get(reverse('api:credential_list'), org_admin, QUERY_STRING='order_by=%s' % order_by, expect=400) @pytest.mark.django_db @@ -399,8 +452,7 @@ def test_inputs_cannot_contain_extra_fields(get, post, organization, admin, cred 'credential_type': credentialtype_ssh.pk, 'inputs': {'invalid_field': 'foo'}, } - response = post(reverse('api:credential_list'), params, admin) - assert response.status_code == 400 + response = post(reverse('api:credential_list'), params, admin, expect=400) assert "'invalid_field' was unexpected" in response.data['inputs'][0] @@ -925,7 +977,7 @@ def _change_credential_type(): response = _change_credential_type() assert response.status_code == 400 - expected = ['You cannot change the credential type of the credential, ' 'as it may break the functionality of the resources using it.'] + expected = ['You cannot change the credential type of the credential, as it may break the functionality of the resources using it.'] assert response.data['credential_type'] == expected response = patch(reverse('api:credential_detail', kwargs={'pk': cred.pk}), {'name': 'Worst credential ever'}, admin) @@ -962,7 +1014,7 @@ def _change_credential_type(): response = _change_credential_type() assert response.status_code == 400 - expected = ['You cannot change the credential type of the credential, ' 'as it may break the functionality of the resources using it.'] + expected = ['You cannot change the credential type of the credential, as it may break the functionality of the resources using it.'] assert response.data['credential_type'] == expected response = patch(reverse('api:credential_detail', kwargs={'pk': cred.pk}), {'name': 'Worst credential ever'}, admin) @@ -994,7 +1046,7 @@ def _change_credential_type(): response = _change_credential_type() assert response.status_code == 400 - expected = ['You cannot change the credential type of the credential, ' 'as it may break the functionality of the resources using it.'] + expected = ['You cannot change the credential type of the credential, as it may break the functionality of the resources using it.'] assert response.data['credential_type'] == expected response = patch(reverse('api:credential_detail', kwargs={'pk': cred.pk}), {'name': 'Worst credential ever'}, admin) @@ -1238,6 +1290,30 @@ def test_custom_credential_type_create(get, post, organization, admin): assert decrypt_field(cred, 'api_token') == 'secret' +@pytest.mark.django_db +def test_galaxy_create_ok(post, organization, admin): + params = { + 'credential_type': 1, + 'name': 'Galaxy credential', + 'inputs': { + 'url': 'https://galaxy.ansible.com', + 'token': 'some_galaxy_token', + }, + } + galaxy = CredentialType.defaults['galaxy_api_token']() + galaxy.save() + params['user'] = admin.id + params['credential_type'] = galaxy.pk + response = post(reverse('api:credential_list'), params, admin) + assert response.status_code == 201 + + assert Credential.objects.count() == 1 + cred = Credential.objects.all()[:1].get() + assert cred.credential_type == galaxy + assert cred.inputs['url'] == 'https://galaxy.ansible.com' + assert decrypt_field(cred, 'token') == 'some_galaxy_token' + + # # misc xfail conditions # diff --git a/awx/main/tests/functional/api/test_deprecated_credential_assignment.py b/awx/main/tests/functional/api/test_deprecated_credential_assignment.py index 266218c0cb23..02937c184514 100644 --- a/awx/main/tests/functional/api/test_deprecated_credential_assignment.py +++ b/awx/main/tests/functional/api/test_deprecated_credential_assignment.py @@ -6,12 +6,6 @@ from awx.api.versioning import reverse -@pytest.fixture -def ec2_source(inventory, project): - with mock.patch('awx.main.models.unified_jobs.UnifiedJobTemplate.update'): - return inventory.inventory_sources.create(name='some_source', source='ec2', source_project=project) - - @pytest.fixture def job_template(job_template, project, inventory): job_template.playbook = 'helloworld.yml' diff --git a/awx/main/tests/functional/api/test_events.py b/awx/main/tests/functional/api/test_events.py index 34ecf4d691cc..ebc8900cae84 100644 --- a/awx/main/tests/functional/api/test_events.py +++ b/awx/main/tests/functional/api/test_events.py @@ -73,6 +73,7 @@ def test_job_job_events_children_summary(get, organization_factory, job_template job_id=job.pk, uuid='uuid3', parent_uuid='uuid2', event="playbook_on_task_start", counter=3, stdout='a' * 1024, job_created=job.created ).save() JobEvent.create_from_data(job_id=job.pk, uuid='uuid4', parent_uuid='', event='verbose', counter=4, stdout='a' * 1024, job_created=job.created).save() + JobEvent.create_from_data( job_id=job.pk, uuid='uuid5', parent_uuid='uuid1', event="playbook_on_play_start", counter=5, stdout='a' * 1024, job_created=job.created ).save() @@ -131,3 +132,46 @@ def test_job_job_events_children_summary_is_tree(get, organization_factory, job_ assert response.data["meta_event_nested_uuid"] == {} assert response.data["event_processing_finished"] == True assert response.data["is_tree"] == False + + +@pytest.mark.django_db +def test_job_job_events_children_summary_empty_event(get, organization_factory, job_template_factory): + objs = organization_factory("org", superusers=['admin']) + jt = job_template_factory("jt", organization=objs.organization, inventory='test_inv', project='test_proj').job_template + job = jt.create_unified_job() + url = reverse('api:job_job_events_children_summary', kwargs={'pk': job.pk}) + response = get(url, user=objs.superusers.admin, expect=200) + assert response.data["event_processing_finished"] == False + ''' + E1 + E2 + E3 + E4 (verbose) + E5 + ''' + JobEvent.create_from_data( + job_id=job.pk, uuid='uuid1', parent_uuid='', event="playbook_on_start", counter=1, stdout='a' * 1024, job_created=job.created + ).save() + JobEvent.create_from_data( + job_id=job.pk, uuid='uuid2', parent_uuid='uuid1', event="playbook_on_play_start", counter=2, stdout='a' * 1024, job_created=job.created + ).save() + JobEvent.create_from_data( + job_id=job.pk, uuid='uuid3', parent_uuid='uuid2', event="playbook_on_task_start", counter=3, stdout='a' * 1024, job_created=job.created + ).save() + JobEvent.create_from_data(job_id=job.pk, uuid='uuid4', parent_uuid='', event='verbose', counter=4, stdout='a' * 1024, job_created=job.created).save() + + JobEvent.create_from_data(job_id=job.pk, uuid='uuid4', parent_uuid='', event='', counter=5, stdout='a' * 1024, job_created=job.created).save() + + JobEvent.create_from_data( + job_id=job.pk, uuid='uuid5', parent_uuid='uuid1', event="playbook_on_play_start", counter=6, stdout='a' * 1024, job_created=job.created + ).save() + + job.emitted_events = job.get_event_queryset().count() + job.status = "successful" + job.save() + url = reverse('api:job_job_events_children_summary', kwargs={'pk': job.pk}) + response = get(url, user=objs.superusers.admin, expect=200) + assert response.data["children_summary"] == {1: {"rowNumber": 0, "numChildren": 4}, 2: {"rowNumber": 1, "numChildren": 2}} + assert response.data["meta_event_nested_uuid"] == {4: "uuid2"} + assert response.data["event_processing_finished"] == True + assert response.data["is_tree"] == True diff --git a/awx/main/tests/functional/api/test_generic.py b/awx/main/tests/functional/api/test_generic.py index 0c064f23a40c..87571c8eeabe 100644 --- a/awx/main/tests/functional/api/test_generic.py +++ b/awx/main/tests/functional/api/test_generic.py @@ -1,22 +1,30 @@ import pytest +from unittest import mock from awx.api.versioning import reverse +from django.test.utils import override_settings + +from ansible_base.jwt_consumer.common.util import generate_x_trusted_proxy_header +from ansible_base.lib.testing.fixtures import rsa_keypair_factory, rsa_keypair # noqa: F401; pylint: disable=unused-import + + +class HeaderTrackingMiddleware(object): + def __init__(self): + self.environ = {} + + def process_request(self, request): + pass + + def process_response(self, request, response): + self.environ = request.environ + @pytest.mark.django_db def test_proxy_ip_allowed(get, patch, admin): url = reverse('api:setting_singleton_detail', kwargs={'category_slug': 'system'}) patch(url, user=admin, data={'REMOTE_HOST_HEADERS': ['HTTP_X_FROM_THE_LOAD_BALANCER', 'REMOTE_ADDR', 'REMOTE_HOST']}) - class HeaderTrackingMiddleware(object): - environ = {} - - def process_request(self, request): - pass - - def process_response(self, request, response): - self.environ = request.environ - # By default, `PROXY_IP_ALLOWED_LIST` is disabled, so custom `REMOTE_HOST_HEADERS` # should just pass through middleware = HeaderTrackingMiddleware() @@ -45,6 +53,51 @@ def process_response(self, request, response): assert middleware.environ['HTTP_X_FROM_THE_LOAD_BALANCER'] == 'some-actual-ip' +@pytest.mark.django_db +class TestTrustedProxyAllowListIntegration: + @pytest.fixture + def url(self, patch, admin): + url = reverse('api:setting_singleton_detail', kwargs={'category_slug': 'system'}) + patch(url, user=admin, data={'REMOTE_HOST_HEADERS': ['HTTP_X_FROM_THE_LOAD_BALANCER', 'REMOTE_ADDR', 'REMOTE_HOST']}) + patch(url, user=admin, data={'PROXY_IP_ALLOWED_LIST': ['my.proxy.example.org']}) + return url + + @pytest.fixture + def middleware(self): + return HeaderTrackingMiddleware() + + def test_x_trusted_proxy_valid_signature(self, get, admin, rsa_keypair, url, middleware): # noqa: F811 + # Headers should NOT get deleted + headers = { + 'HTTP_X_TRUSTED_PROXY': generate_x_trusted_proxy_header(rsa_keypair.private), + 'HTTP_X_FROM_THE_LOAD_BALANCER': 'some-actual-ip', + } + with mock.patch('ansible_base.jwt_consumer.common.cache.JWTCache.get_key_from_cache', lambda self: None): + with override_settings(ANSIBLE_BASE_JWT_KEY=rsa_keypair.public, PROXY_IP_ALLOWED_LIST=[]): + get(url, user=admin, middleware=middleware, **headers) + assert middleware.environ['HTTP_X_FROM_THE_LOAD_BALANCER'] == 'some-actual-ip' + + def test_x_trusted_proxy_invalid_signature(self, get, admin, url, patch, middleware): + # Headers should NOT get deleted + headers = { + 'HTTP_X_TRUSTED_PROXY': 'DEAD-BEEF', + 'HTTP_X_FROM_THE_LOAD_BALANCER': 'some-actual-ip', + } + with override_settings(PROXY_IP_ALLOWED_LIST=[]): + get(url, user=admin, middleware=middleware, **headers) + assert middleware.environ['HTTP_X_FROM_THE_LOAD_BALANCER'] == 'some-actual-ip' + + def test_x_trusted_proxy_invalid_signature_valid_proxy(self, get, admin, url, middleware): + # A valid explicit proxy SHOULD result in sensitive headers NOT being deleted, regardless of the trusted proxy signature results + headers = { + 'HTTP_X_TRUSTED_PROXY': 'DEAD-BEEF', + 'REMOTE_ADDR': 'my.proxy.example.org', + 'HTTP_X_FROM_THE_LOAD_BALANCER': 'some-actual-ip', + } + get(url, user=admin, middleware=middleware, **headers) + assert middleware.environ['HTTP_X_FROM_THE_LOAD_BALANCER'] == 'some-actual-ip' + + @pytest.mark.django_db class TestDeleteViews: def test_sublist_delete_permission_check(self, inventory_source, host, rando, delete): diff --git a/awx/main/tests/functional/api/test_instance.py b/awx/main/tests/functional/api/test_instance.py index b9ec4d2ab088..c2e18b765dae 100644 --- a/awx/main/tests/functional/api/test_instance.py +++ b/awx/main/tests/functional/api/test_instance.py @@ -1,3 +1,5 @@ +from unittest import mock + import pytest from awx.api.versioning import reverse @@ -5,7 +7,9 @@ from awx.main.models.ha import Instance from django.test.utils import override_settings +from django.http import HttpResponse +from rest_framework import status INSTANCE_KWARGS = dict(hostname='example-host', cpu=6, node_type='execution', memory=36000000000, cpu_capacity=6, mem_capacity=42) @@ -84,5 +88,14 @@ def test_custom_hostname_regex(post, admin_user): "hostname": value[0], "node_type": "execution", "node_state": "installed", + "peers": [], } post(url=url, user=admin_user, data=data, expect=value[1]) + + +def test_instance_install_bundle(get, admin_user, system_auditor): + instance = Instance.objects.create(**INSTANCE_KWARGS) + url = reverse('api:instance_install_bundle', kwargs={'pk': instance.pk}) + with mock.patch('awx.api.views.instance_install_bundle.InstanceInstallBundle.get', return_value=HttpResponse({'test': 'data'}, status=status.HTTP_200_OK)): + get(url=url, user=admin_user, expect=200) + get(url=url, user=system_auditor, expect=403) diff --git a/awx/main/tests/functional/api/test_instance_group.py b/awx/main/tests/functional/api/test_instance_group.py index aa8204c6dae9..5bc56940c980 100644 --- a/awx/main/tests/functional/api/test_instance_group.py +++ b/awx/main/tests/functional/api/test_instance_group.py @@ -32,13 +32,6 @@ def fn(hostname, node_type): return fn -@pytest.fixture -def instance_group(job_factory): - ig = InstanceGroup(name="east") - ig.save() - return ig - - @pytest.fixture def containerized_instance_group(instance_group, kube_credential): ig = InstanceGroup(name="container") diff --git a/awx/main/tests/functional/api/test_instance_peers.py b/awx/main/tests/functional/api/test_instance_peers.py new file mode 100644 index 000000000000..1ce6f843bd78 --- /dev/null +++ b/awx/main/tests/functional/api/test_instance_peers.py @@ -0,0 +1,608 @@ +import pytest +import yaml +from unittest import mock + +from awx.api.versioning import reverse +from awx.main.models import Instance, ReceptorAddress +from awx.api.views.instance_install_bundle import generate_group_vars_all_yml + + +def has_peer(group_vars, peer): + peers = group_vars.get('receptor_peers', []) + for p in peers: + if p['address'] == peer: + return True + return False + + +@pytest.mark.django_db +class TestPeers: + @pytest.fixture(autouse=True) + def configure_settings(self, settings): + settings.IS_K8S = True + + @pytest.mark.parametrize('node_type', ['hop', 'execution']) + def test_peering_to_self(self, node_type, admin_user, patch): + """ + cannot peer to self + """ + instance = Instance.objects.create(hostname='abc', node_type=node_type) + addr = ReceptorAddress.objects.create(instance=instance, address='abc', canonical=True) + resp = patch( + url=reverse('api:instance_detail', kwargs={'pk': instance.pk}), + data={"hostname": "abc", "node_type": node_type, "peers": [addr.id]}, + user=admin_user, + expect=400, + ) + assert 'Instance cannot peer to its own address.' in str(resp.data) + + @pytest.mark.parametrize('node_type', ['control', 'hybrid', 'hop', 'execution']) + def test_creating_node(self, node_type, admin_user, post): + """ + can only add hop and execution nodes via API + """ + resp = post( + url=reverse('api:instance_list'), + data={"hostname": "abc", "node_type": node_type}, + user=admin_user, + expect=400 if node_type in ['control', 'hybrid'] else 201, + ) + if resp.status_code == 400: + assert 'Can only create execution or hop nodes.' in str(resp.data) + + def test_changing_node_type(self, admin_user, patch): + """ + cannot change node type + """ + hop = Instance.objects.create(hostname='abc', node_type="hop") + resp = patch( + url=reverse('api:instance_detail', kwargs={'pk': hop.pk}), + data={"node_type": "execution"}, + user=admin_user, + expect=400, + ) + assert 'Cannot change node type.' in str(resp.data) + + @pytest.mark.parametrize( + 'payload_port, payload_peers_from, initial_port, initial_peers_from', + [ + (-1, -1, None, None), + (-1, -1, 27199, False), + (-1, -1, 27199, True), + (None, -1, None, None), + (None, False, None, None), + (-1, False, None, None), + (27199, True, 27199, True), + (27199, False, 27199, False), + (27199, -1, 27199, True), + (27199, -1, 27199, False), + (-1, True, 27199, True), + (-1, False, 27199, False), + ], + ) + def test_no_op(self, payload_port, payload_peers_from, initial_port, initial_peers_from, admin_user, patch): + node = Instance.objects.create(hostname='abc', node_type='hop') + if initial_port is not None: + ReceptorAddress.objects.create(address=node.hostname, port=initial_port, canonical=True, peers_from_control_nodes=initial_peers_from, instance=node) + + assert ReceptorAddress.objects.filter(instance=node).count() == 1 + else: + assert ReceptorAddress.objects.filter(instance=node).count() == 0 + + data = {'enabled': True} # Just to have something to post. + if payload_port != -1: + data['listener_port'] = payload_port + if payload_peers_from != -1: + data['peers_from_control_nodes'] = payload_peers_from + + patch( + url=reverse('api:instance_detail', kwargs={'pk': node.pk}), + data=data, + user=admin_user, + expect=200, + ) + + assert ReceptorAddress.objects.filter(instance=node).count() == (0 if initial_port is None else 1) + if initial_port is not None: + ra = ReceptorAddress.objects.get(instance=node, canonical=True) + assert ra.port == initial_port + assert ra.peers_from_control_nodes == initial_peers_from + + @pytest.mark.parametrize( + 'payload_port, payload_peers_from', + [ + (27199, True), + (27199, False), + (27199, -1), + ], + ) + def test_creates_canonical_address(self, payload_port, payload_peers_from, admin_user, patch): + node = Instance.objects.create(hostname='abc', node_type='hop') + assert ReceptorAddress.objects.filter(instance=node).count() == 0 + + data = {'enabled': True} # Just to have something to post. + if payload_port != -1: + data['listener_port'] = payload_port + if payload_peers_from != -1: + data['peers_from_control_nodes'] = payload_peers_from + + patch( + url=reverse('api:instance_detail', kwargs={'pk': node.pk}), + data=data, + user=admin_user, + expect=200, + ) + + assert ReceptorAddress.objects.filter(instance=node).count() == 1 + ra = ReceptorAddress.objects.get(instance=node, canonical=True) + assert ra.port == payload_port + assert ra.peers_from_control_nodes == (payload_peers_from if payload_peers_from != -1 else False) + + @pytest.mark.parametrize( + 'payload_port, payload_peers_from, initial_port, initial_peers_from', + [ + (None, False, 27199, True), + (None, -1, 27199, True), + (None, False, 27199, False), + (None, -1, 27199, False), + ], + ) + def test_deletes_canonical_address(self, payload_port, payload_peers_from, initial_port, initial_peers_from, admin_user, patch): + node = Instance.objects.create(hostname='abc', node_type='hop') + ReceptorAddress.objects.create(address=node.hostname, port=initial_port, canonical=True, peers_from_control_nodes=initial_peers_from, instance=node) + + assert ReceptorAddress.objects.filter(instance=node).count() == 1 + + data = {'enabled': True} # Just to have something to post. + if payload_port != -1: + data['listener_port'] = payload_port + if payload_peers_from != -1: + data['peers_from_control_nodes'] = payload_peers_from + + patch( + url=reverse('api:instance_detail', kwargs={'pk': node.pk}), + data=data, + user=admin_user, + expect=200, + ) + + assert ReceptorAddress.objects.filter(instance=node).count() == 0 + + @pytest.mark.parametrize( + 'payload_port, payload_peers_from, initial_port, initial_peers_from', + [ + (27199, True, 27199, False), + (27199, False, 27199, True), + (-1, True, 27199, False), + (-1, False, 27199, True), + ], + ) + def test_updates_canonical_address(self, payload_port, payload_peers_from, initial_port, initial_peers_from, admin_user, patch): + node = Instance.objects.create(hostname='abc', node_type='hop') + ReceptorAddress.objects.create(address=node.hostname, port=initial_port, canonical=True, peers_from_control_nodes=initial_peers_from, instance=node) + + assert ReceptorAddress.objects.filter(instance=node).count() == 1 + + data = {'enabled': True} # Just to have something to post. + if payload_port != -1: + data['listener_port'] = payload_port + if payload_peers_from != -1: + data['peers_from_control_nodes'] = payload_peers_from + + patch( + url=reverse('api:instance_detail', kwargs={'pk': node.pk}), + data=data, + user=admin_user, + expect=200, + ) + + assert ReceptorAddress.objects.filter(instance=node).count() == 1 + ra = ReceptorAddress.objects.get(instance=node, canonical=True) + assert ra.port == initial_port # At the present time, changing ports is not allowed + assert ra.peers_from_control_nodes == payload_peers_from + + @pytest.mark.parametrize( + 'payload_port, payload_peers_from, initial_port, initial_peers_from, error_msg', + [ + (-1, True, None, None, "Cannot enable peers_from_control_nodes"), + (None, True, None, None, "Cannot enable peers_from_control_nodes"), + (None, True, 21799, True, "Cannot enable peers_from_control_nodes"), + (None, True, 21799, False, "Cannot enable peers_from_control_nodes"), + (21800, -1, 21799, True, "Cannot change listener port"), + (21800, True, 21799, True, "Cannot change listener port"), + (21800, False, 21799, True, "Cannot change listener port"), + (21800, -1, 21799, False, "Cannot change listener port"), + (21800, True, 21799, False, "Cannot change listener port"), + (21800, False, 21799, False, "Cannot change listener port"), + ], + ) + def test_canonical_address_validation_error(self, payload_port, payload_peers_from, initial_port, initial_peers_from, error_msg, admin_user, patch): + node = Instance.objects.create(hostname='abc', node_type='hop') + if initial_port is not None: + ReceptorAddress.objects.create(address=node.hostname, port=initial_port, canonical=True, peers_from_control_nodes=initial_peers_from, instance=node) + + assert ReceptorAddress.objects.filter(instance=node).count() == 1 + else: + assert ReceptorAddress.objects.filter(instance=node).count() == 0 + + data = {'enabled': True} # Just to have something to post. + if payload_port != -1: + data['listener_port'] = payload_port + if payload_peers_from != -1: + data['peers_from_control_nodes'] = payload_peers_from + + resp = patch( + url=reverse('api:instance_detail', kwargs={'pk': node.pk}), + data=data, + user=admin_user, + expect=400, + ) + + assert error_msg in str(resp.data) + + def test_changing_managed_listener_port(self, admin_user, patch): + """ + if instance is managed, cannot change listener port at all + """ + hop = Instance.objects.create(hostname='abc', node_type="hop", managed=True) + resp = patch( + url=reverse('api:instance_detail', kwargs={'pk': hop.pk}), + data={"listener_port": 5678}, + user=admin_user, + expect=400, # cannot set port + ) + assert 'Cannot change listener port for managed nodes.' in str(resp.data) + ReceptorAddress.objects.create(instance=hop, address='hop', port=27199, canonical=True) + resp = patch( + url=reverse('api:instance_detail', kwargs={'pk': hop.pk}), + data={"listener_port": None}, + user=admin_user, + expect=400, # cannot unset port + ) + assert 'Cannot change listener port for managed nodes.' in str(resp.data) + + def test_bidirectional_peering(self, admin_user, patch): + """ + cannot peer to node that is already to peered to it + if A -> B, then disallow B -> A + """ + hop1 = Instance.objects.create(hostname='hop1', node_type='hop') + hop1addr = ReceptorAddress.objects.create(instance=hop1, address='hop1', canonical=True) + hop2 = Instance.objects.create(hostname='hop2', node_type='hop') + hop2addr = ReceptorAddress.objects.create(instance=hop2, address='hop2', canonical=True) + hop1.peers.add(hop2addr) + resp = patch( + url=reverse('api:instance_detail', kwargs={'pk': hop2.pk}), + data={"peers": [hop1addr.id]}, + user=admin_user, + expect=400, + ) + assert 'Instance hop1 is already peered to this instance.' in str(resp.data) + + def test_multiple_peers_same_instance(self, admin_user, patch): + """ + cannot peer to more than one address of the same instance + """ + hop1 = Instance.objects.create(hostname='hop1', node_type='hop') + hop1addr1 = ReceptorAddress.objects.create(instance=hop1, address='hop1', canonical=True) + hop1addr2 = ReceptorAddress.objects.create(instance=hop1, address='hop1alternate') + hop2 = Instance.objects.create(hostname='hop2', node_type='hop') + resp = patch( + url=reverse('api:instance_detail', kwargs={'pk': hop2.pk}), + data={"peers": [hop1addr1.id, hop1addr2.id]}, + user=admin_user, + expect=400, + ) + assert 'Cannot peer to the same instance more than once.' in str(resp.data) + + @pytest.mark.parametrize('node_type', ['control', 'hybrid']) + def test_changing_peers_control_nodes(self, node_type, admin_user, patch): + """ + for control nodes, peers field should not be + modified directly via patch. + """ + control = Instance.objects.create(hostname='abc', node_type=node_type, managed=True) + hop1 = Instance.objects.create(hostname='hop1', node_type='hop') + hop1addr = ReceptorAddress.objects.create(instance=hop1, address='hop1', peers_from_control_nodes=True, canonical=True) + hop2 = Instance.objects.create(hostname='hop2', node_type='hop') + hop2addr = ReceptorAddress.objects.create(instance=hop2, address='hop2', canonical=True) + assert [hop1addr] == list(control.peers.all()) # only hop1addr should be peered + resp = patch( + url=reverse('api:instance_detail', kwargs={'pk': control.pk}), + data={"peers": [hop2addr.id]}, + user=admin_user, + expect=400, # cannot add peers manually + ) + assert 'Setting peers manually for managed nodes is not allowed.' in str(resp.data) + + patch( + url=reverse('api:instance_detail', kwargs={'pk': control.pk}), + data={"peers": [hop1addr.id]}, + user=admin_user, + expect=200, # patching with current peers list should be okay + ) + resp = patch( + url=reverse('api:instance_detail', kwargs={'pk': control.pk}), + data={"peers": []}, + user=admin_user, + expect=400, # cannot remove peers directly + ) + assert 'Setting peers manually for managed nodes is not allowed.' in str(resp.data) + + patch( + url=reverse('api:instance_detail', kwargs={'pk': control.pk}), + data={}, + user=admin_user, + expect=200, # patching without data should be fine too + ) + # patch hop2 + patch( + url=reverse('api:instance_detail', kwargs={'pk': hop2.pk}), + data={"peers_from_control_nodes": True}, + user=admin_user, + expect=200, + ) + assert {hop1addr, hop2addr} == set(control.peers.all()) # hop1 and hop2 should now be peered from control node + + def test_changing_hostname(self, admin_user, patch): + """ + cannot change hostname + """ + hop = Instance.objects.create(hostname='hop', node_type='hop') + resp = patch( + url=reverse('api:instance_detail', kwargs={'pk': hop.pk}), + data={"hostname": "hop2"}, + user=admin_user, + expect=400, + ) + + assert 'Cannot change hostname.' in str(resp.data) + + def test_changing_node_state(self, admin_user, patch): + """ + only allow setting to deprovisioning + """ + hop = Instance.objects.create(hostname='hop', node_type='hop', node_state='installed') + patch( + url=reverse('api:instance_detail', kwargs={'pk': hop.pk}), + data={"node_state": "deprovisioning"}, + user=admin_user, + expect=200, + ) + resp = patch( + url=reverse('api:instance_detail', kwargs={'pk': hop.pk}), + data={"node_state": "ready"}, + user=admin_user, + expect=400, + ) + assert "Can only change instances to the 'deprovisioning' state." in str(resp.data) + + def test_changing_managed_node_state(self, admin_user, patch): + """ + cannot change node state of managed node + """ + hop = Instance.objects.create(hostname='hop', node_type='hop', managed=True) + resp = patch( + url=reverse('api:instance_detail', kwargs={'pk': hop.pk}), + data={"node_state": "deprovisioning"}, + user=admin_user, + expect=400, + ) + + assert 'Cannot deprovision managed nodes.' in str(resp.data) + + def test_changing_managed_peers_from_control_nodes(self, admin_user, patch): + """ + cannot change peers_from_control_nodes of managed node + """ + hop = Instance.objects.create(hostname='hop', node_type='hop', managed=True) + ReceptorAddress.objects.create(instance=hop, address='hop', peers_from_control_nodes=True, canonical=True) + resp = patch( + url=reverse('api:instance_detail', kwargs={'pk': hop.pk}), + data={"peers_from_control_nodes": False}, + user=admin_user, + expect=400, + ) + + assert 'Cannot change peers_from_control_nodes for managed nodes.' in str(resp.data) + + hop.peers_from_control_nodes = False + hop.save() + + resp = patch( + url=reverse('api:instance_detail', kwargs={'pk': hop.pk}), + data={"peers_from_control_nodes": False}, + user=admin_user, + expect=400, + ) + + assert 'Cannot change peers_from_control_nodes for managed nodes.' in str(resp.data) + + @pytest.mark.parametrize('node_type', ['control', 'hybrid']) + def test_control_node_automatically_peers(self, node_type): + """ + a new control node should automatically + peer to hop + + peer to hop should be removed if hop is deleted + """ + + hop = Instance.objects.create(hostname='hop', node_type='hop') + hopaddr = ReceptorAddress.objects.create(instance=hop, address='hop', peers_from_control_nodes=True, canonical=True) + control = Instance.objects.create(hostname='abc', node_type=node_type) + assert hopaddr in control.peers.all() + hop.delete() + assert not control.peers.exists() + + @pytest.mark.parametrize('node_type', ['control', 'hybrid']) + def test_control_node_retains_other_peers(self, node_type): + """ + if a new node comes online, other peer relationships should + remain intact + """ + hop1 = Instance.objects.create(hostname='hop1', node_type='hop') + hop2 = Instance.objects.create(hostname='hop2', node_type='hop') + hop2addr = ReceptorAddress.objects.create(instance=hop2, address='hop2', canonical=True) + hop1.peers.add(hop2addr) + + # a control node is added + Instance.objects.create(hostname='control', node_type=node_type) + + assert hop1.peers.exists() + + def test_reverse_peers(self, admin_user, get): + """ + if hop1 peers to hop2, hop1 should + be in hop2's reverse_peers list + """ + hop1 = Instance.objects.create(hostname='hop1', node_type='hop') + hop2 = Instance.objects.create(hostname='hop2', node_type='hop') + hop2addr = ReceptorAddress.objects.create(instance=hop2, address='hop2', canonical=True) + hop1.peers.add(hop2addr) + + resp = get( + url=reverse('api:instance_detail', kwargs={'pk': hop2.pk}), + user=admin_user, + expect=200, + ) + + assert hop1.pk in resp.data['reverse_peers'] + + def test_group_vars(self): + """ + control > hop1 > hop2 < execution + """ + control = Instance.objects.create(hostname='control', node_type='control') + hop1 = Instance.objects.create(hostname='hop1', node_type='hop') + ReceptorAddress.objects.create(instance=hop1, address='hop1', peers_from_control_nodes=True, port=6789, canonical=True) + + hop2 = Instance.objects.create(hostname='hop2', node_type='hop') + hop2addr = ReceptorAddress.objects.create(instance=hop2, address='hop2', peers_from_control_nodes=False, port=6789, canonical=True) + + execution = Instance.objects.create(hostname='execution', node_type='execution') + ReceptorAddress.objects.create(instance=execution, address='execution', peers_from_control_nodes=False, port=6789, canonical=True) + + execution.peers.add(hop2addr) + hop1.peers.add(hop2addr) + + control_vars = yaml.safe_load(generate_group_vars_all_yml(control)) + hop1_vars = yaml.safe_load(generate_group_vars_all_yml(hop1)) + hop2_vars = yaml.safe_load(generate_group_vars_all_yml(hop2)) + execution_vars = yaml.safe_load(generate_group_vars_all_yml(execution)) + + # control group vars assertions + assert has_peer(control_vars, 'hop1:6789') + assert not has_peer(control_vars, 'hop2:6789') + assert not has_peer(control_vars, 'execution:6789') + assert not control_vars.get('receptor_listener', False) + + # hop1 group vars assertions + assert has_peer(hop1_vars, 'hop2:6789') + assert not has_peer(hop1_vars, 'execution:6789') + assert hop1_vars.get('receptor_listener', False) + + # hop2 group vars assertions + assert not has_peer(hop2_vars, 'hop1:6789') + assert not has_peer(hop2_vars, 'execution:6789') + assert hop2_vars.get('receptor_listener', False) + assert hop2_vars.get('receptor_peers', []) == [] + + # execution group vars assertions + assert has_peer(execution_vars, 'hop2:6789') + assert not has_peer(execution_vars, 'hop1:6789') + assert execution_vars.get('receptor_listener', False) + + def test_write_receptor_config_called(self): + """ + Assert that write_receptor_config is called + when certain instances are created, or if + peers_from_control_nodes changes. + In general, write_receptor_config should only + be called when necessary, as it will reload + receptor backend connections which is not trivial. + """ + with mock.patch('awx.main.models.ha.schedule_write_receptor_config') as write_method: + # new control instance but nothing to peer to (no) + control = Instance.objects.create(hostname='control1', node_type='control') + write_method.assert_not_called() + + # new address with peers_from_control_nodes False (no) + hop1 = Instance.objects.create(hostname='hop1', node_type='hop') + hop1addr = ReceptorAddress.objects.create(instance=hop1, address='hop1', peers_from_control_nodes=False, canonical=True) + hop1.delete() + write_method.assert_not_called() + + # new address with peers_from_control_nodes True (yes) + hop1 = Instance.objects.create(hostname='hop1', node_type='hop') + hop1addr = ReceptorAddress.objects.create(instance=hop1, address='hop1', peers_from_control_nodes=True, canonical=True) + write_method.assert_called() + write_method.reset_mock() + + # new control instance but with something to peer to (yes) + Instance.objects.create(hostname='control2', node_type='control') + write_method.assert_called() + write_method.reset_mock() + + # new address with peers_from_control_nodes False and peered to another hop node (no) + hop2 = Instance.objects.create(hostname='hop2', node_type='hop') + ReceptorAddress.objects.create(instance=hop2, address='hop2', peers_from_control_nodes=False, canonical=True) + hop2.peers.add(hop1addr) + hop2.delete() + write_method.assert_not_called() + + # changing peers_from_control_nodes to False (yes) + hop1addr.peers_from_control_nodes = False + hop1addr.save() + write_method.assert_called() + write_method.reset_mock() + + # deleting address that has peers_from_control_nodes to False (no) + hop1.delete() # cascade deletes to hop1addr + write_method.assert_not_called() + + # deleting control nodes (no) + control.delete() + write_method.assert_not_called() + + def test_write_receptor_config_data(self): + """ + Assert the correct peers are included in data that will + be written to receptor.conf + """ + from awx.main.tasks.receptor import RECEPTOR_CONFIG_STARTER + + with mock.patch('awx.main.tasks.receptor.read_receptor_config', return_value=list(RECEPTOR_CONFIG_STARTER)): + from awx.main.tasks.receptor import generate_config_data + + _, should_update = generate_config_data() + assert not should_update + + # not peered, so config file should not be updated + for i in range(3): + inst = Instance.objects.create(hostname=f"exNo-{i}", node_type='execution') + ReceptorAddress.objects.create(instance=inst, address=f"exNo-{i}", port=6789, peers_from_control_nodes=False, canonical=True) + _, should_update = generate_config_data() + assert not should_update + + # peered, so config file should be updated + expected_peers = [] + for i in range(3): + expected_peers.append(f"hop-{i}:6789") + inst = Instance.objects.create(hostname=f"hop-{i}", node_type='hop') + ReceptorAddress.objects.create(instance=inst, address=f"hop-{i}", port=6789, peers_from_control_nodes=True, canonical=True) + + for i in range(3): + expected_peers.append(f"exYes-{i}:6789") + inst = Instance.objects.create(hostname=f"exYes-{i}", node_type='execution') + ReceptorAddress.objects.create(instance=inst, address=f"exYes-{i}", port=6789, peers_from_control_nodes=True, canonical=True) + + new_config, should_update = generate_config_data() + assert should_update + + peers = [] + for entry in new_config: + for key, value in entry.items(): + if key == "tcp-peer": + peers.append(value['address']) + + assert set(expected_peers) == set(peers) diff --git a/awx/main/tests/functional/api/test_inventory.py b/awx/main/tests/functional/api/test_inventory.py index 80357a22f96c..da19d62e66f7 100644 --- a/awx/main/tests/functional/api/test_inventory.py +++ b/awx/main/tests/functional/api/test_inventory.py @@ -8,6 +8,7 @@ from awx.api.versioning import reverse from awx.main.models import InventorySource, Inventory, ActivityStream +from awx.main.utils.inventory_vars import update_group_variables @pytest.fixture @@ -17,15 +18,6 @@ def scm_inventory(inventory, project): return inventory -@pytest.fixture -def factory_scm_inventory(inventory, project): - def fn(**kwargs): - with mock.patch('awx.main.models.unified_jobs.UnifiedJobTemplate.update'): - return inventory.inventory_sources.create(source_project=project, overwrite_vars=True, source='scm', **kwargs) - - return fn - - @pytest.mark.django_db def test_inventory_source_notification_on_cloud_only(get, post, inventory_source_factory, user, notification_template): u = user('admin', True) @@ -471,6 +463,26 @@ def test_validating_credential_type(self, organization, inventory, admin_user, p assert 'Cloud-based inventory sources (such as ec2)' in r.data['credential'][0] assert 'require credentials for the matching cloud service' in r.data['credential'][0] + def test_credential_dict_value_returns_400(self, inventory, admin_user, put): + """Passing a dict for the credential field should return 400, not 500. + + Reproduces a bug where int() raises TypeError on non-scalar types + (dict, list) which was uncaught, resulting in a 500 Internal Server Error. + """ + inv_src = InventorySource.objects.create(name='test-src', inventory=inventory, source='ec2') + r = put( + url=reverse('api:inventory_source_detail', kwargs={'pk': inv_src.pk}), + data={ + 'name': 'test-src', + 'inventory': inventory.pk, + 'source': 'ec2', + 'credential': {'username': 'admin', 'password': 'secret'}, + }, + user=admin_user, + expect=400, + ) + assert r.status_code == 400 + def test_vault_credential_not_allowed(self, project, inventory, vault_credential, admin_user, post): """Vault credentials cannot be associated via the deprecated field""" # TODO: when feature is added, add tests to use the related credentials @@ -529,6 +541,20 @@ def test_credentials_relationship_mapping(self, project, inventory, organization patch(url=inv_src.get_absolute_url(), data={'credential': aws_cred.pk}, expect=200, user=admin_user) assert list(inv_src.credentials.values_list('id', flat=True)) == [aws_cred.pk] + @pytest.mark.skip(reason="Delay until AAP-53978 completed") + def test_vmware_cred_create_esxi_source(self, inventory, admin_user, organization, post, get): + """Test that a vmware esxi source can be added with a vmware credential""" + from awx.main.models.credential import Credential, CredentialType + + vmware = CredentialType.defaults['vmware']() + vmware.save() + vmware_cred = Credential.objects.create(credential_type=vmware, name="bar", organization=organization) + inv_src = InventorySource.objects.create(inventory=inventory, name='foobar', source='vmware_esxi') + r = post(url=reverse('api:inventory_source_credentials_list', kwargs={'pk': inv_src.pk}), data={'id': vmware_cred.pk}, expect=204, user=admin_user) + g = get(inv_src.get_absolute_url(), admin_user) + assert r.status_code == 204 + assert g.data['credential'] == vmware_cred.pk + @pytest.mark.django_db class TestControlledBySCM: @@ -594,3 +620,346 @@ def test_adding_inv_src_without_proj_access_prohibited(self, post, project, inve rando, expect=403, ) + + +@pytest.mark.django_db +class TestConstructedInventory: + @pytest.fixture + def constructed_inventory(self, organization): + return Inventory.objects.create(name='constructed-test-inventory', kind='constructed', organization=organization) + + def test_get_constructed_inventory(self, constructed_inventory, admin_user, get): + inv_src = constructed_inventory.inventory_sources.first() + inv_src.update_cache_timeout = 53 + inv_src.save(update_fields=['update_cache_timeout']) + r = get(url=reverse('api:constructed_inventory_detail', kwargs={'pk': constructed_inventory.pk}), user=admin_user, expect=200) + assert r.data['update_cache_timeout'] == 53 + + def test_patch_constructed_inventory(self, constructed_inventory, admin_user, patch): + inv_src = constructed_inventory.inventory_sources.first() + assert inv_src.update_cache_timeout == 0 + assert inv_src.limit == '' + r = patch( + url=reverse('api:constructed_inventory_detail', kwargs={'pk': constructed_inventory.pk}), + data=dict(update_cache_timeout=54, limit='foobar'), + user=admin_user, + expect=200, + ) + assert r.data['update_cache_timeout'] == 54 + inv_src = constructed_inventory.inventory_sources.first() + assert inv_src.update_cache_timeout == 54 + assert inv_src.limit == 'foobar' + + def test_patch_constructed_inventory_generated_source_limits_editable_fields(self, constructed_inventory, admin_user, project, patch): + inv_src = constructed_inventory.inventory_sources.first() + r = patch( + url=inv_src.get_absolute_url(), + data={ + 'source': 'scm', + 'source_project': project.pk, + 'source_path': '', + 'source_vars': 'plugin: a.b.c', + }, + expect=400, + user=admin_user, + ) + assert str(r.data['error'][0]) == "Cannot change field 'source' on a constructed inventory source." + + # Make sure it didn't get updated before we got the error + inv_src_after_err = constructed_inventory.inventory_sources.first() + assert inv_src.id == inv_src_after_err.id + assert inv_src.source == inv_src_after_err.source + assert inv_src.source_project == inv_src_after_err.source_project + assert inv_src.source_path == inv_src_after_err.source_path + assert inv_src.source_vars == inv_src_after_err.source_vars + + def test_patch_constructed_inventory_generated_source_allows_source_vars_edit(self, constructed_inventory, admin_user, patch): + inv_src = constructed_inventory.inventory_sources.first() + patch( + url=inv_src.get_absolute_url(), + data={ + 'source_vars': 'plugin: a.b.c', + }, + expect=200, + user=admin_user, + ) + + inv_src_after_patch = constructed_inventory.inventory_sources.first() + + # sanity checks + assert inv_src.id == inv_src_after_patch.id + assert inv_src.source == 'constructed' + assert inv_src_after_patch.source == 'constructed' + assert inv_src.source_vars == '' + + assert inv_src_after_patch.source_vars == 'plugin: a.b.c' + + def test_create_constructed_inventory(self, constructed_inventory, admin_user, post, organization): + r = post( + url=reverse('api:constructed_inventory_list'), + data=dict(name='constructed-inventory-just-created', kind='constructed', organization=organization.id, update_cache_timeout=55, limit='foobar'), + user=admin_user, + expect=201, + ) + pk = r.data['id'] + constructed_inventory = Inventory.objects.get(pk=pk) + inv_src = constructed_inventory.inventory_sources.first() + assert inv_src.update_cache_timeout == 55 + assert inv_src.limit == 'foobar' + + def test_get_absolute_url_for_constructed_inventory(self, constructed_inventory, admin_user, get): + """ + If we are using the normal inventory API endpoint to look at a + constructed inventory, then we should get a normal inventory API route + back. If we are accessing it via the special constructed inventory + endpoint, then we should get that back. + """ + + url_const = reverse('api:constructed_inventory_detail', kwargs={'pk': constructed_inventory.pk}) + url_inv = reverse('api:inventory_detail', kwargs={'pk': constructed_inventory.pk}) + + const_r = get(url=url_const, user=admin_user, expect=200) + inv_r = get(url=url_inv, user=admin_user, expect=200) + assert const_r.data['url'] == url_const + assert inv_r.data['url'] == url_inv + assert inv_r.data['url'] != const_r.data['url'] + assert inv_r.data['related']['constructed_url'] == url_const + assert const_r.data['related']['constructed_url'] == url_const + + +@pytest.mark.django_db +class TestInventoryAllVariables: + + @staticmethod + def simulate_update_from_source(inv_src, variables_dict, overwrite_vars=True): + """ + Update `inventory` with variables `variables_dict` from source + `inv_src`. + """ + # Perform an update from source the same way it is done in + # `inventory_import.Command._update_inventory`. + new_vars = update_group_variables( + group_id=None, # `None` denotes the 'all' group (which doesn't have a pk). + newvars=variables_dict, + dbvars=inv_src.inventory.variables_dict, + invsrc_id=inv_src.id, + inventory_id=inv_src.inventory.id, + overwrite_vars=overwrite_vars, + ) + inv_src.inventory.variables = json.dumps(new_vars) + inv_src.inventory.save(update_fields=["variables"]) + return new_vars + + def update_and_verify(self, inv_src, new_vars, expect=None, overwrite_vars=True, teststep=None): + """ + Helper: Update from source and verify the new inventory variables. + + :param inv_src: An inventory source object with its inventory property + set to the inventory fixture of the called. + :param dict new_vars: The variables of the inventory source `inv_src`. + :param dict expect: (optional) The expected variables state of the + inventory after the update. If not set or None, expect `new_vars`. + :param bool overwrite_vars: The status of the inventory source option + 'overwrite variables'. Default is `True`. + :raise AssertionError: If the inventory does not contain the expected + variables after the update. + """ + self.simulate_update_from_source(inv_src, new_vars, overwrite_vars=overwrite_vars) + if teststep is not None: + assert inv_src.inventory.variables_dict == (expect if expect is not None else new_vars), f"Test step {teststep}" + else: + assert inv_src.inventory.variables_dict == (expect if expect is not None else new_vars) + + def test_set_variables_through_inventory_details_update(self, inventory, patch, admin_user): + """ + Set an inventory variable by changing the inventory details, simulating + a user edit. + """ + # a: x + patch(url=reverse('api:inventory_detail', kwargs={'pk': inventory.pk}), data={'variables': 'a: x'}, user=admin_user, expect=200) + inventory.refresh_from_db() + assert inventory.variables_dict == {"a": "x"} + + def test_variables_set_by_user_persist_update_from_src(self, inventory, inventory_source, patch, admin_user): + """ + Verify the special behavior that a variable which originates from a user + edit (instead of a source update), is not removed from the inventory + when a source update with overwrite_vars=True does not contain that + variable. This behavior is considered special because a variable which + originates from a source would actually be deleted. + + In addition, verify that an existing variable which was set by a user + edit can be overwritten by a source update. + """ + # Set two variables via user edit. + patch( + url=reverse('api:inventory_detail', kwargs={'pk': inventory.pk}), + data={'variables': '{"a": "a_from_user", "b": "b_from_user"}'}, + user=admin_user, + expect=200, + ) + inventory.refresh_from_db() + assert inventory.variables_dict == {'a': 'a_from_user', 'b': 'b_from_user'} + # Update from a source which contains only one of the two variables from + # the previous update. + self.simulate_update_from_source(inventory_source, {'a': 'a_from_source'}) + # Verify inventory variables. + assert inventory.variables_dict == {'a': 'a_from_source', 'b': 'b_from_user'} + + def test_variables_set_through_src_get_removed_on_update_from_same_src(self, inventory, inventory_source, patch, admin_user): + """ + Verify that a variable which originates from a source update, is removed + from the inventory when a source update with overwrite_vars=True does + not contain that variable. + + In addition, verify that an existing variable which was set by a user + edit can be overwritten by a source update. + """ + # Set two variables via update from source. + self.simulate_update_from_source(inventory_source, {'a': 'a_from_source', 'b': 'b_from_source'}) + # Verify inventory variables. + assert inventory.variables_dict == {'a': 'a_from_source', 'b': 'b_from_source'} + # Update from the same source which now contains only one of the two + # variables from the previous update. + self.simulate_update_from_source(inventory_source, {'b': 'b_from_source'}) + # Verify the variable has been deleted from the inventory. + assert inventory.variables_dict == {'b': 'b_from_source'} + + def test_overwrite_variables_through_inventory_details_update(self, inventory, patch, admin_user): + """ + Set and update the inventory variables multiple times by changing the + inventory details via api, simulating user edits. + + Any variables update by means of an inventory details update shall + overwright all existing inventory variables. + """ + # a: x + patch(url=reverse('api:inventory_detail', kwargs={'pk': inventory.pk}), data={'variables': 'a: x'}, user=admin_user, expect=200) + inventory.refresh_from_db() + assert inventory.variables_dict == {"a": "x"} + # a: x2 + patch(url=reverse('api:inventory_detail', kwargs={'pk': inventory.pk}), data={'variables': 'a: x2'}, user=admin_user, expect=200) + inventory.refresh_from_db() + assert inventory.variables_dict == {"a": "x2"} + # b: y + patch(url=reverse('api:inventory_detail', kwargs={'pk': inventory.pk}), data={'variables': 'b: y'}, user=admin_user, expect=200) + inventory.refresh_from_db() + assert inventory.variables_dict == {"b": "y"} + + def test_inventory_group_variables_internal_data(self, inventory, patch, admin_user): + """ + Basic verification of how variable updates are stored internally. + + .. Warning:: + + This test verifies a specific implementation of the inventory + variables update business logic. It may deliver false negatives if + the implementation changes. + """ + # x: a + patch(url=reverse('api:inventory_detail', kwargs={'pk': inventory.pk}), data={'variables': 'a: x'}, user=admin_user, expect=200) + igv = inventory.inventory_group_variables.first() + assert igv.variables == {'a': [[-1, 'x']]} + # b: y + patch(url=reverse('api:inventory_detail', kwargs={'pk': inventory.pk}), data={'variables': 'b: y'}, user=admin_user, expect=200) + igv = inventory.inventory_group_variables.first() + assert igv.variables == {'b': [[-1, 'y']]} + + def test_update_then_user_change(self, inventory, patch, admin_user, inventory_source): + """ + 1. Update inventory vars by means of an inventory source update. + 2. Update inventory vars by editing the inventory details (aka a 'user + update'), thereby changing variables values and deleting variables + from the inventory. + + .. Warning:: + + This test partly relies on a specific implementation of the + inventory variables update business logic. It may deliver false + negatives if the implementation changes. + """ + assert inventory_source.inventory_id == inventory.pk # sanity + # ---- Test step 1: Set variables by updating from an inventory source. + self.simulate_update_from_source(inventory_source, {'foo': 'foo_from_source', 'bar': 'bar_from_source'}) + # Verify inventory variables. + assert inventory.variables_dict == {'foo': 'foo_from_source', 'bar': 'bar_from_source'} + # Verify internal storage of variables data. Note that this is + # implementation specific + assert inventory.inventory_group_variables.count() == 1 + igv = inventory.inventory_group_variables.first() + assert igv.variables == {'foo': [[inventory_source.id, 'foo_from_source']], 'bar': [[inventory_source.id, 'bar_from_source']]} + # ---- Test step 2: Change the variables by editing the inventory details. + patch(url=reverse('api:inventory_detail', kwargs={'pk': inventory.pk}), data={'variables': 'foo: foo_from_user'}, user=admin_user, expect=200) + inventory.refresh_from_db() + # Verify that variable `foo` contains the new value, and that variable + # `bar` has been deleted from the inventory. + assert inventory.variables_dict == {"foo": "foo_from_user"} + # Verify internal storage of variables data. Note that this is + # implementation specific + inventory.inventory_group_variables.count() == 1 + igv = inventory.inventory_group_variables.first() + assert igv.variables == {'foo': [[-1, 'foo_from_user']]} + + def test_monotonic_deletions(self, inventory, patch, admin_user): + """ + Verify the variables history logic for monotonic deletions. + + Monotonic in this context means that the variables are deleted in the + reverse order of their creation. + + 1. Set inventory variable x: 0, expect INV={x: 0} + + (The following steps use overwrite_variables=False) + + 2. Update from source A={x: 1}, expect INV={x: 1} + 3. Update from source B={x: 2}, expect INV={x: 2} + 4. Update from source B={}, expect INV={x: 1} + 5. Update from source A={}, expect INV={x: 0} + """ + inv_src_a = InventorySource.objects.create(name="inv-src-A", inventory=inventory, source="ec2") + inv_src_b = InventorySource.objects.create(name="inv-src-B", inventory=inventory, source="ec2") + # Test step 1: + patch(url=reverse('api:inventory_detail', kwargs={'pk': inventory.pk}), data={'variables': 'x: 0'}, user=admin_user, expect=200) + inventory.refresh_from_db() + assert inventory.variables_dict == {"x": 0} + # Test step 2: Source A overwrites value of var x + self.update_and_verify(inv_src_a, {"x": 1}, teststep=2) + # Test step 3: Source A overwrites value of var x + self.update_and_verify(inv_src_b, {"x": 2}, teststep=3) + # Test step 4: Value of var x from source A reappears + self.update_and_verify(inv_src_b, {}, expect={"x": 1}, teststep=4) + # Test step 5: Value of var x from initial user edit reappears + self.update_and_verify(inv_src_a, {}, expect={"x": 0}, teststep=5) + + def test_interleaved_deletions(self, inventory, patch, admin_user, inventory_source): + """ + Verify the variables history logic for interleaved deletions. + + Interleaved in this context means that the variables are deleted in a + different order than the sequence of their creation. + + 1. Set inventory variable x: 0, expect INV={x: 0} + 2. Update from source A={x: 1}, expect INV={x: 1} + 3. Update from source B={x: 2}, expect INV={x: 2} + 4. Update from source C={x: 3}, expect INV={x: 3} + 5. Update from source B={}, expect INV={x: 3} + 6. Update from source C={}, expect INV={x: 1} + """ + inv_src_a = InventorySource.objects.create(name="inv-src-A", inventory=inventory, source="ec2") + inv_src_b = InventorySource.objects.create(name="inv-src-B", inventory=inventory, source="ec2") + inv_src_c = InventorySource.objects.create(name="inv-src-C", inventory=inventory, source="ec2") + # Test step 1. Set inventory variable x: 0 + patch(url=reverse('api:inventory_detail', kwargs={'pk': inventory.pk}), data={'variables': 'x: 0'}, user=admin_user, expect=200) + inventory.refresh_from_db() + assert inventory.variables_dict == {"x": 0} + # Test step 2: Source A overwrites value of var x + self.update_and_verify(inv_src_a, {"x": 1}, teststep=2) + # Test step 3: Source B overwrites value of var x + self.update_and_verify(inv_src_b, {"x": 2}, teststep=3) + # Test step 4: Source C overwrites value of var x + self.update_and_verify(inv_src_c, {"x": 3}, teststep=4) + # Test step 5: Value of var x from source C remains unchanged + self.update_and_verify(inv_src_b, {}, expect={"x": 3}, teststep=5) + # Test step 6: Value of var x from source A reappears, because the + # latest update from source B did not contain var x. + self.update_and_verify(inv_src_c, {}, expect={"x": 1}, teststep=6) diff --git a/awx/main/tests/functional/api/test_job.py b/awx/main/tests/functional/api/test_job.py index 53e31e5981a6..8398c9b8c26f 100644 --- a/awx/main/tests/functional/api/test_job.py +++ b/awx/main/tests/functional/api/test_job.py @@ -51,6 +51,16 @@ def test_job_relaunch_permission_denied_response(post, get, inventory, project, r = post(reverse('api:job_relaunch', kwargs={'pk': job.pk}), {}, jt_user, expect=201) +@pytest.mark.django_db +def test_label_sublist(get, admin_user, organization): + job = Job.objects.create() + label = Label.objects.create(organization=organization, name='Steve') + job.labels.add(label) + r = get(url=reverse('api:job_label_list', kwargs={'pk': job.pk}), user=admin_user, expect=200) + assert r.data['count'] == 1 + assert r.data['results'].pop()['id'] == label.id + + @pytest.mark.django_db def test_job_relaunch_prompts_not_accepted_response(post, get, inventory, project, credential, net_credential, machine_credential): jt = JobTemplate.objects.create(name='testjt', inventory=inventory, project=project) @@ -200,6 +210,39 @@ def test_disallowed_http_update_methods(put, patch, post, inventory, project, ad patch(url=reverse('api:job_detail', kwargs={'pk': job.pk}), data={}, user=admin_user, expect=405) +@pytest.mark.django_db +@pytest.mark.parametrize( + "job_type", + [ + 'run', + 'check', + ], +) +def test_job_relaunch_with_job_type(post, inventory, project, machine_credential, admin_user, job_type): + # Create a job template + jt = JobTemplate.objects.create(name='testjt', inventory=inventory, project=project) + + # Set initial job type + init_job_type = 'check' if job_type == 'run' else 'run' + + # Create a job instance + job = jt.create_unified_job(_eager_fields={'job_type': init_job_type}) + + # Perform the POST request + url = reverse('api:job_relaunch', kwargs={'pk': job.pk}) + r = post(url=url, data={'job_type': job_type}, user=admin_user, expect=201) + + # Assert that the response status code is 201 (Created) + assert r.status_code == 201 + + # Retrieve the newly created job from the response + new_job_id = r.data.get('id') + new_job = Job.objects.get(id=new_job_id) + + # Assert that the new job has the correct job type + assert new_job.job_type == job_type + + class TestControllerNode: @pytest.fixture def project_update(self, project): @@ -214,7 +257,7 @@ def adhoc(self, inventory): return AdHocCommand.objects.create(inventory=inventory) @pytest.mark.django_db - def test_field_controller_node_exists(self, sqlite_copy_expert, admin_user, job, project_update, inventory_update, adhoc, get, system_job_factory): + def test_field_controller_node_exists(self, sqlite_copy, admin_user, job, project_update, inventory_update, adhoc, get, system_job_factory): system_job = system_job_factory() r = get(reverse('api:unified_job_list') + '?id={}'.format(job.id), admin_user, expect=200) diff --git a/awx/main/tests/functional/api/test_job_runtime_params.py b/awx/main/tests/functional/api/test_job_runtime_params.py index f477a66ed945..95b55e15b601 100644 --- a/awx/main/tests/functional/api/test_job_runtime_params.py +++ b/awx/main/tests/functional/api/test_job_runtime_params.py @@ -38,11 +38,6 @@ def runtime_data(organization, credentialtype_ssh): ) -@pytest.fixture -def job_with_links(machine_credential, inventory): - return Job.objects.create(name='existing-job', credential=machine_credential, inventory=inventory) - - @pytest.fixture def job_template_prompts(project, inventory, machine_credential): def rf(on_off): @@ -131,11 +126,11 @@ def test_job_ignore_unprompted_vars(runtime_data, job_template_prompts, post, ad mock_job = mocker.MagicMock(spec=Job, id=968, **runtime_data) - with mocker.patch.object(JobTemplate, 'create_unified_job', return_value=mock_job): - with mocker.patch('awx.api.serializers.JobSerializer.to_representation'): - response = post(reverse('api:job_template_launch', kwargs={'pk': job_template.pk}), runtime_data, admin_user, expect=201) - assert JobTemplate.create_unified_job.called - assert JobTemplate.create_unified_job.call_args == () + mocker.patch.object(JobTemplate, 'create_unified_job', return_value=mock_job) + mocker.patch('awx.api.serializers.JobSerializer.to_representation') + response = post(reverse('api:job_template_launch', kwargs={'pk': job_template.pk}), runtime_data, admin_user, expect=201) + assert JobTemplate.create_unified_job.called + assert JobTemplate.create_unified_job.call_args == () # Check that job is serialized correctly job_id = response.data['job'] @@ -167,12 +162,12 @@ def test_job_accept_prompted_vars(runtime_data, job_template_prompts, post, admi mock_job = mocker.MagicMock(spec=Job, id=968, **runtime_data) - with mocker.patch.object(JobTemplate, 'create_unified_job', return_value=mock_job): - with mocker.patch('awx.api.serializers.JobSerializer.to_representation'): - response = post(reverse('api:job_template_launch', kwargs={'pk': job_template.pk}), runtime_data, admin_user, expect=201) - assert JobTemplate.create_unified_job.called - called_with = data_to_internal(runtime_data) - JobTemplate.create_unified_job.assert_called_with(**called_with) + mocker.patch.object(JobTemplate, 'create_unified_job', return_value=mock_job) + mocker.patch('awx.api.serializers.JobSerializer.to_representation') + response = post(reverse('api:job_template_launch', kwargs={'pk': job_template.pk}), runtime_data, admin_user, expect=201) + assert JobTemplate.create_unified_job.called + called_with = data_to_internal(runtime_data) + JobTemplate.create_unified_job.assert_called_with(**called_with) job_id = response.data['job'] assert job_id == 968 @@ -187,11 +182,11 @@ def test_job_accept_empty_tags(job_template_prompts, post, admin_user, mocker): mock_job = mocker.MagicMock(spec=Job, id=968) - with mocker.patch.object(JobTemplate, 'create_unified_job', return_value=mock_job): - with mocker.patch('awx.api.serializers.JobSerializer.to_representation'): - post(reverse('api:job_template_launch', kwargs={'pk': job_template.pk}), {'job_tags': '', 'skip_tags': ''}, admin_user, expect=201) - assert JobTemplate.create_unified_job.called - assert JobTemplate.create_unified_job.call_args == ({'job_tags': '', 'skip_tags': ''},) + mocker.patch.object(JobTemplate, 'create_unified_job', return_value=mock_job) + mocker.patch('awx.api.serializers.JobSerializer.to_representation') + post(reverse('api:job_template_launch', kwargs={'pk': job_template.pk}), {'job_tags': '', 'skip_tags': ''}, admin_user, expect=201) + assert JobTemplate.create_unified_job.called + assert JobTemplate.create_unified_job.call_args == ({'job_tags': '', 'skip_tags': ''},) mock_job.signal_start.assert_called_once() @@ -203,14 +198,14 @@ def test_slice_timeout_forks_need_int(job_template_prompts, post, admin_user, mo mock_job = mocker.MagicMock(spec=Job, id=968) - with mocker.patch.object(JobTemplate, 'create_unified_job', return_value=mock_job): - with mocker.patch('awx.api.serializers.JobSerializer.to_representation'): - response = post( - reverse('api:job_template_launch', kwargs={'pk': job_template.pk}), {'timeout': '', 'job_slice_count': '', 'forks': ''}, admin_user, expect=400 - ) - assert 'forks' in response.data and response.data['forks'][0] == 'A valid integer is required.' - assert 'job_slice_count' in response.data and response.data['job_slice_count'][0] == 'A valid integer is required.' - assert 'timeout' in response.data and response.data['timeout'][0] == 'A valid integer is required.' + mocker.patch.object(JobTemplate, 'create_unified_job', return_value=mock_job) + mocker.patch('awx.api.serializers.JobSerializer.to_representation') + response = post( + reverse('api:job_template_launch', kwargs={'pk': job_template.pk}), {'timeout': '', 'job_slice_count': '', 'forks': ''}, admin_user, expect=400 + ) + assert 'forks' in response.data and response.data['forks'][0] == 'A valid integer is required.' + assert 'job_slice_count' in response.data and response.data['job_slice_count'][0] == 'A valid integer is required.' + assert 'timeout' in response.data and response.data['timeout'][0] == 'A valid integer is required.' @pytest.mark.django_db @@ -244,12 +239,12 @@ def test_job_accept_prompted_vars_null(runtime_data, job_template_prompts_null, mock_job = mocker.MagicMock(spec=Job, id=968, **runtime_data) - with mocker.patch.object(JobTemplate, 'create_unified_job', return_value=mock_job): - with mocker.patch('awx.api.serializers.JobSerializer.to_representation'): - response = post(reverse('api:job_template_launch', kwargs={'pk': job_template.pk}), runtime_data, rando, expect=201) - assert JobTemplate.create_unified_job.called - expected_call = data_to_internal(runtime_data) - assert JobTemplate.create_unified_job.call_args == (expected_call,) + mocker.patch.object(JobTemplate, 'create_unified_job', return_value=mock_job) + mocker.patch('awx.api.serializers.JobSerializer.to_representation') + response = post(reverse('api:job_template_launch', kwargs={'pk': job_template.pk}), runtime_data, rando, expect=201) + assert JobTemplate.create_unified_job.called + expected_call = data_to_internal(runtime_data) + assert JobTemplate.create_unified_job.call_args == (expected_call,) job_id = response.data['job'] assert job_id == 968 @@ -641,18 +636,18 @@ def test_job_launch_unprompted_vars_with_survey(mocker, survey_spec_factory, job job_template.survey_spec = survey_spec_factory('survey_var') job_template.save() - with mocker.patch('awx.main.access.BaseAccess.check_license'): - mock_job = mocker.MagicMock(spec=Job, id=968, extra_vars={"job_launch_var": 3, "survey_var": 4}) - with mocker.patch.object(JobTemplate, 'create_unified_job', return_value=mock_job): - with mocker.patch('awx.api.serializers.JobSerializer.to_representation', return_value={}): - response = post( - reverse('api:job_template_launch', kwargs={'pk': job_template.pk}), - dict(extra_vars={"job_launch_var": 3, "survey_var": 4}), - admin_user, - expect=201, - ) - assert JobTemplate.create_unified_job.called - assert JobTemplate.create_unified_job.call_args == ({'extra_vars': {'survey_var': 4}},) + mocker.patch('awx.main.access.BaseAccess.check_license') + mock_job = mocker.MagicMock(spec=Job, id=968, extra_vars={"job_launch_var": 3, "survey_var": 4}) + mocker.patch.object(JobTemplate, 'create_unified_job', return_value=mock_job) + mocker.patch('awx.api.serializers.JobSerializer.to_representation', return_value={}) + response = post( + reverse('api:job_template_launch', kwargs={'pk': job_template.pk}), + dict(extra_vars={"job_launch_var": 3, "survey_var": 4}), + admin_user, + expect=201, + ) + assert JobTemplate.create_unified_job.called + assert JobTemplate.create_unified_job.call_args == ({'extra_vars': {'survey_var': 4}},) job_id = response.data['job'] assert job_id == 968 @@ -670,22 +665,22 @@ def test_callback_accept_prompted_extra_var(mocker, survey_spec_factory, job_tem job_template.survey_spec = survey_spec_factory('survey_var') job_template.save() - with mocker.patch('awx.main.access.BaseAccess.check_license'): - mock_job = mocker.MagicMock(spec=Job, id=968, extra_vars={"job_launch_var": 3, "survey_var": 4}) - with mocker.patch.object(UnifiedJobTemplate, 'create_unified_job', return_value=mock_job): - with mocker.patch('awx.api.serializers.JobSerializer.to_representation', return_value={}): - with mocker.patch('awx.api.views.JobTemplateCallback.find_matching_hosts', return_value=[host]): - post( - reverse('api:job_template_callback', kwargs={'pk': job_template.pk}), - dict(extra_vars={"job_launch_var": 3, "survey_var": 4}, host_config_key="foo"), - admin_user, - expect=201, - format='json', - ) - assert UnifiedJobTemplate.create_unified_job.called - call_args = UnifiedJobTemplate.create_unified_job.call_args[1] - call_args.pop('_eager_fields', None) # internal purposes - assert call_args == {'extra_vars': {'survey_var': 4, 'job_launch_var': 3}, 'limit': 'single-host'} + mocker.patch('awx.main.access.BaseAccess.check_license') + mock_job = mocker.MagicMock(spec=Job, id=968, extra_vars={"job_launch_var": 3, "survey_var": 4}) + mocker.patch.object(UnifiedJobTemplate, 'create_unified_job', return_value=mock_job) + mocker.patch('awx.api.serializers.JobSerializer.to_representation', return_value={}) + mocker.patch('awx.api.views.JobTemplateCallback.find_matching_hosts', return_value=[host]) + post( + reverse('api:job_template_callback', kwargs={'pk': job_template.pk}), + dict(extra_vars={"job_launch_var": 3, "survey_var": 4}, host_config_key="foo"), + admin_user, + expect=201, + format='json', + ) + assert UnifiedJobTemplate.create_unified_job.called + call_args = UnifiedJobTemplate.create_unified_job.call_args[1] + call_args.pop('_eager_fields', None) # internal purposes + assert call_args == {'extra_vars': {'survey_var': 4, 'job_launch_var': 3}, 'limit': 'single-host'} mock_job.signal_start.assert_called_once() @@ -697,22 +692,22 @@ def test_callback_ignore_unprompted_extra_var(mocker, survey_spec_factory, job_t job_template.host_config_key = "foo" job_template.save() - with mocker.patch('awx.main.access.BaseAccess.check_license'): - mock_job = mocker.MagicMock(spec=Job, id=968, extra_vars={"job_launch_var": 3, "survey_var": 4}) - with mocker.patch.object(UnifiedJobTemplate, 'create_unified_job', return_value=mock_job): - with mocker.patch('awx.api.serializers.JobSerializer.to_representation', return_value={}): - with mocker.patch('awx.api.views.JobTemplateCallback.find_matching_hosts', return_value=[host]): - post( - reverse('api:job_template_callback', kwargs={'pk': job_template.pk}), - dict(extra_vars={"job_launch_var": 3, "survey_var": 4}, host_config_key="foo"), - admin_user, - expect=201, - format='json', - ) - assert UnifiedJobTemplate.create_unified_job.called - call_args = UnifiedJobTemplate.create_unified_job.call_args[1] - call_args.pop('_eager_fields', None) # internal purposes - assert call_args == {'limit': 'single-host'} + mocker.patch('awx.main.access.BaseAccess.check_license') + mock_job = mocker.MagicMock(spec=Job, id=968, extra_vars={"job_launch_var": 3, "survey_var": 4}) + mocker.patch.object(UnifiedJobTemplate, 'create_unified_job', return_value=mock_job) + mocker.patch('awx.api.serializers.JobSerializer.to_representation', return_value={}) + mocker.patch('awx.api.views.JobTemplateCallback.find_matching_hosts', return_value=[host]) + post( + reverse('api:job_template_callback', kwargs={'pk': job_template.pk}), + dict(extra_vars={"job_launch_var": 3, "survey_var": 4}, host_config_key="foo"), + admin_user, + expect=201, + format='json', + ) + assert UnifiedJobTemplate.create_unified_job.called + call_args = UnifiedJobTemplate.create_unified_job.call_args[1] + call_args.pop('_eager_fields', None) # internal purposes + assert call_args == {'limit': 'single-host'} mock_job.signal_start.assert_called_once() @@ -725,9 +720,9 @@ def test_callback_find_matching_hosts(mocker, get, job_template_prompts, admin_u job_template.save() host_with_alias = Host(name='localhost', inventory=job_template.inventory) host_with_alias.save() - with mocker.patch('awx.main.access.BaseAccess.check_license'): - r = get(reverse('api:job_template_callback', kwargs={'pk': job_template.pk}), user=admin_user, expect=200) - assert tuple(r.data['matching_hosts']) == ('localhost',) + mocker.patch('awx.main.access.BaseAccess.check_license') + r = get(reverse('api:job_template_callback', kwargs={'pk': job_template.pk}), user=admin_user, expect=200) + assert tuple(r.data['matching_hosts']) == ('localhost',) @pytest.mark.django_db @@ -738,6 +733,6 @@ def test_callback_extra_var_takes_priority_over_host_name(mocker, get, job_templ job_template.save() host_with_alias = Host(name='localhost', variables={'ansible_host': 'foobar'}, inventory=job_template.inventory) host_with_alias.save() - with mocker.patch('awx.main.access.BaseAccess.check_license'): - r = get(reverse('api:job_template_callback', kwargs={'pk': job_template.pk}), user=admin_user, expect=200) - assert not r.data['matching_hosts'] + mocker.patch('awx.main.access.BaseAccess.check_license') + r = get(reverse('api:job_template_callback', kwargs={'pk': job_template.pk}), user=admin_user, expect=200) + assert not r.data['matching_hosts'] diff --git a/awx/main/tests/functional/api/test_job_template.py b/awx/main/tests/functional/api/test_job_template.py index dc6ce0c7a008..4cdf43d37b9f 100644 --- a/awx/main/tests/functional/api/test_job_template.py +++ b/awx/main/tests/functional/api/test_job_template.py @@ -1,17 +1,23 @@ import pytest +from unittest import mock # AWX from awx.api.serializers import JobTemplateSerializer from awx.api.versioning import reverse -from awx.main.models import Job, JobTemplate, CredentialType, WorkflowJobTemplate, Organization, Project +from awx.main.models import Job, JobTemplate, CredentialType, WorkflowJobTemplate, Organization, Project, Inventory from awx.main.migrations import _save_password_keys as save_password_keys # Django from django.apps import apps +from django.test.utils import override_settings # DRF from rest_framework.exceptions import ValidationError +# DAB +from ansible_base.jwt_consumer.common.util import generate_x_trusted_proxy_header +from ansible_base.lib.testing.fixtures import rsa_keypair_factory, rsa_keypair # noqa: F401; pylint: disable=unused-import + @pytest.mark.django_db @pytest.mark.parametrize( @@ -353,3 +359,129 @@ def test_job_template_branch_prompt_error(project, inventory, post, admin_user): expect=400, ) assert 'Project does not allow overriding branch' in str(r.data['ask_scm_branch_on_launch']) + + +@pytest.mark.django_db +def test_job_template_missing_inventory(project, inventory, admin_user, post): + jt = JobTemplate.objects.create( + name='test-jt', inventory=inventory, ask_inventory_on_launch=True, project=project, playbook='helloworld.yml', host_config_key='abcd' + ) + Inventory.objects.get(pk=inventory.pk).delete() + r = post( + url=reverse('api:job_template_callback', kwargs={'pk': jt.pk}), + data={'host_config_key': 'abcd'}, + user=admin_user, + expect=400, + ) + assert r.status_code == 400 + assert "Cannot start automatically, an inventory is required." in str(r.data) + + +@pytest.mark.django_db +class TestJobTemplateCallbackProxyIntegration: + """ + Test the interaction of provision job template callback feature and: + settings.PROXY_IP_ALLOWED_LIST + x-trusted-proxy http header + """ + + @pytest.fixture + def job_template(self, inventory, project): + jt = JobTemplate.objects.create(name='test-jt', inventory=inventory, project=project, playbook='helloworld.yml', host_config_key='abcd') + return jt + + @override_settings(REMOTE_HOST_HEADERS=['HTTP_X_FROM_THE_LOAD_BALANCER', 'REMOTE_ADDR', 'REMOTE_HOST'], PROXY_IP_ALLOWED_LIST=['my.proxy.example.org']) + def test_host_not_found(self, job_template, admin_user, post, rsa_keypair): # noqa: F811 + job_template.inventory.hosts.create(name='foobar') + + headers = { + 'HTTP_X_FROM_THE_LOAD_BALANCER': 'baz', + 'REMOTE_HOST': 'baz', + 'REMOTE_ADDR': 'baz', + } + r = post( + url=reverse('api:job_template_callback', kwargs={'pk': job_template.pk}), data={'host_config_key': 'abcd'}, user=admin_user, expect=400, **headers + ) + assert r.data['msg'] == 'No matching host could be found!' + + @pytest.mark.parametrize( + 'headers, expected', + ( + pytest.param( + { + 'HTTP_X_FROM_THE_LOAD_BALANCER': 'foobar', + 'REMOTE_HOST': 'my.proxy.example.org', + }, + 201, + ), + pytest.param( + { + 'HTTP_X_FROM_THE_LOAD_BALANCER': 'foobar', + 'REMOTE_HOST': 'not-my-proxy.org', + }, + 400, + ), + ), + ) + @override_settings(REMOTE_HOST_HEADERS=['HTTP_X_FROM_THE_LOAD_BALANCER', 'REMOTE_ADDR', 'REMOTE_HOST'], PROXY_IP_ALLOWED_LIST=['my.proxy.example.org']) + def test_proxy_ip_allowed_list(self, job_template, admin_user, post, headers, expected): # noqa: F811 + job_template.inventory.hosts.create(name='my.proxy.example.org') + + post( + url=reverse('api:job_template_callback', kwargs={'pk': job_template.pk}), + data={'host_config_key': 'abcd'}, + user=admin_user, + expect=expected, + **headers + ) + + @override_settings(REMOTE_HOST_HEADERS=['HTTP_X_FROM_THE_LOAD_BALANCER', 'REMOTE_ADDR', 'REMOTE_HOST'], PROXY_IP_ALLOWED_LIST=[]) + def test_no_proxy_trust_all_headers(self, job_template, admin_user, post): + job_template.inventory.hosts.create(name='foobar') + + headers = { + 'HTTP_X_FROM_THE_LOAD_BALANCER': 'foobar', + 'REMOTE_ADDR': 'bar', + 'REMOTE_HOST': 'baz', + } + post(url=reverse('api:job_template_callback', kwargs={'pk': job_template.pk}), data={'host_config_key': 'abcd'}, user=admin_user, expect=201, **headers) + + @override_settings(REMOTE_HOST_HEADERS=['HTTP_X_FROM_THE_LOAD_BALANCER', 'REMOTE_ADDR', 'REMOTE_HOST'], PROXY_IP_ALLOWED_LIST=['my.proxy.example.org']) + def test_trusted_proxy(self, job_template, admin_user, post, rsa_keypair): # noqa: F811 + job_template.inventory.hosts.create(name='foobar') + + headers = { + 'HTTP_X_TRUSTED_PROXY': generate_x_trusted_proxy_header(rsa_keypair.private), + 'HTTP_X_FROM_THE_LOAD_BALANCER': 'foobar, my.proxy.example.org', + } + + with mock.patch('ansible_base.jwt_consumer.common.cache.JWTCache.get_key_from_cache', lambda self: None): + with override_settings(ANSIBLE_BASE_JWT_KEY=rsa_keypair.public): + post( + url=reverse('api:job_template_callback', kwargs={'pk': job_template.pk}), + data={'host_config_key': 'abcd'}, + user=admin_user, + expect=201, + **headers + ) + + @override_settings(REMOTE_HOST_HEADERS=['HTTP_X_FROM_THE_LOAD_BALANCER', 'REMOTE_ADDR', 'REMOTE_HOST'], PROXY_IP_ALLOWED_LIST=['my.proxy.example.org']) + def test_trusted_proxy_host_not_found(self, job_template, admin_user, post, rsa_keypair): # noqa: F811 + job_template.inventory.hosts.create(name='foobar') + + headers = { + 'HTTP_X_TRUSTED_PROXY': generate_x_trusted_proxy_header(rsa_keypair.private), + 'HTTP_X_FROM_THE_LOAD_BALANCER': 'baz, my.proxy.example.org', + 'REMOTE_ADDR': 'bar', + 'REMOTE_HOST': 'baz', + } + + with mock.patch('ansible_base.jwt_consumer.common.cache.JWTCache.get_key_from_cache', lambda self: None): + with override_settings(ANSIBLE_BASE_JWT_KEY=rsa_keypair.public): + post( + url=reverse('api:job_template_callback', kwargs={'pk': job_template.pk}), + data={'host_config_key': 'abcd'}, + user=admin_user, + expect=400, + **headers + ) diff --git a/awx/main/tests/functional/api/test_license_cache_clearing.py b/awx/main/tests/functional/api/test_license_cache_clearing.py new file mode 100644 index 000000000000..08b8e3513822 --- /dev/null +++ b/awx/main/tests/functional/api/test_license_cache_clearing.py @@ -0,0 +1,191 @@ +import pytest +from unittest.mock import patch, MagicMock + +from awx.api.versioning import reverse + + +# Generated by Cursor (claude-4-sonnet) +@pytest.mark.django_db +class TestLicenseCacheClearing: + """Test cache clearing for LICENSE setting changes""" + + def test_license_from_manifest_clears_cache(self, admin_user, post): + """Test that posting a manifest to /api/v2/config/ clears the LICENSE cache""" + + # Mock the licenser and clear_setting_cache + with patch('awx.api.views.root.get_licenser') as mock_get_licenser, patch('awx.api.views.root.validate_entitlement_manifest') as mock_validate, patch( + 'awx.api.views.root.clear_setting_cache' + ) as mock_clear_cache, patch('django.db.connection.on_commit') as mock_on_commit: + + # Set up mock license data + mock_license_data = {'valid_key': True, 'license_type': 'enterprise', 'instance_count': 100, 'subscription_name': 'Test Enterprise License'} + + # Mock the validation and license processing + mock_validate.return_value = [{'some': 'manifest_data'}] + mock_licenser = MagicMock() + mock_licenser.license_from_manifest.return_value = mock_license_data + mock_get_licenser.return_value = mock_licenser + + # Prepare the request data (base64 encoded manifest) + manifest_data = {'manifest': 'ZmFrZS1tYW5pZmVzdC1kYXRh'} # base64 for "fake-manifest-data" + + # Make the POST request + url = reverse('api:api_v2_config_view') + response = post(url, manifest_data, admin_user, expect=200) + + # Verify the response + assert response.data == mock_license_data + + # Verify license_from_manifest was called + mock_licenser.license_from_manifest.assert_called_once() + + # Verify on_commit was called (may be multiple times due to other settings) + assert mock_on_commit.call_count >= 1 + + # Execute all on_commit callbacks to trigger cache clearing + for call_args in mock_on_commit.call_args_list: + callback = call_args[0][0] + callback() + + # Verify that clear_setting_cache.delay was called with ['LICENSE'] + mock_clear_cache.delay.assert_any_call(['LICENSE']) + + def test_config_delete_clears_cache(self, admin_user, delete): + """Test that DELETE /api/v2/config/ clears the LICENSE cache""" + + with patch('awx.api.views.root.clear_setting_cache') as mock_clear_cache, patch('django.db.connection.on_commit') as mock_on_commit: + + # Make the DELETE request + url = reverse('api:api_v2_config_view') + delete(url, admin_user, expect=204) + + # Verify on_commit was called at least once + assert mock_on_commit.call_count >= 1 + + # Execute all on_commit callbacks to trigger cache clearing + for call_args in mock_on_commit.call_args_list: + callback = call_args[0][0] + callback() + + mock_clear_cache.delay.assert_called_once_with(['LICENSE']) + + def test_attach_view_clears_cache(self, admin_user, post): + """Test that posting to /api/v2/config/attach/ clears the LICENSE cache""" + + with patch('awx.api.views.root.get_licenser') as mock_get_licenser, patch('awx.api.views.root.clear_setting_cache') as mock_clear_cache, patch( + 'django.db.connection.on_commit' + ) as mock_on_commit, patch('awx.api.views.root.settings') as mock_settings: + + # Set up subscription credentials in settings + mock_settings.SUBSCRIPTIONS_CLIENT_ID = 'test-client-id' + mock_settings.SUBSCRIPTIONS_CLIENT_SECRET = 'test-client-secret' + + # Set up mock licenser with validated subscriptions + mock_licenser = MagicMock() + subscription_data = {'subscription_id': 'test-subscription-123', 'valid_key': False, 'license_type': 'enterprise', 'instance_count': 50} + mock_licenser.validate_rh.return_value = [subscription_data] + mock_get_licenser.return_value = mock_licenser + + # Prepare request data + request_data = {'subscription_id': 'test-subscription-123'} + + # Make the POST request + url = reverse('api:api_v2_attach_view') + response = post(url, request_data, admin_user, expect=200) + + # Verify the response includes valid_key=True + assert response.data['valid_key'] is True + assert response.data['subscription_id'] == 'test-subscription-123' + + # Verify settings.LICENSE was set + expected_license = subscription_data.copy() + expected_license['valid_key'] = True + assert mock_settings.LICENSE == expected_license + + # Verify cache clearing was scheduled + mock_on_commit.assert_called_once() + call_args = mock_on_commit.call_args[0][0] # Get the lambda function + + # Execute the lambda to verify it calls clear_setting_cache + call_args() + mock_clear_cache.delay.assert_called_once_with(['LICENSE']) + + def test_attach_view_subscription_not_found_no_cache_clear(self, admin_user, post): + """Test that attach view doesn't clear cache when subscription is not found""" + + with patch('awx.api.views.root.get_licenser') as mock_get_licenser, patch('awx.api.views.root.clear_setting_cache') as mock_clear_cache, patch( + 'django.db.connection.on_commit' + ) as mock_on_commit: + + # Set up mock licenser with different subscription + mock_licenser = MagicMock() + subscription_data = {'subscription_id': 'different-subscription-456', 'valid_key': False, 'license_type': 'enterprise'} # Different ID + mock_licenser.validate_rh.return_value = [subscription_data] + mock_get_licenser.return_value = mock_licenser + + # Request data with non-matching subscription ID + request_data = { + 'subscription_id': 'test-subscription-123', # This won't match + } + + # Make the POST request + url = reverse('api:api_v2_attach_view') + response = post(url, request_data, admin_user, expect=400) + + # Verify error response + assert 'error' in response.data + + # Verify cache clearing was NOT called (no matching subscription) + mock_on_commit.assert_not_called() + mock_clear_cache.delay.assert_not_called() + + def test_manifest_validation_error_no_cache_clear(self, admin_user, post): + """Test that config view doesn't clear cache when manifest validation fails""" + + with patch('awx.api.views.root.validate_entitlement_manifest') as mock_validate, patch( + 'awx.api.views.root.clear_setting_cache' + ) as mock_clear_cache, patch('django.db.connection.on_commit') as mock_on_commit: + + # Mock validation to raise ValueError + mock_validate.side_effect = ValueError("Invalid manifest") + + # Prepare request data + manifest_data = {'manifest': 'aW52YWxpZC1tYW5pZmVzdA=='} # base64 for "invalid-manifest" + + # Make the POST request + url = reverse('api:api_v2_config_view') + response = post(url, manifest_data, admin_user, expect=400) + + # Verify error response + assert response.data['error'] == 'Invalid manifest' + + # Verify cache clearing was NOT called (validation failed) + mock_on_commit.assert_not_called() + mock_clear_cache.delay.assert_not_called() + + def test_license_processing_error_no_cache_clear(self, admin_user, post): + """Test that config view doesn't clear cache when license processing fails""" + + with patch('awx.api.views.root.get_licenser') as mock_get_licenser, patch('awx.api.views.root.validate_entitlement_manifest') as mock_validate, patch( + 'awx.api.views.root.clear_setting_cache' + ) as mock_clear_cache, patch('django.db.connection.on_commit') as mock_on_commit: + + # Mock validation to succeed but license processing to fail + mock_validate.return_value = [{'some': 'manifest_data'}] + mock_licenser = MagicMock() + mock_licenser.license_from_manifest.side_effect = Exception("License processing failed") + mock_get_licenser.return_value = mock_licenser + + # Prepare request data + manifest_data = {'manifest': 'ZmFrZS1tYW5pZmVzdA=='} # base64 for "fake-manifest" + + # Make the POST request + url = reverse('api:api_v2_config_view') + response = post(url, manifest_data, admin_user, expect=400) + + # Verify error response + assert response.data['error'] == 'Invalid License' + + # Verify cache clearing was NOT called (license processing failed) + mock_on_commit.assert_not_called() + mock_clear_cache.delay.assert_not_called() diff --git a/awx/main/tests/functional/api/test_licensing.py b/awx/main/tests/functional/api/test_licensing.py new file mode 100644 index 000000000000..a752f0d3f2be --- /dev/null +++ b/awx/main/tests/functional/api/test_licensing.py @@ -0,0 +1,244 @@ +from unittest.mock import patch, MagicMock + +import pytest +from awx.api.versioning import reverse +from rest_framework import status + + +@pytest.mark.django_db +class TestApiV2SubscriptionView: + """Test cases for the /api/v2/config/subscriptions/ endpoint""" + + def test_basic_auth(self, post, admin): + """Test POST with subscriptions_username and subscriptions_password calls validate_rh with basic_auth=True""" + data = {'subscriptions_username': 'test_user', 'subscriptions_password': 'test_password'} + + with patch('awx.api.views.root.get_licenser') as mock_get_licenser: + mock_licenser = MagicMock() + mock_licenser.validate_rh.return_value = [] + mock_get_licenser.return_value = mock_licenser + + response = post(reverse('api:api_v2_subscription_view'), data, admin) + + assert response.status_code == status.HTTP_200_OK + mock_licenser.validate_rh.assert_called_once_with('test_user', 'test_password', True) + + def test_service_account(self, post, admin): + """Test POST with subscriptions_client_id and subscriptions_client_secret calls validate_rh with basic_auth=False""" + data = {'subscriptions_client_id': 'test_client_id', 'subscriptions_client_secret': 'test_client_secret'} + + with patch('awx.api.views.root.get_licenser') as mock_get_licenser: + mock_licenser = MagicMock() + mock_licenser.validate_rh.return_value = [] + mock_get_licenser.return_value = mock_licenser + + response = post(reverse('api:api_v2_subscription_view'), data, admin) + + assert response.status_code == status.HTTP_200_OK + mock_licenser.validate_rh.assert_called_once_with('test_client_id', 'test_client_secret', False) + + def test_encrypted_password_basic_auth(self, post, admin, settings): + """Test POST with $encrypted$ password uses settings value for basic auth""" + data = {'subscriptions_username': 'test_user', 'subscriptions_password': '$encrypted$'} + + settings.SUBSCRIPTIONS_PASSWORD = 'actual_password_from_settings' + + with patch('awx.api.views.root.get_licenser') as mock_get_licenser: + mock_licenser = MagicMock() + mock_licenser.validate_rh.return_value = [] + mock_get_licenser.return_value = mock_licenser + + response = post(reverse('api:api_v2_subscription_view'), data, admin) + + assert response.status_code == status.HTTP_200_OK + mock_licenser.validate_rh.assert_called_once_with('test_user', 'actual_password_from_settings', True) + + def test_encrypted_client_secret_service_account(self, post, admin, settings): + """Test POST with $encrypted$ client_secret uses settings value for service_account""" + data = {'subscriptions_client_id': 'test_client_id', 'subscriptions_client_secret': '$encrypted$'} + + settings.SUBSCRIPTIONS_CLIENT_SECRET = 'actual_secret_from_settings' + + with patch('awx.api.views.root.get_licenser') as mock_get_licenser: + mock_licenser = MagicMock() + mock_licenser.validate_rh.return_value = [] + mock_get_licenser.return_value = mock_licenser + + response = post(reverse('api:api_v2_subscription_view'), data, admin) + + assert response.status_code == status.HTTP_200_OK + mock_licenser.validate_rh.assert_called_once_with('test_client_id', 'actual_secret_from_settings', False) + + def test_missing_username_returns_error(self, post, admin): + """Test POST with missing username returns 400 error""" + data = {'subscriptions_password': 'test_password'} + + response = post(reverse('api:api_v2_subscription_view'), data, admin) + + assert response.status_code == status.HTTP_400_BAD_REQUEST + assert 'Missing subscription credentials' in response.data['error'] + + def test_missing_password_returns_error(self, post, admin, settings): + """Test POST with missing password returns 400 error""" + data = {'subscriptions_username': 'test_user'} + settings.SUBSCRIPTIONS_PASSWORD = None + + response = post(reverse('api:api_v2_subscription_view'), data, admin) + + assert response.status_code == status.HTTP_400_BAD_REQUEST + assert 'Missing subscription credentials' in response.data['error'] + + def test_missing_client_id_returns_error(self, post, admin): + """Test POST with missing client_id returns 400 error""" + data = {'subscriptions_client_secret': 'test_secret'} + + response = post(reverse('api:api_v2_subscription_view'), data, admin) + + assert response.status_code == status.HTTP_400_BAD_REQUEST + assert 'Missing subscription credentials' in response.data['error'] + + def test_missing_client_secret_returns_error(self, post, admin, settings): + """Test POST with missing client_secret returns 400 error""" + data = {'subscriptions_client_id': 'test_client_id'} + settings.SUBSCRIPTIONS_CLIENT_SECRET = None + + response = post(reverse('api:api_v2_subscription_view'), data, admin) + + assert response.status_code == status.HTTP_400_BAD_REQUEST + assert 'Missing subscription credentials' in response.data['error'] + + def test_empty_username_returns_error(self, post, admin): + """Test POST with empty username returns 400 error""" + data = {'subscriptions_username': '', 'subscriptions_password': 'test_password'} + + response = post(reverse('api:api_v2_subscription_view'), data, admin) + + assert response.status_code == status.HTTP_400_BAD_REQUEST + assert 'Missing subscription credentials' in response.data['error'] + + def test_empty_password_returns_error(self, post, admin, settings): + """Test POST with empty password returns 400 error""" + data = {'subscriptions_username': 'test_user', 'subscriptions_password': ''} + settings.SUBSCRIPTIONS_PASSWORD = None + + response = post(reverse('api:api_v2_subscription_view'), data, admin) + + assert response.status_code == status.HTTP_400_BAD_REQUEST + assert 'Missing subscription credentials' in response.data['error'] + + def test_non_superuser_permission_denied(self, post, rando): + """Test that non-superuser cannot access the endpoint""" + data = {'subscriptions_username': 'test_user', 'subscriptions_password': 'test_password'} + + response = post(reverse('api:api_v2_subscription_view'), data, rando) + + assert response.status_code == status.HTTP_403_FORBIDDEN + + def test_settings_updated_on_successful_basic_auth(self, post, admin, settings): + """Test that settings are updated when basic auth validation succeeds""" + data = {'subscriptions_username': 'new_username', 'subscriptions_password': 'new_password'} + + with patch('awx.api.views.root.get_licenser') as mock_get_licenser: + mock_licenser = MagicMock() + mock_licenser.validate_rh.return_value = [] + mock_get_licenser.return_value = mock_licenser + + response = post(reverse('api:api_v2_subscription_view'), data, admin) + + assert response.status_code == status.HTTP_200_OK + assert settings.SUBSCRIPTIONS_USERNAME == 'new_username' + assert settings.SUBSCRIPTIONS_PASSWORD == 'new_password' + + def test_settings_updated_on_successful_service_account(self, post, admin, settings): + """Test that settings are updated when service account validation succeeds""" + data = {'subscriptions_client_id': 'new_client_id', 'subscriptions_client_secret': 'new_client_secret'} + + with patch('awx.api.views.root.get_licenser') as mock_get_licenser: + mock_licenser = MagicMock() + mock_licenser.validate_rh.return_value = [] + mock_get_licenser.return_value = mock_licenser + + response = post(reverse('api:api_v2_subscription_view'), data, admin) + + assert response.status_code == status.HTTP_200_OK + assert settings.SUBSCRIPTIONS_CLIENT_ID == 'new_client_id' + assert settings.SUBSCRIPTIONS_CLIENT_SECRET == 'new_client_secret' + + def test_validate_rh_exception_handling(self, post, admin): + """Test that exceptions from validate_rh are properly handled""" + data = {'subscriptions_username': 'test_user', 'subscriptions_password': 'test_password'} + + with patch('awx.api.views.root.get_licenser') as mock_get_licenser: + mock_licenser = MagicMock() + mock_licenser.validate_rh.side_effect = Exception("Connection error") + mock_get_licenser.return_value = mock_licenser + + response = post(reverse('api:api_v2_subscription_view'), data, admin) + + assert response.status_code == status.HTTP_400_BAD_REQUEST + + def test_mixed_credentials_prioritizes_client_id(self, post, admin): + """Test that when both username and client_id are provided, client_id takes precedence""" + data = { + 'subscriptions_username': 'test_user', + 'subscriptions_password': 'test_password', + 'subscriptions_client_id': 'test_client_id', + 'subscriptions_client_secret': 'test_client_secret', + } + + with patch('awx.api.views.root.get_licenser') as mock_get_licenser: + mock_licenser = MagicMock() + mock_licenser.validate_rh.return_value = [] + mock_get_licenser.return_value = mock_licenser + + response = post(reverse('api:api_v2_subscription_view'), data, admin) + + assert response.status_code == status.HTTP_200_OK + # Should use service account (basic_auth=False) since client_id is present + mock_licenser.validate_rh.assert_called_once_with('test_client_id', 'test_client_secret', False) + + def test_basic_auth_clears_service_account_settings(self, post, admin, settings): + """Test that setting basic auth credentials clears service account settings""" + # Pre-populate service account settings + settings.SUBSCRIPTIONS_CLIENT_ID = 'existing_client_id' + settings.SUBSCRIPTIONS_CLIENT_SECRET = 'existing_client_secret' + + data = {'subscriptions_username': 'test_user', 'subscriptions_password': 'test_password'} + + with patch('awx.api.views.root.get_licenser') as mock_get_licenser: + mock_licenser = MagicMock() + mock_licenser.validate_rh.return_value = [] + mock_get_licenser.return_value = mock_licenser + + response = post(reverse('api:api_v2_subscription_view'), data, admin) + + assert response.status_code == status.HTTP_200_OK + # Basic auth settings should be set + assert settings.SUBSCRIPTIONS_USERNAME == 'test_user' + assert settings.SUBSCRIPTIONS_PASSWORD == 'test_password' + # Service account settings should be cleared + assert settings.SUBSCRIPTIONS_CLIENT_ID == "" + assert settings.SUBSCRIPTIONS_CLIENT_SECRET == "" + + def test_service_account_clears_basic_auth_settings(self, post, admin, settings): + """Test that setting service account credentials clears basic auth settings""" + # Pre-populate basic auth settings + settings.SUBSCRIPTIONS_USERNAME = 'existing_username' + settings.SUBSCRIPTIONS_PASSWORD = 'existing_password' + + data = {'subscriptions_client_id': 'test_client_id', 'subscriptions_client_secret': 'test_client_secret'} + + with patch('awx.api.views.root.get_licenser') as mock_get_licenser: + mock_licenser = MagicMock() + mock_licenser.validate_rh.return_value = [] + mock_get_licenser.return_value = mock_licenser + + response = post(reverse('api:api_v2_subscription_view'), data, admin) + + assert response.status_code == status.HTTP_200_OK + # Service account settings should be set + assert settings.SUBSCRIPTIONS_CLIENT_ID == 'test_client_id' + assert settings.SUBSCRIPTIONS_CLIENT_SECRET == 'test_client_secret' + # Basic auth settings should be cleared + assert settings.SUBSCRIPTIONS_USERNAME == "" + assert settings.SUBSCRIPTIONS_PASSWORD == "" diff --git a/awx/main/tests/functional/api/test_notifications.py b/awx/main/tests/functional/api/test_notifications.py index 92f604519109..431065396d5f 100644 --- a/awx/main/tests/functional/api/test_notifications.py +++ b/awx/main/tests/functional/api/test_notifications.py @@ -153,3 +153,13 @@ def test_post_org_approval_notification(get, post, admin, notification_template, response = get(url, admin) assert response.status_code == 200 assert len(response.data['results']) == 1 + + +@pytest.mark.django_db +def test_post_wfj_notification(get, post, admin, workflow_job, notification): + workflow_job.notifications.add(notification) + workflow_job.save() + url = reverse("api:workflow_job_notifications_list", kwargs={'pk': workflow_job.pk}) + response = get(url, admin) + assert response.status_code == 200 + assert len(response.data['results']) == 1 diff --git a/awx/main/tests/functional/api/test_oauth.py b/awx/main/tests/functional/api/test_oauth.py deleted file mode 100644 index 4387f06b9caa..000000000000 --- a/awx/main/tests/functional/api/test_oauth.py +++ /dev/null @@ -1,342 +0,0 @@ -import base64 -import json -import time - -import pytest - -from django.db import connection -from django.test.utils import override_settings -from django.utils.encoding import smart_str, smart_bytes - -from awx.main.utils.encryption import decrypt_value, get_encryption_key -from awx.api.versioning import reverse, drf_reverse -from awx.main.models.oauth import OAuth2Application as Application, OAuth2AccessToken as AccessToken -from awx.main.tests.functional import immediate_on_commit -from awx.sso.models import UserEnterpriseAuth -from oauth2_provider.models import RefreshToken - - -@pytest.mark.django_db -def test_personal_access_token_creation(oauth_application, post, alice): - url = drf_reverse('api:oauth_authorization_root_view') + 'token/' - resp = post( - url, - data='grant_type=password&username=alice&password=alice&scope=read', - content_type='application/x-www-form-urlencoded', - HTTP_AUTHORIZATION='Basic ' + smart_str(base64.b64encode(smart_bytes(':'.join([oauth_application.client_id, oauth_application.client_secret])))), - ) - resp_json = smart_str(resp._container[0]) - assert 'access_token' in resp_json - assert 'scope' in resp_json - assert 'refresh_token' in resp_json - - -@pytest.mark.django_db -@pytest.mark.parametrize('allow_oauth, status', [(True, 201), (False, 403)]) -def test_token_creation_disabled_for_external_accounts(oauth_application, post, alice, allow_oauth, status): - UserEnterpriseAuth(user=alice, provider='radius').save() - url = drf_reverse('api:oauth_authorization_root_view') + 'token/' - - with override_settings(RADIUS_SERVER='example.org', ALLOW_OAUTH2_FOR_EXTERNAL_USERS=allow_oauth): - resp = post( - url, - data='grant_type=password&username=alice&password=alice&scope=read', - content_type='application/x-www-form-urlencoded', - HTTP_AUTHORIZATION='Basic ' + smart_str(base64.b64encode(smart_bytes(':'.join([oauth_application.client_id, oauth_application.client_secret])))), - status=status, - ) - if allow_oauth: - assert AccessToken.objects.count() == 1 - else: - assert 'OAuth2 Tokens cannot be created by users associated with an external authentication provider' in smart_str(resp.content) # noqa - assert AccessToken.objects.count() == 0 - - -@pytest.mark.django_db -def test_existing_token_enabled_for_external_accounts(oauth_application, get, post, admin): - UserEnterpriseAuth(user=admin, provider='radius').save() - url = drf_reverse('api:oauth_authorization_root_view') + 'token/' - with override_settings(RADIUS_SERVER='example.org', ALLOW_OAUTH2_FOR_EXTERNAL_USERS=True): - resp = post( - url, - data='grant_type=password&username=admin&password=admin&scope=read', - content_type='application/x-www-form-urlencoded', - HTTP_AUTHORIZATION='Basic ' + smart_str(base64.b64encode(smart_bytes(':'.join([oauth_application.client_id, oauth_application.client_secret])))), - status=201, - ) - token = json.loads(resp.content)['access_token'] - assert AccessToken.objects.count() == 1 - - with immediate_on_commit(): - resp = get(drf_reverse('api:user_me_list', kwargs={'version': 'v2'}), HTTP_AUTHORIZATION='Bearer ' + token, status=200) - assert json.loads(resp.content)['results'][0]['username'] == 'admin' - - with override_settings(RADIUS_SERVER='example.org', ALLOW_OAUTH2_FOR_EXTERNAL_USER=False): - with immediate_on_commit(): - resp = get(drf_reverse('api:user_me_list', kwargs={'version': 'v2'}), HTTP_AUTHORIZATION='Bearer ' + token, status=200) - assert json.loads(resp.content)['results'][0]['username'] == 'admin' - - -@pytest.mark.django_db -def test_pat_creation_no_default_scope(oauth_application, post, admin): - # tests that the default scope is overriden - url = reverse('api:o_auth2_token_list') - response = post( - url, - { - 'description': 'test token', - 'scope': 'read', - 'application': oauth_application.pk, - }, - admin, - ) - assert response.data['scope'] == 'read' - - -@pytest.mark.django_db -def test_pat_creation_no_scope(oauth_application, post, admin): - url = reverse('api:o_auth2_token_list') - response = post( - url, - { - 'description': 'test token', - 'application': oauth_application.pk, - }, - admin, - ) - assert response.data['scope'] == 'write' - - -@pytest.mark.django_db -def test_oauth2_application_create(admin, organization, post): - response = post( - reverse('api:o_auth2_application_list'), - { - 'name': 'test app', - 'organization': organization.pk, - 'client_type': 'confidential', - 'authorization_grant_type': 'password', - }, - admin, - expect=201, - ) - assert 'modified' in response.data - assert 'updated' not in response.data - created_app = Application.objects.get(client_id=response.data['client_id']) - assert created_app.name == 'test app' - assert created_app.skip_authorization is False - assert created_app.redirect_uris == '' - assert created_app.client_type == 'confidential' - assert created_app.authorization_grant_type == 'password' - assert created_app.organization == organization - - -@pytest.mark.django_db -def test_oauth2_validator(admin, oauth_application, post): - post( - reverse('api:o_auth2_application_list'), - { - 'name': 'Write App Token', - 'application': oauth_application.pk, - 'scope': 'Write', - }, - admin, - expect=400, - ) - - -@pytest.mark.django_db -def test_oauth_application_update(oauth_application, organization, patch, admin, alice): - patch( - reverse('api:o_auth2_application_detail', kwargs={'pk': oauth_application.pk}), - { - 'name': 'Test app with immutable grant type and user', - 'organization': organization.pk, - 'redirect_uris': 'http://localhost/api/', - 'authorization_grant_type': 'password', - 'skip_authorization': True, - }, - admin, - expect=200, - ) - updated_app = Application.objects.get(client_id=oauth_application.client_id) - assert updated_app.name == 'Test app with immutable grant type and user' - assert updated_app.redirect_uris == 'http://localhost/api/' - assert updated_app.skip_authorization is True - assert updated_app.authorization_grant_type == 'password' - assert updated_app.organization == organization - - -@pytest.mark.django_db -def test_oauth_application_encryption(admin, organization, post): - response = post( - reverse('api:o_auth2_application_list'), - { - 'name': 'test app', - 'organization': organization.pk, - 'client_type': 'confidential', - 'authorization_grant_type': 'password', - }, - admin, - expect=201, - ) - pk = response.data.get('id') - secret = response.data.get('client_secret') - with connection.cursor() as cursor: - encrypted = cursor.execute('SELECT client_secret FROM main_oauth2application WHERE id={}'.format(pk)).fetchone()[0] - assert encrypted.startswith('$encrypted$') - assert decrypt_value(get_encryption_key('value', pk=None), encrypted) == secret - - -@pytest.mark.django_db -def test_oauth_token_create(oauth_application, get, post, admin): - response = post(reverse('api:o_auth2_application_token_list', kwargs={'pk': oauth_application.pk}), {'scope': 'read'}, admin, expect=201) - assert 'modified' in response.data and response.data['modified'] is not None - assert 'updated' not in response.data - token = AccessToken.objects.get(token=response.data['token']) - refresh_token = RefreshToken.objects.get(token=response.data['refresh_token']) - assert token.application == oauth_application - assert refresh_token.application == oauth_application - assert token.user == admin - assert refresh_token.user == admin - assert refresh_token.access_token == token - assert token.scope == 'read' - response = get(reverse('api:o_auth2_application_token_list', kwargs={'pk': oauth_application.pk}), admin, expect=200) - assert response.data['count'] == 1 - response = get(reverse('api:o_auth2_application_detail', kwargs={'pk': oauth_application.pk}), admin, expect=200) - assert response.data['summary_fields']['tokens']['count'] == 1 - assert response.data['summary_fields']['tokens']['results'][0] == {'id': token.pk, 'scope': token.scope, 'token': '************'} - - response = post(reverse('api:o_auth2_token_list'), {'scope': 'read', 'application': oauth_application.pk}, admin, expect=201) - assert response.data['refresh_token'] - response = post( - reverse('api:user_authorized_token_list', kwargs={'pk': admin.pk}), {'scope': 'read', 'application': oauth_application.pk}, admin, expect=201 - ) - assert response.data['refresh_token'] - response = post(reverse('api:application_o_auth2_token_list', kwargs={'pk': oauth_application.pk}), {'scope': 'read'}, admin, expect=201) - assert response.data['refresh_token'] - - -@pytest.mark.django_db -def test_oauth_token_update(oauth_application, post, patch, admin): - response = post(reverse('api:o_auth2_application_token_list', kwargs={'pk': oauth_application.pk}), {'scope': 'read'}, admin, expect=201) - token = AccessToken.objects.get(token=response.data['token']) - patch(reverse('api:o_auth2_token_detail', kwargs={'pk': token.pk}), {'scope': 'write'}, admin, expect=200) - token = AccessToken.objects.get(token=token.token) - assert token.scope == 'write' - - -@pytest.mark.django_db -def test_oauth_token_delete(oauth_application, post, delete, get, admin): - response = post(reverse('api:o_auth2_application_token_list', kwargs={'pk': oauth_application.pk}), {'scope': 'read'}, admin, expect=201) - token = AccessToken.objects.get(token=response.data['token']) - delete(reverse('api:o_auth2_token_detail', kwargs={'pk': token.pk}), admin, expect=204) - assert AccessToken.objects.count() == 0 - assert RefreshToken.objects.count() == 1 - response = get(reverse('api:o_auth2_application_token_list', kwargs={'pk': oauth_application.pk}), admin, expect=200) - assert response.data['count'] == 0 - response = get(reverse('api:o_auth2_application_detail', kwargs={'pk': oauth_application.pk}), admin, expect=200) - assert response.data['summary_fields']['tokens']['count'] == 0 - - -@pytest.mark.django_db -def test_oauth_application_delete(oauth_application, post, delete, admin): - post(reverse('api:o_auth2_application_token_list', kwargs={'pk': oauth_application.pk}), {'scope': 'read'}, admin, expect=201) - delete(reverse('api:o_auth2_application_detail', kwargs={'pk': oauth_application.pk}), admin, expect=204) - assert Application.objects.filter(client_id=oauth_application.client_id).count() == 0 - assert RefreshToken.objects.filter(application=oauth_application).count() == 0 - assert AccessToken.objects.filter(application=oauth_application).count() == 0 - - -@pytest.mark.django_db -def test_oauth_list_user_tokens(oauth_application, post, get, admin, alice): - for user in (admin, alice): - url = reverse('api:o_auth2_token_list', kwargs={'pk': user.pk}) - post(url, {'scope': 'read'}, user, expect=201) - response = get(url, admin, expect=200) - assert response.data['count'] == 1 - - -@pytest.mark.django_db -def test_refresh_accesstoken(oauth_application, post, get, delete, admin): - response = post(reverse('api:o_auth2_application_token_list', kwargs={'pk': oauth_application.pk}), {'scope': 'read'}, admin, expect=201) - assert AccessToken.objects.count() == 1 - assert RefreshToken.objects.count() == 1 - token = AccessToken.objects.get(token=response.data['token']) - refresh_token = RefreshToken.objects.get(token=response.data['refresh_token']) - - refresh_url = drf_reverse('api:oauth_authorization_root_view') + 'token/' - response = post( - refresh_url, - data='grant_type=refresh_token&refresh_token=' + refresh_token.token, - content_type='application/x-www-form-urlencoded', - HTTP_AUTHORIZATION='Basic ' + smart_str(base64.b64encode(smart_bytes(':'.join([oauth_application.client_id, oauth_application.client_secret])))), - ) - assert RefreshToken.objects.filter(token=refresh_token).exists() - original_refresh_token = RefreshToken.objects.get(token=refresh_token) - assert token not in AccessToken.objects.all() - assert AccessToken.objects.count() == 1 - # the same RefreshToken remains but is marked revoked - assert RefreshToken.objects.count() == 2 - new_token = json.loads(response._container[0])['access_token'] - new_refresh_token = json.loads(response._container[0])['refresh_token'] - assert AccessToken.objects.filter(token=new_token).count() == 1 - # checks that RefreshTokens are rotated (new RefreshToken issued) - assert RefreshToken.objects.filter(token=new_refresh_token).count() == 1 - assert original_refresh_token.revoked # is not None - - -@pytest.mark.django_db -def test_refresh_token_expiration_is_respected(oauth_application, post, get, delete, admin): - response = post(reverse('api:o_auth2_application_token_list', kwargs={'pk': oauth_application.pk}), {'scope': 'read'}, admin, expect=201) - assert AccessToken.objects.count() == 1 - assert RefreshToken.objects.count() == 1 - refresh_token = RefreshToken.objects.get(token=response.data['refresh_token']) - refresh_url = drf_reverse('api:oauth_authorization_root_view') + 'token/' - short_lived = {'ACCESS_TOKEN_EXPIRE_SECONDS': 1, 'AUTHORIZATION_CODE_EXPIRE_SECONDS': 1, 'REFRESH_TOKEN_EXPIRE_SECONDS': 1} - time.sleep(1) - with override_settings(OAUTH2_PROVIDER=short_lived): - response = post( - refresh_url, - data='grant_type=refresh_token&refresh_token=' + refresh_token.token, - content_type='application/x-www-form-urlencoded', - HTTP_AUTHORIZATION='Basic ' + smart_str(base64.b64encode(smart_bytes(':'.join([oauth_application.client_id, oauth_application.client_secret])))), - ) - assert response.status_code == 403 - assert b'The refresh token has expired.' in response.content - assert RefreshToken.objects.filter(token=refresh_token).exists() - assert AccessToken.objects.count() == 1 - assert RefreshToken.objects.count() == 1 - - -@pytest.mark.django_db -def test_revoke_access_then_refreshtoken(oauth_application, post, get, delete, admin): - response = post(reverse('api:o_auth2_application_token_list', kwargs={'pk': oauth_application.pk}), {'scope': 'read'}, admin, expect=201) - token = AccessToken.objects.get(token=response.data['token']) - refresh_token = RefreshToken.objects.get(token=response.data['refresh_token']) - assert AccessToken.objects.count() == 1 - assert RefreshToken.objects.count() == 1 - - token.revoke() - assert AccessToken.objects.count() == 0 - assert RefreshToken.objects.count() == 1 - assert not refresh_token.revoked - - refresh_token.revoke() - assert AccessToken.objects.count() == 0 - assert RefreshToken.objects.count() == 1 - - -@pytest.mark.django_db -def test_revoke_refreshtoken(oauth_application, post, get, delete, admin): - response = post(reverse('api:o_auth2_application_token_list', kwargs={'pk': oauth_application.pk}), {'scope': 'read'}, admin, expect=201) - refresh_token = RefreshToken.objects.get(token=response.data['refresh_token']) - assert AccessToken.objects.count() == 1 - assert RefreshToken.objects.count() == 1 - - refresh_token.revoke() - assert AccessToken.objects.count() == 0 - # the same RefreshToken is recycled - new_refresh_token = RefreshToken.objects.all().first() - assert refresh_token == new_refresh_token - assert new_refresh_token.revoked diff --git a/awx/main/tests/functional/api/test_organizations.py b/awx/main/tests/functional/api/test_organizations.py index f86963ecc64b..af2f918ba0c5 100644 --- a/awx/main/tests/functional/api/test_organizations.py +++ b/awx/main/tests/functional/api/test_organizations.py @@ -329,3 +329,21 @@ def test_galaxy_credential_association(alice, admin, organization, post, get): 'Public Galaxy 4', 'Public Galaxy 5', ] + + +@pytest.mark.django_db +def test_org_admin_credential_count(org_admin, admin, organization, post, get): + galaxy = CredentialType.defaults['galaxy_api_token']() + galaxy.save() + + for i in range(3): + cred = Credential.objects.create(credential_type=galaxy, name=f'test_{i}', inputs={'url': 'https://galaxy.ansible.com/'}) + url = reverse('api:organization_galaxy_credentials_list', kwargs={'pk': organization.pk}) + post(url, {'associate': True, 'id': cred.pk}, user=admin, expect=204) + # org admin should see all associated galaxy credentials + resp = get(url, user=org_admin) + assert resp.data['count'] == 3 + # removing one to validate new count + post(url, {'disassociate': True, 'id': Credential.objects.get(name='test_1').pk}, user=admin, expect=204) + resp_new = get(url, user=org_admin) + assert resp_new.data['count'] == 2 diff --git a/awx/main/tests/functional/api/test_rbac_displays.py b/awx/main/tests/functional/api/test_rbac_displays.py index 8178da672c05..22d9ec9990a9 100644 --- a/awx/main/tests/functional/api/test_rbac_displays.py +++ b/awx/main/tests/functional/api/test_rbac_displays.py @@ -165,8 +165,8 @@ def _assert_one_in_list(self, data, sublist='direct_access'): def test_access_list_direct_access_capability(self, inventory, rando, get, mocker, mock_access_method): inventory.admin_role.members.add(rando) - with mocker.patch.object(access_registry[Role], 'can_unattach', mock_access_method): - response = get(reverse('api:inventory_access_list', kwargs={'pk': inventory.id}), rando) + mocker.patch.object(access_registry[Role], 'can_unattach', mock_access_method) + response = get(reverse('api:inventory_access_list', kwargs={'pk': inventory.id}), rando) mock_access_method.assert_called_once_with(inventory.admin_role, rando, 'members', **self.extra_kwargs) self._assert_one_in_list(response.data) @@ -174,8 +174,8 @@ def test_access_list_direct_access_capability(self, inventory, rando, get, mocke assert direct_access_list[0]['role']['user_capabilities']['unattach'] == 'foobar' def test_access_list_indirect_access_capability(self, inventory, organization, org_admin, get, mocker, mock_access_method): - with mocker.patch.object(access_registry[Role], 'can_unattach', mock_access_method): - response = get(reverse('api:inventory_access_list', kwargs={'pk': inventory.id}), org_admin) + mocker.patch.object(access_registry[Role], 'can_unattach', mock_access_method) + response = get(reverse('api:inventory_access_list', kwargs={'pk': inventory.id}), org_admin) mock_access_method.assert_called_once_with(organization.admin_role, org_admin, 'members', **self.extra_kwargs) self._assert_one_in_list(response.data, sublist='indirect_access') @@ -185,8 +185,8 @@ def test_access_list_indirect_access_capability(self, inventory, organization, o def test_access_list_team_direct_access_capability(self, inventory, team, team_member, get, mocker, mock_access_method): team.member_role.children.add(inventory.admin_role) - with mocker.patch.object(access_registry[Role], 'can_unattach', mock_access_method): - response = get(reverse('api:inventory_access_list', kwargs={'pk': inventory.id}), team_member) + mocker.patch.object(access_registry[Role], 'can_unattach', mock_access_method) + response = get(reverse('api:inventory_access_list', kwargs={'pk': inventory.id}), team_member) mock_access_method.assert_called_once_with(inventory.admin_role, team.member_role, 'parents', **self.extra_kwargs) self._assert_one_in_list(response.data) @@ -198,8 +198,8 @@ def test_access_list_team_direct_access_capability(self, inventory, team, team_m def test_team_roles_unattach(mocker, team, team_member, inventory, mock_access_method, get): team.member_role.children.add(inventory.admin_role) - with mocker.patch.object(access_registry[Role], 'can_unattach', mock_access_method): - response = get(reverse('api:team_roles_list', kwargs={'pk': team.id}), team_member) + mocker.patch.object(access_registry[Role], 'can_unattach', mock_access_method) + response = get(reverse('api:team_roles_list', kwargs={'pk': team.id}), team_member) # Did we assess whether team_member can remove team's permission to the inventory? mock_access_method.assert_called_once_with(inventory.admin_role, team.member_role, 'parents', skip_sub_obj_read_check=True, data={}) @@ -212,8 +212,8 @@ def test_user_roles_unattach(mocker, organization, alice, bob, mock_access_metho organization.member_role.members.add(alice) organization.member_role.members.add(bob) - with mocker.patch.object(access_registry[Role], 'can_unattach', mock_access_method): - response = get(reverse('api:user_roles_list', kwargs={'pk': alice.id}), bob) + mocker.patch.object(access_registry[Role], 'can_unattach', mock_access_method) + response = get(reverse('api:user_roles_list', kwargs={'pk': alice.id}), bob) # Did we assess whether bob can remove alice's permission to the inventory? mock_access_method.assert_called_once_with(organization.member_role, alice, 'members', skip_sub_obj_read_check=True, data={}) diff --git a/awx/main/tests/functional/api/test_role.py b/awx/main/tests/functional/api/test_role.py index cec31d9d7ede..68ce8855feab 100644 --- a/awx/main/tests/functional/api/test_role.py +++ b/awx/main/tests/functional/api/test_role.py @@ -3,17 +3,6 @@ from awx.api.versioning import reverse -@pytest.mark.django_db -def test_admin_visible_to_orphaned_users(get, alice): - names = set() - - response = get(reverse('api:role_list'), user=alice) - for item in response.data['results']: - names.add(item['name']) - assert 'System Auditor' in names - assert 'System Administrator' in names - - @pytest.mark.django_db @pytest.mark.parametrize('role,code', [('member_role', 400), ('admin_role', 400), ('inventory_admin_role', 204)]) @pytest.mark.parametrize('reversed', [True, False]) diff --git a/awx/main/tests/functional/api/test_schedules.py b/awx/main/tests/functional/api/test_schedules.py index c1cd0779c35f..cb49a53d22a5 100644 --- a/awx/main/tests/functional/api/test_schedules.py +++ b/awx/main/tests/functional/api/test_schedules.py @@ -8,7 +8,6 @@ from awx.main.models import JobTemplate, Schedule from awx.main.utils.encryption import decrypt_value, get_encryption_key - RRULE_EXAMPLE = 'DTSTART:20151117T050000Z RRULE:FREQ=DAILY;INTERVAL=1;COUNT=1' diff --git a/awx/main/tests/functional/api/test_serializers.py b/awx/main/tests/functional/api/test_serializers.py new file mode 100644 index 000000000000..ab31e186e9c4 --- /dev/null +++ b/awx/main/tests/functional/api/test_serializers.py @@ -0,0 +1,75 @@ +import pytest + +from django.test.utils import override_settings + +from rest_framework.serializers import ValidationError + +from awx.api.serializers import UserSerializer +from django.contrib.auth.models import User + + +@pytest.mark.parametrize( + "password,min_length,min_digits,min_upper,min_special,expect_error", + [ + # Test length + ("a", 1, 0, 0, 0, False), + ("a", 2, 0, 0, 0, True), + ("aa", 2, 0, 0, 0, False), + ("aaabcDEF123$%^", 2, 0, 0, 0, False), + # Test digits + ("a", 0, 1, 0, 0, True), + ("1", 0, 1, 0, 0, False), + ("1", 0, 2, 0, 0, True), + ("12", 0, 2, 0, 0, False), + ("12abcDEF123$%^", 0, 2, 0, 0, False), + # Test upper + ("a", 0, 0, 1, 0, True), + ("A", 0, 0, 1, 0, False), + ("A", 0, 0, 2, 0, True), + ("AB", 0, 0, 2, 0, False), + ("ABabcDEF123$%^", 0, 0, 2, 0, False), + # Test special + ("a", 0, 0, 0, 1, True), + ("!", 0, 0, 0, 1, False), + ("!", 0, 0, 0, 2, True), + ("!@", 0, 0, 0, 2, False), + ("!@abcDEF123$%^", 0, 0, 0, 2, False), + ], +) +@pytest.mark.django_db +def test_validate_password_rules(password, min_length, min_digits, min_upper, min_special, expect_error): + user_serializer = UserSerializer() + + # First test password with no params, this should always pass + try: + user_serializer.validate_password(password) + except ValidationError: + assert False, f"Password {password} should not have validation issue if no params are used" + + with override_settings( + LOCAL_PASSWORD_MIN_LENGTH=min_length, LOCAL_PASSWORD_MIN_DIGITS=min_digits, LOCAL_PASSWORD_MIN_UPPER=min_upper, LOCAL_PASSWORD_MIN_SPECIAL=min_special + ): + if expect_error: + with pytest.raises(ValidationError): + user_serializer.validate_password(password) + else: + try: + user_serializer.validate_password(password) + except ValidationError: + assert False, "validate_password raised an unexpected exception" + + +@pytest.mark.django_db +def test_validate_password_too_long(): + password_max_length = User._meta.get_field('password').max_length + password = "x" * password_max_length + + user_serializer = UserSerializer() + try: + user_serializer.validate_password(password) + except ValidationError: + assert False, f"Password {password} should not have validation" + + password = f"{password}x" + with pytest.raises(ValidationError): + user_serializer.validate_password(password) diff --git a/awx/main/tests/functional/api/test_settings.py b/awx/main/tests/functional/api/test_settings.py index a1ae7398a5bf..e096637dc28c 100644 --- a/awx/main/tests/functional/api/test_settings.py +++ b/awx/main/tests/functional/api/test_settings.py @@ -7,10 +7,8 @@ # AWX from awx.api.versioning import reverse -from awx.conf.models import Setting from awx.conf.registry import settings_registry - TEST_GIF_LOGO = 'data:image/gif;base64,R0lGODlhIQAjAPIAAP//////AP8AAMzMAJmZADNmAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJCgAHACwAAAAAIQAjAAADo3i63P4wykmrvTjrzZsxXfR94WMQBFh6RECuixHMLyzPQ13ewZCvow9OpzEAjIBj79cJJmU+FceIVEZ3QRozxBttmyOBwPBtisdX4Bha3oxmS+llFIPHQXQKkiSEXz9PeklHBzx3hYNyEHt4fmmAhHp8Nz45KgV5FgWFOFEGmwWbGqEfniChohmoQZ+oqRiZDZhEgk81I4mwg4EKVbxzrDHBEAkAIfkECQoABwAsAAAAACEAIwAAA6V4utz+MMpJq724GpP15p1kEAQYQmOwnWjgrmxjuMEAx8rsDjZ+fJvdLWQAFAHGWo8FRM54JqIRmYTigDrDMqZTbbbMj0CgjTLHZKvPQH6CTx+a2vKR0XbbOsoZ7SphG057gjl+c0dGgzeGNiaBiSgbBQUHBV08NpOVlkMSk0FKjZuURHiiOJxQnSGfQJuoEKREejK0dFRGjoiQt7iOuLx0rgxYEQkAIfkECQoABwAsAAAAACEAIwAAA7h4utxnxslJDSGR6nrz/owxYB64QUEwlGaVqlB7vrAJscsd3Lhy+wBArGEICo3DUFH4QDqK0GMy51xOgcGlEAfJ+iAFie62chR+jYKaSAuQGOqwJp7jGQRDuol+F/jxZWsyCmoQfwYwgoM5Oyg1i2w0A2WQIW2TPYOIkleQmy+UlYygoaIPnJmapKmqKiusMmSdpjxypnALtrcHioq3ury7hGm3dnVosVpMWFmwREZbddDOSsjVswcJACH5BAkKAAcALAAAAAAhACMAAAOxeLrc/jDKSZUxNS9DCNYV54HURQwfGRlDEFwqdLVuGjOsW9/Odb0wnsUAKBKNwsMFQGwyNUHckVl8bqI4o43lA26PNkv1S9DtNuOeVirw+aTI3qWAQwnud1vhLSnQLS0GeFF+GoVKNF0fh4Z+LDQ6Bn5/MTNmL0mAl2E3j2aclTmRmYCQoKEDiaRDKFhJez6UmbKyQowHtzy1uEl8DLCnEktrQ2PBD1NxSlXKIW5hz6cJACH5BAkKAAcALAAAAAAhACMAAAOkeLrc/jDKSau9OOvNlTFd9H3hYxAEWDJfkK5LGwTq+g0zDR/GgM+10A04Cm56OANgqTRmkDTmSOiLMgFOTM9AnFJHuexzYBAIijZf2SweJ8ttbbXLmd5+wBiJosSCoGF/fXEeS1g8gHl9hxODKkh4gkwVIwUekESIhA4FlgV3PyCWG52WI2oGnR2lnUWpqhqVEF4Xi7QjhpsshpOFvLosrnpoEAkAIfkECQoABwAsAAAAACEAIwAAA6l4utz+MMpJq71YGpPr3t1kEAQXQltQnk8aBCa7bMMLy4wx1G8s072PL6SrGQDI4zBThCU/v50zCVhidIYgNPqxWZkDg0AgxB2K4vEXbBSvr1JtZ3uOext0x7FqovF6OXtfe1UzdjAxhINPM013ChtJER8FBQeVRX8GlpggFZWWfjwblTiigGZnfqRmpUKbljKxDrNMeY2eF4R8jUiSur6/Z8GFV2WBtwwJACH5BAkKAAcALAAAAAAhACMAAAO6eLrcZi3KyQwhkGpq8f6ONWQgaAxB8JTfg6YkO50pzD5xhaurhCsGAKCnEw6NucNDCAkyI8ugdAhFKpnJJdMaeiofBejowUseCr9GYa0j1GyMdVgjBxoEuPSZXWKf7gKBeHtzMms0gHgGfDIVLztmjScvNZEyk28qjT40b5aXlHCbDgOhnzedoqOOlKeopaqrCy56sgtotbYKhYW6e7e9tsHBssO6eSTIm1peV0iuFUZDyU7NJnmcuQsJACH5BAkKAAcALAAAAAAhACMAAAOteLrc/jDKSZsxNS9DCNYV54Hh4H0kdAXBgKaOwbYX/Miza1vrVe8KA2AoJL5gwiQgeZz4GMXlcHl8xozQ3kW3KTajL9zsBJ1+sV2fQfALem+XAlRApxu4ioI1UpC76zJ4fRqDBzI+LFyFhH1iiS59fkgziW07jjRAG5QDeECOLk2Tj6KjnZafW6hAej6Smgevr6yysza2tiCuMasUF2Yov2gZUUQbU8YaaqjLpQkAOw==' # NOQA TEST_PNG_LOGO = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAjCAYAAAAaLGNkAAAAAXNSR0IB2cksfwAAAdVpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iPgogICAgICAgICA8dGlmZjpDb21wcmVzc2lvbj4xPC90aWZmOkNvbXByZXNzaW9uPgogICAgICAgICA8dGlmZjpQaG90b21ldHJpY0ludGVycHJldGF0aW9uPjI8L3RpZmY6UGhvdG9tZXRyaWNJbnRlcnByZXRhdGlvbj4KICAgICAgICAgPHRpZmY6T3JpZW50YXRpb24+MTwvdGlmZjpPcmllbnRhdGlvbj4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+Cjl0tmoAAAHVSURBVFgJ7VZRsoMgDNTOu5E9U+/Ud6Z6JssGNg2oNKD90xkHCNnNkgTbYbieKwNXBn6bgSXQ4+16xi5UDiqDN3Pecr6+1fM5DHh7n1NEIPjjoRLKzOjG3qQ5dRtEy2LCjh/Gz2wDZE2nZYKkrxdn/kY9XQQkGCGqqDY5IgJFkEKgBCzDNGXhTKEye7boFRH6IPJj5EshiNCSjV4R4eSx7zhmR2tcdIuwmWiMeao7e0JHViZEWUI5aP8a9O+rx74D6sGEiJftiX3YeueIiFXg2KrhpqzjVC3dPZFYJZ7NOwwtNwM8R0UkLfH0sT5qck+OlkMq0BucKr0iWG7gpAQksD9esM1z3Lnf6SHjLh67nnKEGxC/iomWhByTeXOQJGHHcKxwHhHKnt1HIdYtmexkIb/HOURWTSJqn2gKMDG0bDUc/D0iAseovxUBoylmQCug6IVhSv+4DIeKI94jAr4AjiSEgQ25JYB+YWT9BZ94AM8erwgFkRifaArA6U0G5KT0m//z26REZuK9okgrT6VwE1jTHjbVzyNAyRwTEPOtuiex9FVBNZCkruaA4PZqFp1u8Rpww9/6rcK5y0EkAxRiZJt79PWOVYWGRE9pbJhavMengMflGyumk0akMsQnAAAAAElFTkSuQmCC' # NOQA TEST_JPEG_LOGO = 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAASABIAAD/4QBkRXhpZgAATU0AKgAAAAgAAwEGAAMAAAABAAIAAAESAAMAAAABAAEAAIdpAAQAAAABAAAAMgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAIaADAAQAAAABAAAAIwAAAAD/4QkhaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA1LjQuMCI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiLz4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8P3hwYWNrZXQgZW5kPSJ3Ij8+AP/tADhQaG90b3Nob3AgMy4wADhCSU0EBAAAAAAAADhCSU0EJQAAAAAAENQdjNmPALIE6YAJmOz4Qn7/wAARCAAjACEDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9sAQwAGBgYGBgYKBgYKDgoKCg4SDg4ODhIXEhISEhIXHBcXFxcXFxwcHBwcHBwcIiIiIiIiJycnJycsLCwsLCwsLCws/9sAQwEHBwcLCgsTCgoTLh8aHy4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4u/90ABAAD/9oADAMBAAIRAxEAPwD6poormvFfivSvB2lHVtWLGMtsRE2hnYKzlVLsi52oxALDdjauWKqQCXQfFXh7xP8Aaf7AvYrz7HL5U3lk/K3YjIGVODtcZVsHBODXQV806bcT+E9L03XbCOS2udMsLQanbB4po72xYMfOQpKYyV2zPEwcNwVK7WAr6WriwWMWIUvdcZRdmnuu33rVFSjYKKKK7ST/0PqmuF8Vv4X8S+HNZ0+e/gIsYJvtEsL+bJZsI3UuyxNvBA3gpxvXchyCRXdV8ta3bW667DoloW1y10tLLTJxZWP2hoLSGYzNHclGZpJC0ESk8IAZcRB8is61T2cHK1/1DrY526h8YXHh691vxCz6dafY5Q0U7yGSeQxSxohNzJLcbUeQ4VnVNxBRCWL19b2eraVqE9xa2F3BcS2jbJ0ikV2ibJG1wpJU5UjBx0PpXzrrniy4k17TrrWrGex022ufMijvd9m11PGH8naXKqsUcgR3MhB5U7MA16x4L8F3vhq2sY9Ru4rg6day2tusEAhCrcOkknmEMRI2Y1AcLGT8xYMzZHjZFGu6cquKjaUnt2XS76vv/SN8RVjOdoKyXY9Cooor3TA//9H6pr4gfxRrMvxJ0/whLJE+maVrcVnZRtBCzwQQ3SIipMU80fKignflgPmJr7fr4A/5rf8A9zJ/7eUAdX8SfGviPwl8TtaPh6eK1eTyN0n2eCSUg28OV8ySNn2/KDtztzzjNfZVhY2umWMGm2KeXb2sSQxJknakYCqMkknAHUnNfBXxt/5Kdq//AG7/APpPFX3/AEAFFFFAH//Z' # NOQA @@ -67,129 +65,6 @@ def test_awx_task_env_validity(get, patch, admin, value, expected): assert resp.data['AWX_TASK_ENV'] == dict() -@pytest.mark.django_db -def test_ldap_settings(get, put, patch, delete, admin): - url = reverse('api:setting_singleton_detail', kwargs={'category_slug': 'ldap'}) - get(url, user=admin, expect=200) - # The PUT below will fail at the moment because AUTH_LDAP_GROUP_TYPE - # defaults to None but cannot be set to None. - # put(url, user=admin, data=response.data, expect=200) - delete(url, user=admin, expect=204) - patch(url, user=admin, data={'AUTH_LDAP_SERVER_URI': ''}, expect=200) - patch(url, user=admin, data={'AUTH_LDAP_SERVER_URI': 'ldap.example.com'}, expect=400) - patch(url, user=admin, data={'AUTH_LDAP_SERVER_URI': 'ldap://ldap.example.com'}, expect=200) - patch(url, user=admin, data={'AUTH_LDAP_SERVER_URI': 'ldaps://ldap.example.com'}, expect=200) - patch(url, user=admin, data={'AUTH_LDAP_SERVER_URI': 'ldap://ldap.example.com:389'}, expect=200) - patch(url, user=admin, data={'AUTH_LDAP_SERVER_URI': 'ldaps://ldap.example.com:636'}, expect=200) - patch(url, user=admin, data={'AUTH_LDAP_SERVER_URI': 'ldap://ldap.example.com ldap://ldap2.example.com'}, expect=200) - patch(url, user=admin, data={'AUTH_LDAP_SERVER_URI': 'ldap://ldap.example.com,ldap://ldap2.example.com'}, expect=200) - patch(url, user=admin, data={'AUTH_LDAP_SERVER_URI': 'ldap://ldap.example.com, ldap://ldap2.example.com'}, expect=200) - patch(url, user=admin, data={'AUTH_LDAP_BIND_DN': 'cn=Manager,dc=example,dc=com'}, expect=200) - patch(url, user=admin, data={'AUTH_LDAP_BIND_DN': u'cn=暴力膜,dc=大新闻,dc=真的粉丝'}, expect=200) - - -@pytest.mark.django_db -@pytest.mark.parametrize( - 'value', - [ - None, - '', - 'INVALID', - 1, - [1], - ['INVALID'], - ], -) -def test_ldap_user_flags_by_group_invalid_dn(get, patch, admin, value): - url = reverse('api:setting_singleton_detail', kwargs={'category_slug': 'ldap'}) - patch(url, user=admin, data={'AUTH_LDAP_USER_FLAGS_BY_GROUP': {'is_superuser': value}}, expect=400) - - -@pytest.mark.django_db -def test_ldap_user_flags_by_group_string(get, patch, admin): - expected = 'CN=Admins,OU=Groups,DC=example,DC=com' - url = reverse('api:setting_singleton_detail', kwargs={'category_slug': 'ldap'}) - patch(url, user=admin, data={'AUTH_LDAP_USER_FLAGS_BY_GROUP': {'is_superuser': expected}}, expect=200) - resp = get(url, user=admin) - assert resp.data['AUTH_LDAP_USER_FLAGS_BY_GROUP']['is_superuser'] == [expected] - - -@pytest.mark.django_db -def test_ldap_user_flags_by_group_list(get, patch, admin): - expected = ['CN=Admins,OU=Groups,DC=example,DC=com', 'CN=Superadmins,OU=Groups,DC=example,DC=com'] - url = reverse('api:setting_singleton_detail', kwargs={'category_slug': 'ldap'}) - patch(url, user=admin, data={'AUTH_LDAP_USER_FLAGS_BY_GROUP': {'is_superuser': expected}}, expect=200) - resp = get(url, user=admin) - assert resp.data['AUTH_LDAP_USER_FLAGS_BY_GROUP']['is_superuser'] == expected - - -@pytest.mark.parametrize( - 'setting', - [ - 'AUTH_LDAP_USER_DN_TEMPLATE', - 'AUTH_LDAP_REQUIRE_GROUP', - 'AUTH_LDAP_DENY_GROUP', - ], -) -@pytest.mark.django_db -def test_empty_ldap_dn(get, put, patch, delete, admin, setting): - url = reverse('api:setting_singleton_detail', kwargs={'category_slug': 'ldap'}) - patch(url, user=admin, data={setting: ''}, expect=200) - resp = get(url, user=admin, expect=200) - assert resp.data[setting] is None - - patch(url, user=admin, data={setting: None}, expect=200) - resp = get(url, user=admin, expect=200) - assert resp.data[setting] is None - - -@pytest.mark.django_db -def test_radius_settings(get, put, patch, delete, admin, settings): - url = reverse('api:setting_singleton_detail', kwargs={'category_slug': 'radius'}) - response = get(url, user=admin, expect=200) - put(url, user=admin, data=response.data, expect=200) - # Set secret via the API. - patch(url, user=admin, data={'RADIUS_SECRET': 'mysecret'}, expect=200) - response = get(url, user=admin, expect=200) - assert response.data['RADIUS_SECRET'] == '$encrypted$' - assert Setting.objects.filter(key='RADIUS_SECRET').first().value.startswith('$encrypted$') - assert settings.RADIUS_SECRET == 'mysecret' - # Set secret via settings wrapper. - settings_wrapper = settings._awx_conf_settings - settings_wrapper.RADIUS_SECRET = 'mysecret2' - response = get(url, user=admin, expect=200) - assert response.data['RADIUS_SECRET'] == '$encrypted$' - assert Setting.objects.filter(key='RADIUS_SECRET').first().value.startswith('$encrypted$') - assert settings.RADIUS_SECRET == 'mysecret2' - # If we send back $encrypted$, the setting is not updated. - patch(url, user=admin, data={'RADIUS_SECRET': '$encrypted$'}, expect=200) - response = get(url, user=admin, expect=200) - assert response.data['RADIUS_SECRET'] == '$encrypted$' - assert Setting.objects.filter(key='RADIUS_SECRET').first().value.startswith('$encrypted$') - assert settings.RADIUS_SECRET == 'mysecret2' - # If we send an empty string, the setting is also set to an empty string. - patch(url, user=admin, data={'RADIUS_SECRET': ''}, expect=200) - response = get(url, user=admin, expect=200) - assert response.data['RADIUS_SECRET'] == '' - assert Setting.objects.filter(key='RADIUS_SECRET').first().value == '' - assert settings.RADIUS_SECRET == '' - - -@pytest.mark.django_db -def test_tacacsplus_settings(get, put, patch, admin): - url = reverse('api:setting_singleton_detail', kwargs={'category_slug': 'tacacsplus'}) - response = get(url, user=admin, expect=200) - put(url, user=admin, data=response.data, expect=200) - patch(url, user=admin, data={'TACACSPLUS_SECRET': 'mysecret'}, expect=200) - patch(url, user=admin, data={'TACACSPLUS_SECRET': ''}, expect=200) - patch(url, user=admin, data={'TACACSPLUS_HOST': 'localhost'}, expect=400) - patch(url, user=admin, data={'TACACSPLUS_SECRET': 'mysecret'}, expect=200) - patch(url, user=admin, data={'TACACSPLUS_HOST': 'localhost'}, expect=200) - patch(url, user=admin, data={'TACACSPLUS_HOST': '', 'TACACSPLUS_SECRET': ''}, expect=200) - patch(url, user=admin, data={'TACACSPLUS_HOST': 'localhost', 'TACACSPLUS_SECRET': ''}, expect=400) - patch(url, user=admin, data={'TACACSPLUS_HOST': 'localhost', 'TACACSPLUS_SECRET': 'mysecret'}, expect=200) - - @pytest.mark.django_db def test_ui_settings(get, put, patch, delete, admin): url = reverse('api:setting_singleton_detail', kwargs={'category_slug': 'ui'}) @@ -318,76 +193,3 @@ def test_logging_aggregator_connection_test_valid(put, post, admin): # "Test" the logger url = reverse('api:setting_logging_test') post(url, {}, user=admin, expect=202) - - -@pytest.mark.django_db -@pytest.mark.parametrize('headers', [True, False]) -def test_saml_x509cert_validation(patch, get, admin, headers): - cert = "MIIEogIBAAKCAQEA1T4za6qBbHxFpN5f9eFvA74MFjrsjcp1uvzOaE23AYKMDEJghJ6dqQ7GwHLNIeIeumqDFmODauIzrgSDJTT5+NG30Rr+rRi0zDkrkBAj/AtA+SaVhbzqB6ZSd7LaMly9XAc+82OKlNpuWS9hPmFaSShzDTXRu5RRyvm4NDCAOGDu5hyVR2pV/ffKDNfNkChnqzvRRW9laQcVmliZhlTGn7nPZ+JbjpwEy0nwW+4zoAiEvwnT52N4xTqIcYOnXtGiaf13dh7FkUfYmS0tzF3+h8QRKwtIm4y+sq84R/kr79/0t5aRUpJynNrECajzmArpL4IjXKTPIyUpTKirJgGnCwIDAQABAoIBAC6bbbm2hpsjfkVOpUKkhxMWUqX5MwK6oYjBAIwjkEAwPFPhnh7eXC87H42oidVCCt1LsmMOVQbjcdAzBEb5kTkk/Twi3k8O+1U3maHfJT5NZ2INYNjeNXh+jb/Dw5UGWAzpOIUR2JQ4Oa4cgPCVbppW0O6uOKz6+fWXJv+hKiUoBCC0TiY52iseHJdUOaKNxYRD2IyIzCAxFSd5tZRaARIYDsugXp3E/TdbsVWA7bmjIBOXq+SquTrlB8x7j3B7+Pi09nAJ2U/uV4PHE+/2Fl009ywfmqancvnhwnz+GQ5jjP+gTfghJfbO+Z6M346rS0Vw+osrPgfyudNHlCswHOECgYEA/Cfq25gDP07wo6+wYWbx6LIzj/SSZy/Ux9P8zghQfoZiPoaq7BQBPAzwLNt7JWST8U11LZA8/wo6ch+HSTMk+m5ieVuru2cHxTDqeNlh94eCrNwPJ5ayA5U6LxAuSCTAzp+rv6KQUx1JcKSEHuh+nRYTKvUDE6iA6YtPLO96lLUCgYEA2H5rOPX2M4w1Q9zjol77lplbPRdczXNd0PIzhy8Z2ID65qvmr1nxBG4f2H96ykW8CKLXNvSXreNZ1BhOXc/3Hv+3mm46iitB33gDX4mlV4Jyo/w5IWhUKRyoW6qXquFFsScxRzTrx/9M+aZeRRLdsBk27HavFEg6jrbQ0SleZL8CgYAaM6Op8d/UgkVrHOR9Go9kmK/W85kK8+NuaE7Ksf57R0eKK8AzC9kc/lMuthfTyOG+n0ff1i8gaVWtai1Ko+/hvfqplacAsDIUgYK70AroB8LCZ5ODj5sr2CPVpB7LDFakod7c6O2KVW6+L7oy5AHUHOkc+5y4PDg5DGrLxo68SQKBgAlGoWF3aG0c/MtDk51JZI43U+lyLs++ua5SMlMAeaMFI7rucpvgxqrh7Qthqukvw7a7A22fXUBeFWM5B2KNnpD9c+hyAKAa6l+gzMQzKZpuRGsyS2BbEAAS8kO7M3Rm4o2MmFfstI2FKs8nibJ79HOvIONQ0n+T+K5Utu2/UAQRAoGAFB4fiIyQ0nYzCf18Z4Wvi/qeIOW+UoBonIN3y1h4wruBywINHxFMHx4aVImJ6R09hoJ9D3Mxli3xF/8JIjfTG5fBSGrGnuofl14d/XtRDXbT2uhVXrIkeLL/ojODwwEx0VhxIRUEjPTvEl6AFSRRcBp3KKzQ/cu7ENDY6GTlOUI=" # noqa - if headers: - cert = '-----BEGIN CERTIFICATE-----\n' + cert + '\n-----END CERTIFICATE-----' - url = reverse('api:setting_singleton_detail', kwargs={'category_slug': 'saml'}) - resp = patch( - url, - user=admin, - data={ - 'SOCIAL_AUTH_SAML_ENABLED_IDPS': { - "okta": { - "attr_last_name": "LastName", - "attr_username": "login", - "entity_id": "http://www.okta.com/abc123", - "attr_user_permanent_id": "login", - "url": "https://example.okta.com/app/abc123/xyz123/sso/saml", - "attr_email": "Email", - "x509cert": cert, - "attr_first_name": "FirstName", - } - } - }, - ) - assert resp.status_code == 200 - - -@pytest.mark.django_db -def test_github_settings(get, put, patch, delete, admin): - url = reverse('api:setting_singleton_detail', kwargs={'category_slug': 'github'}) - get(url, user=admin, expect=200) - delete(url, user=admin, expect=204) - response = get(url, user=admin, expect=200) - data = dict(response.data.items()) - put(url, user=admin, data=data, expect=200) - patch(url, user=admin, data={'SOCIAL_AUTH_GITHUB_KEY': '???'}, expect=200) - response = get(url, user=admin, expect=200) - assert response.data['SOCIAL_AUTH_GITHUB_KEY'] == '???' - data.pop('SOCIAL_AUTH_GITHUB_KEY') - put(url, user=admin, data=data, expect=200) - response = get(url, user=admin, expect=200) - assert response.data['SOCIAL_AUTH_GITHUB_KEY'] == '' - - -@pytest.mark.django_db -def test_github_enterprise_settings(get, put, patch, delete, admin): - url = reverse('api:setting_singleton_detail', kwargs={'category_slug': 'github-enterprise'}) - get(url, user=admin, expect=200) - delete(url, user=admin, expect=204) - response = get(url, user=admin, expect=200) - data = dict(response.data.items()) - put(url, user=admin, data=data, expect=200) - patch( - url, - user=admin, - data={ - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_URL': 'example.com', - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL': 'example.com', - }, - expect=200, - ) - response = get(url, user=admin, expect=200) - assert response.data['SOCIAL_AUTH_GITHUB_ENTERPRISE_URL'] == 'example.com' - assert response.data['SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL'] == 'example.com' - data.pop('SOCIAL_AUTH_GITHUB_ENTERPRISE_URL') - data.pop('SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL') - put(url, user=admin, data=data, expect=200) - response = get(url, user=admin, expect=200) - assert response.data['SOCIAL_AUTH_GITHUB_ENTERPRISE_URL'] == '' - assert response.data['SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL'] == '' diff --git a/awx/main/tests/functional/api/test_survey_spec.py b/awx/main/tests/functional/api/test_survey_spec.py index cbb22b3bdcce..ec20806f6bfd 100644 --- a/awx/main/tests/functional/api/test_survey_spec.py +++ b/awx/main/tests/functional/api/test_survey_spec.py @@ -2,12 +2,12 @@ import pytest import json +from ansible_base.lib.utils.models import get_type_for_model from awx.api.versioning import reverse from awx.main.models.jobs import JobTemplate, Job from awx.main.models.activity_stream import ActivityStream from awx.main.access import JobTemplateAccess -from awx.main.utils.common import get_type_for_model @pytest.fixture diff --git a/awx/main/tests/functional/api/test_unified_job_template.py b/awx/main/tests/functional/api/test_unified_job_template.py index 1a9adc396583..c293827e437b 100644 --- a/awx/main/tests/functional/api/test_unified_job_template.py +++ b/awx/main/tests/functional/api/test_unified_job_template.py @@ -18,7 +18,7 @@ class TestUnifiedOrganization: def data_for_model(self, model, orm_style=False): data = {'name': 'foo', 'organization': None} if model == 'JobTemplate': - proj = models.Project.objects.create(name="test-proj", playbook_files=['helloworld.yml']) + proj = models.Project.objects.create(name="test-proj", playbook_files=['helloworld.yml'], scm_type='git', scm_url='https://foo.invalid') if orm_style: data['project_id'] = proj.id else: diff --git a/awx/main/tests/functional/api/test_unified_jobs_stdout.py b/awx/main/tests/functional/api/test_unified_jobs_stdout.py index dad55c5ba061..3565a73d77a7 100644 --- a/awx/main/tests/functional/api/test_unified_jobs_stdout.py +++ b/awx/main/tests/functional/api/test_unified_jobs_stdout.py @@ -57,7 +57,7 @@ def _mk_inventory_update(created=None): [_mk_inventory_update, InventoryUpdateEvent, 'inventory_update', 'api:inventory_update_stdout'], ], ) -def test_text_stdout(sqlite_copy_expert, Parent, Child, relation, view, get, admin): +def test_text_stdout(sqlite_copy, Parent, Child, relation, view, get, admin): job = Parent() job.save() for i in range(3): @@ -79,11 +79,11 @@ def test_text_stdout(sqlite_copy_expert, Parent, Child, relation, view, get, adm ], ) @pytest.mark.parametrize('download', [True, False]) -def test_ansi_stdout_filtering(sqlite_copy_expert, Parent, Child, relation, view, download, get, admin): +def test_ansi_stdout_filtering(sqlite_copy, Parent, Child, relation, view, download, get, admin): job = Parent() job.save() for i in range(3): - Child(**{relation: job, 'stdout': '\x1B[0;36mTesting {}\x1B[0m\n'.format(i), 'start_line': i}).save() + Child(**{relation: job, 'stdout': '\x1b[0;36mTesting {}\x1b[0m\n'.format(i), 'start_line': i}).save() url = reverse(view, kwargs={'pk': job.pk}) # ansi codes in ?format=txt should get filtered @@ -96,7 +96,7 @@ def test_ansi_stdout_filtering(sqlite_copy_expert, Parent, Child, relation, view # ask for ansi and you'll get it fmt = "?format={}".format("ansi_download" if download else "ansi") response = get(url + fmt, user=admin, expect=200) - assert smart_str(response.content).splitlines() == ['\x1B[0;36mTesting %d\x1B[0m' % i for i in range(3)] + assert smart_str(response.content).splitlines() == ['\x1b[0;36mTesting %d\x1b[0m' % i for i in range(3)] has_download_header = response.has_header('Content-Disposition') assert has_download_header if download else not has_download_header @@ -111,11 +111,11 @@ def test_ansi_stdout_filtering(sqlite_copy_expert, Parent, Child, relation, view [_mk_inventory_update, InventoryUpdateEvent, 'inventory_update', 'api:inventory_update_stdout'], ], ) -def test_colorized_html_stdout(sqlite_copy_expert, Parent, Child, relation, view, get, admin): +def test_colorized_html_stdout(sqlite_copy, Parent, Child, relation, view, get, admin): job = Parent() job.save() for i in range(3): - Child(**{relation: job, 'stdout': '\x1B[0;36mTesting {}\x1B[0m\n'.format(i), 'start_line': i}).save() + Child(**{relation: job, 'stdout': '\x1b[0;36mTesting {}\x1b[0m\n'.format(i), 'start_line': i}).save() url = reverse(view, kwargs={'pk': job.pk}) + '?format=html' response = get(url, user=admin, expect=200) @@ -134,7 +134,7 @@ def test_colorized_html_stdout(sqlite_copy_expert, Parent, Child, relation, view [_mk_inventory_update, InventoryUpdateEvent, 'inventory_update', 'api:inventory_update_stdout'], ], ) -def test_stdout_line_range(sqlite_copy_expert, Parent, Child, relation, view, get, admin): +def test_stdout_line_range(sqlite_copy, Parent, Child, relation, view, get, admin): job = Parent() job.save() for i in range(20): @@ -146,7 +146,7 @@ def test_stdout_line_range(sqlite_copy_expert, Parent, Child, relation, view, ge @pytest.mark.django_db -def test_text_stdout_from_system_job_events(sqlite_copy_expert, get, admin): +def test_text_stdout_from_system_job_events(sqlite_copy, get, admin): created = tz_now() job = SystemJob(created=created) job.save() @@ -158,7 +158,7 @@ def test_text_stdout_from_system_job_events(sqlite_copy_expert, get, admin): @pytest.mark.django_db -def test_text_stdout_with_max_stdout(sqlite_copy_expert, get, admin): +def test_text_stdout_with_max_stdout(sqlite_copy, get, admin): created = tz_now() job = SystemJob(created=created) job.save() @@ -185,7 +185,7 @@ def test_text_stdout_with_max_stdout(sqlite_copy_expert, get, admin): ) @pytest.mark.parametrize('fmt', ['txt', 'ansi']) @mock.patch('awx.main.redact.UriCleaner.SENSITIVE_URI_PATTERN', mock.Mock(**{'search.return_value': None})) # really slow for large strings -def test_max_bytes_display(sqlite_copy_expert, Parent, Child, relation, view, fmt, get, admin): +def test_max_bytes_display(sqlite_copy, Parent, Child, relation, view, fmt, get, admin): created = tz_now() job = Parent(created=created) job.save() @@ -255,7 +255,7 @@ def test_legacy_result_stdout_with_max_bytes(Cls, view, fmt, get, admin): ], ) @pytest.mark.parametrize('fmt', ['txt', 'ansi', 'txt_download', 'ansi_download']) -def test_text_with_unicode_stdout(sqlite_copy_expert, Parent, Child, relation, view, get, admin, fmt): +def test_text_with_unicode_stdout(sqlite_copy, Parent, Child, relation, view, get, admin, fmt): job = Parent() job.save() for i in range(3): @@ -267,7 +267,7 @@ def test_text_with_unicode_stdout(sqlite_copy_expert, Parent, Child, relation, v @pytest.mark.django_db -def test_unicode_with_base64_ansi(sqlite_copy_expert, get, admin): +def test_unicode_with_base64_ansi(sqlite_copy, get, admin): created = tz_now() job = Job(created=created) job.save() diff --git a/awx/main/tests/functional/api/test_unified_jobs_view.py b/awx/main/tests/functional/api/test_unified_jobs_view.py index a8c7b53461e8..9a0955ba8012 100644 --- a/awx/main/tests/functional/api/test_unified_jobs_view.py +++ b/awx/main/tests/functional/api/test_unified_jobs_view.py @@ -7,7 +7,6 @@ from awx.main.tests.URI import URI from awx.main.constants import ACTIVE_STATES - TEST_STATES = list(ACTIVE_STATES) TEST_STATES.remove('new') diff --git a/awx/main/tests/functional/api/test_user.py b/awx/main/tests/functional/api/test_user.py index c19192c90caa..366f6f943c8d 100644 --- a/awx/main/tests/functional/api/test_user.py +++ b/awx/main/tests/functional/api/test_user.py @@ -1,14 +1,13 @@ -from datetime import date from unittest import mock import pytest from django.contrib.sessions.middleware import SessionMiddleware +from django.test.utils import override_settings from awx.main.models import User from awx.api.versioning import reverse - # # user creation # @@ -24,6 +23,175 @@ def test_user_create(post, admin): assert not response.data['is_system_auditor'] +# Disable local password checks to ensure that any ValidationError originates from the Django validators. +@override_settings( + LOCAL_PASSWORD_MIN_LENGTH=1, + LOCAL_PASSWORD_MIN_DIGITS=0, + LOCAL_PASSWORD_MIN_UPPER=0, + LOCAL_PASSWORD_MIN_SPECIAL=0, +) +@pytest.mark.django_db +def test_user_create_with_django_password_validation_basic(post, admin): + """Test if the Django password validators are applied correctly.""" + with override_settings( + AUTH_PASSWORD_VALIDATORS=[ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + 'OPTIONS': { + 'min_length': 3, + }, + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, + ], + ): + # This user should fail the UserAttrSimilarity, MinLength and CommonPassword validators. + user_attrs = ( + { + "password": "Password", # NOSONAR + "username": "Password", + "is_superuser": False, + }, + ) + print(f"Create user with invalid password {user_attrs=}") + response = post(reverse('api:user_list'), user_attrs, admin, middleware=SessionMiddleware(mock.Mock())) + assert response.status_code == 400 + # This user should pass all Django validators. + user_attrs = { + "password": "r$TyKiOCb#ED", # NOSONAR + "username": "TestUser", + "is_superuser": False, + } + print(f"Create user with valid password {user_attrs=}") + response = post(reverse('api:user_list'), user_attrs, admin, middleware=SessionMiddleware(mock.Mock())) + assert response.status_code == 201 + + +@pytest.mark.parametrize( + "user_attrs,validators,expected_status_code", + [ + # Test password similarity with username. + ( + {"password": "TestUser1", "username": "TestUser1", "is_superuser": False}, # NOSONAR + [ + {'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'}, + ], + 400, + ), + ( + {"password": "abc", "username": "TestUser1", "is_superuser": False}, # NOSONAR + [ + {'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'}, + ], + 201, + ), + # Test password min length criterion. + ( + {"password": "TooShort", "username": "TestUser1", "is_superuser": False}, # NOSONAR + [ + {'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 'OPTIONS': {'min_length': 9}}, + ], + 400, + ), + ( + {"password": "LongEnough", "username": "TestUser1", "is_superuser": False}, # NOSONAR + [ + {'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 'OPTIONS': {'min_length': 9}}, + ], + 201, + ), + # Test password is too common criterion. + ( + {"password": "Password", "username": "TestUser1", "is_superuser": False}, # NOSONAR + [ + {'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'}, + ], + 400, + ), + ( + {"password": "aEArV$5Vkdw", "username": "TestUser1", "is_superuser": False}, # NOSONAR + [ + {'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'}, + ], + 201, + ), + # Test if password is only numeric. + ( + {"password": "1234567890", "username": "TestUser1", "is_superuser": False}, # NOSONAR + [ + {'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'}, + ], + 400, + ), + ( + {"password": "abc4567890", "username": "TestUser1", "is_superuser": False}, # NOSONAR + [ + {'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'}, + ], + 201, + ), + ], +) +# Disable local password checks to ensure that any ValidationError originates from the Django validators. +@override_settings( + LOCAL_PASSWORD_MIN_LENGTH=1, + LOCAL_PASSWORD_MIN_DIGITS=0, + LOCAL_PASSWORD_MIN_UPPER=0, + LOCAL_PASSWORD_MIN_SPECIAL=0, +) +@pytest.mark.django_db +def test_user_create_with_django_password_validation_ext(post, delete, admin, user_attrs, validators, expected_status_code): + """Test the functionality of the single Django password validators.""" + # + default_parameters = { + # Default values for input parameters which are None. + "user_attrs": { + "password": "r$TyKiOCb#ED", # NOSONAR + "username": "DefaultUser", + "is_superuser": False, + }, + "validators": [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + 'OPTIONS': { + 'min_length': 8, + }, + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, + ], + } + user_attrs = user_attrs if user_attrs is not None else default_parameters["user_attrs"] + validators = validators if validators is not None else default_parameters["validators"] + with override_settings(AUTH_PASSWORD_VALIDATORS=validators): + response = post(reverse('api:user_list'), user_attrs, admin, middleware=SessionMiddleware(mock.Mock())) + assert response.status_code == expected_status_code + # Delete user if it was created succesfully. + if response.status_code == 201: + response = delete(reverse('api:user_detail', kwargs={'pk': response.data['id']}), admin, middleware=SessionMiddleware(mock.Mock())) + assert response.status_code == 204 + else: + # Catch the unexpected behavior that sometimes the user is written + # into the database before the validation fails. This actually can + # happen if UserSerializer.validate instantiates User(**attrs)! + username = user_attrs['username'] + assert not User.objects.filter(username=username) + + @pytest.mark.django_db def test_fail_double_create_user(post, admin): response = post(reverse('api:user_list'), EXAMPLE_USER_DATA, admin, middleware=SessionMiddleware(mock.Mock())) @@ -33,6 +201,31 @@ def test_fail_double_create_user(post, admin): assert response.status_code == 400 +@pytest.mark.django_db +def test_creating_user_retains_session(post, admin): + ''' + Creating a new user should not refresh a new session id for the current user. + ''' + with mock.patch('awx.api.serializers.update_session_auth_hash') as update_session_auth_hash: + response = post(reverse('api:user_list'), EXAMPLE_USER_DATA, admin) + assert response.status_code == 201 + assert not update_session_auth_hash.called + + +@pytest.mark.django_db +def test_updating_own_password_refreshes_session(patch, admin): + ''' + Updating your own password should refresh the session id. + ''' + with mock.patch('awx.api.serializers.update_session_auth_hash') as update_session_auth_hash: + # Attention: If the Django password validator `CommonPasswordValidator` + # is active, this test case will fail because this validator raises on + # password 'newpassword'. Consider changing the hard-coded password to + # something uncommon. + patch(reverse('api:user_detail', kwargs={'pk': admin.pk}), {'password': 'newpassword'}, admin, middleware=SessionMiddleware(mock.Mock())) + assert update_session_auth_hash.called + + @pytest.mark.django_db def test_create_delete_create_user(post, delete, admin): response = post(reverse('api:user_list'), EXAMPLE_USER_DATA, admin, middleware=SessionMiddleware(mock.Mock())) @@ -59,7 +252,23 @@ def test_user_verify_attribute_created(admin, get): resp = get(reverse('api:user_detail', kwargs={'pk': admin.pk}), admin) assert resp.data['created'] == admin.date_joined - past = date(2020, 1, 1).isoformat() + past = "2020-01-01T00:00:00Z" for op, count in (('gt', 1), ('lt', 0)): resp = get(reverse('api:user_list') + f'?created__{op}={past}', admin) assert resp.data['count'] == count + + +@pytest.mark.django_db +def test_org_not_shown_in_admin_user_sublists(admin_user, get, organization): + for view_name in ('user_admin_of_organizations_list', 'user_organizations_list'): + url = reverse(f'api:{view_name}', kwargs={'pk': admin_user.pk}) + r = get(url, user=admin_user, expect=200) + assert organization.pk not in [org['id'] for org in r.data['results']] + + +@pytest.mark.django_db +def test_admin_user_not_shown_in_org_users(admin_user, get, organization): + for view_name in ('organization_users_list', 'organization_admins_list'): + url = reverse(f'api:{view_name}', kwargs={'pk': organization.pk}) + r = get(url, user=admin_user, expect=200) + assert admin_user.pk not in [u['id'] for u in r.data['results']] diff --git a/awx/main/tests/functional/api/test_workflow_job.py b/awx/main/tests/functional/api/test_workflow_job.py new file mode 100644 index 000000000000..36553258dbb4 --- /dev/null +++ b/awx/main/tests/functional/api/test_workflow_job.py @@ -0,0 +1,54 @@ +import pytest + + +from awx.api.versioning import reverse + + +@pytest.mark.django_db +@pytest.mark.parametrize( + "is_admin, status", + [ + [True, 201], + [False, 403], + ], # if they're a WFJ admin, they get a 201 # if they're not a WFJ *nor* org admin, they get a 403 +) +def test_workflow_job_relaunch(workflow_job, post, admin_user, alice, is_admin, status): + url = reverse("api:workflow_job_relaunch", kwargs={'pk': workflow_job.pk}) + if is_admin: + post(url, user=admin_user, expect=status) + else: + post(url, user=alice, expect=status) + + +@pytest.mark.django_db +def test_workflow_job_relaunch_failure(workflow_job, post, admin_user): + workflow_job.is_sliced_job = True + workflow_job.job_template = None + workflow_job.save() + url = reverse("api:workflow_job_relaunch", kwargs={'pk': workflow_job.pk}) + post(url, user=admin_user, expect=400) + + +@pytest.mark.django_db +def test_workflow_job_relaunch_not_inventory_failure(workflow_job, post, admin_user): + workflow_job.is_sliced_job = True + workflow_job.inventory = None + workflow_job.save() + url = reverse("api:workflow_job_relaunch", kwargs={'pk': workflow_job.pk}) + post(url, user=admin_user, expect=400) + + +@pytest.mark.django_db +@pytest.mark.parametrize( + "is_admin, status", + [ + [True, 202], + [False, 403], + ], # if they're a WFJ admin, they get a 202 # if they're not a WFJ *nor* org admin, they get a 403 +) +def test_workflow_job_cancel(workflow_job, post, admin_user, alice, is_admin, status): + url = reverse("api:workflow_job_cancel", kwargs={'pk': workflow_job.pk}) + if is_admin: + post(url, user=admin_user, expect=status) + else: + post(url, user=alice, expect=status) diff --git a/awx/main/tests/functional/commands/test_callback_receiver.py b/awx/main/tests/functional/commands/test_callback_receiver.py index 7b9346fe73e3..145c48d605bf 100644 --- a/awx/main/tests/functional/commands/test_callback_receiver.py +++ b/awx/main/tests/functional/commands/test_callback_receiver.py @@ -34,40 +34,18 @@ def test_wrapup_does_send_notifications(mocker): mock.assert_called_once_with('succeeded') -class FakeRedis: - def keys(self, *args, **kwargs): - return [] - - def set(self): - pass - - def get(self): - return None - - @classmethod - def from_url(cls, *args, **kwargs): - return cls() - - def pipeline(self): - return self - - class TestCallbackBrokerWorker(TransactionTestCase): @pytest.fixture(autouse=True) - def turn_off_websockets(self): + def turn_off_websockets_and_redis(self, fake_redis): with mock.patch('awx.main.dispatch.worker.callback.emit_event_detail', lambda *a, **kw: None): yield - def get_worker(self): - with mock.patch('redis.Redis', new=FakeRedis): # turn off redis stuff - return CallbackBrokerWorker() - def event_create_kwargs(self): inventory_update = InventoryUpdate.objects.create(source='file', inventory_source=InventorySource.objects.create(source='file')) return dict(inventory_update=inventory_update, created=inventory_update.created) def test_flush_with_valid_event(self): - worker = self.get_worker() + worker = CallbackBrokerWorker() events = [InventoryUpdateEvent(uuid=str(uuid4()), **self.event_create_kwargs())] worker.buff = {InventoryUpdateEvent: events} worker.flush() @@ -75,7 +53,7 @@ def test_flush_with_valid_event(self): assert InventoryUpdateEvent.objects.filter(uuid=events[0].uuid).count() == 1 def test_flush_with_invalid_event(self): - worker = self.get_worker() + worker = CallbackBrokerWorker() kwargs = self.event_create_kwargs() events = [ InventoryUpdateEvent(uuid=str(uuid4()), stdout='good1', **kwargs), @@ -90,7 +68,7 @@ def test_flush_with_invalid_event(self): assert worker.buff == {InventoryUpdateEvent: [events[1]]} def test_duplicate_key_not_saved_twice(self): - worker = self.get_worker() + worker = CallbackBrokerWorker() events = [InventoryUpdateEvent(uuid=str(uuid4()), **self.event_create_kwargs())] worker.buff = {InventoryUpdateEvent: events.copy()} worker.flush() @@ -104,7 +82,7 @@ def test_duplicate_key_not_saved_twice(self): assert worker.buff.get(InventoryUpdateEvent, []) == [] def test_give_up_on_bad_event(self): - worker = self.get_worker() + worker = CallbackBrokerWorker() events = [InventoryUpdateEvent(uuid=str(uuid4()), counter=-2, **self.event_create_kwargs())] worker.buff = {InventoryUpdateEvent: events.copy()} @@ -117,7 +95,7 @@ def test_give_up_on_bad_event(self): assert InventoryUpdateEvent.objects.filter(uuid=events[0].uuid).count() == 0 # sanity def test_flush_with_empty_buffer(self): - worker = self.get_worker() + worker = CallbackBrokerWorker() worker.buff = {InventoryUpdateEvent: []} with mock.patch.object(InventoryUpdateEvent.objects, 'bulk_create') as flush_mock: worker.flush() @@ -127,7 +105,7 @@ def test_postgres_invalid_NUL_char(self): # In postgres, text fields reject NUL character, 0x00 # tests use sqlite3 which will not raise an error # but we can still test that it is sanitized before saving - worker = self.get_worker() + worker = CallbackBrokerWorker() kwargs = self.event_create_kwargs() events = [InventoryUpdateEvent(uuid=str(uuid4()), stdout="\x00", **kwargs)] assert "\x00" in events[0].stdout # sanity diff --git a/awx/main/tests/functional/commands/test_cleanup_host_metrics.py b/awx/main/tests/functional/commands/test_cleanup_host_metrics.py new file mode 100644 index 000000000000..ac6d0bde3243 --- /dev/null +++ b/awx/main/tests/functional/commands/test_cleanup_host_metrics.py @@ -0,0 +1,78 @@ +import pytest + +from awx.main.tasks.host_metrics import HostMetricTask +from awx.main.models.inventory import HostMetric +from awx.main.tests.factories.fixtures import mk_host_metric +from dateutil.relativedelta import relativedelta +from django.conf import settings +from django.utils import timezone + + +@pytest.mark.django_db +def test_no_host_metrics(): + """No-crash test""" + assert HostMetric.objects.count() == 0 + HostMetricTask().cleanup(soft_threshold=0, hard_threshold=0) + HostMetricTask().cleanup(soft_threshold=24, hard_threshold=42) + assert HostMetric.objects.count() == 0 + + +@pytest.mark.django_db +def test_delete_exception(): + """Crash test""" + with pytest.raises(ValueError): + HostMetricTask().soft_cleanup("") + with pytest.raises(TypeError): + HostMetricTask().hard_cleanup(set()) + + +@pytest.mark.django_db +@pytest.mark.parametrize('threshold', [settings.CLEANUP_HOST_METRICS_SOFT_THRESHOLD, 20]) +def test_soft_delete(threshold): + """Metrics with last_automation < threshold are updated to deleted=True""" + mk_host_metric('host_1', first_automation=ago(months=1), last_automation=ago(months=1), deleted=False) + mk_host_metric('host_2', first_automation=ago(months=1), last_automation=ago(months=1), deleted=True) + mk_host_metric('host_3', first_automation=ago(months=1), last_automation=ago(months=threshold, hours=-1), deleted=False) + mk_host_metric('host_4', first_automation=ago(months=1), last_automation=ago(months=threshold, hours=-1), deleted=True) + mk_host_metric('host_5', first_automation=ago(months=1), last_automation=ago(months=threshold, hours=1), deleted=False) + mk_host_metric('host_6', first_automation=ago(months=1), last_automation=ago(months=threshold, hours=1), deleted=True) + mk_host_metric('host_7', first_automation=ago(months=1), last_automation=ago(months=42), deleted=False) + mk_host_metric('host_8', first_automation=ago(months=1), last_automation=ago(months=42), deleted=True) + + assert HostMetric.objects.count() == 8 + assert HostMetric.active_objects.count() == 4 + + for i in range(2): + HostMetricTask().cleanup(soft_threshold=threshold) + assert HostMetric.objects.count() == 8 + + hostnames = set(HostMetric.objects.filter(deleted=False).order_by('hostname').values_list('hostname', flat=True)) + assert hostnames == {'host_1', 'host_3'} + + +@pytest.mark.django_db +@pytest.mark.parametrize('threshold', [settings.CLEANUP_HOST_METRICS_HARD_THRESHOLD, 20]) +def test_hard_delete(threshold): + """Metrics with last_deleted < threshold and deleted=True are deleted from the db""" + mk_host_metric('host_1', first_automation=ago(months=1), last_deleted=ago(months=1), deleted=False) + mk_host_metric('host_2', first_automation=ago(months=1), last_deleted=ago(months=1), deleted=True) + mk_host_metric('host_3', first_automation=ago(months=1), last_deleted=ago(months=threshold, hours=-1), deleted=False) + mk_host_metric('host_4', first_automation=ago(months=1), last_deleted=ago(months=threshold, hours=-1), deleted=True) + mk_host_metric('host_5', first_automation=ago(months=1), last_deleted=ago(months=threshold, hours=1), deleted=False) + mk_host_metric('host_6', first_automation=ago(months=1), last_deleted=ago(months=threshold, hours=1), deleted=True) + mk_host_metric('host_7', first_automation=ago(months=1), last_deleted=ago(months=42), deleted=False) + mk_host_metric('host_8', first_automation=ago(months=1), last_deleted=ago(months=42), deleted=True) + + assert HostMetric.objects.count() == 8 + assert HostMetric.active_objects.count() == 4 + + for i in range(2): + HostMetricTask().cleanup(hard_threshold=threshold) + assert HostMetric.objects.count() == 6 + + hostnames = set(HostMetric.objects.order_by('hostname').values_list('hostname', flat=True)) + assert hostnames == {'host_1', 'host_2', 'host_3', 'host_4', 'host_5', 'host_7'} + + +def ago(months=0, hours=0): + return timezone.now() - relativedelta(months=months, hours=hours) diff --git a/awx/main/tests/functional/commands/test_commands.py b/awx/main/tests/functional/commands/test_commands.py index 69f584c2871b..f62dac02064d 100644 --- a/awx/main/tests/functional/commands/test_commands.py +++ b/awx/main/tests/functional/commands/test_commands.py @@ -43,9 +43,9 @@ def run_command(name, *args, **options): ], ) def test_update_password_command(mocker, username, password, expected, changed): - with mocker.patch.object(UpdatePassword, 'update_password', return_value=changed): - result, stdout, stderr = run_command('update_password', username=username, password=password) - if result is None: - assert stdout == expected - else: - assert str(result) == expected + mocker.patch.object(UpdatePassword, 'update_password', return_value=changed) + result, stdout, stderr = run_command('update_password', username=username, password=password) + if result is None: + assert stdout == expected + else: + assert str(result) == expected diff --git a/awx/main/tests/functional/commands/test_host_metric_summary_monthly.py b/awx/main/tests/functional/commands/test_host_metric_summary_monthly.py new file mode 100644 index 000000000000..525fdd789ff0 --- /dev/null +++ b/awx/main/tests/functional/commands/test_host_metric_summary_monthly.py @@ -0,0 +1,382 @@ +import pytest +import datetime +from dateutil.relativedelta import relativedelta +from django.conf import settings +from django.utils import timezone + + +from awx.main.management.commands.host_metric_summary_monthly import Command +from awx.main.models.inventory import HostMetric, HostMetricSummaryMonthly +from awx.main.tests.factories.fixtures import mk_host_metric, mk_host_metric_summary + + +@pytest.fixture +def threshold(): + return int(getattr(settings, 'CLEANUP_HOST_METRICS_HARD_THRESHOLD', 36)) + + +@pytest.mark.django_db +@pytest.mark.parametrize("metrics_cnt", [0, 1, 2, 3]) +@pytest.mark.parametrize("mode", ["old_data", "actual_data", "all_data"]) +def test_summaries_counts(threshold, metrics_cnt, mode): + assert HostMetricSummaryMonthly.objects.count() == 0 + + for idx in range(metrics_cnt): + if mode == "old_data" or mode == "all_data": + mk_host_metric(None, months_ago(threshold + idx, "dt")) + elif mode == "actual_data" or mode == "all_data": + mk_host_metric(None, (months_ago(threshold - idx, "dt"))) + + Command().handle() + + # Number of records is equal to host metrics' hard cleanup months + assert HostMetricSummaryMonthly.objects.count() == threshold + + # Records start with date in the month following to the threshold month + date = months_ago(threshold - 1) + for metric in list(HostMetricSummaryMonthly.objects.order_by('date').all()): + assert metric.date == date + date += relativedelta(months=1) + + # Older record are untouched + mk_host_metric_summary(date=months_ago(threshold + 10)) + Command().handle() + + assert HostMetricSummaryMonthly.objects.count() == threshold + 1 + + +@pytest.mark.django_db +@pytest.mark.parametrize("mode", ["old_data", "actual_data", "all_data"]) +def test_summary_values(threshold, mode): + tester = {"old_data": MetricsTesterOldData(threshold), "actual_data": MetricsTesterActualData(threshold), "all_data": MetricsTesterCombinedData(threshold)}[ + mode + ] + + for iteration in ["create_metrics", "add_old_summaries", "change_metrics", "delete_metrics", "add_metrics"]: + getattr(tester, iteration)() # call method by string + + # Operation is idempotent, repeat twice + for _ in range(2): + Command().handle() + # call assert method by string + getattr(tester, f"assert_{iteration}")() + + +class MetricsTester: + def __init__(self, threshold, ignore_asserts=False): + self.threshold = threshold + self.expected_summaries = {} + self.ignore_asserts = ignore_asserts + + def add_old_summaries(self): + """These records don't correspond with Host metrics""" + mk_host_metric_summary(self.below(4), license_consumed=100, hosts_added=10, hosts_deleted=5) + mk_host_metric_summary(self.below(3), license_consumed=105, hosts_added=20, hosts_deleted=10) + mk_host_metric_summary(self.below(2), license_consumed=115, hosts_added=60, hosts_deleted=75) + + def assert_add_old_summaries(self): + """Old summary records should be untouched""" + self.expected_summaries[self.below(4)] = {"date": self.below(4), "license_consumed": 100, "hosts_added": 10, "hosts_deleted": 5} + self.expected_summaries[self.below(3)] = {"date": self.below(3), "license_consumed": 105, "hosts_added": 20, "hosts_deleted": 10} + self.expected_summaries[self.below(2)] = {"date": self.below(2), "license_consumed": 115, "hosts_added": 60, "hosts_deleted": 75} + + self.assert_host_metric_summaries() + + def assert_host_metric_summaries(self): + """Ignore asserts when old/actual test object is used only as a helper for Combined test""" + if self.ignore_asserts: + return True + + for summary in list(HostMetricSummaryMonthly.objects.order_by('date').all()): + assert self.expected_summaries.get(summary.date, None) is not None + + assert self.expected_summaries[summary.date] == { + "date": summary.date, + "license_consumed": summary.license_consumed, + "hosts_added": summary.hosts_added, + "hosts_deleted": summary.hosts_deleted, + } + + def below(self, months, fmt="date"): + """months below threshold, returns first date of that month""" + date = months_ago(self.threshold + months) + if fmt == "dt": + return timezone.make_aware(datetime.datetime.combine(date, datetime.datetime.min.time())) + else: + return date + + def above(self, months, fmt="date"): + """months above threshold, returns first date of that month""" + date = months_ago(self.threshold - months) + if fmt == "dt": + return timezone.make_aware(datetime.datetime.combine(date, datetime.datetime.min.time())) + else: + return date + + +class MetricsTesterOldData(MetricsTester): + def create_metrics(self): + """Creates 7 host metrics older than delete threshold""" + mk_host_metric("host_1", first_automation=self.below(3, "dt")) + mk_host_metric("host_2", first_automation=self.below(2, "dt")) + mk_host_metric("host_3", first_automation=self.below(2, "dt"), last_deleted=self.above(2, "dt"), deleted=False) + mk_host_metric("host_4", first_automation=self.below(2, "dt"), last_deleted=self.above(2, "dt"), deleted=True) + mk_host_metric("host_5", first_automation=self.below(2, "dt"), last_deleted=self.below(2, "dt"), deleted=True) + mk_host_metric("host_6", first_automation=self.below(1, "dt"), last_deleted=self.below(1, "dt"), deleted=False) + mk_host_metric("host_7", first_automation=self.below(1, "dt")) + + def assert_create_metrics(self): + """ + Month 1 is computed from older host metrics, + Month 2 has deletion (host_4) + Other months are unchanged (same as month 2) + """ + self.expected_summaries = { + self.above(1): {"date": self.above(1), "license_consumed": 6, "hosts_added": 0, "hosts_deleted": 0}, + self.above(2): {"date": self.above(2), "license_consumed": 5, "hosts_added": 0, "hosts_deleted": 1}, + } + # no change in months 3+ + idx = 3 + month = self.above(idx) + while month <= beginning_of_the_month(): + self.expected_summaries[self.above(idx)] = {"date": self.above(idx), "license_consumed": 5, "hosts_added": 0, "hosts_deleted": 0} + month += relativedelta(months=1) + idx += 1 + + self.assert_host_metric_summaries() + + def add_old_summaries(self): + super().add_old_summaries() + + def assert_add_old_summaries(self): + super().assert_add_old_summaries() + + @staticmethod + def change_metrics(): + """Hosts 1,2 soft deleted, host_4 automated again (undeleted)""" + HostMetric.objects.filter(hostname='host_1').update(last_deleted=beginning_of_the_month("dt"), deleted=True) + HostMetric.objects.filter(hostname='host_2').update(last_deleted=timezone.now(), deleted=True) + HostMetric.objects.filter(hostname='host_4').update(deleted=False) + + def assert_change_metrics(self): + """ + Summaries since month 2 were changed (host_4 restored == automated again) + Current month has 2 deletions (host_1, host_2) + """ + self.expected_summaries[self.above(2)] |= {'hosts_deleted': 0} + for idx in range(2, self.threshold): + self.expected_summaries[self.above(idx)] |= {'license_consumed': 6} + self.expected_summaries[beginning_of_the_month()] |= {'license_consumed': 4, 'hosts_deleted': 2} + + self.assert_host_metric_summaries() + + @staticmethod + def delete_metrics(): + """Deletes metric deleted before the threshold""" + HostMetric.objects.filter(hostname='host_5').delete() + + def assert_delete_metrics(self): + """No change""" + self.assert_host_metric_summaries() + + @staticmethod + def add_metrics(): + """Adds new metrics""" + mk_host_metric("host_24", first_automation=beginning_of_the_month("dt")) + mk_host_metric("host_25", first_automation=beginning_of_the_month("dt")) # timezone.now()) + + def assert_add_metrics(self): + """Summary in current month is updated""" + self.expected_summaries[beginning_of_the_month()]['license_consumed'] = 6 + self.expected_summaries[beginning_of_the_month()]['hosts_added'] = 2 + + self.assert_host_metric_summaries() + + +class MetricsTesterActualData(MetricsTester): + def create_metrics(self): + """Creates 16 host metrics newer than delete threshold""" + mk_host_metric("host_8", first_automation=self.above(1, "dt")) + mk_host_metric("host_9", first_automation=self.above(1, "dt"), last_deleted=self.above(1, "dt")) + mk_host_metric("host_10", first_automation=self.above(1, "dt"), last_deleted=self.above(1, "dt"), deleted=True) + mk_host_metric("host_11", first_automation=self.above(1, "dt"), last_deleted=self.above(2, "dt")) + mk_host_metric("host_12", first_automation=self.above(1, "dt"), last_deleted=self.above(2, "dt"), deleted=True) + mk_host_metric("host_13", first_automation=self.above(2, "dt")) + mk_host_metric("host_14", first_automation=self.above(2, "dt"), last_deleted=self.above(2, "dt")) + mk_host_metric("host_15", first_automation=self.above(2, "dt"), last_deleted=self.above(2, "dt"), deleted=True) + mk_host_metric("host_16", first_automation=self.above(2, "dt"), last_deleted=self.above(3, "dt")) + mk_host_metric("host_17", first_automation=self.above(2, "dt"), last_deleted=self.above(3, "dt"), deleted=True) + mk_host_metric("host_18", first_automation=self.above(4, "dt")) + # next one shouldn't happen in real (deleted=True, last_deleted = NULL) + mk_host_metric("host_19", first_automation=self.above(4, "dt"), deleted=True) + mk_host_metric("host_20", first_automation=self.above(4, "dt"), last_deleted=self.above(4, "dt")) + mk_host_metric("host_21", first_automation=self.above(4, "dt"), last_deleted=self.above(4, "dt"), deleted=True) + mk_host_metric("host_22", first_automation=self.above(4, "dt"), last_deleted=self.above(5, "dt")) + mk_host_metric("host_23", first_automation=self.above(4, "dt"), last_deleted=self.above(5, "dt"), deleted=True) + + def assert_create_metrics(self): + self.expected_summaries = { + self.above(1): {"date": self.above(1), "license_consumed": 4, "hosts_added": 5, "hosts_deleted": 1}, + self.above(2): {"date": self.above(2), "license_consumed": 7, "hosts_added": 5, "hosts_deleted": 2}, + self.above(3): {"date": self.above(3), "license_consumed": 6, "hosts_added": 0, "hosts_deleted": 1}, + self.above(4): {"date": self.above(4), "license_consumed": 11, "hosts_added": 6, "hosts_deleted": 1}, + self.above(5): {"date": self.above(5), "license_consumed": 10, "hosts_added": 0, "hosts_deleted": 1}, + } + # no change in months 6+ + idx = 6 + month = self.above(idx) + while month <= beginning_of_the_month(): + self.expected_summaries[self.above(idx)] = {"date": self.above(idx), "license_consumed": 10, "hosts_added": 0, "hosts_deleted": 0} + month += relativedelta(months=1) + idx += 1 + + self.assert_host_metric_summaries() + + def add_old_summaries(self): + super().add_old_summaries() + + def assert_add_old_summaries(self): + super().assert_add_old_summaries() + + @staticmethod + def change_metrics(): + """ + - Hosts 12, 19, 21 were automated again (undeleted) + - Host 16 was soft deleted + - Host 17 was undeleted and soft deleted again + """ + HostMetric.objects.filter(hostname='host_12').update(deleted=False) + HostMetric.objects.filter(hostname='host_16').update(last_deleted=timezone.now(), deleted=True) + HostMetric.objects.filter(hostname='host_17').update(last_deleted=beginning_of_the_month("dt"), deleted=True) + HostMetric.objects.filter(hostname='host_19').update(deleted=False) + HostMetric.objects.filter(hostname='host_21').update(deleted=False) + + def assert_change_metrics(self): + """ + Summaries since month 2 were changed + Current month has 2 deletions (host_16, host_17) + """ + self.expected_summaries[self.above(2)] |= {'license_consumed': 8, 'hosts_deleted': 1} + self.expected_summaries[self.above(3)] |= {'license_consumed': 8, 'hosts_deleted': 0} + self.expected_summaries[self.above(4)] |= {'license_consumed': 14, 'hosts_deleted': 0} + + # month 5 had hosts_deleted 1 => license_consumed == 14 - 1 + for idx in range(5, self.threshold): + self.expected_summaries[self.above(idx)] |= {'license_consumed': 13} + self.expected_summaries[beginning_of_the_month()] |= {'license_consumed': 11, 'hosts_deleted': 2} + + self.assert_host_metric_summaries() + + def delete_metrics(self): + """Hard cleanup can't delete metrics newer than threshold. No change""" + pass + + def assert_delete_metrics(self): + """No change""" + self.assert_host_metric_summaries() + + @staticmethod + def add_metrics(): + """Adds new metrics""" + mk_host_metric("host_26", first_automation=beginning_of_the_month("dt")) + mk_host_metric("host_27", first_automation=timezone.now()) + + def assert_add_metrics(self): + """ + Two metrics were deleted in current month by change_metrics() + Two metrics are added now + => license_consumed is equal to the previous month (13 - 2 + 2) + """ + self.expected_summaries[beginning_of_the_month()] |= {'license_consumed': 13, 'hosts_added': 2} + + self.assert_host_metric_summaries() + + +class MetricsTesterCombinedData(MetricsTester): + def __init__(self, threshold): + super().__init__(threshold) + self.old_data = MetricsTesterOldData(threshold, ignore_asserts=True) + self.actual_data = MetricsTesterActualData(threshold, ignore_asserts=True) + + def assert_host_metric_summaries(self): + self._combine_expected_summaries() + super().assert_host_metric_summaries() + + def create_metrics(self): + self.old_data.create_metrics() + self.actual_data.create_metrics() + + def assert_create_metrics(self): + self.old_data.assert_create_metrics() + self.actual_data.assert_create_metrics() + + self.assert_host_metric_summaries() + + def add_old_summaries(self): + super().add_old_summaries() + + def assert_add_old_summaries(self): + self.old_data.assert_add_old_summaries() + self.actual_data.assert_add_old_summaries() + + self.assert_host_metric_summaries() + + def change_metrics(self): + self.old_data.change_metrics() + self.actual_data.change_metrics() + + def assert_change_metrics(self): + self.old_data.assert_change_metrics() + self.actual_data.assert_change_metrics() + + self.assert_host_metric_summaries() + + def delete_metrics(self): + self.old_data.delete_metrics() + self.actual_data.delete_metrics() + + def assert_delete_metrics(self): + self.old_data.assert_delete_metrics() + self.actual_data.assert_delete_metrics() + + self.assert_host_metric_summaries() + + def add_metrics(self): + self.old_data.add_metrics() + self.actual_data.add_metrics() + + def assert_add_metrics(self): + self.old_data.assert_add_metrics() + self.actual_data.assert_add_metrics() + + self.assert_host_metric_summaries() + + def _combine_expected_summaries(self): + """ + Expected summaries are sum of expected values for tests with old and actual data + Except data older than hard delete threshold (these summaries are untouched by task => the same in all tests) + """ + for date, summary in self.old_data.expected_summaries.items(): + if date <= months_ago(self.threshold): + license_consumed = summary['license_consumed'] + hosts_added = summary['hosts_added'] + hosts_deleted = summary['hosts_deleted'] + else: + license_consumed = summary['license_consumed'] + self.actual_data.expected_summaries[date]['license_consumed'] + hosts_added = summary['hosts_added'] + self.actual_data.expected_summaries[date]['hosts_added'] + hosts_deleted = summary['hosts_deleted'] + self.actual_data.expected_summaries[date]['hosts_deleted'] + self.expected_summaries[date] = {'date': date, 'license_consumed': license_consumed, 'hosts_added': hosts_added, 'hosts_deleted': hosts_deleted} + + +def months_ago(num, fmt="date"): + if num is None: + return None + return beginning_of_the_month(fmt) - relativedelta(months=num) + + +def beginning_of_the_month(fmt="date"): + date = datetime.date.today().replace(day=1) + if fmt == "dt": + return timezone.make_aware(datetime.datetime.combine(date, datetime.datetime.min.time())) + else: + return date diff --git a/awx/main/tests/functional/commands/test_inventory_import.py b/awx/main/tests/functional/commands/test_inventory_import.py index 75a09fc47627..6860889bee2b 100644 --- a/awx/main/tests/functional/commands/test_inventory_import.py +++ b/awx/main/tests/functional/commands/test_inventory_import.py @@ -18,7 +18,6 @@ from awx.main.models import Inventory, Host, Group, InventorySource from awx.main.utils.mem_inventory import MemGroup - TEST_INVENTORY_CONTENT = { "_meta": {"hostvars": {}}, "all": {"children": ["others", "servers", "ungrouped"], "vars": {"vara": "A"}}, diff --git a/awx/main/tests/functional/commands/test_oauth2_token_create.py b/awx/main/tests/functional/commands/test_oauth2_token_create.py deleted file mode 100644 index 5c7a13813717..000000000000 --- a/awx/main/tests/functional/commands/test_oauth2_token_create.py +++ /dev/null @@ -1,44 +0,0 @@ -# Python -import pytest -import string -import random -from io import StringIO - -# Django -from django.contrib.auth.models import User -from django.core.management import call_command -from django.core.management.base import CommandError - -# AWX -from awx.main.models.oauth import OAuth2AccessToken - - -@pytest.mark.django_db -@pytest.mark.inventory_import -class TestOAuth2CreateCommand: - def test_no_user_option(self): - out = StringIO() - with pytest.raises(CommandError) as excinfo: - call_command('create_oauth2_token', stdout=out) - assert 'Username not supplied.' in str(excinfo.value) - out.close() - - def test_non_existing_user(self): - out = StringIO() - fake_username = '' - while fake_username == '' or User.objects.filter(username=fake_username).exists(): - fake_username = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6)) - arg = '--user=' + fake_username - with pytest.raises(CommandError) as excinfo: - call_command('create_oauth2_token', arg, stdout=out) - assert 'The user does not exist.' in str(excinfo.value) - out.close() - - def test_correct_user(self, alice): - out = StringIO() - arg = '--user=' + 'alice' - call_command('create_oauth2_token', arg, stdout=out) - generated_token = out.getvalue().strip() - assert OAuth2AccessToken.objects.filter(user=alice, token=generated_token).count() == 1 - assert OAuth2AccessToken.objects.get(user=alice, token=generated_token).scope == 'write' - out.close() diff --git a/awx/main/tests/functional/commands/test_oauth2_token_revoke.py b/awx/main/tests/functional/commands/test_oauth2_token_revoke.py deleted file mode 100644 index 69b25fd0a849..000000000000 --- a/awx/main/tests/functional/commands/test_oauth2_token_revoke.py +++ /dev/null @@ -1,62 +0,0 @@ -# Python -import datetime -import pytest -import string -import random -from io import StringIO - -# Django -from django.core.management import call_command -from django.core.management.base import CommandError - -# AWX -from awx.main.models import RefreshToken -from awx.main.models.oauth import OAuth2AccessToken -from awx.api.versioning import reverse - - -@pytest.mark.django_db -class TestOAuth2RevokeCommand: - def test_non_existing_user(self): - out = StringIO() - fake_username = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6)) - arg = '--user=' + fake_username - with pytest.raises(CommandError) as excinfo: - call_command('revoke_oauth2_tokens', arg, stdout=out) - assert 'A user with that username does not exist' in str(excinfo.value) - out.close() - - def test_revoke_all_access_tokens(self, post, admin, alice): - url = reverse('api:o_auth2_token_list') - for user in (admin, alice): - post(url, {'description': 'test token', 'scope': 'read'}, user) - assert OAuth2AccessToken.objects.count() == 2 - call_command('revoke_oauth2_tokens') - assert OAuth2AccessToken.objects.count() == 0 - - def test_revoke_access_token_for_user(self, post, admin, alice): - url = reverse('api:o_auth2_token_list') - post(url, {'description': 'test token', 'scope': 'read'}, alice) - assert OAuth2AccessToken.objects.count() == 1 - call_command('revoke_oauth2_tokens', '--user=admin') - assert OAuth2AccessToken.objects.count() == 1 - call_command('revoke_oauth2_tokens', '--user=alice') - assert OAuth2AccessToken.objects.count() == 0 - - def test_revoke_all_refresh_tokens(self, post, admin, oauth_application): - url = reverse('api:o_auth2_token_list') - post(url, {'description': 'test token for', 'scope': 'read', 'application': oauth_application.pk}, admin) - assert OAuth2AccessToken.objects.count() == 1 - assert RefreshToken.objects.count() == 1 - - call_command('revoke_oauth2_tokens') - assert OAuth2AccessToken.objects.count() == 0 - assert RefreshToken.objects.count() == 1 - for r in RefreshToken.objects.all(): - assert r.revoked is None - - call_command('revoke_oauth2_tokens', '--all') - assert RefreshToken.objects.count() == 1 - for r in RefreshToken.objects.all(): - assert r.revoked is not None - assert isinstance(r.revoked, datetime.datetime) diff --git a/awx/main/tests/functional/commands/test_secret_key_regeneration.py b/awx/main/tests/functional/commands/test_secret_key_regeneration.py index 808fefbdc997..05584e5101e7 100644 --- a/awx/main/tests/functional/commands/test_secret_key_regeneration.py +++ b/awx/main/tests/functional/commands/test_secret_key_regeneration.py @@ -12,7 +12,6 @@ from awx.main.management.commands import regenerate_secret_key from awx.main.utils.encryption import encrypt_field, decrypt_field, encrypt_value - PREFIX = '$encrypted$UTF8$AESCBC$' @@ -147,22 +146,6 @@ def test_survey_spec(self, inventory, project, survey_spec_factory, cls): with override_settings(SECRET_KEY=new_key): assert json.loads(new_job.decrypted_extra_vars())['secret_key'] == 'donttell' - def test_oauth2_application_client_secret(self, oauth_application): - # test basic decryption - secret = oauth_application.client_secret - assert len(secret) == 128 - - # re-key the client_secret - new_key = regenerate_secret_key.Command().handle() - - # verify that the old SECRET_KEY doesn't work - with pytest.raises(InvalidToken): - models.OAuth2Application.objects.get(pk=oauth_application.pk).client_secret - - # verify that the new SECRET_KEY *does* work - with override_settings(SECRET_KEY=new_key): - assert models.OAuth2Application.objects.get(pk=oauth_application.pk).client_secret == secret - def test_use_custom_key_with_tower_secret_key_env_var(self): custom_key = 'MXSq9uqcwezBOChl/UfmbW1k4op+bC+FQtwPqgJ1u9XV' os.environ['TOWER_SECRET_KEY'] = custom_key diff --git a/awx/main/tests/functional/conftest.py b/awx/main/tests/functional/conftest.py index 4f8b6bc83c5a..8f2186112090 100644 --- a/awx/main/tests/functional/conftest.py +++ b/awx/main/tests/functional/conftest.py @@ -1,22 +1,28 @@ +import logging + # Python import pytest from unittest import mock -import tempfile -import shutil import urllib.parse from unittest.mock import PropertyMock +import importlib # Django from django.urls import resolve from django.http import Http404 +from django.apps import apps as global_apps from django.core.handlers.exception import response_for_exception from django.contrib.auth.models import User from django.core.serializers.json import DjangoJSONEncoder from django.db.backends.sqlite3.base import SQLiteCursorWrapper +from django.db.models.signals import post_migrate + +from awx.main.migrations._dab_rbac import setup_managed_role_definitions + # AWX from awx.main.models.projects import Project -from awx.main.models.ha import Instance +from awx.main.models.ha import Instance, InstanceGroup from rest_framework.test import ( APIRequestFactory, @@ -30,7 +36,6 @@ Organization, Team, ) -from awx.main.models.rbac import Role from awx.main.models.notifications import NotificationTemplate, Notification from awx.main.models.events import ( JobEvent, @@ -41,17 +46,82 @@ ) from awx.main.models.workflow import WorkflowJobTemplate from awx.main.models.ad_hoc_commands import AdHocCommand -from awx.main.models.oauth import OAuth2Application as Application from awx.main.models.execution_environments import ExecutionEnvironment +from awx.main.utils import is_testing + +logger = logging.getLogger(__name__) __SWAGGER_REQUESTS__ = {} +# HACK: the dab_resource_registry app required ServiceID in migrations which checks do not run +dab_rr_initial = importlib.import_module('ansible_base.resource_registry.migrations.0001_initial') + + +def create_service_id(app_config, apps=global_apps, **kwargs): + try: + apps.get_model("dab_resource_registry", "ServiceID") + except LookupError: + logger.info('Looks like reverse migration, not creating resource registry ServiceID') + return + dab_rr_initial.create_service_id(apps, None) + + +if is_testing(): + post_migrate.connect(create_service_id) + + @pytest.fixture(scope="session") def swagger_autogen(requests=__SWAGGER_REQUESTS__): return requests +class FakeRedis: + def __init__(self, *args, **kwargs): + # Accept and ignore all arguments to match redis.Redis signature + pass + + def keys(self, *args, **kwargs): + return [] + + def set(self, *args, **kwargs): + pass + + def get(self, *args, **kwargs): + return None + + def rpush(self, *args, **kwargs): + return 1 + + def blpop(self, *args, **kwargs): + return None + + def delete(self, *args, **kwargs): + pass + + def llen(self, *args, **kwargs): + return 0 + + def scan_iter(self, *args, **kwargs): + return iter([]) + + @classmethod + def from_url(cls, *args, **kwargs): + return cls() + + def pipeline(self): + return self + + def ping(self): + return + + +@pytest.fixture +def fake_redis(): + with mock.patch('redis.Redis', new=FakeRedis): # turn off redis stuff + yield + + @pytest.fixture def user(): def u(name, is_superuser=False): @@ -80,6 +150,17 @@ def deploy_jobtemplate(project, inventory, credential): return jt +@pytest.fixture() +def execution_environment(): + return ExecutionEnvironment.objects.create(name="test-ee", description="test-ee", managed=True) + + +@pytest.fixture +def setup_managed_roles(): + "Run the migration script to pre-create managed role definitions" + setup_managed_role_definitions(global_apps, None) + + @pytest.fixture def team(organization): return organization.teams.create(name='test-team') @@ -92,20 +173,6 @@ def team_member(user, team): return ret -@pytest.fixture(scope="session", autouse=True) -def project_playbooks(): - """ - Return playbook_files as playbooks for manual projects when testing. - """ - - class PlaybooksMock(mock.PropertyMock): - def __get__(self, obj, obj_type): - return obj.playbook_files - - mocked = mock.patch.object(Project, 'playbooks', new_callable=PlaybooksMock) - mocked.start() - - @pytest.fixture def run_computed_fields_right_away(request): def run_me(inventory_id): @@ -178,12 +245,6 @@ def factory(name): return factory -@pytest.fixture -def user_project(user): - owner = user('owner') - return Project.objects.create(name="test-user-project", created_by=owner, description="test-user-project-desc") - - @pytest.fixture def insights_project(): return Project.objects.create(name="test-insights-project", scm_type="insights") @@ -333,13 +394,6 @@ def inventory(organization): return organization.inventories.create(name="test-inv") -@pytest.fixture -def insights_inventory(inventory): - inventory.scm_type = 'insights' - inventory.save() - return inventory - - @pytest.fixture def scm_inventory_source(inventory, project): inv_src = InventorySource( @@ -423,7 +477,7 @@ def admin(user): @pytest.fixture def system_auditor(user): u = user('an-auditor', False) - Role.singleton('system_auditor').members.add(u) + u.is_system_auditor = True return u @@ -490,25 +544,16 @@ def g(name): @pytest.fixture -def hosts(group_factory): - group1 = group_factory('group-1') - - def rf(host_count=1): - hosts = [] - for i in range(0, host_count): - name = '%s-host-%s' % (group1.name, i) - (host, created) = group1.inventory.hosts.get_or_create(name=name) - if created: - group1.hosts.add(host) - hosts.append(host) - return hosts - - return rf +def group(inventory): + return inventory.groups.create(name='single-group') @pytest.fixture -def group(inventory): - return inventory.groups.create(name='single-group') +def constructed_inventory(organization): + """ + creates a new constructed inventory source + """ + return Inventory.objects.create(name='dummy1', kind='constructed', organization=organization) @pytest.fixture @@ -704,6 +749,11 @@ def jt_linked(organization, project, inventory, machine_credential, credential, return jt +@pytest.fixture +def instance_group(): + return InstanceGroup.objects.create(name="east") + + @pytest.fixture def workflow_job_template(organization): wjt = WorkflowJobTemplate.objects.create(name='test-workflow_job_template', organization=organization) @@ -735,6 +785,30 @@ def factory(system_job_template=system_job_template, initial_state='new', create return factory +@pytest.fixture +def wfjt(workflow_job_template_factory, organization): + objects = workflow_job_template_factory('test_workflow', organization=organization, persisted=True) + return objects.workflow_job_template + + +@pytest.fixture +def wfjt_with_nodes(workflow_job_template_factory, organization, job_template): + objects = workflow_job_template_factory( + 'test_workflow', organization=organization, workflow_job_template_nodes=[{'unified_job_template': job_template}], persisted=True + ) + return objects.workflow_job_template + + +@pytest.fixture +def wfjt_node(wfjt_with_nodes): + return wfjt_with_nodes.workflow_job_template_nodes.all()[0] + + +@pytest.fixture +def workflow_job(wfjt): + return wfjt.workflow_jobs.create(name='test_workflow') + + def dumps(value): return DjangoJSONEncoder().encode(value) @@ -752,30 +826,43 @@ def get_db_prep_save(self, value, connection, **kwargs): return value -@pytest.fixture -def oauth_application(admin): - return Application.objects.create(name='test app', user=admin, client_type='confidential', authorization_grant_type='password') - - -@pytest.fixture -def sqlite_copy_expert(request): - # copy_expert is postgres-specific, and SQLite doesn't support it; mock its - # behavior to test that it writes a file that contains stdout from events - path = tempfile.mkdtemp(prefix='job-event-stdout') +class MockCopy: + events = [] + index = -1 - def write_stdout(self, sql, fd): - # simulate postgres copy_expert support with ORM code + def __init__(self, sql): + self.events = [] parts = sql.split(' ') tablename = parts[parts.index('from') + 1] for cls in (JobEvent, AdHocCommandEvent, ProjectUpdateEvent, InventoryUpdateEvent, SystemJobEvent): if cls._meta.db_table == tablename: for event in cls.objects.order_by('start_line').all(): - fd.write(event.stdout) + self.events.append(event.stdout) + + def read(self): + self.index = self.index + 1 + if self.index < len(self.events): + return memoryview(self.events[self.index].encode()) + + return None + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + pass + + +@pytest.fixture +def sqlite_copy(request, mocker): + # copy is postgres-specific, and SQLite doesn't support it; mock its + # behavior to test that it writes a file that contains stdout from events + + def write_stdout(self, sql): + mock_copy = MockCopy(sql) + return mock_copy - setattr(SQLiteCursorWrapper, 'copy_expert', write_stdout) - request.addfinalizer(lambda: shutil.rmtree(path)) - request.addfinalizer(lambda: delattr(SQLiteCursorWrapper, 'copy_expert')) - return path + mocker.patch.object(SQLiteCursorWrapper, 'copy', write_stdout, create=True) @pytest.fixture diff --git a/awx/main/tests/functional/dab_feature_flags/test_feature_flags_api.py b/awx/main/tests/functional/dab_feature_flags/test_feature_flags_api.py new file mode 100644 index 000000000000..fb483000fb90 --- /dev/null +++ b/awx/main/tests/functional/dab_feature_flags/test_feature_flags_api.py @@ -0,0 +1,35 @@ +import pytest +from flags.state import get_flags, flag_state +from ansible_base.feature_flags.models import AAPFlag +from ansible_base.feature_flags.utils import create_initial_data as seed_feature_flags +from django.conf import settings +from awx.main.models import User + + +@pytest.mark.django_db +def test_feature_flags_list_endpoint(get): + bob = User.objects.create(username='bob', password='test_user', is_superuser=True) + url = "/api/v2/feature_flags/states/" + response = get(url, user=bob, expect=200) + assert len(get_flags()) > 0 + assert len(response.data["results"]) == len(get_flags()) + + +@pytest.mark.django_db +@pytest.mark.parametrize('flag_val', (True, False)) +def test_feature_flags_list_endpoint_override(get, flag_val): + bob = User.objects.create(username='bob', password='test_user', is_superuser=True) + + AAPFlag.objects.all().delete() + flag_name = "FEATURE_INDIRECT_NODE_COUNTING_ENABLED" + setattr(settings, flag_name, flag_val) + seed_feature_flags() + url = "/api/v2/feature_flags/states/" + response = get(url, user=bob, expect=200) + + results = response.data["results"] + flag_names = [flag["name"] for flag in results] + + assert flag_name in flag_names, f"{flag_name} should be present in feature flags" + assert all(name.startswith("FEATURE_") for name in flag_names), "All feature flags should start with FEATURE_ prefix" + assert flag_state(flag_name) == flag_val diff --git a/awx/main/tests/functional/dab_rbac/test_access_list.py b/awx/main/tests/functional/dab_rbac/test_access_list.py new file mode 100644 index 000000000000..0a409efa9c8a --- /dev/null +++ b/awx/main/tests/functional/dab_rbac/test_access_list.py @@ -0,0 +1,125 @@ +import pytest + +from awx.main.models import User +from awx.api.versioning import reverse + + +@pytest.mark.django_db +def test_access_list_superuser(get, admin_user, inventory): + url = reverse('api:inventory_access_list', kwargs={'pk': inventory.id}) + + response = get(url, user=admin_user, expect=200) + by_username = {} + for entry in response.data['results']: + by_username[entry['username']] = entry + assert 'admin' in by_username + + assert len(by_username['admin']['summary_fields']['indirect_access']) == 1 + assert len(by_username['admin']['summary_fields']['direct_access']) == 0 + access_entry = by_username['admin']['summary_fields']['indirect_access'][0] + assert sorted(access_entry['descendant_roles']) == sorted(['adhoc_role', 'use_role', 'update_role', 'read_role', 'admin_role']) + + +@pytest.mark.django_db +def test_access_list_system_auditor(get, admin_user, inventory): + sys_auditor = User.objects.create(username='sys-aud') + sys_auditor.is_system_auditor = True + assert sys_auditor.is_system_auditor + url = reverse('api:inventory_access_list', kwargs={'pk': inventory.id}) + + response = get(url, user=admin_user, expect=200) + by_username = {} + for entry in response.data['results']: + by_username[entry['username']] = entry + assert 'sys-aud' in by_username + + assert len(by_username['sys-aud']['summary_fields']['indirect_access']) == 1 + assert len(by_username['sys-aud']['summary_fields']['direct_access']) == 0 + access_entry = by_username['sys-aud']['summary_fields']['indirect_access'][0] + assert access_entry['descendant_roles'] == ['read_role'] + + +@pytest.mark.django_db +def test_access_list_direct_access(get, admin_user, inventory): + u1 = User.objects.create(username='u1') + + inventory.admin_role.members.add(u1) + + url = reverse('api:inventory_access_list', kwargs={'pk': inventory.id}) + response = get(url, user=admin_user, expect=200) + by_username = {} + for entry in response.data['results']: + by_username[entry['username']] = entry + assert 'u1' in by_username + + assert len(by_username['u1']['summary_fields']['direct_access']) == 1 + assert len(by_username['u1']['summary_fields']['indirect_access']) == 0 + access_entry = by_username['u1']['summary_fields']['direct_access'][0] + assert sorted(access_entry['descendant_roles']) == sorted(['adhoc_role', 'use_role', 'update_role', 'read_role', 'admin_role']) + + +@pytest.mark.django_db +def test_access_list_organization_access(get, admin_user, inventory): + u2 = User.objects.create(username='u2') + + inventory.organization.inventory_admin_role.members.add(u2) + + # User has indirect access to the inventory + url = reverse('api:inventory_access_list', kwargs={'pk': inventory.id}) + response = get(url, user=admin_user, expect=200) + by_username = {} + for entry in response.data['results']: + by_username[entry['username']] = entry + assert 'u2' in by_username + + assert len(by_username['u2']['summary_fields']['indirect_access']) == 1 + assert len(by_username['u2']['summary_fields']['direct_access']) == 0 + access_entry = by_username['u2']['summary_fields']['indirect_access'][0] + assert sorted(access_entry['descendant_roles']) == sorted(['adhoc_role', 'use_role', 'update_role', 'read_role', 'admin_role']) + + # Test that user shows up in the organization access list with direct access of expected roles + url = reverse('api:organization_access_list', kwargs={'pk': inventory.organization_id}) + response = get(url, user=admin_user, expect=200) + by_username = {} + for entry in response.data['results']: + by_username[entry['username']] = entry + assert 'u2' in by_username + + assert len(by_username['u2']['summary_fields']['direct_access']) == 1 + assert len(by_username['u2']['summary_fields']['indirect_access']) == 0 + access_entry = by_username['u2']['summary_fields']['direct_access'][0] + assert sorted(access_entry['descendant_roles']) == sorted(['inventory_admin_role', 'read_role']) + + +@pytest.mark.django_db +def test_team_indirect_access(get, team, admin_user, inventory): + u1 = User.objects.create(username='u1') + team.member_role.members.add(u1) + + inventory.organization.inventory_admin_role.parents.add(team.member_role) + + url = reverse('api:inventory_access_list', kwargs={'pk': inventory.id}) + response = get(url, user=admin_user, expect=200) + by_username = {} + for entry in response.data['results']: + by_username[entry['username']] = entry + assert 'u1' in by_username + + assert len(by_username['u1']['summary_fields']['direct_access']) == 1 + assert len(by_username['u1']['summary_fields']['indirect_access']) == 0 + access_entry = by_username['u1']['summary_fields']['direct_access'][0] + assert sorted(access_entry['descendant_roles']) == sorted(['adhoc_role', 'use_role', 'update_role', 'read_role', 'admin_role']) + + +@pytest.mark.django_db +def test_workflow_access_list(workflow_job_template, alice, bob, setup_managed_roles, get, admin_user): + """Basic verification that WFJT access_list is functional""" + workflow_job_template.admin_role.members.add(alice) + workflow_job_template.organization.workflow_admin_role.members.add(bob) + + url = reverse('api:workflow_job_template_access_list', kwargs={'pk': workflow_job_template.pk}) + for u in (alice, bob, admin_user): + response = get(url, user=u, expect=200) + user_ids = [item['id'] for item in response.data['results']] + assert alice.pk in user_ids + assert bob.pk in user_ids diff --git a/awx/main/tests/functional/dab_rbac/test_access_regressions.py b/awx/main/tests/functional/dab_rbac/test_access_regressions.py new file mode 100644 index 000000000000..abd334269709 --- /dev/null +++ b/awx/main/tests/functional/dab_rbac/test_access_regressions.py @@ -0,0 +1,41 @@ +import pytest + +from awx.main.access import InstanceGroupAccess, NotificationTemplateAccess + +from ansible_base.rbac.models import RoleDefinition + + +@pytest.mark.django_db +def test_instance_group_object_role_delete(rando, instance_group, setup_managed_roles): + """Basic functionality of IG object-level admin role function AAP-25506""" + rd = RoleDefinition.objects.get(name='InstanceGroup Admin') + rd.give_permission(rando, instance_group) + access = InstanceGroupAccess(rando) + assert access.can_delete(instance_group) + + +@pytest.mark.django_db +def test_notification_template_object_role_change(rando, notification_template, setup_managed_roles): + """Basic functionality of NT object-level admin role function AAP-25493""" + rd = RoleDefinition.objects.get(name='NotificationTemplate Admin') + rd.give_permission(rando, notification_template) + access = NotificationTemplateAccess(rando) + assert access.can_change(notification_template, {'name': 'new name'}) + + +@pytest.mark.django_db +def test_organization_auditor_role(rando, setup_managed_roles, organization, inventory, project, jt_linked): + obj_list = (inventory, project, jt_linked) + for obj in obj_list: + assert obj.organization == organization, obj # sanity + + assert [rando.has_obj_perm(obj, 'view') for obj in obj_list] == [False for i in range(3)], obj_list + + rd = RoleDefinition.objects.get(name='Organization Audit') + rd.give_permission(rando, organization) + + codename_set = set(rd.permissions.values_list('codename', flat=True)) + assert not ({'view_inventory', 'view_jobtemplate', 'audit_organization'} - codename_set) # sanity + + assert [obj in type(obj).access_qs(rando) for obj in obj_list] == [True for i in range(3)], obj_list + assert [rando.has_obj_perm(obj, 'view') for obj in obj_list] == [True for i in range(3)], obj_list diff --git a/awx/main/tests/functional/dab_rbac/test_consolidate_teams.py b/awx/main/tests/functional/dab_rbac/test_consolidate_teams.py new file mode 100644 index 000000000000..1e42059e5664 --- /dev/null +++ b/awx/main/tests/functional/dab_rbac/test_consolidate_teams.py @@ -0,0 +1,147 @@ +import pytest + +from django.contrib.contenttypes.models import ContentType +from django.test import override_settings +from django.apps import apps + +from ansible_base.rbac.models import RoleDefinition, RoleUserAssignment, RoleTeamAssignment +from ansible_base.rbac.migrations._utils import give_permissions + +from awx.main.models import User, Team +from awx.main.migrations._dab_rbac import consolidate_indirect_user_roles + + +@pytest.mark.django_db +@override_settings(ANSIBLE_BASE_ALLOW_TEAM_PARENTS=True) +def test_consolidate_indirect_user_roles_with_nested_teams(setup_managed_roles, organization): + """ + Test the consolidate_indirect_user_roles function with a nested team hierarchy. + Setup: + - Users: A, B, C, D + - Teams: E, F, G + - Direct assignments: A→(E,F,G), B→E, C→F, D→G + - Team hierarchy: F→E (F is member of E), G→F (G is member of F) + Expected result after consolidation: + - Team E should have users: A, B, C, D (A directly, B directly, C through F, D through G→F) + - Team F should have users: A, C, D (A directly, C directly, D through G) + - Team G should have users: A, D (A directly, D directly) + """ + user_a = User.objects.create_user(username='user_a') + user_b = User.objects.create_user(username='user_b') + user_c = User.objects.create_user(username='user_c') + user_d = User.objects.create_user(username='user_d') + + team_e = Team.objects.create(name='Team E', organization=organization) + team_f = Team.objects.create(name='Team F', organization=organization) + team_g = Team.objects.create(name='Team G', organization=organization) + + # Get role definition and content type for give_permissions + team_member_role = RoleDefinition.objects.get(name='Team Member') + team_content_type = ContentType.objects.get_for_model(Team) + + # Assign users to teams + give_permissions(apps=apps, rd=team_member_role, users=[user_a], object_id=team_e.id, content_type_id=team_content_type.id) + give_permissions(apps=apps, rd=team_member_role, users=[user_a], object_id=team_f.id, content_type_id=team_content_type.id) + give_permissions(apps=apps, rd=team_member_role, users=[user_a], object_id=team_g.id, content_type_id=team_content_type.id) + give_permissions(apps=apps, rd=team_member_role, users=[user_b], object_id=team_e.id, content_type_id=team_content_type.id) + give_permissions(apps=apps, rd=team_member_role, users=[user_c], object_id=team_f.id, content_type_id=team_content_type.id) + give_permissions(apps=apps, rd=team_member_role, users=[user_d], object_id=team_g.id, content_type_id=team_content_type.id) + + # Mirror user assignments in the old RBAC system because signals don't run in tests + team_e.member_role.members.add(user_a.id, user_b.id) + team_f.member_role.members.add(user_a.id, user_c.id) + team_g.member_role.members.add(user_a.id, user_d.id) + + # Setup team-to-team relationships + give_permissions(apps=apps, rd=team_member_role, teams=[team_f], object_id=team_e.id, content_type_id=team_content_type.id) + give_permissions(apps=apps, rd=team_member_role, teams=[team_g], object_id=team_f.id, content_type_id=team_content_type.id) + + # Verify initial direct assignments + team_e_users_before = set(RoleUserAssignment.objects.filter(role_definition=team_member_role, object_id=team_e.id).values_list('user_id', flat=True)) + assert team_e_users_before == {user_a.id, user_b.id} + team_f_users_before = set(RoleUserAssignment.objects.filter(role_definition=team_member_role, object_id=team_f.id).values_list('user_id', flat=True)) + assert team_f_users_before == {user_a.id, user_c.id} + team_g_users_before = set(RoleUserAssignment.objects.filter(role_definition=team_member_role, object_id=team_g.id).values_list('user_id', flat=True)) + assert team_g_users_before == {user_a.id, user_d.id} + + # Verify team-to-team relationships exist + assert RoleTeamAssignment.objects.filter(role_definition=team_member_role, team=team_f, object_id=team_e.id).exists() + assert RoleTeamAssignment.objects.filter(role_definition=team_member_role, team=team_g, object_id=team_f.id).exists() + + # Run the consolidation function + consolidate_indirect_user_roles(apps, None) + + # Verify consolidation + team_e_users_after = set(RoleUserAssignment.objects.filter(role_definition=team_member_role, object_id=team_e.id).values_list('user_id', flat=True)) + assert team_e_users_after == {user_a.id, user_b.id, user_c.id, user_d.id}, f"Team E should have users A, B, C, D but has {team_e_users_after}" + team_f_users_after = set(RoleUserAssignment.objects.filter(role_definition=team_member_role, object_id=team_f.id).values_list('user_id', flat=True)) + assert team_f_users_after == {user_a.id, user_c.id, user_d.id}, f"Team F should have users A, C, D but has {team_f_users_after}" + team_g_users_after = set(RoleUserAssignment.objects.filter(role_definition=team_member_role, object_id=team_g.id).values_list('user_id', flat=True)) + assert team_g_users_after == {user_a.id, user_d.id}, f"Team G should have users A, D but has {team_g_users_after}" + + # Verify team member changes are mirrored to the old RBAC system + assert team_e_users_after == set(team_e.member_role.members.all().values_list('id', flat=True)) + assert team_f_users_after == set(team_f.member_role.members.all().values_list('id', flat=True)) + assert team_g_users_after == set(team_g.member_role.members.all().values_list('id', flat=True)) + + # Verify team-to-team relationships are removed after consolidation + assert not RoleTeamAssignment.objects.filter( + role_definition=team_member_role, team=team_f, object_id=team_e.id + ).exists(), "Team-to-team relationship F→E should be removed" + assert not RoleTeamAssignment.objects.filter( + role_definition=team_member_role, team=team_g, object_id=team_f.id + ).exists(), "Team-to-team relationship G→F should be removed" + + +@pytest.mark.django_db +@override_settings(ANSIBLE_BASE_ALLOW_TEAM_PARENTS=True) +def test_consolidate_indirect_user_roles_no_team_relationships(setup_managed_roles, organization): + """ + Test that the function handles the case where there are no team-to-team relationships. + It should return early without making any changes. + """ + # Create a user and team with direct assignment + user = User.objects.create_user(username='test_user') + team = Team.objects.create(name='Test Team', organization=organization) + + team_member_role = RoleDefinition.objects.get(name='Team Member') + team_content_type = ContentType.objects.get_for_model(Team) + give_permissions(apps=apps, rd=team_member_role, users=[user], object_id=team.id, content_type_id=team_content_type.id) + + # Compare count of assignments before and after consolidation + assignments_before = RoleUserAssignment.objects.filter(role_definition=team_member_role).count() + consolidate_indirect_user_roles(apps, None) + assignments_after = RoleUserAssignment.objects.filter(role_definition=team_member_role).count() + + assert assignments_before == assignments_after, "Number of assignments should not change when there are no team-to-team relationships" + + +@pytest.mark.django_db +@override_settings(ANSIBLE_BASE_ALLOW_TEAM_PARENTS=True) +def test_consolidate_indirect_user_roles_circular_reference(setup_managed_roles, organization): + """ + Test that the function handles circular team references without infinite recursion. + """ + team_a = Team.objects.create(name='Team A', organization=organization) + team_b = Team.objects.create(name='Team B', organization=organization) + + # Create a user assigned to team A + user = User.objects.create_user(username='test_user') + + team_member_role = RoleDefinition.objects.get(name='Team Member') + team_content_type = ContentType.objects.get_for_model(Team) + give_permissions(apps=apps, rd=team_member_role, users=[user], object_id=team_a.id, content_type_id=team_content_type.id) + + # Create circular team relationships: A → B → A + give_permissions(apps=apps, rd=team_member_role, teams=[team_b], object_id=team_a.id, content_type_id=team_content_type.id) + give_permissions(apps=apps, rd=team_member_role, teams=[team_a], object_id=team_b.id, content_type_id=team_content_type.id) + + # Run the consolidation function - should not raise an exception + consolidate_indirect_user_roles(apps, None) + + # Both teams should have the user assigned + team_a_users = set(RoleUserAssignment.objects.filter(role_definition=team_member_role, object_id=team_a.id).values_list('user_id', flat=True)) + team_b_users = set(RoleUserAssignment.objects.filter(role_definition=team_member_role, object_id=team_b.id).values_list('user_id', flat=True)) + + assert user.id in team_a_users, "User should be assigned to team A" + assert user.id in team_b_users, "User should be assigned to team B" diff --git a/awx/main/tests/functional/dab_rbac/test_dab_rbac_api.py b/awx/main/tests/functional/dab_rbac/test_dab_rbac_api.py new file mode 100644 index 000000000000..3b09272d8c84 --- /dev/null +++ b/awx/main/tests/functional/dab_rbac/test_dab_rbac_api.py @@ -0,0 +1,196 @@ +import pytest + +from django.urls import reverse as django_reverse + +from awx.api.versioning import reverse +from awx.main.models import JobTemplate, Inventory, Organization +from awx.main.access import JobTemplateAccess, WorkflowJobTemplateAccess + +from ansible_base.rbac.models import RoleDefinition +from ansible_base.rbac import permission_registry + + +@pytest.mark.django_db +def test_managed_roles_created(setup_managed_roles): + "Managed RoleDefinitions are created in post_migration signal, we expect to see them here" + for cls in (JobTemplate, Inventory): + ct = permission_registry.content_type_model.objects.get_for_model(cls) + rds = list(RoleDefinition.objects.filter(content_type=ct)) + assert len(rds) > 1 + assert f'{cls.__name__} Admin' in [rd.name for rd in rds] + for rd in rds: + assert rd.managed is True + + +@pytest.mark.django_db +def test_custom_read_role(admin_user, post, setup_managed_roles): + rd_url = django_reverse('roledefinition-list') + resp = post( + url=rd_url, + data={"name": "read role made for test", "content_type": "awx.inventory", "permissions": ['awx.view_inventory']}, + user=admin_user, + expect=201, + ) + rd_id = resp.data['id'] + rd = RoleDefinition.objects.get(id=rd_id) + assert rd.content_type == permission_registry.content_type_model.objects.get_for_model(Inventory) + + +@pytest.mark.django_db +def test_custom_system_roles_prohibited(admin_user, post): + rd_url = django_reverse('roledefinition-list') + resp = post(url=rd_url, data={"name": "read role made for test", "content_type": None, "permissions": ['awx.view_inventory']}, user=admin_user, expect=400) + assert 'System-wide roles are not enabled' in str(resp.data) + + +@pytest.mark.django_db +def test_assignment_to_invisible_user(admin_user, alice, rando, inventory, post, setup_managed_roles): + "Alice can not see rando, and so can not give them a role assignment" + rd = RoleDefinition.objects.get(name='Inventory Admin') + rd.give_permission(alice, inventory) + url = django_reverse('roleuserassignment-list') + r = post(url=url, data={"user": rando.id, "role_definition": rd.id, "object_id": inventory.id}, user=alice, expect=400) + assert 'does not exist' in str(r.data) + assert not rando.has_obj_perm(inventory, 'change') + + +@pytest.mark.django_db +def test_assign_managed_role(admin_user, alice, rando, inventory, post, setup_managed_roles, organization): + rd = RoleDefinition.objects.get(name='Inventory Admin') + rd.give_permission(alice, inventory) + # When alice and rando are members of the same org, they can see each other + member_rd = RoleDefinition.objects.get(name='Organization Member') + for u in (alice, rando): + member_rd.give_permission(u, organization) + # Now that alice has full permissions to the inventory, and can see rando, she will give rando permission + url = django_reverse('roleuserassignment-list') + post(url=url, data={"user": rando.id, "role_definition": rd.id, "object_id": inventory.id}, user=alice, expect=201) + assert rando.has_obj_perm(inventory, 'change') is True + + +@pytest.mark.django_db +def test_assign_custom_delete_role(admin_user, rando, inventory, delete, patch): + # TODO: just a delete_inventory, without change_inventory + rd, _ = RoleDefinition.objects.get_or_create( + name='inventory-delete', + permissions=['delete_inventory', 'view_inventory', 'change_inventory'], + content_type=permission_registry.content_type_model.objects.get_for_model(Inventory), + ) + rd.give_permission(rando, inventory) + inv_id = inventory.pk + inv_url = reverse('api:inventory_detail', kwargs={'pk': inv_id}) + # TODO: eventually this will be valid test, for now ignore + # patch(url=inv_url, data={"description": "new"}, user=rando, expect=403) + delete(url=inv_url, user=rando, expect=202) + assert Inventory.objects.get(id=inv_id).pending_deletion + + +@pytest.mark.django_db +def test_assign_custom_add_role(admin_user, rando, organization, post, setup_managed_roles): + rd, _ = RoleDefinition.objects.get_or_create( + name='inventory-add', + permissions=['add_inventory', 'view_organization'], + content_type=permission_registry.content_type_model.objects.get_for_model(Organization), + ) + rd.give_permission(rando, organization) + url = reverse('api:inventory_list') + r = post(url=url, data={'name': 'abc', 'organization': organization.id}, user=rando, expect=201) + inv_id = r.data['id'] + inventory = Inventory.objects.get(id=inv_id) + assert rando.has_obj_perm(inventory, 'change') + + +@pytest.mark.django_db +def test_jt_creation_permissions(setup_managed_roles, inventory, project, rando): + """This tests that if you assign someone required permissions in the new API + using the managed roles, then that works to give permissions to create a job template""" + inv_rd = RoleDefinition.objects.get(name='Inventory Admin') + proj_rd = RoleDefinition.objects.get(name='Project Admin') + # establish prior state + access = JobTemplateAccess(rando) + assert not access.can_add({'inventory': inventory.pk, 'project': project.pk, 'name': 'foo-jt'}) + + inv_rd.give_permission(rando, inventory) + proj_rd.give_permission(rando, project) + + assert access.can_add({'inventory': inventory.pk, 'project': project.pk, 'name': 'foo-jt'}) + + +@pytest.mark.django_db +def test_workflow_creation_permissions(setup_managed_roles, organization, workflow_job_template, rando): + """Similar to JT, assigning new roles gives creator permissions""" + org_wf_rd = RoleDefinition.objects.get(name='Organization WorkflowJobTemplate Admin') + assert workflow_job_template.organization == organization # sanity + # establish prior state + access = WorkflowJobTemplateAccess(rando) + assert not access.can_add({'name': 'foo-flow', 'organization': organization.pk}) + org_wf_rd.give_permission(rando, organization) + + assert access.can_add({'name': 'foo-flow', 'organization': organization.pk}) + + +@pytest.mark.django_db +def test_assign_credential_to_user_of_another_org(setup_managed_roles, credential, admin_user, rando, org_admin, organization, post): + '''Test that a credential can only be assigned to a user in the same organization''' + # cannot assign credential to rando, as rando is not in the same org as the credential + rd = RoleDefinition.objects.get(name="Credential Admin") + credential.organization = organization + credential.save(update_fields=['organization']) + assert credential.organization not in Organization.access_qs(rando, 'member') + url = django_reverse('roleuserassignment-list') + resp = post(url=url, data={"user": rando.id, "role_definition": rd.id, "object_id": credential.id}, user=admin_user, expect=400) + assert "You cannot grant credential access to a User not in the credentials' organization" in str(resp.data) + + # can assign credential to superuser + rando.is_superuser = True + rando.save() + post(url=url, data={"user": rando.id, "role_definition": rd.id, "object_id": credential.id}, user=admin_user, expect=201) + + # can assign credential to org_admin + assert credential.organization in Organization.access_qs(org_admin, 'member') + post(url=url, data={"user": org_admin.id, "role_definition": rd.id, "object_id": credential.id}, user=admin_user, expect=201) + + +@pytest.mark.django_db +def test_adding_user_to_org_member_role(setup_managed_roles, organization, admin, bob, post, get): + ''' + Adding user to organization member role via the legacy RBAC endpoints + should give them access to the organization detail + ''' + url_detail = reverse('api:organization_detail', kwargs={'pk': organization.id}) + get(url_detail, user=bob, expect=403) + + role = organization.member_role + url = reverse('api:role_users_list', kwargs={'pk': role.id}) + post(url, data={'id': bob.id}, user=admin, expect=204) + + get(url_detail, user=bob, expect=200) + + +@pytest.mark.django_db +@pytest.mark.parametrize('actor', ['user', 'team']) +@pytest.mark.parametrize('role_name', ['Organization Admin', 'Organization Member', 'Team Admin', 'Team Member']) +def test_adding_actor_to_platform_roles(setup_managed_roles, role_name, actor, organization, team, admin, bob, post): + ''' + Allow user to be added to platform-level roles + Exceptions: + - Team cannot be added to Organization Member or Admin role + - Team cannot be added to Team Admin or Team Member role + ''' + if actor == 'team': + expect = 400 + else: + expect = 201 + rd = RoleDefinition.objects.get(name=role_name) + endpoint = 'roleuserassignment-list' if actor == 'user' else 'roleteamassignment-list' + url = django_reverse(endpoint) + object_id = team.id if 'Team' in role_name else organization.id + data = {'object_id': object_id, 'role_definition': rd.id} + actor_id = bob.id if actor == 'user' else team.id + data[actor] = actor_id + r = post(url, data=data, user=admin, expect=expect) + if expect == 400: + if 'Organization' in role_name: + assert 'Assigning organization member permission to teams is not allowed' in str(r.data) + if 'Team' in role_name: + assert 'Assigning team permissions to other teams is not allowed' in str(r.data) diff --git a/awx/main/tests/functional/dab_rbac/test_external_auditor.py b/awx/main/tests/functional/dab_rbac/test_external_auditor.py new file mode 100644 index 000000000000..c3602d736627 --- /dev/null +++ b/awx/main/tests/functional/dab_rbac/test_external_auditor.py @@ -0,0 +1,120 @@ +import pytest + +from django.apps import apps + +from ansible_base.rbac.managed import SystemAuditor +from ansible_base.rbac import permission_registry + +from awx.main.access import check_user_access, get_user_queryset +from awx.main.models import User, AdHocCommandEvent +from awx.api.versioning import reverse + + +@pytest.fixture +def ext_auditor_rd(): + info = SystemAuditor(overrides={'name': 'Alien Auditor', 'shortname': 'ext_auditor'}) + rd, _ = info.get_or_create(apps) + return rd + + +@pytest.fixture +def ext_auditor(ext_auditor_rd): + u = User.objects.create(username='external-auditor-user') + ext_auditor_rd.give_global_permission(u) + return u + + +@pytest.fixture +def obj_factory(request): + def _rf(fixture_name): + obj = request.getfixturevalue(fixture_name) + + # special case to make obj organization-scoped + if obj._meta.model_name == 'executionenvironment': + obj.organization = request.getfixturevalue('organization') + obj.save(update_fields=['organization']) + + return obj + + return _rf + + +@pytest.mark.django_db +def test_access_qs_external_auditor(ext_auditor_rd, rando, job_template): + ext_auditor_rd.give_global_permission(rando) + jt_cls = apps.get_model('main', 'JobTemplate') + ujt_cls = apps.get_model('main', 'UnifiedJobTemplate') + assert job_template in jt_cls.access_qs(rando) + assert job_template.id in jt_cls.access_ids_qs(rando) + assert job_template.id in ujt_cls.accessible_pk_qs(rando, 'read_role') + + +@pytest.mark.django_db +@pytest.mark.parametrize('model', sorted(permission_registry.all_registered_models, key=lambda cls: cls._meta.model_name)) +class TestExternalAuditorRoleAllModels: + def test_access_can_read_method(self, obj_factory, model, ext_auditor, rando): + fixture_name = model._meta.verbose_name.replace(' ', '_') + obj = obj_factory(fixture_name) + + assert check_user_access(rando, model, 'read', obj) is False + assert check_user_access(ext_auditor, model, 'read', obj) is True + + def test_access_get_queryset(self, obj_factory, model, ext_auditor, rando): + fixture_name = model._meta.verbose_name.replace(' ', '_') + obj = obj_factory(fixture_name) + + assert obj not in get_user_queryset(rando, model) + assert obj in get_user_queryset(ext_auditor, model) + + def test_global_list(self, obj_factory, model, ext_auditor, rando, get): + fixture_name = model._meta.verbose_name.replace(' ', '_') + obj_factory(fixture_name) + + url = reverse(f'api:{fixture_name}_list') + r = get(url, user=rando, expect=200) + initial_ct = r.data['count'] + + r = get(url, user=ext_auditor, expect=200) + assert r.data['count'] == initial_ct + 1 + + if fixture_name in ('job_template', 'workflow_job_template'): + url = reverse('api:unified_job_template_list') + r = get(url, user=rando, expect=200) + initial_ct = r.data['count'] + + r = get(url, user=ext_auditor, expect=200) + assert r.data['count'] == initial_ct + 1 + + def test_detail_view(self, obj_factory, model, ext_auditor, rando, get): + fixture_name = model._meta.verbose_name.replace(' ', '_') + obj = obj_factory(fixture_name) + + url = reverse(f'api:{fixture_name}_detail', kwargs={'pk': obj.pk}) + get(url, user=rando, expect=403) # NOTE: should be 401 + get(url, user=ext_auditor, expect=200) + + +@pytest.mark.django_db +class TestExternalAuditorNonRoleModels: + def test_ad_hoc_command_view(self, ad_hoc_command_factory, rando, ext_auditor, get): + """The AdHocCommandAccess class references is_system_auditor + + this is to prove it works with other system-level view roles""" + ad_hoc_command = ad_hoc_command_factory() + url = reverse('api:ad_hoc_command_list') + r = get(url, user=rando, expect=200) + assert r.data['count'] == 0 + r = get(url, user=ext_auditor, expect=200) + assert r.data['count'] == 1 + assert r.data['results'][0]['id'] == ad_hoc_command.id + + event = AdHocCommandEvent.objects.create(ad_hoc_command=ad_hoc_command) + url = reverse('api:ad_hoc_command_ad_hoc_command_events_list', kwargs={'pk': ad_hoc_command.id}) + r = get(url, user=rando, expect=403) + r = get(url, user=ext_auditor, expect=200) + assert r.data['count'] == 1 + + url = reverse('api:ad_hoc_command_event_detail', kwargs={'pk': event.id}) + r = get(url, user=rando, expect=403) + r = get(url, user=ext_auditor, expect=200) + assert r.data['id'] == event.id diff --git a/awx/main/tests/functional/dab_rbac/test_managed_roles.py b/awx/main/tests/functional/dab_rbac/test_managed_roles.py new file mode 100644 index 000000000000..82fd661fa593 --- /dev/null +++ b/awx/main/tests/functional/dab_rbac/test_managed_roles.py @@ -0,0 +1,56 @@ +import pytest + +from ansible_base.rbac.models import RoleDefinition, DABPermission, RoleUserAssignment + + +@pytest.mark.django_db +def test_roles_to_not_create(setup_managed_roles): + assert RoleDefinition.objects.filter(name='Organization Admin').count() == 1 + + SHOULD_NOT_EXIST = ('Organization Organization Admin', 'Organization Team Admin', 'Organization InstanceGroup Admin') + + bad_rds = RoleDefinition.objects.filter(name__in=SHOULD_NOT_EXIST) + if bad_rds.exists(): + bad_names = list(bad_rds.values_list('name', flat=True)) + raise Exception(f'Found RoleDefinitions that should not exist: {bad_names}') + + +@pytest.mark.django_db +def test_org_admin_role(setup_managed_roles): + rd = RoleDefinition.objects.get(name='Organization Admin') + codenames = list(rd.permissions.values_list('codename', flat=True)) + assert 'view_inventory' in codenames + assert 'change_inventory' in codenames + + +@pytest.mark.django_db +def test_project_update_role(setup_managed_roles): + """Role to allow updating a project on the object-level should exist""" + assert RoleDefinition.objects.filter(name='Project Update').count() == 1 + + +@pytest.mark.django_db +def test_org_child_add_permission(setup_managed_roles): + for model_name in ('Project', 'NotificationTemplate', 'WorkflowJobTemplate', 'Inventory'): + rd = RoleDefinition.objects.get(name=f'Organization {model_name} Admin') + assert 'add_' in str(rd.permissions.values_list('codename', flat=True)), f'The {rd.name} role definition expected to contain add_ permissions' + + # special case for JobTemplate, anyone can create one with use permission to project/inventory + assert not DABPermission.objects.filter(codename='add_jobtemplate').exists() + + +@pytest.mark.django_db +@pytest.mark.parametrize('resource_name', ['Team', 'Organization']) +@pytest.mark.parametrize('action', ['Member', 'Admin']) +def test_legacy_RBAC_uses_platform_roles(setup_managed_roles, resource_name, action, team, bob, organization): + ''' + Assignment to legacy RBAC roles should use platform role definitions + e.g. Team Admin, Team Member, Organization Member, Organization Admin + ''' + resource = team if resource_name == 'Team' else organization + if action == 'Member': + resource.member_role.members.add(bob) + else: + resource.admin_role.members.add(bob) + rd = RoleDefinition.objects.get(name=f'{resource_name} {action}') + assert RoleUserAssignment.objects.filter(role_definition=rd, user=bob, object_id=resource.id).exists() diff --git a/awx/main/tests/functional/dab_rbac/test_translation_layer.py b/awx/main/tests/functional/dab_rbac/test_translation_layer.py new file mode 100644 index 000000000000..98ee58f5b8c3 --- /dev/null +++ b/awx/main/tests/functional/dab_rbac/test_translation_layer.py @@ -0,0 +1,210 @@ +from unittest import mock +import json + +import pytest + +from crum import impersonate + +from awx.main.fields import ImplicitRoleField +from awx.main.models.rbac import get_role_from_object_role, give_creator_permissions, get_role_codenames, get_role_definition +from awx.main.models import User, Organization, WorkflowJobTemplate, WorkflowJobTemplateNode, Team +from awx.api.versioning import reverse + +from ansible_base.rbac.models import RoleUserAssignment, RoleDefinition +from ansible_base.rbac import permission_registry + + +@pytest.mark.django_db +@pytest.mark.parametrize( + 'role_name', + [ + 'execution_environment_admin_role', + 'workflow_admin_role', + 'project_admin_role', + 'admin_role', + 'auditor_role', + 'read_role', + 'execute_role', + 'approval_role', + 'notification_admin_role', + ], +) +def test_round_trip_roles(organization, rando, role_name, setup_managed_roles): + """ + Make an assignment with the old-style role, + get the equivelent new role + get the old role again + """ + getattr(organization, role_name).members.add(rando) + assignment = RoleUserAssignment.objects.get(user=rando) + old_role = get_role_from_object_role(assignment.object_role) + assert old_role.id == getattr(organization, role_name).id + + +@pytest.mark.django_db +@pytest.mark.parametrize('model', sorted(permission_registry.all_registered_models, key=lambda cls: cls._meta.model_name)) +def test_role_migration_matches(request, model, setup_managed_roles): + fixture_name = model._meta.verbose_name.replace(' ', '_') + obj = request.getfixturevalue(fixture_name) + role_ct = 0 + for field in obj._meta.get_fields(): + if isinstance(field, ImplicitRoleField): + if field.name == 'read_role': + continue # intentionally left as "Compat" roles + role_ct += 1 + old_role = getattr(obj, field.name) + old_codenames = set(get_role_codenames(old_role)) + rd = get_role_definition(old_role) + new_codenames = set(rd.permissions.values_list('codename', flat=True)) + # all the old roles should map to a non-Compat role definition + if 'Compat' not in rd.name: + model_rds = RoleDefinition.objects.filter(content_type=permission_registry.content_type_model.objects.get_for_model(obj)) + rd_data = {} + for rd in model_rds: + rd_data[rd.name] = list(rd.permissions.values_list('codename', flat=True)) + assert ( + 'Compat' not in rd.name + ), f'Permissions for old vs new roles did not match.\nold {field.name}: {old_codenames}\nnew:\n{json.dumps(rd_data, indent=2)}' + assert new_codenames == set(old_codenames) + + # In the old system these models did not have object-level roles, all others expect some model roles + if model._meta.model_name not in ('notificationtemplate', 'executionenvironment'): + assert role_ct > 0 + + +@pytest.mark.django_db +def test_role_naming(setup_managed_roles): + qs = RoleDefinition.objects.filter(content_type=permission_registry.content_type_model.objects.get(model='jobtemplate'), name__endswith='dmin') + assert qs.count() == 1 # sanity + rd = qs.first() + assert rd.name == 'JobTemplate Admin' + assert rd.description + assert rd.created_by is None + + +@pytest.mark.django_db +def test_action_role_naming(setup_managed_roles): + qs = RoleDefinition.objects.filter(content_type=permission_registry.content_type_model.objects.get(model='jobtemplate'), name__endswith='ecute') + assert qs.count() == 1 # sanity + rd = qs.first() + assert rd.name == 'JobTemplate Execute' + assert rd.description + assert rd.created_by is None + + +@pytest.mark.django_db +def test_compat_role_naming(setup_managed_roles, job_template, rando, alice): + with impersonate(alice): + job_template.read_role.members.add(rando) + qs = RoleDefinition.objects.filter(content_type=permission_registry.content_type_model.objects.get(model='jobtemplate'), name__endswith='ompat') + assert qs.count() == 1 # sanity + rd = qs.first() + assert rd.name == 'JobTemplate Read Compat' + assert rd.description + assert rd.created_by is None + + +@pytest.mark.django_db +def test_organization_admin_has_audit(setup_managed_roles): + """This formalizes a behavior change from old to new RBAC system + + Previously, the auditor_role did not list admin_role as a parent + this made various queries hard to deal with, requiring adding 2 conditions + The new system should explicitly list the auditor permission in org admin role""" + rd = RoleDefinition.objects.get(name='Organization Admin') + assert 'audit_organization' in rd.permissions.values_list('codename', flat=True) + + +@pytest.mark.django_db +def test_organization_level_permissions(organization, inventory, setup_managed_roles): + u1 = User.objects.create(username='alice') + u2 = User.objects.create(username='bob') + + organization.inventory_admin_role.members.add(u1) + organization.workflow_admin_role.members.add(u2) + + assert u1 in inventory.admin_role + assert u1 in organization.inventory_admin_role + assert u2 in organization.workflow_admin_role + + assert u2 not in organization.inventory_admin_role + assert u1 not in organization.workflow_admin_role + assert not (set(u1.has_roles.all()) & set(u2.has_roles.all())) # user have no roles in common + + # Old style + assert set(Organization.accessible_objects(u1, 'inventory_admin_role')) == set([organization]) + assert set(Organization.accessible_objects(u2, 'inventory_admin_role')) == set() + assert set(Organization.accessible_objects(u1, 'workflow_admin_role')) == set() + assert set(Organization.accessible_objects(u2, 'workflow_admin_role')) == set([organization]) + + # New style + assert set(Organization.access_qs(u1, 'add_inventory')) == set([organization]) + assert set(Organization.access_qs(u1, 'change_inventory')) == set([organization]) + assert set(Organization.access_qs(u2, 'add_inventory')) == set() + assert set(Organization.access_qs(u1, 'add_workflowjobtemplate')) == set() + assert set(Organization.access_qs(u2, 'add_workflowjobtemplate')) == set([organization]) + + +@pytest.mark.django_db +def test_organization_execute_role(organization, rando, setup_managed_roles): + organization.execute_role.members.add(rando) + assert rando in organization.execute_role + assert set(Organization.accessible_objects(rando, 'execute_role')) == set([organization]) + + +@pytest.mark.django_db +def test_workflow_approval_list(get, post, admin_user, setup_managed_roles): + workflow_job_template = WorkflowJobTemplate.objects.create() + approval_node = WorkflowJobTemplateNode.objects.create(workflow_job_template=workflow_job_template) + url = reverse('api:workflow_job_template_node_create_approval', kwargs={'pk': approval_node.pk, 'version': 'v2'}) + post(url, {'name': 'URL Test', 'description': 'An approval', 'timeout': 0}, user=admin_user) + approval_node.refresh_from_db() + approval_jt = approval_node.unified_job_template + approval_jt.create_unified_job() + + r = get(url=reverse('api:workflow_approval_list'), user=admin_user, expect=200) + assert r.data['count'] >= 1 + + +@pytest.mark.django_db +def test_creator_permission(rando, admin_user, inventory, setup_managed_roles): + give_creator_permissions(rando, inventory) + assert rando in inventory.admin_role + assert rando in inventory.admin_role.members.all() + + +@pytest.mark.django_db +def test_implicit_parents_no_assignments(organization): + """Through the normal course of creating models, we should not be changing DAB RBAC permissions""" + with mock.patch('awx.main.models.rbac.give_or_remove_permission') as mck: + Team.objects.create(name='random team', organization=organization) + mck.assert_not_called() + + +@pytest.mark.django_db +def test_user_auditor_rel(organization, rando, setup_managed_roles): + assert rando not in organization.auditor_role + audit_rd = RoleDefinition.objects.get(name='Organization Audit') + audit_rd.give_permission(rando, organization) + assert list(Organization.access_qs(rando, 'audit')) == [organization] + + +@pytest.mark.django_db +@pytest.mark.parametrize('resource_name', ['Organization', 'Team']) +@pytest.mark.parametrize('role_name', ['Member', 'Admin']) +def test_mapping_from_role_definitions_to_roles(organization, team, rando, role_name, resource_name, setup_managed_roles): + """ + ensure mappings for platform roles are correct + e.g. + Organization Member > organization.member_role + Organization Admin > organization.admin_role + Team Member > team.member_role + Team Admin > team.admin_role + """ + resource = organization if resource_name == 'Organization' else team + old_role_name = f"{role_name.lower()}_role" + getattr(resource, old_role_name).members.add(rando) + assignment = RoleUserAssignment.objects.get(user=rando) + assert assignment.role_definition.name == f'{resource_name} {role_name}' + old_role = get_role_from_object_role(assignment.object_role) + assert old_role.id == getattr(resource, old_role_name).id diff --git a/awx/main/tests/functional/dab_rbac/test_translation_layer_new_to_old.py b/awx/main/tests/functional/dab_rbac/test_translation_layer_new_to_old.py new file mode 100644 index 000000000000..92efef838769 --- /dev/null +++ b/awx/main/tests/functional/dab_rbac/test_translation_layer_new_to_old.py @@ -0,0 +1,80 @@ +from ansible_base.rbac.models import RoleDefinition, RoleUserAssignment, RoleTeamAssignment +from ansible_base.lib.utils.response import get_relative_url +import pytest + + +@pytest.mark.django_db +class TestNewToOld: + ''' + Tests that the DAB RBAC system is correctly translated to the old RBAC system + Namely, tests functionality of the _sync_assignments_to_old_rbac signal handler + ''' + + def test_new_to_old_rbac_addition(self, admin, post, inventory, bob, setup_managed_roles): + ''' + Assign user to Inventory Admin role definition, should be added to inventory.admin_role.members + ''' + rd = RoleDefinition.objects.get(name='Inventory Admin') + + url = get_relative_url('roleuserassignment-list') + post(url, user=admin, data={'role_definition': rd.id, 'user': bob.id, 'object_id': inventory.id}, expect=201) + assert bob in inventory.admin_role.members.all() + + def test_new_to_old_rbac_removal(self, admin, delete, inventory, bob, setup_managed_roles): + ''' + Remove user from Inventory Admin role definition, should be deleted from inventory.admin_role.members + ''' + inventory.admin_role.members.add(bob) + + rd = RoleDefinition.objects.get(name='Inventory Admin') + user_assignment = RoleUserAssignment.objects.get(user=bob, role_definition=rd, object_id=inventory.id) + + url = get_relative_url('roleuserassignment-detail', kwargs={'pk': user_assignment.id}) + delete(url, user=admin, expect=204) + assert bob not in inventory.admin_role.members.all() + + def test_new_to_old_rbac_team_member_addition(self, admin, post, team, bob, setup_managed_roles): + ''' + Assign user to Team Member role definition, should be added to team.member_role.members + ''' + rd = RoleDefinition.objects.get(name='Team Member') + + url = get_relative_url('roleuserassignment-list') + post(url, user=admin, data={'role_definition': rd.id, 'user': bob.id, 'object_id': team.id}, expect=201) + assert bob in team.member_role.members.all() + + def test_new_to_old_rbac_team_member_removal(self, admin, delete, team, bob, setup_managed_roles): + ''' + Remove user from Team Member role definition, should be deleted from team.member_role.members + ''' + team.member_role.members.add(bob) + + rd = RoleDefinition.objects.get(name='Team Member') + user_assignment = RoleUserAssignment.objects.get(user=bob, role_definition=rd, object_id=team.id) + + url = get_relative_url('roleuserassignment-detail', kwargs={'pk': user_assignment.id}) + delete(url, user=admin, expect=204) + assert bob not in team.member_role.members.all() + + def test_new_to_old_rbac_team_addition(self, admin, post, team, inventory, setup_managed_roles): + ''' + Assign team to Inventory Admin role definition, should be added to inventory.admin_role.parents + ''' + rd = RoleDefinition.objects.get(name='Inventory Admin') + + url = get_relative_url('roleteamassignment-list') + post(url, user=admin, data={'role_definition': rd.id, 'team': team.id, 'object_id': inventory.id}, expect=201) + assert team.member_role in inventory.admin_role.parents.all() + + def test_new_to_old_rbac_team_removal(self, admin, delete, team, inventory, setup_managed_roles): + ''' + Remove team from Inventory Admin role definition, should be deleted from inventory.admin_role.parents + ''' + inventory.admin_role.parents.add(team.member_role) + + rd = RoleDefinition.objects.get(name='Inventory Admin') + team_assignment = RoleTeamAssignment.objects.get(team=team, role_definition=rd, object_id=inventory.id) + + url = get_relative_url('roleteamassignment-detail', kwargs={'pk': team_assignment.id}) + delete(url, user=admin, expect=204) + assert team.member_role not in inventory.admin_role.parents.all() diff --git a/awx/main/tests/functional/dab_resource_registry/test_ansible_id_display.py b/awx/main/tests/functional/dab_resource_registry/test_ansible_id_display.py new file mode 100644 index 000000000000..bf0d5502628b --- /dev/null +++ b/awx/main/tests/functional/dab_resource_registry/test_ansible_id_display.py @@ -0,0 +1,39 @@ +import pytest + +from ansible_base.resource_registry.models import Resource + +from awx.api.versioning import reverse + + +def assert_has_resource(list_response, obj=None): + data = list_response.data + assert 'resource' in data['results'][0]['summary_fields'] + resource_data = data['results'][0]['summary_fields']['resource'] + assert resource_data['ansible_id'] + resource = Resource.objects.filter(ansible_id=resource_data['ansible_id']).first() + assert resource + assert resource.content_object + if obj: + objects = [Resource.objects.get(ansible_id=entry['summary_fields']['resource']['ansible_id']).content_object for entry in data['results']] + assert obj in objects + + +@pytest.mark.django_db +def test_organization_ansible_id(organization, admin_user, get): + url = reverse('api:organization_list') + response = get(url=url, user=admin_user, expect=200) + assert_has_resource(response, obj=organization) + + +@pytest.mark.django_db +def test_team_ansible_id(team, admin_user, get): + url = reverse('api:team_list') + response = get(url=url, user=admin_user, expect=200) + assert_has_resource(response, obj=team) + + +@pytest.mark.django_db +def test_user_ansible_id(rando, admin_user, get): + url = reverse('api:user_list') + response = get(url=url, user=admin_user, expect=200) + assert_has_resource(response, obj=rando) diff --git a/awx/main/tests/functional/dab_resource_registry/test_resource_list.py b/awx/main/tests/functional/dab_resource_registry/test_resource_list.py new file mode 100644 index 000000000000..b57030fb46bc --- /dev/null +++ b/awx/main/tests/functional/dab_resource_registry/test_resource_list.py @@ -0,0 +1,15 @@ +import pytest + +from ansible_base.lib.utils.response import get_relative_url + + +@pytest.mark.django_db +def test_users_in_resource_list(admin_user, rando, get): + url = get_relative_url("resource-list") + get(url=url, expect=200, user=admin_user) + + +@pytest.mark.django_db +def test_user_resource_detail(admin_user, rando, get): + url = get_relative_url("resource-detail", kwargs={'ansible_id': str(rando.resource.ansible_id)}) + get(url=url, expect=200, user=admin_user) diff --git a/awx/main/tests/functional/management/test_dispatcherd.py b/awx/main/tests/functional/management/test_dispatcherd.py new file mode 100644 index 000000000000..92f1d208d9a8 --- /dev/null +++ b/awx/main/tests/functional/management/test_dispatcherd.py @@ -0,0 +1,17 @@ +import pytest + +from awx.main.dispatch.config import get_dispatcherd_config +from awx.main.management.commands.dispatcherd import _hash_config + + +@pytest.mark.django_db +def test_dispatcherd_config_hash_is_stable(settings, monkeypatch): + monkeypatch.setenv('AWX_COMPONENT', 'dispatcher') + settings.CLUSTER_HOST_ID = 'test-node' + settings.JOB_EVENT_WORKERS = 1 + settings.DISPATCHER_SCHEDULE = {} + + config_one = get_dispatcherd_config(for_service=True) + config_two = get_dispatcherd_config(for_service=True) + + assert _hash_config(config_one) == _hash_config(config_two) diff --git a/awx/main/tests/functional/test_inventory_source_migration.py b/awx/main/tests/functional/migrations/test_inventory_source_migration.py similarity index 84% rename from awx/main/tests/functional/test_inventory_source_migration.py rename to awx/main/tests/functional/migrations/test_inventory_source_migration.py index 812b4b45b940..6d17e22936cf 100644 --- a/awx/main/tests/functional/test_inventory_source_migration.py +++ b/awx/main/tests/functional/migrations/test_inventory_source_migration.py @@ -31,15 +31,30 @@ def test_apply_new_instance_id(inventory_source): assert host2.instance_id == 'bad_user' -@pytest.mark.django_db -def test_cloudforms_inventory_removal(inventory): - ManagedCredentialType( +def cleanup_cloudforms(): + if 'cloudforms' in ManagedCredentialType.registry: + del ManagedCredentialType.registry['cloudforms'] + assert 'cloudforms' not in CredentialType.defaults + + +@pytest.fixture +def cloudforms_mct(): + ManagedCredentialType.registry['cloudforms'] = ManagedCredentialType( name='Red Hat CloudForms', namespace='cloudforms', kind='cloud', managed=True, inputs={}, + injectors={}, ) + yield + ManagedCredentialType.registry.pop('cloudforms', None) + + +@pytest.mark.django_db +def test_cloudforms_inventory_removal(request, inventory, cloudforms_mct): + request.addfinalizer(cleanup_cloudforms) + CredentialType.defaults['cloudforms']().save() cloudforms = CredentialType.objects.get(namespace='cloudforms') Credential.objects.create( diff --git a/awx/main/tests/functional/migrations/test_jt_rename_migration.py b/awx/main/tests/functional/migrations/test_jt_rename_migration.py new file mode 100644 index 000000000000..4d624c41be2c --- /dev/null +++ b/awx/main/tests/functional/migrations/test_jt_rename_migration.py @@ -0,0 +1,56 @@ +import pytest + +from awx.main.migrations._db_constraints import _rename_duplicates +from awx.main.models import JobTemplate + + +@pytest.mark.django_db +def test_rename_job_template_duplicates(organization, project): + ids = [] + for i in range(5): + jt = JobTemplate.objects.create(name=f'jt-{i}', organization=organization, project=project) + ids.append(jt.id) # saved in order of creation + + # Hack to first allow duplicate names of JT to test migration + JobTemplate.objects.filter(id__in=ids).update(org_unique=False) + + # Set all JTs to the same name + JobTemplate.objects.filter(id__in=ids).update(name='same_name_for_test') + + _rename_duplicates(JobTemplate) + + first_jt = JobTemplate.objects.get(id=ids[0]) + assert first_jt.name == 'same_name_for_test' + + for i, pk in enumerate(ids): + if i == 0: + continue + jt = JobTemplate.objects.get(id=pk) + # Name should be set based on creation order + assert jt.name == f'same_name_for_test_dup{i}' + + +@pytest.mark.django_db +def test_rename_job_template_name_too_long(organization, project): + ids = [] + for i in range(3): + jt = JobTemplate.objects.create(name=f'jt-{i}', organization=organization, project=project) + ids.append(jt.id) # saved in order of creation + + JobTemplate.objects.filter(id__in=ids).update(org_unique=False) + + chars = 512 + # Set all JTs to the same reaaaaaaly long name + JobTemplate.objects.filter(id__in=ids).update(name='A' * chars) + + _rename_duplicates(JobTemplate) + + first_jt = JobTemplate.objects.get(id=ids[0]) + assert first_jt.name == 'A' * chars + + for i, pk in enumerate(ids): + if i == 0: + continue + jt = JobTemplate.objects.get(id=pk) + assert jt.name.endswith(f'dup{i}') + assert len(jt.name) <= 512 diff --git a/awx/main/tests/functional/migrations/test_org_admin_migration.py b/awx/main/tests/functional/migrations/test_org_admin_migration.py new file mode 100644 index 000000000000..84bed9ac8839 --- /dev/null +++ b/awx/main/tests/functional/migrations/test_org_admin_migration.py @@ -0,0 +1,16 @@ +import pytest + +from django.apps import apps + +from awx.main.models import InstanceGroup +from awx.main.migrations import _OrgAdmin_to_use_ig as orgadmin + + +@pytest.mark.django_db +def test_migrate_admin_role(org_admin, organization): + instance_group = InstanceGroup.objects.create(name='test') + organization.admin_role.members.add(org_admin) + organization.instance_groups.add(instance_group) + orgadmin.migrate_org_admin_to_use(apps, None) + assert org_admin in instance_group.use_role.members.all() + assert instance_group.use_role.members.count() == 1 diff --git a/awx/main/tests/functional/migrations/test_rbac_migration.py b/awx/main/tests/functional/migrations/test_rbac_migration.py new file mode 100644 index 000000000000..8ee411ba1a5a --- /dev/null +++ b/awx/main/tests/functional/migrations/test_rbac_migration.py @@ -0,0 +1,49 @@ +import pytest + +from awx.main.migrations import _rbac as rbac +from awx.main.models import UnifiedJobTemplate, InventorySource, Inventory, JobTemplate, Project, Organization + + +@pytest.mark.django_db +def test_implied_organization_subquery_inventory(): + orgs = [] + for i in range(3): + orgs.append(Organization.objects.create(name='foo{}'.format(i))) + orgs.append(orgs[0]) + for i in range(4): + org = orgs[i] + if i == 2: + inventory = Inventory.objects.create(name='foo{}'.format(i)) + else: + inventory = Inventory.objects.create(name='foo{}'.format(i), organization=org) + inv_src = InventorySource.objects.create(name='foo{}'.format(i), inventory=inventory, source='ec2') + sources = UnifiedJobTemplate.objects.annotate(test_field=rbac.implicit_org_subquery(UnifiedJobTemplate, InventorySource)) + for inv_src in sources: + assert inv_src.test_field == inv_src.inventory.organization_id + + +@pytest.mark.django_db +def test_implied_organization_subquery_job_template(): + jts = [] + for i in range(5): + if i <= 3: + org = Organization.objects.create(name='foo{}'.format(i)) + else: + org = None + if i <= 4: + proj = Project.objects.create(name='foo{}'.format(i), organization=org) + else: + proj = None + jts.append(JobTemplate.objects.create(name='foo{}'.format(i), project=proj)) + # test case of sharing same org + jts[2].project.organization = jts[3].project.organization + jts[2].save() + ujts = UnifiedJobTemplate.objects.annotate(test_field=rbac.implicit_org_subquery(UnifiedJobTemplate, JobTemplate)) + for jt in ujts: + if not isinstance(jt, JobTemplate): # some are projects + assert jt.test_field is None + else: + if jt.project is None: + assert jt.test_field is None + else: + assert jt.test_field == jt.project.organization_id diff --git a/awx/main/tests/functional/migrations/test_token_sjt_removal.py b/awx/main/tests/functional/migrations/test_token_sjt_removal.py new file mode 100644 index 000000000000..35770fd4ca4e --- /dev/null +++ b/awx/main/tests/functional/migrations/test_token_sjt_removal.py @@ -0,0 +1,58 @@ +import pytest +from django.apps import apps +from django.utils.timezone import now + +from awx.main.migrations._create_system_jobs import delete_clear_tokens_sjt + +SJT_NAME = 'Cleanup Expired OAuth 2 Tokens' + + +def create_cleartokens_jt(apps, schema_editor): + # Deleted data migration + SystemJobTemplate = apps.get_model('main', 'SystemJobTemplate') + Schedule = apps.get_model('main', 'Schedule') + ContentType = apps.get_model('contenttypes', 'ContentType') + sjt_ct = ContentType.objects.get_for_model(SystemJobTemplate) + now_dt = now() + schedule_time = now_dt.strftime('%Y%m%dT%H%M%SZ') + + sjt, created = SystemJobTemplate.objects.get_or_create( + job_type='cleanup_tokens', + defaults=dict( + name=SJT_NAME, + description='Cleanup expired OAuth 2 access and refresh tokens', + polymorphic_ctype=sjt_ct, + created=now_dt, + modified=now_dt, + ), + ) + if created: + sched = Schedule( + name=SJT_NAME, + rrule='DTSTART:%s RRULE:FREQ=WEEKLY;INTERVAL=1' % schedule_time, + description='Removes expired OAuth 2 access and refresh tokens', + enabled=True, + created=now_dt, + modified=now_dt, + extra_data={}, + ) + sched.unified_job_template = sjt + sched.save() + + +@pytest.mark.django_db +def test_clear_token_sjt(): + SystemJobTemplate = apps.get_model('main', 'SystemJobTemplate') + Schedule = apps.get_model('main', 'Schedule') + create_cleartokens_jt(apps, None) + qs = SystemJobTemplate.objects.filter(name=SJT_NAME) + assert qs.count() == 1 + sjt = qs.first() + assert Schedule.objects.filter(unified_job_template=sjt).count() == 1 + assert Schedule.objects.filter(unified_job_template__systemjobtemplate__name=SJT_NAME).count() == 1 + + # Now run the migration logic to remove + delete_clear_tokens_sjt(apps, None) + assert SystemJobTemplate.objects.filter(name=SJT_NAME).count() == 0 + # Making sure that the schedule is cleaned up is the main point of this test + assert Schedule.objects.filter(unified_job_template__systemjobtemplate__name=SJT_NAME).count() == 0 diff --git a/awx/main/tests/functional/models/test_activity_stream.py b/awx/main/tests/functional/models/test_activity_stream.py index f8ae40b54054..8be052628d97 100644 --- a/awx/main/tests/functional/models/test_activity_stream.py +++ b/awx/main/tests/functional/models/test_activity_stream.py @@ -104,11 +104,13 @@ def test_auditor_is_recorded(self, post, value): else: assert len(entry_qs) == 1 # unfortunate, the original creation does _not_ set a real is_auditor field - assert 'is_system_auditor' not in json.loads(entry_qs[0].changes) + assert 'is_system_auditor' not in json.loads(entry_qs[0].changes) # NOTE: if this fails, see special note + # special note - if system auditor flag is moved to user model then we expect this assertion to be changed + # make sure that an extra entry is not created, expectation for count would change to 1 if value: - auditor_changes = json.loads(entry_qs[1].changes) - assert auditor_changes['object2'] == 'user' - assert auditor_changes['object2_pk'] == u.pk + entry = entry_qs[1] + assert json.loads(entry.changes) == {'is_system_auditor': [False, True]} + assert entry.object1 == 'user' def test_user_no_op_api(self, system_auditor): as_ct = ActivityStream.objects.count() diff --git a/awx/main/tests/functional/models/test_context_managers.py b/awx/main/tests/functional/models/test_context_managers.py index 9807d8a6e9cb..7dfc0da11729 100644 --- a/awx/main/tests/functional/models/test_context_managers.py +++ b/awx/main/tests/functional/models/test_context_managers.py @@ -1,7 +1,6 @@ import pytest # AWX context managers for testing -from awx.main.models.rbac import batch_role_ancestor_rebuilding from awx.main.signals import disable_activity_stream, disable_computed_fields, update_inventory_computed_fields # AWX models @@ -10,15 +9,6 @@ from awx.main.tests.functional import immediate_on_commit -@pytest.mark.django_db -def test_rbac_batch_rebuilding(rando, organization): - with batch_role_ancestor_rebuilding(): - organization.admin_role.members.add(rando) - inventory = organization.inventories.create(name='test-inventory') - assert rando not in inventory.admin_role - assert rando in inventory.admin_role - - @pytest.mark.django_db def test_disable_activity_stream(): with disable_activity_stream(): @@ -31,13 +21,13 @@ class TestComputedFields: def test_computed_fields_normal_use(self, mocker, inventory): job = Job.objects.create(name='fake-job', inventory=inventory) with immediate_on_commit(): - with mocker.patch.object(update_inventory_computed_fields, 'delay'): - job.delete() - update_inventory_computed_fields.delay.assert_called_once_with(inventory.id) + mocker.patch.object(update_inventory_computed_fields, 'delay') + job.delete() + update_inventory_computed_fields.delay.assert_called_once_with(inventory.id) def test_disable_computed_fields(self, mocker, inventory): job = Job.objects.create(name='fake-job', inventory=inventory) with disable_computed_fields(): - with mocker.patch.object(update_inventory_computed_fields, 'delay'): - job.delete() - update_inventory_computed_fields.delay.assert_not_called() + mocker.patch.object(update_inventory_computed_fields, 'delay') + job.delete() + update_inventory_computed_fields.delay.assert_not_called() diff --git a/awx/main/tests/functional/test_db_credential.py b/awx/main/tests/functional/models/test_db_credential.py similarity index 100% rename from awx/main/tests/functional/test_db_credential.py rename to awx/main/tests/functional/models/test_db_credential.py diff --git a/awx/main/tests/functional/models/test_events.py b/awx/main/tests/functional/models/test_events.py index 758e69b64146..51c1adf529ee 100644 --- a/awx/main/tests/functional/models/test_events.py +++ b/awx/main/tests/functional/models/test_events.py @@ -3,178 +3,212 @@ from django.utils.timezone import now -from awx.main.models import Job, JobEvent, Inventory, Host, JobHostSummary +from django.db.models import Q - -@pytest.mark.django_db -@mock.patch('awx.main.models.events.emit_event_detail') -def test_parent_changed(emit): - j = Job() - j.save() - JobEvent.create_from_data(job_id=j.pk, uuid='abc123', event='playbook_on_task_start').save() - assert JobEvent.objects.count() == 1 - for e in JobEvent.objects.all(): - assert e.changed is False - - JobEvent.create_from_data(job_id=j.pk, parent_uuid='abc123', event='runner_on_ok', event_data={'res': {'changed': ['localhost']}}).save() - # the `playbook_on_stats` event is where we update the parent changed linkage - JobEvent.create_from_data(job_id=j.pk, parent_uuid='abc123', event='playbook_on_stats').save() - events = JobEvent.objects.filter(event__in=['playbook_on_task_start', 'runner_on_ok']) - assert events.count() == 2 - for e in events.all(): - assert e.changed is True - - -@pytest.mark.django_db -@pytest.mark.parametrize('event', JobEvent.FAILED_EVENTS) -@mock.patch('awx.main.models.events.emit_event_detail') -def test_parent_failed(emit, event): - j = Job() - j.save() - JobEvent.create_from_data(job_id=j.pk, uuid='abc123', event='playbook_on_task_start').save() - assert JobEvent.objects.count() == 1 - for e in JobEvent.objects.all(): - assert e.failed is False - - JobEvent.create_from_data(job_id=j.pk, parent_uuid='abc123', event=event).save() - - # the `playbook_on_stats` event is where we update the parent failed linkage - JobEvent.create_from_data(job_id=j.pk, parent_uuid='abc123', event='playbook_on_stats').save() - events = JobEvent.objects.filter(event__in=['playbook_on_task_start', event]) - assert events.count() == 2 - for e in events.all(): - assert e.failed is True - - -@pytest.mark.django_db -def test_host_summary_generation(): - hostnames = [f'Host {i}' for i in range(100)] - inv = Inventory() - inv.save() - Host.objects.bulk_create([Host(created=now(), modified=now(), name=h, inventory_id=inv.id) for h in hostnames]) - j = Job(inventory=inv) - j.save() - host_map = dict((host.name, host.id) for host in inv.hosts.all()) - JobEvent.create_from_data( - job_id=j.pk, - parent_uuid='abc123', - event='playbook_on_stats', - event_data={ - 'ok': dict((hostname, len(hostname)) for hostname in hostnames), - 'changed': {}, - 'dark': {}, - 'failures': {}, - 'ignored': {}, - 'processed': {}, - 'rescued': {}, - 'skipped': {}, - }, - host_map=host_map, - ).save() - - assert j.job_host_summaries.count() == len(hostnames) - assert sorted([s.host_name for s in j.job_host_summaries.all()]) == sorted(hostnames) - - for s in j.job_host_summaries.all(): - assert host_map[s.host_name] == s.host_id - assert s.ok == len(s.host_name) - assert s.changed == 0 - assert s.dark == 0 - assert s.failures == 0 - assert s.ignored == 0 - assert s.processed == 0 - assert s.rescued == 0 - assert s.skipped == 0 - - for host in Host.objects.all(): - assert host.last_job_id == j.id - assert host.last_job_host_summary.host == host - - -@pytest.mark.django_db -def test_host_summary_generation_with_deleted_hosts(): - hostnames = [f'Host {i}' for i in range(10)] - inv = Inventory() - inv.save() - Host.objects.bulk_create([Host(created=now(), modified=now(), name=h, inventory_id=inv.id) for h in hostnames]) - j = Job(inventory=inv) - j.save() - host_map = dict((host.name, host.id) for host in inv.hosts.all()) - - # delete half of the hosts during the playbook run - for h in inv.hosts.all()[:5]: - h.delete() - - JobEvent.create_from_data( - job_id=j.pk, - parent_uuid='abc123', - event='playbook_on_stats', - event_data={ - 'ok': dict((hostname, len(hostname)) for hostname in hostnames), - 'changed': {}, - 'dark': {}, - 'failures': {}, - 'ignored': {}, - 'processed': {}, - 'rescued': {}, - 'skipped': {}, - }, - host_map=host_map, - ).save() - - ids = sorted([s.host_id or -1 for s in j.job_host_summaries.order_by('id').all()]) - names = sorted([s.host_name for s in j.job_host_summaries.all()]) - assert ids == [-1, -1, -1, -1, -1, 6, 7, 8, 9, 10] - assert names == ['Host 0', 'Host 1', 'Host 2', 'Host 3', 'Host 4', 'Host 5', 'Host 6', 'Host 7', 'Host 8', 'Host 9'] +from awx.main.models import Job, JobEvent, Inventory, Host, JobHostSummary, HostMetric @pytest.mark.django_db -def test_host_summary_generation_with_limit(): - # Make an inventory with 10 hosts, run a playbook with a --limit - # pointed at *one* host, - # Verify that *only* that host has an associated JobHostSummary and that - # *only* that host has an updated value for .last_job. - hostnames = [f'Host {i}' for i in range(10)] - inv = Inventory() - inv.save() - Host.objects.bulk_create([Host(created=now(), modified=now(), name=h, inventory_id=inv.id) for h in hostnames]) - j = Job(inventory=inv) - j.save() - - # host map is a data structure that tracks a mapping of host name --> ID - # for the inventory, _regardless_ of whether or not there's a limit - # applied to the actual playbook run - host_map = dict((host.name, host.id) for host in inv.hosts.all()) - - # by making the playbook_on_stats *only* include Host 1, we're emulating - # the behavior of a `--limit=Host 1` - matching_host = Host.objects.get(name='Host 1') - JobEvent.create_from_data( - job_id=j.pk, +class TestEvents: + def setup_method(self): + self.hostnames = [] + self.host_map = dict() + self.inventory = None + self.job = None + + @mock.patch('awx.main.models.events.emit_event_detail') + def test_parent_changed(self, emit): + j = Job() + j.save() + JobEvent.create_from_data(job_id=j.pk, uuid='abc123', event='playbook_on_task_start').save() + assert JobEvent.objects.count() == 1 + for e in JobEvent.objects.all(): + assert e.changed is False + + JobEvent.create_from_data(job_id=j.pk, parent_uuid='abc123', event='runner_on_ok', event_data={'res': {'changed': ['localhost']}}).save() + # the `playbook_on_stats` event is where we update the parent changed linkage + JobEvent.create_from_data(job_id=j.pk, parent_uuid='abc123', event='playbook_on_stats').save() + events = JobEvent.objects.filter(event__in=['playbook_on_task_start', 'runner_on_ok']) + assert events.count() == 2 + for e in events.all(): + assert e.changed is True + + @pytest.mark.parametrize('event', JobEvent.FAILED_EVENTS) + @mock.patch('awx.main.models.events.emit_event_detail') + def test_parent_failed(self, emit, event): + j = Job() + j.save() + JobEvent.create_from_data(job_id=j.pk, uuid='abc123', event='playbook_on_task_start').save() + assert JobEvent.objects.count() == 1 + for e in JobEvent.objects.all(): + assert e.failed is False + + JobEvent.create_from_data(job_id=j.pk, parent_uuid='abc123', event=event).save() + + # the `playbook_on_stats` event is where we update the parent failed linkage + JobEvent.create_from_data(job_id=j.pk, parent_uuid='abc123', event='playbook_on_stats').save() + events = JobEvent.objects.filter(event__in=['playbook_on_task_start', event]) + assert events.count() == 2 + for e in events.all(): + assert e.failed is True + + def test_host_summary_generation(self): + self._generate_hosts(100) + self._create_job_event(ok=dict((hostname, len(hostname)) for hostname in self.hostnames)) + + assert self.job.job_host_summaries.count() == len(self.hostnames) + assert sorted([s.host_name for s in self.job.job_host_summaries.all()]) == sorted(self.hostnames) + + for s in self.job.job_host_summaries.all(): + assert self.host_map[s.host_name] == s.host_id + assert s.ok == len(s.host_name) + assert s.changed == 0 + assert s.dark == 0 + assert s.failures == 0 + assert s.ignored == 0 + assert s.processed == 0 + assert s.rescued == 0 + assert s.skipped == 0 + + for host in Host.objects.all(): + assert host.last_job_id == self.job.id + assert host.last_job_host_summary.host == host + + def test_host_summary_generation_with_deleted_hosts(self): + self._generate_hosts(10) + + # delete half of the hosts during the playbook run + for h in self.inventory.hosts.all()[:5]: + h.delete() + + self._create_job_event(ok=dict((hostname, len(hostname)) for hostname in self.hostnames)) + + ids = sorted([s.host_id or -1 for s in self.job.job_host_summaries.order_by('id').all()]) + names = sorted([s.host_name for s in self.job.job_host_summaries.all()]) + assert ids == [-1, -1, -1, -1, -1, 6, 7, 8, 9, 10] + assert names == ['Host 0', 'Host 1', 'Host 2', 'Host 3', 'Host 4', 'Host 5', 'Host 6', 'Host 7', 'Host 8', 'Host 9'] + + def test_host_summary_generation_with_limit(self): + # Make an inventory with 10 hosts, run a playbook with a --limit + # pointed at *one* host, + # Verify that *only* that host has an associated JobHostSummary and that + # *only* that host has an updated value for .last_job. + self._generate_hosts(10) + + # by making the playbook_on_stats *only* include Host 1, we're emulating + # the behavior of a `--limit=Host 1` + matching_host = Host.objects.get(name='Host 1') + self._create_job_event(ok={matching_host.name: len(matching_host.name)}) # effectively, limit=Host 1 + + # since the playbook_on_stats only references one host, + # there should *only* be on JobHostSummary record (and it should + # be related to the appropriate Host) + assert JobHostSummary.objects.count() == 1 + for h in Host.objects.all(): + if h.name == 'Host 1': + assert h.last_job_id == self.job.id + assert h.last_job_host_summary_id == JobHostSummary.objects.first().id + else: + # all other hosts in the inventory should remain untouched + assert h.last_job_id is None + assert h.last_job_host_summary_id is None + + def test_host_metrics_insert(self): + self._generate_hosts(10) + + self._create_job_event( + ok=dict((hostname, len(hostname)) for hostname in self.hostnames[0:3]), + failures=dict((hostname, len(hostname)) for hostname in self.hostnames[3:6]), + processed=dict((hostname, len(hostname)) for hostname in self.hostnames[6:9]), + skipped=dict((hostname, len(hostname)) for hostname in [self.hostnames[9]]), + ) + + metrics = HostMetric.objects.all() + assert len(metrics) == 10 + for hm in metrics: + assert hm.automated_counter == 1 + assert hm.last_automation is not None + assert hm.deleted is False + + def test_host_metrics_update(self): + self._generate_hosts(12) + + self._create_job_event(ok=dict((hostname, len(hostname)) for hostname in self.hostnames)) + + # Soft delete 6 of the 12 host metrics, every even host like "Host 2" or "Host 4" + for host_name in self.hostnames[::2]: + hm = HostMetric.objects.get(hostname=host_name.lower()) + hm.soft_delete() + + assert len(HostMetric.objects.filter(Q(deleted=False) & Q(deleted_counter=0) & Q(last_deleted__isnull=True))) == 6 + assert len(HostMetric.objects.filter(Q(deleted=True) & Q(deleted_counter=1) & Q(last_deleted__isnull=False))) == 6 + + # hostnames in 'ignored' and 'rescued' stats are ignored + self.job = Job(inventory=self.inventory) + self.job.save() + self._create_job_event( + ignored=dict((hostname, len(hostname)) for hostname in self.hostnames[0:6]), + rescued=dict((hostname, len(hostname)) for hostname in self.hostnames[6:11]), + ) + + assert len(HostMetric.objects.filter(Q(deleted=False) & Q(deleted_counter=0) & Q(last_deleted__isnull=True))) == 6 + assert len(HostMetric.objects.filter(Q(deleted=True) & Q(deleted_counter=1) & Q(last_deleted__isnull=False))) == 6 + + # hostnames in 'changed', 'dark', 'failures', 'ok', 'processed', 'skipped' are processed + self.job = Job(inventory=self.inventory) + self.job.save() + self._create_job_event( + changed=dict((hostname, len(hostname)) for hostname in self.hostnames[0:2]), + dark=dict((hostname, len(hostname)) for hostname in self.hostnames[2:4]), + failures=dict((hostname, len(hostname)) for hostname in self.hostnames[4:6]), + ok=dict((hostname, len(hostname)) for hostname in self.hostnames[6:8]), + processed=dict((hostname, len(hostname)) for hostname in self.hostnames[8:10]), + skipped=dict((hostname, len(hostname)) for hostname in self.hostnames[10:12]), + ) + assert len(HostMetric.objects.filter(Q(deleted=False) & Q(deleted_counter=0) & Q(last_deleted__isnull=True))) == 6 + + # one of those 6 hosts is dark, so will not be counted + assert len(HostMetric.objects.filter(Q(deleted=False) & Q(deleted_counter=1) & Q(last_deleted__isnull=False))) == 5 + + def _generate_hosts(self, cnt, id_from=0): + self.hostnames = [f'Host {i}' for i in range(id_from, id_from + cnt)] + self.inventory = Inventory() + self.inventory.save() + Host.objects.bulk_create([Host(created=now(), modified=now(), name=h, inventory_id=self.inventory.id) for h in self.hostnames]) + self.job = Job(inventory=self.inventory) + self.job.save() + + # host map is a data structure that tracks a mapping of host name --> ID + # for the inventory, _regardless_ of whether or not there's a limit + # applied to the actual playbook run + self.host_map = dict((host.name, host.id) for host in self.inventory.hosts.all()) + + def _create_job_event( + self, parent_uuid='abc123', event='playbook_on_stats', - event_data={ - 'ok': {matching_host.name: len(matching_host.name)}, # effectively, limit=Host 1 - 'changed': {}, - 'dark': {}, - 'failures': {}, - 'ignored': {}, - 'processed': {}, - 'rescued': {}, - 'skipped': {}, - }, - host_map=host_map, - ).save() - - # since the playbook_on_stats only references one host, - # there should *only* be on JobHostSummary record (and it should - # be related to the appropriate Host) - assert JobHostSummary.objects.count() == 1 - for h in Host.objects.all(): - if h.name == 'Host 1': - assert h.last_job_id == j.id - assert h.last_job_host_summary_id == JobHostSummary.objects.first().id - else: - # all other hosts in the inventory should remain untouched - assert h.last_job_id is None - assert h.last_job_host_summary_id is None + ok=None, + changed=None, + dark=None, + failures=None, + ignored=None, + processed=None, + rescued=None, + skipped=None, + ): + JobEvent.create_from_data( + job_id=self.job.pk, + parent_uuid=parent_uuid, + event=event, + event_data={ + 'ok': ok or {}, + 'changed': changed or {}, + 'dark': dark or {}, + 'failures': failures or {}, + 'ignored': ignored or {}, + 'processed': processed or {}, + 'rescued': rescued or {}, + 'skipped': skipped or {}, + }, + host_map=self.host_map, + ).save() diff --git a/awx/main/tests/functional/models/test_ha.py b/awx/main/tests/functional/models/test_ha.py new file mode 100644 index 000000000000..c8ee9dc0a7b3 --- /dev/null +++ b/awx/main/tests/functional/models/test_ha.py @@ -0,0 +1,45 @@ +import pytest + +# AWX +from awx.main.ha import is_ha_environment +from awx.main.models.ha import Instance +from awx.main.utils.common import get_auto_max_workers + +# Django +from django.test.utils import override_settings + + +@pytest.mark.django_db +def test_multiple_instances(): + for i in range(2): + Instance.objects.create(hostname=f'foo{i}', node_type='hybrid') + assert is_ha_environment() + + +@pytest.mark.django_db +def test_db_localhost(): + Instance.objects.create(hostname='foo', node_type='hybrid') + Instance.objects.create(hostname='bar', node_type='execution') + assert is_ha_environment() is False + + +@pytest.mark.django_db +@pytest.mark.parametrize( + 'settings', + [ + dict(SYSTEM_TASK_ABS_MEM='16Gi', SYSTEM_TASK_ABS_CPU='24', SYSTEM_TASK_FORKS_MEM=400, SYSTEM_TASK_FORKS_CPU=4), + dict(SYSTEM_TASK_ABS_MEM='124Gi', SYSTEM_TASK_ABS_CPU='2', SYSTEM_TASK_FORKS_MEM=None, SYSTEM_TASK_FORKS_CPU=None), + ], + ids=['cpu_dominated', 'memory_dominated'], +) +def test_dispatcher_max_workers_reserve(settings, fake_redis): + """This tests that the dispatcher max_workers matches instance capacity + + Assumes capacity_adjustment is 1, + plus reserve worker count + """ + with override_settings(**settings): + i = Instance.objects.create(hostname='test-1', node_type='hybrid') + i.local_health_check() + + assert get_auto_max_workers() == i.capacity + 7, (i.cpu, i.memory, i.cpu_capacity, i.mem_capacity) diff --git a/awx/main/tests/functional/models/test_host_metric.py b/awx/main/tests/functional/models/test_host_metric.py index 1f560e474fec..dad829543590 100644 --- a/awx/main/tests/functional/models/test_host_metric.py +++ b/awx/main/tests/functional/models/test_host_metric.py @@ -20,3 +20,53 @@ def test_host_metrics_generation(): date_today = now().strftime('%Y-%m-%d') result = HostMetric.objects.filter(first_automation__startswith=date_today).count() assert result == len(hostnames) + + +@pytest.mark.django_db +def test_soft_delete(): + hostnames = [f'Host to delete {i}' for i in range(2)] + current_time = now() + HostMetric.objects.bulk_create([HostMetric(hostname=h, last_automation=current_time, automated_counter=42) for h in hostnames]) + + hm = HostMetric.objects.get(hostname="Host to delete 0") + assert hm.last_deleted is None + + last_deleted = None + for _ in range(3): + # soft delete 1st + # 2nd/3rd delete don't have an effect + hm.soft_delete() + if last_deleted is None: + last_deleted = hm.last_deleted + + assert hm.deleted is True + assert hm.deleted_counter == 1 + assert hm.last_deleted == last_deleted + assert hm.automated_counter == 42 + + # 2nd record is not touched + hm = HostMetric.objects.get(hostname="Host to delete 1") + assert hm.deleted is False + assert hm.deleted_counter == 0 + assert hm.last_deleted is None + assert hm.automated_counter == 42 + + +@pytest.mark.django_db +def test_soft_restore(): + current_time = now() + HostMetric.objects.create(hostname="Host 1", last_automation=current_time, deleted=True) + HostMetric.objects.create(hostname="Host 2", last_automation=current_time, deleted=True, last_deleted=current_time) + HostMetric.objects.create(hostname="Host 3", last_automation=current_time, deleted=False, last_deleted=current_time) + HostMetric.objects.all().update(automated_counter=42, deleted_counter=10) + + # 1. deleted, last_deleted not null + for hm in HostMetric.objects.all(): + for _ in range(3): + hm.soft_restore() + assert hm.deleted is False + assert hm.automated_counter == 42 and hm.deleted_counter == 10 + if hm.hostname == "Host 1": + assert hm.last_deleted is None + else: + assert hm.last_deleted == current_time diff --git a/awx/main/tests/functional/models/test_inventory.py b/awx/main/tests/functional/models/test_inventory.py index a1db473d3ed0..3a739a3b815e 100644 --- a/awx/main/tests/functional/models/test_inventory.py +++ b/awx/main/tests/functional/models/test_inventory.py @@ -5,8 +5,8 @@ # AWX from awx.main.models import Host, Inventory, InventorySource, InventoryUpdate, CredentialType, Credential, Job -from awx.main.constants import CLOUD_PROVIDERS from awx.main.utils.filters import SmartFilter +from awx.main.utils.plugins import discover_available_cloud_provider_plugin_names @pytest.mark.django_db @@ -166,10 +166,11 @@ def test_extra_credentials(self, project, credential): def test_all_cloud_sources_covered(self): """Code in several places relies on the fact that the older - CLOUD_PROVIDERS constant contains the same names as what are + discover_cloud_provider_plugin_names returns the same names as what are defined within the injectors """ - assert set(CLOUD_PROVIDERS) == set(InventorySource.injectors.keys()) + # slight exception case for constructed, because it has a FQCN but is not a cloud source + assert set(discover_available_cloud_provider_plugin_names()) | set(['constructed']) == set(InventorySource.injectors.keys()) @pytest.mark.parametrize('source,filename', [('ec2', 'aws_ec2.yml'), ('openstack', 'openstack.yml'), ('gce', 'gcp_compute.yml')]) def test_plugin_filenames(self, source, filename): @@ -192,6 +193,7 @@ def test_plugin_filenames(self, source, filename): ('satellite6', 'theforeman.foreman.foreman'), ('insights', 'redhatinsights.insights.insights'), ('controller', 'awx.awx.tower'), + ('terraform', 'cloud.terraform.terraform_state'), ], ) def test_plugin_proper_names(self, source, proper_name): @@ -270,6 +272,7 @@ def test_inventory_update_excessively_long_name(inventory, inventory_source): class TestHostManager: def test_host_filter_not_smart(self, setup_ec2_gce, organization): smart_inventory = Inventory(name='smart', organization=organization, host_filter='inventory_sources__source=ec2') + smart_inventory.save() assert len(smart_inventory.hosts.all()) == 0 def test_host_distinctness(self, setup_inventory_groups, organization): diff --git a/awx/main/tests/functional/models/test_notifications.py b/awx/main/tests/functional/models/test_notifications.py index 2d1d5e0f1719..2c1d6022de45 100644 --- a/awx/main/tests/functional/models/test_notifications.py +++ b/awx/main/tests/functional/models/test_notifications.py @@ -98,7 +98,7 @@ def check_structure(self, expected_structure, obj): @pytest.mark.django_db @pytest.mark.parametrize('JobClass', [AdHocCommand, InventoryUpdate, Job, ProjectUpdate, SystemJob, WorkflowJob]) - def test_context(self, JobClass, sqlite_copy_expert, project, inventory_source): + def test_context(self, JobClass, sqlite_copy, project, inventory_source): """The Jinja context defines all of the fields that can be used by a template. Ensure that the context generated for each job type has the expected structure.""" kwargs = {} diff --git a/awx/main/tests/functional/models/test_schedule.py b/awx/main/tests/functional/models/test_schedule.py index 6ad711537386..97051ae45f0e 100644 --- a/awx/main/tests/functional/models/test_schedule.py +++ b/awx/main/tests/functional/models/test_schedule.py @@ -1,11 +1,11 @@ -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone from contextlib import contextmanager +from zoneinfo import ZoneInfo from django.utils.timezone import now from django.db.utils import IntegrityError from unittest import mock import pytest -import pytz from awx.main.models import JobTemplate, Schedule, ActivityStream @@ -76,7 +76,7 @@ def test_computed_fields_time_change(self, job_template): with self.assert_no_unwanted_stuff(s): # force update of next_run, as if schedule re-calculation had not happened # since this time - old_next_run = datetime(2009, 3, 13, tzinfo=pytz.utc) + old_next_run = datetime(2009, 3, 13, tzinfo=timezone.utc) Schedule.objects.filter(pk=s.pk).update(next_run=old_next_run) s.next_run = old_next_run prior_modified = s.modified @@ -121,30 +121,16 @@ def test_computed_fields_turning_off_by_deleting(self, job_template): assert job_template.next_schedule == expected_schedule -@pytest.mark.django_db -@pytest.mark.parametrize('freq, delta', (('MINUTELY', 1), ('HOURLY', 1))) -def test_past_week_rrule(job_template, freq, delta): - # see: https://github.com/ansible/awx/issues/8071 - recent = datetime.utcnow() - timedelta(days=3) - recent = recent.replace(hour=0, minute=0, second=0, microsecond=0) - recent_dt = recent.strftime('%Y%m%d') - rrule = f'DTSTART;TZID=America/New_York:{recent_dt}T000000 RRULE:FREQ={freq};INTERVAL={delta};COUNT=5' # noqa - sched = Schedule.objects.create(name='example schedule', rrule=rrule, unified_job_template=job_template) - first_event = sched.rrulestr(sched.rrule)[0] - assert first_event.replace(tzinfo=None) == recent - - @pytest.mark.django_db @pytest.mark.parametrize('freq, delta', (('MINUTELY', 1), ('HOURLY', 1))) def test_really_old_dtstart(job_template, freq, delta): # see: https://github.com/ansible/awx/issues/8071 # If an event is per-minute/per-hour and was created a *really long* - # time ago, we should just bump forward to start counting "in the last week" + # time ago, we should just bump forward the dtstart rrule = f'DTSTART;TZID=America/New_York:20150101T000000 RRULE:FREQ={freq};INTERVAL={delta}' # noqa sched = Schedule.objects.create(name='example schedule', rrule=rrule, unified_job_template=job_template) - last_week = (datetime.utcnow() - timedelta(days=7)).date() first_event = sched.rrulestr(sched.rrule)[0] - assert last_week == first_event.date() + assert now() - first_event < timedelta(days=1) # the next few scheduled events should be the next minute/hour incremented next_five_events = list(sched.rrulestr(sched.rrule).xafter(now(), count=5)) @@ -273,7 +259,7 @@ def test_utc_until_in_the_past(job_template): @pytest.mark.django_db -@mock.patch('awx.main.models.schedules.now', lambda: datetime(2030, 3, 5, tzinfo=pytz.utc)) +@mock.patch('awx.main.models.schedules.now', lambda: datetime(2030, 3, 5, tzinfo=timezone.utc)) def test_dst_phantom_hour(job_template): # The DST period in the United States begins at 02:00 (2 am) local time, so # the hour from 2:00:00 to 2:59:59 does not exist in the night of the @@ -470,15 +456,15 @@ def test_skip_sundays(): RRULE:INTERVAL=1;FREQ=DAILY EXRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=SU ''' - timezone = pytz.timezone("America/New_York") - friday_apr_29th = datetime(2022, 4, 29, 0, 0, 0, 0, timezone) - monday_may_2nd = datetime(2022, 5, 2, 23, 59, 59, 999, timezone) + tz = ZoneInfo("America/New_York") + friday_apr_29th = datetime(2022, 4, 29, 0, 0, 0, 0, tz) + monday_may_2nd = datetime(2022, 5, 2, 23, 59, 59, 999, tz) ruleset = Schedule.rrulestr(rrule) gen = ruleset.between(friday_apr_29th, monday_may_2nd, True) # We should only get Fri, Sat and Mon (skipping Sunday) assert len(list(gen)) == 3 - saturday_night = datetime(2022, 4, 30, 23, 59, 59, 9999, timezone) - monday_morning = datetime(2022, 5, 2, 0, 0, 0, 0, timezone) + saturday_night = datetime(2022, 4, 30, 23, 59, 59, 9999, tz) + monday_morning = datetime(2022, 5, 2, 0, 0, 0, 0, tz) gen = ruleset.between(saturday_night, monday_morning, True) assert len(list(gen)) == 0 @@ -490,17 +476,17 @@ def test_skip_sundays(): [ pytest.param( 'DTSTART;TZID=America/New_York:20210310T150000 RRULE:INTERVAL=1;FREQ=DAILY;UNTIL=20210430T150000Z EXRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=SU;COUNT=5', - datetime(2021, 4, 29, 19, 0, 0, tzinfo=pytz.utc), + datetime(2021, 4, 29, 19, 0, 0, tzinfo=timezone.utc), id="Single rule in rule set with UTC TZ aware until", ), pytest.param( 'DTSTART;TZID=America/New_York:20220310T150000 RRULE:INTERVAL=1;FREQ=DAILY;UNTIL=20220430T150000 EXRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=SU;COUNT=5', - datetime(2022, 4, 30, 19, 0, tzinfo=pytz.utc), + datetime(2022, 4, 30, 19, 0, tzinfo=timezone.utc), id="Single rule in ruleset with naive until", ), pytest.param( 'DTSTART;TZID=America/New_York:20220310T150000 RRULE:INTERVAL=1;FREQ=DAILY;COUNT=4 EXRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=SU;COUNT=5', - datetime(2022, 3, 12, 20, 0, tzinfo=pytz.utc), + datetime(2022, 3, 12, 20, 0, tzinfo=timezone.utc), id="Single rule in ruleset with count", ), pytest.param( @@ -515,12 +501,12 @@ def test_skip_sundays(): ), pytest.param( 'DTSTART;TZID=America/New_York:20220310T150000 RRULE:INTERVAL=1;FREQ=DAILY;UNTIL=20220430T150000Z', - datetime(2022, 4, 29, 19, 0, tzinfo=pytz.utc), + datetime(2022, 4, 29, 19, 0, tzinfo=timezone.utc), id="Single rule in rule with UTZ TZ aware until", ), pytest.param( 'DTSTART;TZID=America/New_York:20220310T150000 RRULE:INTERVAL=1;FREQ=DAILY;UNTIL=20220430T150000', - datetime(2022, 4, 30, 19, 0, tzinfo=pytz.utc), + datetime(2022, 4, 30, 19, 0, tzinfo=timezone.utc), id="Single rule in rule with naive until", ), pytest.param( @@ -535,12 +521,12 @@ def test_skip_sundays(): ), pytest.param( 'DTSTART;TZID=America/New_York:20220310T150000 RRULE:INTERVAL=1;FREQ=DAILY;BYDAY=SU;UNTIL=20220430T1500Z RRULE:INTERVAL=1;FREQ=DAILY;BYDAY=MO;COUNT=4', - datetime(2022, 4, 24, 19, 0, tzinfo=pytz.utc), + datetime(2022, 4, 24, 19, 0, tzinfo=timezone.utc), id="Multi rule one with until and one with an count", ), pytest.param( 'DTSTART;TZID=America/New_York:20010430T1500 RRULE:INTERVAL=1;FREQ=DAILY;BYDAY=SU;COUNT=1', - datetime(2001, 5, 6, 19, 0, tzinfo=pytz.utc), + datetime(2001, 5, 6, 19, 0, tzinfo=timezone.utc), id="Rule with count but ends in the past", ), pytest.param( diff --git a/awx/main/tests/functional/models/test_unified_job.py b/awx/main/tests/functional/models/test_unified_job.py index 389ea731b91c..0618085cef5f 100644 --- a/awx/main/tests/functional/models/test_unified_job.py +++ b/awx/main/tests/functional/models/test_unified_job.py @@ -1,28 +1,23 @@ import itertools import pytest +from uuid import uuid4 # CRUM from crum import impersonate -# Django -from django.contrib.contenttypes.models import ContentType - # AWX -from awx.main.models import UnifiedJobTemplate, Job, JobTemplate, WorkflowJobTemplate, WorkflowApprovalTemplate, Project, WorkflowJob, Schedule, Credential +from awx.main.models import UnifiedJobTemplate, Job, JobTemplate, WorkflowJobTemplate, Project, WorkflowJob, Schedule, Credential from awx.api.versioning import reverse from awx.main.constants import JOB_VARIABLE_PREFIXES @pytest.mark.django_db -def test_subclass_types(rando): - assert set(UnifiedJobTemplate._submodels_with_roles()) == set( - [ - ContentType.objects.get_for_model(JobTemplate).id, - ContentType.objects.get_for_model(Project).id, - ContentType.objects.get_for_model(WorkflowJobTemplate).id, - ContentType.objects.get_for_model(WorkflowApprovalTemplate).id, - ] - ) +def test_subclass_types(): + assert set(UnifiedJobTemplate._submodels_with_roles()) == { + JobTemplate, + Project, + WorkflowJobTemplate, + } @pytest.mark.django_db @@ -39,6 +34,64 @@ def test_soft_unique_together(post, project, admin_user): assert 'combination already exists' in str(r.data) +@pytest.mark.django_db +class TestJobCancel: + """ + Coverage for UnifiedJob.cancel, focused on interaction with dispatcherd objects. + Using mocks for the dispatcherd objects, because tests by default use a no-op broker. + """ + + def test_cancel_sets_flag_and_clears_start_args(self, mocker): + job = Job.objects.create(status='running', name='foo-job', celery_task_id=str(uuid4()), controller_node='foo', start_args='{"secret": "value"}') + job.websocket_emit_status = mocker.MagicMock() + + assert job.can_cancel is True + assert job.cancel_flag is False + + job.cancel() + job.refresh_from_db() + + assert job.cancel_flag is True + assert job.start_args == '' + + def test_cancel_sets_job_explanation(self, mocker): + job = Job.objects.create(status='running', name='foo-job', celery_task_id=str(uuid4()), controller_node='foo') + job.websocket_emit_status = mocker.MagicMock() + job_explanation = 'giggity giggity' + + job.cancel(job_explanation=job_explanation) + job.refresh_from_db() + + assert job.job_explanation == job_explanation + + def test_cancel_sends_control_message(self, mocker): + celery_task_id = str(uuid4()) + job = Job.objects.create(status='running', name='foo-job', celery_task_id=celery_task_id, controller_node='foo') + job.websocket_emit_status = mocker.MagicMock() + control = mocker.MagicMock() + get_control = mocker.patch('awx.main.models.unified_jobs.get_control_from_settings', return_value=control) + + job.cancel() + + get_control.assert_called_once_with(default_publish_channel='foo') + control.control.assert_called_once_with('cancel', data={'uuid': celery_task_id}) + + def test_cancel_refreshes_task_id_before_sending_control(self, mocker): + job = Job.objects.create(status='pending', name='foo-job', celery_task_id='', controller_node='bar') + job.websocket_emit_status = mocker.MagicMock() + celery_task_id = str(uuid4()) + Job.objects.filter(pk=job.pk).update(status='running', celery_task_id=celery_task_id) + control = mocker.MagicMock() + get_control = mocker.patch('awx.main.models.unified_jobs.get_control_from_settings', return_value=control) + refresh_spy = mocker.spy(job, 'refresh_from_db') + + job.cancel() + + refresh_spy.assert_called_once_with(fields=['celery_task_id', 'controller_node']) + get_control.assert_called_once_with(default_publish_channel='bar') + control.control.assert_called_once_with('cancel', data={'uuid': celery_task_id}) + + @pytest.mark.django_db class TestCreateUnifiedJob: """ diff --git a/awx/main/tests/functional/models/test_workflow.py b/awx/main/tests/functional/models/test_workflow.py index a21fbaa73bc1..924b5346c550 100644 --- a/awx/main/tests/functional/models/test_workflow.py +++ b/awx/main/tests/functional/models/test_workflow.py @@ -377,7 +377,7 @@ def test_apply_workflow_job_prompts(self, workflow_job_template, wfjt_prompts, p assert workflow_job.scm_branch is None assert workflow_job.job_tags is None assert workflow_job.skip_tags is None - assert len(workflow_job.labels.all()) is 0 + assert len(workflow_job.labels.all()) == 0 # fields from prompts used workflow_job = workflow_job_template.create_unified_job(**prompts_data) diff --git a/awx/main/tests/functional/test_rbac_api.py b/awx/main/tests/functional/rbac/test_rbac_api.py similarity index 90% rename from awx/main/tests/functional/test_rbac_api.py rename to awx/main/tests/functional/rbac/test_rbac_api.py index b697ef3144c2..61e7425c4da1 100644 --- a/awx/main/tests/functional/test_rbac_api.py +++ b/awx/main/tests/functional/rbac/test_rbac_api.py @@ -3,7 +3,9 @@ from django.db import transaction from awx.api.versioning import reverse -from awx.main.models.rbac import Role, ROLE_SINGLETON_SYSTEM_ADMINISTRATOR +from awx.main.models.rbac import Role + +from django.test.utils import override_settings @pytest.fixture @@ -31,8 +33,6 @@ def test_get_roles_list_user(organization, inventory, team, get, user): 'Users can see all roles they have access to, but not all roles' this_user = user('user-test_get_roles_list_user') organization.member_role.members.add(this_user) - custom_role = Role.objects.create(role_field='custom_role-test_get_roles_list_user') - organization.member_role.children.add(custom_role) url = reverse('api:role_list') response = get(url, this_user) @@ -46,10 +46,8 @@ def test_get_roles_list_user(organization, inventory, team, get, user): for r in roles['results']: role_hash[r['id']] = r - assert Role.singleton(ROLE_SINGLETON_SYSTEM_ADMINISTRATOR).id in role_hash assert organization.admin_role.id in role_hash assert organization.member_role.id in role_hash - assert custom_role.id in role_hash assert inventory.admin_role.id not in role_hash assert team.member_role.id not in role_hash @@ -57,7 +55,8 @@ def test_get_roles_list_user(organization, inventory, team, get, user): @pytest.mark.django_db def test_roles_visibility(get, organization, project, admin, alice, bob): - Role.singleton('system_auditor').members.add(alice) + alice.is_system_auditor = True + alice.save() assert get(reverse('api:role_list') + '?id=%d' % project.update_role.id, user=admin).data['count'] == 1 assert get(reverse('api:role_list') + '?id=%d' % project.update_role.id, user=alice).data['count'] == 1 assert get(reverse('api:role_list') + '?id=%d' % project.update_role.id, user=bob).data['count'] == 0 @@ -67,7 +66,8 @@ def test_roles_visibility(get, organization, project, admin, alice, bob): @pytest.mark.django_db def test_roles_filter_visibility(get, organization, project, admin, alice, bob): - Role.singleton('system_auditor').members.add(alice) + alice.is_system_auditor = True + alice.save() project.update_role.members.add(admin) assert get(reverse('api:user_roles_list', kwargs={'pk': admin.id}) + '?id=%d' % project.update_role.id, user=admin).data['count'] == 1 @@ -105,15 +105,6 @@ def test_cant_delete_role(delete, admin, inventory): # -@pytest.mark.django_db -def test_get_user_roles_list(get, admin): - url = reverse('api:user_roles_list', kwargs={'pk': admin.id}) - response = get(url, admin) - assert response.status_code == 200 - roles = response.data - assert roles['count'] > 0 # 'system_administrator' role if nothing else - - @pytest.mark.django_db def test_user_view_other_user_roles(organization, inventory, team, get, alice, bob): 'Users can see roles for other users, but only the roles that that user has access to see as well' @@ -141,7 +132,6 @@ def test_user_view_other_user_roles(organization, inventory, team, get, alice, b assert organization.admin_role.id in role_hash assert custom_role.id not in role_hash # doesn't show up in the user roles list, not an explicit grant - assert Role.singleton(ROLE_SINGLETON_SYSTEM_ADMINISTRATOR).id not in role_hash assert inventory.admin_role.id not in role_hash assert team.member_role.id not in role_hash # alice can't see this @@ -197,6 +187,7 @@ def test_remove_role_from_user(role, post, admin): @pytest.mark.django_db +@override_settings(ANSIBLE_BASE_ALLOW_TEAM_ORG_ADMIN=True, ANSIBLE_BASE_ALLOW_TEAM_ORG_MEMBER=True) def test_get_teams_roles_list(get, team, organization, admin): team.member_role.children.add(organization.admin_role) url = reverse('api:team_roles_list', kwargs={'pk': team.id}) @@ -396,36 +387,6 @@ def test_remove_team_from_role(post, team, admin, role): assert role.parents.filter(id=team.member_role.id).count() == 0 -# -# /roles//parents/ -# - - -@pytest.mark.django_db -def test_role_parents(get, team, admin, role): - role.parents.add(team.member_role) - url = reverse('api:role_parents_list', kwargs={'pk': role.id}) - response = get(url, admin) - assert response.status_code == 200 - assert response.data['count'] == 1 - assert response.data['results'][0]['id'] == team.member_role.id - - -# -# /roles//children/ -# - - -@pytest.mark.django_db -def test_role_children(get, team, admin, role): - role.parents.add(team.member_role) - url = reverse('api:role_children_list', kwargs={'pk': team.member_role.id}) - response = get(url, admin) - assert response.status_code == 200 - assert response.data['count'] == 2 - assert response.data['results'][0]['id'] == role.id or response.data['results'][1]['id'] == role.id - - # # Generics # diff --git a/awx/main/tests/functional/test_rbac_credential.py b/awx/main/tests/functional/rbac/test_rbac_credential.py similarity index 100% rename from awx/main/tests/functional/test_rbac_credential.py rename to awx/main/tests/functional/rbac/test_rbac_credential.py diff --git a/awx/main/tests/functional/rbac/test_rbac_execution_environment.py b/awx/main/tests/functional/rbac/test_rbac_execution_environment.py new file mode 100644 index 000000000000..b6d98f073b9e --- /dev/null +++ b/awx/main/tests/functional/rbac/test_rbac_execution_environment.py @@ -0,0 +1,147 @@ +import pytest + +from awx.main.access import ExecutionEnvironmentAccess +from awx.main.models import ExecutionEnvironment, Organization, Team +from awx.main.models.rbac import get_role_codenames + +from awx.api.versioning import reverse +from django.urls import reverse as django_reverse + +from ansible_base.rbac.models import RoleDefinition +from ansible_base.rbac import permission_registry + + +@pytest.fixture +def ee_rd(): + return RoleDefinition.objects.create_from_permissions( + name='EE object admin', + permissions=['change_executionenvironment', 'delete_executionenvironment'], + content_type=permission_registry.content_type_model.objects.get_for_model(ExecutionEnvironment), + ) + + +@pytest.fixture +def org_ee_rd(): + return RoleDefinition.objects.create_from_permissions( + name='EE org admin', + permissions=['add_executionenvironment', 'change_executionenvironment', 'delete_executionenvironment', 'view_organization'], + content_type=permission_registry.content_type_model.objects.get_for_model(Organization), + ) + + +@pytest.mark.django_db +def test_old_ee_role_maps_to_correct_permissions(organization): + assert set(get_role_codenames(organization.execution_environment_admin_role)) == { + 'view_organization', + 'add_executionenvironment', + 'change_executionenvironment', + 'delete_executionenvironment', + } + + +@pytest.fixture +def org_ee(organization): + return ExecutionEnvironment.objects.create(name='some user ee', organization=organization) + + +@pytest.fixture +def check_user_capabilities(get, setup_managed_roles): + def _rf(user, obj, expected): + url = reverse('api:execution_environment_list') + r = get(url, user=user, expect=200) + for item in r.data['results']: + if item['id'] == obj.pk: + assert expected == item['summary_fields']['user_capabilities'] + break + else: + raise RuntimeError(f'Could not find expected object ({obj}) in EE list result: {r.data}') + + return _rf + + +# ___ begin tests ___ + + +@pytest.mark.django_db +def test_any_user_can_view_global_ee(control_plane_execution_environment, rando): + assert ExecutionEnvironmentAccess(rando).can_read(control_plane_execution_environment) + + +@pytest.mark.django_db +def test_managed_ee_not_assignable(control_plane_execution_environment, ee_rd, rando, admin_user, post): + url = django_reverse('roleuserassignment-list') + r = post(url, {'role_definition': ee_rd.pk, 'user': rando.id, 'object_id': control_plane_execution_environment.pk}, user=admin_user, expect=400) + assert 'Can not assign object roles to managed Execution Environment' in str(r.data) + + +@pytest.mark.django_db +def test_org_member_required_for_assignment(org_ee, ee_rd, rando, admin_user, post): + url = django_reverse('roleuserassignment-list') + r = post(url, {'role_definition': ee_rd.pk, 'user': rando.id, 'object_id': org_ee.pk}, user=admin_user, expect=400) + assert 'User must have view permission to Execution Environment organization' in str(r.data) + + +@pytest.mark.django_db +def test_team_can_have_permission(org_ee, ee_rd, rando, admin_user, post): + org2 = Organization.objects.create(name='a different team') + team = Team.objects.create(name='a team', organization=org2) + team.member_role.members.add(rando) + assert org_ee not in ExecutionEnvironmentAccess(rando).get_queryset() # user can not view the EE + + url = django_reverse('roleteamassignment-list') + + # can give object roles to the team now + post(url, {'role_definition': ee_rd.pk, 'team': team.id, 'object_id': org_ee.pk}, user=admin_user, expect=201) + assert rando.has_obj_perm(org_ee, 'change') + assert org_ee in ExecutionEnvironmentAccess(rando).get_queryset() # user can view the EE now + + +@pytest.mark.django_db +def test_give_object_permission_to_ee(setup_managed_roles, org_ee, ee_rd, org_member, check_user_capabilities): + access = ExecutionEnvironmentAccess(org_member) + assert access.can_read(org_ee) # by virtue of being an org member + assert not access.can_change(org_ee, {'name': 'new'}) + check_user_capabilities(org_member, org_ee, {'edit': False, 'delete': False, 'copy': False}) + + ee_rd.give_permission(org_member, org_ee) + assert access.can_change(org_ee, {'name': 'new', 'organization': org_ee.organization.id}) + + check_user_capabilities(org_member, org_ee, {'edit': True, 'delete': True, 'copy': False}) + + +@pytest.mark.django_db +def test_need_related_organization_access(org_ee, ee_rd, org_member): + org2 = Organization.objects.create(name='another organization') + ee_rd.give_permission(org_member, org_ee) + org2.member_role.members.add(org_member) + access = ExecutionEnvironmentAccess(org_member) + assert access.can_change(org_ee, {'name': 'new', 'organization': org_ee.organization}) + assert access.can_change(org_ee, {'name': 'new', 'organization': org_ee.organization.id}) + assert not access.can_change(org_ee, {'name': 'new', 'organization': org2.id}) + assert not access.can_change(org_ee, {'name': 'new', 'organization': org2}) + + # User can make the change if they have relevant permission to the new organization + org_ee.organization.execution_environment_admin_role.members.add(org_member) + org2.execution_environment_admin_role.members.add(org_member) + assert access.can_change(org_ee, {'name': 'new', 'organization': org2.id}) + assert access.can_change(org_ee, {'name': 'new', 'organization': org2}) + + +@pytest.mark.django_db +@pytest.mark.parametrize('style', ['new', 'old']) +def test_give_org_permission_to_ee(setup_managed_roles, org_ee, organization, org_member, check_user_capabilities, style, org_ee_rd): + access = ExecutionEnvironmentAccess(org_member) + assert not access.can_change(org_ee, {'name': 'new'}) + check_user_capabilities(org_member, org_ee, {'edit': False, 'delete': False, 'copy': False}) + + if style == 'new': + org_ee_rd.give_permission(org_member, organization) + assert org_member.has_obj_perm(org_ee.organization, 'add_executionenvironment') # sanity + else: + organization.execution_environment_admin_role.members.add(org_member) + + assert access.can_change(org_ee, {'name': 'new', 'organization': organization.id}) + check_user_capabilities(org_member, org_ee, {'edit': True, 'delete': True, 'copy': True}) + + # Extra check, user can not remove the EE from the organization + assert not access.can_change(org_ee, {'name': 'new', 'organization': None}) diff --git a/awx/main/tests/functional/rbac/test_rbac_instance_groups.py b/awx/main/tests/functional/rbac/test_rbac_instance_groups.py new file mode 100644 index 000000000000..418e5a351a34 --- /dev/null +++ b/awx/main/tests/functional/rbac/test_rbac_instance_groups.py @@ -0,0 +1,117 @@ +import pytest + +from awx.main.access import ( + InstanceGroupAccess, + OrganizationAccess, + InventoryAccess, + JobTemplateAccess, +) + + +@pytest.mark.django_db +@pytest.mark.parametrize( + "obj_perm,allowed,readonly,partial", [("admin_role", True, True, True), ("use_role", False, True, True), ("read_role", False, True, False)] +) +def test_ig_role_base_visibility(default_instance_group, rando, obj_perm, allowed, partial, readonly): + if obj_perm: + getattr(default_instance_group, obj_perm).members.add(rando) + + assert readonly == InstanceGroupAccess(rando).can_read(default_instance_group) + assert partial == InstanceGroupAccess(rando).can_use(default_instance_group) + assert not InstanceGroupAccess(rando).can_add(default_instance_group) + assert allowed == InstanceGroupAccess(rando).can_admin(default_instance_group) + assert allowed == InstanceGroupAccess(rando).can_change(default_instance_group, {'name': 'New Name'}) + + +@pytest.mark.django_db +@pytest.mark.parametrize( + "obj_perm,subobj_perm,allowed", [('admin_role', 'use_role', True), ('admin_role', 'read_role', False), ('admin_role', 'admin_role', True)] +) +def test_ig_role_based_associability(default_instance_group, rando, organization, job_template_factory, obj_perm, subobj_perm, allowed): + objects = job_template_factory('jt', organization=organization, project='p', inventory='i', credential='c') + if obj_perm: + getattr(objects.job_template, obj_perm).members.add(rando) + getattr(objects.inventory, obj_perm).members.add(rando) + getattr(objects.organization, obj_perm).members.add(rando) + if subobj_perm: + getattr(default_instance_group, subobj_perm).members.add(rando) + + assert allowed == JobTemplateAccess(rando).can_attach(objects.job_template, default_instance_group, 'instance_groups', None) + assert allowed == InventoryAccess(rando).can_attach(objects.inventory, default_instance_group, 'instance_groups', None) + assert allowed == OrganizationAccess(rando).can_attach(objects.organization, default_instance_group, 'instance_groups', None) + + +@pytest.mark.django_db +def test_ig_use_with_org_admin(default_instance_group, rando, org_admin): + default_instance_group.use_role.members.add(rando) + + assert list(InstanceGroupAccess(org_admin).get_queryset()) != [default_instance_group] + assert list(InstanceGroupAccess(rando).get_queryset()) == [default_instance_group] + + +@pytest.mark.django_db +def test_ig_normal_user_visibility(organization, default_instance_group, user): + u = user('user', False) + assert len(InstanceGroupAccess(u).get_queryset()) == 0 + organization.instance_groups.add(default_instance_group) + organization.member_role.members.add(u) + assert len(InstanceGroupAccess(u).get_queryset()) == 0 + + +@pytest.mark.django_db +def test_ig_admin_user_visibility(organization, default_instance_group, admin, system_auditor, org_admin): + assert len(InstanceGroupAccess(admin).get_queryset()) == 1 + assert len(InstanceGroupAccess(system_auditor).get_queryset()) == 1 + assert len(InstanceGroupAccess(org_admin).get_queryset()) == 0 + organization.instance_groups.add(default_instance_group) + assert len(InstanceGroupAccess(org_admin).get_queryset()) == 0 + + +@pytest.mark.django_db +def test_ig_normal_user_associability(organization, default_instance_group, user): + u = user('user', False) + access = OrganizationAccess(u) + assert not access.can_attach(organization, default_instance_group, 'instance_groups', None) + organization.instance_groups.add(default_instance_group) + organization.member_role.members.add(u) + assert not access.can_attach(organization, default_instance_group, 'instance_groups', None) + + +@pytest.mark.django_db +def test_ig_associability(organization, default_instance_group, admin, system_auditor, org_admin, org_member, job_template_factory): + admin_access = OrganizationAccess(admin) + auditor_access = OrganizationAccess(system_auditor) + oadmin_access = OrganizationAccess(org_admin) + omember_access = OrganizationAccess(org_member) + assert admin_access.can_attach(organization, default_instance_group, 'instance_groups', None) + assert not oadmin_access.can_attach(organization, default_instance_group, 'instance_groups', None) + assert not auditor_access.can_attach(organization, default_instance_group, 'instance_groups', None) + assert not omember_access.can_attach(organization, default_instance_group, 'instance_groups', None) + + organization.instance_groups.add(default_instance_group) + + assert admin_access.can_unattach(organization, default_instance_group, 'instance_groups', None) + assert not oadmin_access.can_unattach(organization, default_instance_group, 'instance_groups', None) + assert not auditor_access.can_unattach(organization, default_instance_group, 'instance_groups', None) + assert not omember_access.can_unattach(organization, default_instance_group, 'instance_groups', None) + + objects = job_template_factory('jt', organization=organization, project='p', inventory='i', credential='c') + admin_access = InventoryAccess(admin) + auditor_access = InventoryAccess(system_auditor) + oadmin_access = InventoryAccess(org_admin) + omember_access = InventoryAccess(org_member) + + assert admin_access.can_attach(objects.inventory, default_instance_group, 'instance_groups', None) + assert not oadmin_access.can_attach(objects.inventory, default_instance_group, 'instance_groups', None) + assert not auditor_access.can_attach(objects.inventory, default_instance_group, 'instance_groups', None) + assert not omember_access.can_attach(objects.inventory, default_instance_group, 'instance_groups', None) + + admin_access = JobTemplateAccess(admin) + auditor_access = JobTemplateAccess(system_auditor) + oadmin_access = JobTemplateAccess(org_admin) + omember_access = JobTemplateAccess(org_member) + + assert admin_access.can_attach(objects.job_template, default_instance_group, 'instance_groups', None) + assert not oadmin_access.can_attach(objects.job_template, default_instance_group, 'instance_groups', None) + assert not auditor_access.can_attach(objects.job_template, default_instance_group, 'instance_groups', None) + assert not omember_access.can_attach(objects.job_template, default_instance_group, 'instance_groups', None) diff --git a/awx/main/tests/functional/test_rbac_inventory.py b/awx/main/tests/functional/rbac/test_rbac_inventory.py similarity index 100% rename from awx/main/tests/functional/test_rbac_inventory.py rename to awx/main/tests/functional/rbac/test_rbac_inventory.py diff --git a/awx/main/tests/functional/test_rbac_job.py b/awx/main/tests/functional/rbac/test_rbac_job.py similarity index 92% rename from awx/main/tests/functional/test_rbac_job.py rename to awx/main/tests/functional/rbac/test_rbac_job.py index ff5c6c25a255..c4bcee00d684 100644 --- a/awx/main/tests/functional/test_rbac_job.py +++ b/awx/main/tests/functional/rbac/test_rbac_job.py @@ -2,7 +2,15 @@ from rest_framework.exceptions import PermissionDenied -from awx.main.access import JobAccess, JobLaunchConfigAccess, AdHocCommandAccess, InventoryUpdateAccess, ProjectUpdateAccess +from awx.main.access import ( + JobAccess, + JobLaunchConfigAccess, + AdHocCommandAccess, + InventoryUpdateAccess, + ProjectUpdateAccess, + SystemJobTemplateAccess, + SystemJobAccess, +) from awx.main.models import ( Job, JobLaunchConfig, @@ -350,3 +358,26 @@ def test_can_use_minor(self, rando): assert access.can_use(config) assert rando.can_access(JobLaunchConfig, 'use', config) + + +@pytest.mark.django_db +class TestSystemJobTemplateAccess: + def test_system_job_template_auditor(self, system_auditor, system_job_template): + access = SystemJobTemplateAccess(system_auditor) + assert access.can_read(system_job_template) + assert not access.can_start(system_job_template) + + def test_system_job_template_rando(self, rando, system_job_template): + access = SystemJobTemplateAccess(rando) + assert not access.can_read(system_job_template) + assert not access.can_start(system_job_template) + + def test_system_job_template_superuser(self, admin_user, system_job_template): + access = SystemJobTemplateAccess(admin_user) + assert access.can_read(system_job_template) + assert access.can_start(system_job_template) + + def test_org_auditor_view_system_job(self, system_job_template, org_auditor): + system_job = system_job_template.create_unified_job() + access = SystemJobAccess(org_auditor) + assert not access.can_read(system_job) diff --git a/awx/main/tests/functional/test_rbac_job_start.py b/awx/main/tests/functional/rbac/test_rbac_job_start.py similarity index 100% rename from awx/main/tests/functional/test_rbac_job_start.py rename to awx/main/tests/functional/rbac/test_rbac_job_start.py diff --git a/awx/main/tests/functional/test_rbac_job_templates.py b/awx/main/tests/functional/rbac/test_rbac_job_templates.py similarity index 86% rename from awx/main/tests/functional/test_rbac_job_templates.py rename to awx/main/tests/functional/rbac/test_rbac_job_templates.py index bccec0a1c2e1..34f82d9a74b9 100644 --- a/awx/main/tests/functional/test_rbac_job_templates.py +++ b/awx/main/tests/functional/rbac/test_rbac_job_templates.py @@ -4,7 +4,7 @@ from awx.api.versioning import reverse from awx.main.access import BaseAccess, JobTemplateAccess, ScheduleAccess from awx.main.models.jobs import JobTemplate -from awx.main.models import Project, Organization, Inventory, Schedule, User +from awx.main.models import Project, Organization, Schedule @mock.patch.object(BaseAccess, 'check_license', return_value=None) @@ -165,7 +165,7 @@ def test_system_admin_orphan_capabilities(self, job_template, admin_user): @pytest.mark.django_db @pytest.mark.job_permissions -def test_job_template_creator_access(project, organization, rando, post): +def test_job_template_creator_access(project, organization, rando, post, setup_managed_roles): project.use_role.members.add(rando) response = post( url=reverse('api:job_template_list'), @@ -177,13 +177,19 @@ def test_job_template_creator_access(project, organization, rando, post): jt_pk = response.data['id'] jt_obj = JobTemplate.objects.get(pk=jt_pk) # Creating a JT should place the creator in the admin role - assert rando in jt_obj.admin_role.members.all() + assert rando in jt_obj.admin_role @pytest.mark.django_db @pytest.mark.job_permissions -@pytest.mark.parametrize('lacking', ['project', 'inventory']) -def test_job_template_insufficient_creator_permissions(lacking, project, inventory, organization, rando, post): +@pytest.mark.parametrize( + 'lacking,reason', + [ + ('project', 'You do not have use permission on Project'), + ('inventory', 'You do not have use permission on Inventory'), + ], +) +def test_job_template_insufficient_creator_permissions(lacking, reason, project, inventory, organization, rando, post): if lacking != 'project': project.use_role.members.add(rando) else: @@ -192,12 +198,13 @@ def test_job_template_insufficient_creator_permissions(lacking, project, invento inventory.use_role.members.add(rando) else: inventory.read_role.members.add(rando) - post( + response = post( url=reverse('api:job_template_list'), data=dict(name='newly-created-jt', inventory=inventory.id, project=project.pk, playbook='helloworld.yml'), user=rando, expect=403, ) + assert reason in response.data[lacking] @pytest.mark.django_db @@ -283,48 +290,3 @@ def test_orphan_JT_adoption(self, project, patch, admin_user, org_admin): assert org_admin not in jt.admin_role patch(url=jt.get_absolute_url(), data={'project': project.id}, user=admin_user, expect=200) assert org_admin in jt.admin_role - - def test_inventory_read_transfer_direct(self, patch): - orgs = [] - invs = [] - admins = [] - for i in range(2): - org = Organization.objects.create(name='org{}'.format(i)) - org_admin = User.objects.create(username='user{}'.format(i)) - inv = Inventory.objects.create(organization=org, name='inv{}'.format(i)) - org.auditor_role.members.add(org_admin) - - orgs.append(org) - admins.append(org_admin) - invs.append(inv) - - jt = JobTemplate.objects.create(name='foo', inventory=invs[0]) - assert admins[0] in jt.read_role - assert admins[1] not in jt.read_role - - jt.inventory = invs[1] - jt.save(update_fields=['inventory']) - assert admins[0] not in jt.read_role - assert admins[1] in jt.read_role - - def test_inventory_read_transfer_indirect(self, patch): - orgs = [] - admins = [] - for i in range(2): - org = Organization.objects.create(name='org{}'.format(i)) - org_admin = User.objects.create(username='user{}'.format(i)) - org.auditor_role.members.add(org_admin) - - orgs.append(org) - admins.append(org_admin) - - inv = Inventory.objects.create(organization=orgs[0], name='inv{}'.format(i)) - - jt = JobTemplate.objects.create(name='foo', inventory=inv) - assert admins[0] in jt.read_role - assert admins[1] not in jt.read_role - - inv.organization = orgs[1] - inv.save(update_fields=['organization']) - assert admins[0] not in jt.read_role - assert admins[1] in jt.read_role diff --git a/awx/main/tests/functional/test_rbac_label.py b/awx/main/tests/functional/rbac/test_rbac_label.py similarity index 100% rename from awx/main/tests/functional/test_rbac_label.py rename to awx/main/tests/functional/rbac/test_rbac_label.py diff --git a/awx/main/tests/functional/test_labels.py b/awx/main/tests/functional/rbac/test_rbac_labels.py similarity index 100% rename from awx/main/tests/functional/test_labels.py rename to awx/main/tests/functional/rbac/test_rbac_labels.py diff --git a/awx/main/tests/functional/test_rbac_notifications.py b/awx/main/tests/functional/rbac/test_rbac_notifications.py similarity index 98% rename from awx/main/tests/functional/test_rbac_notifications.py rename to awx/main/tests/functional/rbac/test_rbac_notifications.py index d05efa244c9b..72d5d016a954 100644 --- a/awx/main/tests/functional/test_rbac_notifications.py +++ b/awx/main/tests/functional/rbac/test_rbac_notifications.py @@ -99,7 +99,9 @@ def test_notification_template_access_org_user(notification_template, user): @pytest.mark.django_db def test_notificaiton_template_orphan_access_org_admin(notification_template, organization, org_admin): notification_template.organization = None + notification_template.save(update_fields=['organization']) access = NotificationTemplateAccess(org_admin) + assert not org_admin.has_obj_perm(notification_template, 'change') assert not access.can_change(notification_template, {'organization': organization.id}) diff --git a/awx/main/tests/functional/test_rbac_organization.py b/awx/main/tests/functional/rbac/test_rbac_organization.py similarity index 75% rename from awx/main/tests/functional/test_rbac_organization.py rename to awx/main/tests/functional/rbac/test_rbac_organization.py index ddb0692ea3ed..7a07225d3057 100644 --- a/awx/main/tests/functional/test_rbac_organization.py +++ b/awx/main/tests/functional/rbac/test_rbac_organization.py @@ -48,3 +48,17 @@ def test_org_resource_role(ext_auth, organization, rando, org_admin): assert access.can_attach(organization, rando, 'member_role.members') == ext_auth organization.member_role.members.add(rando) assert access.can_unattach(organization, rando, 'member_role.members') == ext_auth + + +@pytest.mark.django_db +def test_delete_org_while_workflow_active(workflow_job_template): + ''' + Delete org while workflow job is active (i.e. changing status) + ''' + assert workflow_job_template.organization # sanity check + wj = workflow_job_template.create_unified_job() # status should be new + workflow_job_template.organization.delete() + wj.refresh_from_db() + assert wj.status != 'pending' # sanity check + wj.status = 'pending' # status needs to change in order to trigger workflow_job_template.save() + wj.save(update_fields=['status']) diff --git a/awx/main/tests/functional/test_rbac_project.py b/awx/main/tests/functional/rbac/test_rbac_project.py similarity index 100% rename from awx/main/tests/functional/test_rbac_project.py rename to awx/main/tests/functional/rbac/test_rbac_project.py diff --git a/awx/main/tests/functional/test_rbac_role.py b/awx/main/tests/functional/rbac/test_rbac_role.py similarity index 100% rename from awx/main/tests/functional/test_rbac_role.py rename to awx/main/tests/functional/rbac/test_rbac_role.py diff --git a/awx/main/tests/functional/test_rbac_team.py b/awx/main/tests/functional/rbac/test_rbac_team.py similarity index 98% rename from awx/main/tests/functional/test_rbac_team.py rename to awx/main/tests/functional/rbac/test_rbac_team.py index a18a69a94bb3..6c3e68c6c1d7 100644 --- a/awx/main/tests/functional/test_rbac_team.py +++ b/awx/main/tests/functional/rbac/test_rbac_team.py @@ -92,7 +92,7 @@ def test_team_accessible_by(team, user, project): u = user('team_member', False) team.member_role.children.add(project.use_role) - assert team in project.read_role + assert list(Project.accessible_objects(team, 'read_role')) == [project] assert u not in project.read_role team.member_role.members.add(u) diff --git a/awx/main/tests/functional/test_rbac_user.py b/awx/main/tests/functional/rbac/test_rbac_user.py similarity index 78% rename from awx/main/tests/functional/test_rbac_user.py rename to awx/main/tests/functional/rbac/test_rbac_user.py index d5386343bd8f..10ca851bbe57 100644 --- a/awx/main/tests/functional/test_rbac_user.py +++ b/awx/main/tests/functional/rbac/test_rbac_user.py @@ -4,7 +4,7 @@ from django.test import TransactionTestCase from awx.main.access import UserAccess, RoleAccess, TeamAccess -from awx.main.models import User, Organization, Inventory, Role +from awx.main.models import User, Organization, Inventory, get_system_auditor_role class TestSysAuditorTransactional(TransactionTestCase): @@ -18,7 +18,8 @@ def inventory(self): def test_auditor_caching(self): rando = self.rando() - with self.assertNumQueries(1): + get_system_auditor_role() # pre-create role, normally done by migrations + with self.assertNumQueries(2): v = rando.is_system_auditor assert not v with self.assertNumQueries(0): @@ -122,25 +123,6 @@ def test_team_org_resource_role(ext_auth, organization, rando, org_admin, team): ] == [True for i in range(2)] -@pytest.mark.django_db -def test_user_accessible_objects(user, organization): - """ - We cannot directly use accessible_objects for User model because - both editing and read permissions are obligated to complex business logic - """ - admin = user('admin', False) - u = user('john', False) - access = UserAccess(admin) - assert access.get_queryset().count() == 1 # can only see himself - - organization.member_role.members.add(u) - organization.member_role.members.add(admin) - assert access.get_queryset().count() == 2 - - organization.member_role.members.remove(u) - assert access.get_queryset().count() == 1 - - @pytest.mark.django_db def test_org_admin_create_sys_auditor(org_admin): access = UserAccess(org_admin) @@ -172,34 +154,3 @@ def test_org_admin_cannot_delete_member_attached_to_other_group(org_admin, org_m access = UserAccess(org_admin) other_org.member_role.members.add(org_member) assert not access.can_delete(org_member) - - -@pytest.mark.parametrize('reverse', (True, False)) -@pytest.mark.django_db -def test_consistency_of_is_superuser_flag(reverse): - users = [User.objects.create(username='rando_{}'.format(i)) for i in range(2)] - for u in users: - assert u.is_superuser is False - - system_admin = Role.singleton('system_administrator') - if reverse: - for u in users: - u.roles.add(system_admin) - else: - system_admin.members.add(*[u.id for u in users]) # like .add(42, 54) - - for u in users: - u.refresh_from_db() - assert u.is_superuser is True - - users[0].roles.clear() - for u in users: - u.refresh_from_db() - assert users[0].is_superuser is False - assert users[1].is_superuser is True - - system_admin.members.clear() - - for u in users: - u.refresh_from_db() - assert u.is_superuser is False diff --git a/awx/main/tests/functional/test_rbac_workflow.py b/awx/main/tests/functional/rbac/test_rbac_workflow.py similarity index 88% rename from awx/main/tests/functional/test_rbac_workflow.py rename to awx/main/tests/functional/rbac/test_rbac_workflow.py index 4c29907519c1..c94f4f4df881 100644 --- a/awx/main/tests/functional/test_rbac_workflow.py +++ b/awx/main/tests/functional/rbac/test_rbac_workflow.py @@ -1,6 +1,7 @@ import pytest from awx.main.access import ( + UnifiedJobAccess, WorkflowJobTemplateAccess, WorkflowJobTemplateNodeAccess, WorkflowJobAccess, @@ -13,30 +14,6 @@ from awx.main.models import InventorySource, JobLaunchConfig -@pytest.fixture -def wfjt(workflow_job_template_factory, organization): - objects = workflow_job_template_factory('test_workflow', organization=organization, persisted=True) - return objects.workflow_job_template - - -@pytest.fixture -def wfjt_with_nodes(workflow_job_template_factory, organization, job_template): - objects = workflow_job_template_factory( - 'test_workflow', organization=organization, workflow_job_template_nodes=[{'unified_job_template': job_template}], persisted=True - ) - return objects.workflow_job_template - - -@pytest.fixture -def wfjt_node(wfjt_with_nodes): - return wfjt_with_nodes.workflow_job_template_nodes.all()[0] - - -@pytest.fixture -def workflow_job(wfjt): - return wfjt.workflow_jobs.create(name='test_workflow') - - @pytest.mark.django_db class TestWorkflowJobTemplateAccess: def test_random_user_no_edit(self, wfjt, rando): @@ -59,6 +36,13 @@ def test_org_workflow_admin_role_inheritance(self, wfjt, org_member): assert org_member in wfjt.execute_role assert org_member in wfjt.read_role + def test_non_super_admin_no_add_without_org(self, wfjt, organization, rando): + organization.member_role.members.add(rando) + wfjt.admin_role.members.add(rando) + access = WorkflowJobTemplateAccess(rando, save_messages=True) + assert not access.can_add({'name': 'without org'}) + assert 'An organization is required to create a workflow job template for normal user' in access.messages['organization'] + @pytest.mark.django_db class TestWorkflowJobTemplateNodeAccess: @@ -148,7 +132,7 @@ def test_attacher_permissions(self, wfjt_node, job_template, rando, add_wfjt_adm elif permission_type == 'instance_groups': sub_obj = InstanceGroup.objects.create() org = Organization.objects.create() - org.admin_role.members.add(rando) # only admins can see IGs + sub_obj.use_role.members.add(rando) # only admins can see IGs org.instance_groups.add(sub_obj) access = WorkflowJobTemplateNodeAccess(rando) @@ -262,6 +246,30 @@ def test_relaunch_inventory_access(self, workflow_job, inventory, rando): inventory.use_role.members.add(rando) assert WorkflowJobAccess(rando).can_start(workflow_job) + @pytest.mark.parametrize('org_role', ['admin_role', 'auditor_role']) + def test_workflow_job_org_audit_access(self, workflow_job_template, rando, org_role): + assert workflow_job_template.organization # sanity + workflow_job = workflow_job_template.create_unified_job() + assert workflow_job.organization # sanity + + assert not UnifiedJobAccess(rando).can_read(workflow_job) + assert not WorkflowJobAccess(rando).can_read(workflow_job) + assert workflow_job not in WorkflowJobAccess(rando).filtered_queryset() + + org = workflow_job.organization + role = getattr(org, org_role) + role.members.add(rando) + + assert UnifiedJobAccess(rando).can_read(workflow_job) + assert WorkflowJobAccess(rando).can_read(workflow_job) + assert workflow_job in WorkflowJobAccess(rando).filtered_queryset() + + # Organization-level permissions should persist after deleting the WFJT + workflow_job_template.delete() + assert UnifiedJobAccess(rando).can_read(workflow_job) + assert WorkflowJobAccess(rando).can_read(workflow_job) + assert workflow_job in WorkflowJobAccess(rando).filtered_queryset() + @pytest.mark.django_db class TestWFJTCopyAccess: diff --git a/awx/main/tests/functional/task_management/test_rampart_groups.py b/awx/main/tests/functional/task_management/test_rampart_groups.py index 48ea9edb0805..f4bb81f405a6 100644 --- a/awx/main/tests/functional/task_management/test_rampart_groups.py +++ b/awx/main/tests/functional/task_management/test_rampart_groups.py @@ -21,13 +21,13 @@ def test_multi_group_basic_job_launch(instance_factory, controlplane_instance_gr j2 = create_job(objects2.job_template) with mock.patch('awx.main.models.Job.task_impact', new_callable=mock.PropertyMock) as mock_task_impact: mock_task_impact.return_value = 500 - with mocker.patch("awx.main.scheduler.TaskManager.start_task"): - TaskManager().schedule() - TaskManager.start_task.assert_has_calls([mock.call(j1, ig1, i1), mock.call(j2, ig2, i2)]) + mocker.patch("awx.main.scheduler.TaskManager.start_task") + TaskManager().schedule() + TaskManager.start_task.assert_has_calls([mock.call(j1, ig1, i1), mock.call(j2, ig2, i2)]) @pytest.mark.django_db -def test_multi_group_with_shared_dependency(instance_factory, controlplane_instance_group, mocker, instance_group_factory, job_template_factory): +def test_multi_group_with_shared_dependency(instance_factory, controlplane_instance_group, instance_group_factory, job_template_factory): i1 = instance_factory("i1") i2 = instance_factory("i2") ig1 = instance_group_factory("ig1", instances=[i1]) @@ -50,7 +50,7 @@ def test_multi_group_with_shared_dependency(instance_factory, controlplane_insta objects2 = job_template_factory('jt2', organization=objects1.organization, project=p, inventory='inv2', credential='cred2') objects2.job_template.instance_groups.add(ig2) j2 = create_job(objects2.job_template, dependencies_processed=False) - with mocker.patch("awx.main.scheduler.TaskManager.start_task"): + with mock.patch("awx.main.scheduler.TaskManager.start_task"): DependencyManager().schedule() TaskManager().schedule() pu = p.project_updates.first() @@ -73,10 +73,10 @@ def test_workflow_job_no_instancegroup(workflow_job_template_factory, controlpla wfj = wfjt.create_unified_job() wfj.status = "pending" wfj.save() - with mocker.patch("awx.main.scheduler.TaskManager.start_task"): - TaskManager().schedule() - TaskManager.start_task.assert_called_once_with(wfj, None, None) - assert wfj.instance_group is None + mocker.patch("awx.main.scheduler.TaskManager.start_task") + TaskManager().schedule() + TaskManager.start_task.assert_called_once_with(wfj, None, None) + assert wfj.instance_group is None @pytest.mark.django_db diff --git a/awx/main/tests/functional/task_management/test_scheduler.py b/awx/main/tests/functional/task_management/test_scheduler.py index 42d144d5ccd3..7293873d7ccd 100644 --- a/awx/main/tests/functional/task_management/test_scheduler.py +++ b/awx/main/tests/functional/task_management/test_scheduler.py @@ -5,7 +5,7 @@ from awx.main.scheduler import TaskManager, DependencyManager, WorkflowManager from awx.main.utils import encrypt_field -from awx.main.models import WorkflowJobTemplate, JobTemplate, Job +from awx.main.models import WorkflowJobTemplate, JobTemplate, Job, Project, InventorySource, Inventory from awx.main.models.ha import Instance from . import create_job from django.conf import settings @@ -16,9 +16,9 @@ def test_single_job_scheduler_launch(hybrid_instance, controlplane_instance_grou instance = controlplane_instance_group.instances.all()[0] objects = job_template_factory('jt', organization='org1', project='proj', inventory='inv', credential='cred') j = create_job(objects.job_template) - with mocker.patch("awx.main.scheduler.TaskManager.start_task"): - TaskManager().schedule() - TaskManager.start_task.assert_called_once_with(j, controlplane_instance_group, instance) + mocker.patch("awx.main.scheduler.TaskManager.start_task") + TaskManager().schedule() + TaskManager.start_task.assert_called_once_with(j, controlplane_instance_group, instance) @pytest.mark.django_db @@ -331,15 +331,13 @@ def test_single_job_dependencies_project_launch(controlplane_instance_group, job p.save(skip_update=True) with mock.patch("awx.main.scheduler.TaskManager.start_task"): dm = DependencyManager() - with mock.patch.object(DependencyManager, "create_project_update", wraps=dm.create_project_update) as mock_pu: - dm.schedule() - mock_pu.assert_called_once_with(j) - pu = [x for x in p.project_updates.all()] - assert len(pu) == 1 - TaskManager().schedule() - TaskManager.start_task.assert_called_once_with(pu[0], controlplane_instance_group, instance) - pu[0].status = "successful" - pu[0].save() + dm.schedule() + pu = [x for x in p.project_updates.all()] + assert len(pu) == 1 + TaskManager().schedule() + TaskManager.start_task.assert_called_once_with(pu[0], controlplane_instance_group, instance) + pu[0].status = "successful" + pu[0].save() with mock.patch("awx.main.scheduler.TaskManager.start_task"): TaskManager().schedule() TaskManager.start_task.assert_called_once_with(j, controlplane_instance_group, instance) @@ -359,22 +357,21 @@ def test_single_job_dependencies_inventory_update_launch(controlplane_instance_g i.inventory_sources.add(ii) with mock.patch("awx.main.scheduler.TaskManager.start_task"): dm = DependencyManager() - with mock.patch.object(DependencyManager, "create_inventory_update", wraps=dm.create_inventory_update) as mock_iu: - dm.schedule() - mock_iu.assert_called_once_with(j, ii) - iu = [x for x in ii.inventory_updates.all()] - assert len(iu) == 1 - TaskManager().schedule() - TaskManager.start_task.assert_called_once_with(iu[0], controlplane_instance_group, instance) - iu[0].status = "successful" - iu[0].save() + dm.schedule() + assert ii.inventory_updates.count() == 1 + iu = [x for x in ii.inventory_updates.all()] + assert len(iu) == 1 + TaskManager().schedule() + TaskManager.start_task.assert_called_once_with(iu[0], controlplane_instance_group, instance) + iu[0].status = "successful" + iu[0].save() with mock.patch("awx.main.scheduler.TaskManager.start_task"): TaskManager().schedule() TaskManager.start_task.assert_called_once_with(j, controlplane_instance_group, instance) @pytest.mark.django_db -def test_inventory_update_launches_project_update(controlplane_instance_group, scm_inventory_source): +def test_inventory_update_launches_project_update(scm_inventory_source): ii = scm_inventory_source project = scm_inventory_source.source_project project.scm_update_on_launch = True @@ -382,11 +379,51 @@ def test_inventory_update_launches_project_update(controlplane_instance_group, s iu = ii.create_inventory_update() iu.status = "pending" iu.save() + assert project.project_updates.count() == 0 with mock.patch("awx.main.scheduler.TaskManager.start_task"): dm = DependencyManager() - with mock.patch.object(DependencyManager, "create_project_update", wraps=dm.create_project_update) as mock_pu: - dm.schedule() - mock_pu.assert_called_with(iu, project_id=project.id) + dm.schedule() + assert project.project_updates.count() == 1 + + +@pytest.mark.django_db +def test_dependency_isolation(organization): + """Spawning both a job project update dependency, and an inventory update project dependency + + this should keep dependencies isolated""" + with mock.patch('awx.main.models.unified_jobs.UnifiedJobTemplate.update'): + updating_projects = [ + Project.objects.create(name=f'iso-proj{i}', organization=organization, scm_url='https://foo.invalid', scm_type='git', scm_update_on_launch=True) + for i in range(2) + ] + + inv_src = InventorySource.objects.create( + name='iso-inv', + organization=organization, + source_project=updating_projects[0], + source='scm', + inventory=Inventory.objects.create(name='for-inv-src', organization=organization), + ) + + inv_update = inv_src.create_unified_job() + inv_update.signal_start() + assert not inv_update.dependent_jobs.exists() + + jt = JobTemplate.objects.create( + project=updating_projects[1], + inventory=Inventory.objects.create(name='one-off', organization=organization), # non-updating inventory source + ) + job = jt.create_unified_job() + job.signal_start() + assert not job.dependent_jobs.exists() + + dm = DependencyManager() + dm.schedule() + + # in a single run, the completely unrelated inventory and jobs are linked to their own dependencies + assert (inv_update.dependent_jobs.count(), job.dependent_jobs.count()) == (1, 1) + assert inv_update.dependent_jobs.first().project == updating_projects[0] + assert job.dependent_jobs.first().project == updating_projects[1] @pytest.mark.django_db @@ -407,9 +444,8 @@ def test_job_dependency_with_already_updated(controlplane_instance_group, job_te j.save() with mock.patch("awx.main.scheduler.TaskManager.start_task"): dm = DependencyManager() - with mock.patch.object(DependencyManager, "create_inventory_update", wraps=dm.create_inventory_update) as mock_iu: - dm.schedule() - mock_iu.assert_not_called() + dm.schedule() + assert ii.inventory_updates.count() == 0 with mock.patch("awx.main.scheduler.TaskManager.start_task"): TaskManager().schedule() TaskManager.start_task.assert_called_once_with(j, controlplane_instance_group, instance) @@ -442,7 +478,9 @@ def test_shared_dependencies_launch(controlplane_instance_group, job_template_fa TaskManager().schedule() pu = p.project_updates.first() iu = ii.inventory_updates.first() - TaskManager.start_task.assert_has_calls([mock.call(iu, controlplane_instance_group, instance), mock.call(pu, controlplane_instance_group, instance)]) + TaskManager.start_task.assert_has_calls( + [mock.call(iu, controlplane_instance_group, instance), mock.call(pu, controlplane_instance_group, instance)], any_order=True + ) pu.status = "successful" pu.finished = pu.created + timedelta(seconds=1) pu.save() @@ -451,7 +489,9 @@ def test_shared_dependencies_launch(controlplane_instance_group, job_template_fa iu.save() with mock.patch("awx.main.scheduler.TaskManager.start_task"): TaskManager().schedule() - TaskManager.start_task.assert_has_calls([mock.call(j1, controlplane_instance_group, instance), mock.call(j2, controlplane_instance_group, instance)]) + TaskManager.start_task.assert_has_calls( + [mock.call(j1, controlplane_instance_group, instance), mock.call(j2, controlplane_instance_group, instance)], any_order=True + ) pu = [x for x in p.project_updates.all()] iu = [x for x in ii.inventory_updates.all()] assert len(pu) == 1 diff --git a/awx/main/tests/functional/tasks/test_host_indirect.py b/awx/main/tests/functional/tasks/test_host_indirect.py new file mode 100644 index 000000000000..cfa98d2391cc --- /dev/null +++ b/awx/main/tests/functional/tasks/test_host_indirect.py @@ -0,0 +1,366 @@ +import yaml +from functools import reduce +from unittest import mock + +import pytest + +from django.utils.timezone import now, timedelta + +from awx.main.tasks.host_indirect import ( + build_indirect_host_data, + fetch_job_event_query, + save_indirect_host_entries, + cleanup_and_save_indirect_host_entries_fallback, +) +from awx.main.models.event_query import EventQuery +from awx.main.models.indirect_managed_node_audit import IndirectManagedNodeAudit + +"""These are unit tests, similar to test_indirect_host_counting in the live tests""" + + +TEST_JQ = "{name: .name, canonical_facts: {host_name: .direct_host_name}, facts: {another_host_name: .direct_host_name}}" + + +class Query(dict): + def __init__(self, resolved_action: str, query_jq: dict): + self._resolved_action = resolved_action.split('.') + self._collection_ns, self._collection_name, self._module_name = self._resolved_action + + super().__init__({self.resolve_key: {'query': query_jq}}) + + def get_fqcn(self): + return f'{self._collection_ns}.{self._collection_name}' + + @property + def resolve_value(self): + return self[self.resolve_key] + + @property + def resolve_key(self): + return f'{self.get_fqcn()}.{self._module_name}' + + def resolve(self, module_name=None): + return {f'{self.get_fqcn()}.{module_name or self._module_name}': self.resolve_value} + + def create_event_query(self, module_name=None): + if (module_name := module_name or self._module_name) == '*': + raise ValueError('Invalid module name *') + return self.create_event_queries([module_name]) + + def create_event_queries(self, module_names): + queries = {} + for name in module_names: + queries |= self.resolve(name) + return EventQuery.objects.create( + fqcn=self.get_fqcn(), + collection_version='1.0.1', + event_query=yaml.dump(queries, default_flow_style=False), + ) + + def create_registered_event(self, job, module_name): + job.job_events.create(event_data={'resolved_action': f'{self.get_fqcn()}.{module_name}', 'res': {'direct_host_name': 'foo_host', 'name': 'vm-foo'}}) + + +@pytest.fixture +def bare_job(job_factory): + job = job_factory() + job.installed_collections = {'demo.query': {'version': '1.0.1'}, 'demo2.query': {'version': '1.0.1'}} + job.event_queries_processed = False + job.save(update_fields=['installed_collections', 'event_queries_processed']) + return job + + +def create_registered_event(job, task_name='demo.query.example'): + return job.job_events.create(event_data={'resolved_action': task_name, 'res': {'direct_host_name': 'foo_host', 'name': 'vm-foo'}}) + + +@pytest.fixture +def job_with_counted_event(bare_job): + create_registered_event(bare_job) + return bare_job + + +def create_audit_record(name, job, organization, created=now()): + record = IndirectManagedNodeAudit.objects.create(name=name, job=job, organization=organization) + record.created = created + record.save() + return record + + +@pytest.fixture +def event_query(): + "This is ordinarily created by the artifacts callback" + return Query('demo.query.example', TEST_JQ).create_event_query() + + +@pytest.fixture +def old_audit_record(bare_job, organization): + created_at = now() - timedelta(days=10) + return create_audit_record(name="old_job", job=bare_job, organization=organization, created=created_at) + + +@pytest.fixture +def new_audit_record(bare_job, organization): + return IndirectManagedNodeAudit.objects.create(name="new_job", job=bare_job, organization=organization) + + +# ---- end fixtures ---- + + +@pytest.mark.django_db +@pytest.mark.parametrize( + 'queries,expected_matches', + ( + pytest.param( + [], + 0, + id='no_results', + ), + pytest.param( + [Query('demo.query.example', TEST_JQ)], + 1, + id='fully_qualified', + ), + pytest.param( + [Query('demo.query.*', TEST_JQ)], + 1, + id='wildcard', + ), + pytest.param( + [ + Query('demo.query.*', TEST_JQ), + Query('demo.query.example', TEST_JQ), + ], + 1, + id='wildcard_and_fully_qualified', + ), + pytest.param( + [ + Query('demo.query.*', TEST_JQ), + Query('demo.query.example', {}), + ], + 0, + id='wildcard_and_fully_qualified', + ), + pytest.param( + [ + Query('demo.query.example', {}), + Query('demo.query.*', TEST_JQ), + ], + 0, + id='ordering_should_not_matter', + ), + ), +) +def test_build_indirect_host_data(job_with_counted_event, queries: Query, expected_matches: int): + data = build_indirect_host_data(job_with_counted_event, {k: v for d in queries for k, v in d.items()}) + assert len(data) == expected_matches + + +@mock.patch('awx.main.tasks.host_indirect.logger.debug') +@pytest.mark.django_db +@pytest.mark.parametrize( + 'task_name', + ( + pytest.param( + 'demo.query', + id='no_results', + ), + pytest.param( + 'demo', + id='no_results', + ), + pytest.param( + 'a.b.c.d', + id='no_results', + ), + ), +) +def test_build_indirect_host_data_malformed_module_name(mock_logger_debug, bare_job, task_name: str): + create_registered_event(bare_job, task_name) + assert build_indirect_host_data(bare_job, Query('demo.query.example', TEST_JQ)) == [] + mock_logger_debug.assert_called_once_with(f"Malformed invocation module name '{task_name}'. Expected to be of the form 'a.b.c'") + + +@mock.patch('awx.main.tasks.host_indirect.logger.info') +@pytest.mark.django_db +@pytest.mark.parametrize( + 'query', + ( + pytest.param( + 'demo.query', + id='no_results', + ), + pytest.param( + 'demo', + id='no_results', + ), + pytest.param( + 'a.b.c.d', + id='no_results', + ), + ), +) +def test_build_indirect_host_data_malformed_query(mock_logger_info, job_with_counted_event, query: str): + assert build_indirect_host_data(job_with_counted_event, {query: {'query': TEST_JQ}}) == [] + mock_logger_info.assert_called_once_with(f"Skiping malformed query '{query}'. Expected to be of the form 'a.b.c'") + + +@pytest.mark.django_db +@pytest.mark.parametrize( + 'query', + ( + pytest.param( + Query('demo.query.example', TEST_JQ), + id='fully_qualified', + ), + pytest.param( + Query('demo.query.*', TEST_JQ), + id='wildcard', + ), + ), +) +def test_fetch_job_event_query(bare_job, query: Query): + query.create_event_query(module_name='example') + assert fetch_job_event_query(bare_job) == query.resolve('example') + + +@pytest.mark.django_db +@pytest.mark.parametrize( + 'queries', + ( + [ + Query('demo.query.example', TEST_JQ), + Query('demo2.query.example', TEST_JQ), + ], + [ + Query('demo.query.*', TEST_JQ), + Query('demo2.query.example', TEST_JQ), + ], + ), +) +def test_fetch_multiple_job_event_query(bare_job, queries: list[Query]): + for q in queries: + q.create_event_query(module_name='example') + assert fetch_job_event_query(bare_job) == reduce(lambda acc, q: acc | q.resolve('example'), queries, {}) + + +@pytest.mark.django_db +@pytest.mark.parametrize( + ('state',), + ( + pytest.param( + [ + ( + Query('demo.query.example', TEST_JQ), + ['example'], + ), + ], + id='fully_qualified', + ), + pytest.param( + [ + ( + Query('demo.query.example', TEST_JQ), + ['example'] * 3, + ), + ], + id='multiple_events_same_module_same_host', + ), + pytest.param( + [ + ( + Query('demo.query.example', TEST_JQ), + ['example'], + ), + ( + Query('demo2.query.example', TEST_JQ), + ['example'], + ), + ], + id='multiple_modules', + ), + pytest.param( + [ + ( + Query('demo.query.*', TEST_JQ), + ['example', 'example2'], + ), + ], + id='multiple_modules_same_collection', + ), + ), +) +def test_save_indirect_host_entries(bare_job, state): + all_task_names = [] + for entry in state: + query, module_names = entry + all_task_names.extend([f'{query.get_fqcn()}.{module_name}' for module_name in module_names]) + query.create_event_queries(module_names) + [query.create_registered_event(bare_job, n) for n in module_names] + + save_indirect_host_entries(bare_job.id) + bare_job.refresh_from_db() + + assert bare_job.event_queries_processed is True + + assert IndirectManagedNodeAudit.objects.filter(job=bare_job).count() == 1 + host_audit = IndirectManagedNodeAudit.objects.filter(job=bare_job).first() + + assert host_audit.count == len(all_task_names) + assert host_audit.canonical_facts == {'host_name': 'foo_host'} + assert host_audit.facts == {'another_host_name': 'foo_host'} + assert host_audit.organization == bare_job.organization + assert host_audit.name == 'vm-foo' + assert set(host_audit.events) == set(all_task_names) + + +@pytest.mark.django_db +def test_events_not_fully_processed_no_op(bare_job): + # I have a job that produced 12 events, but those are not saved + bare_job.emitted_events = 12 + bare_job.finished = now() + bare_job.save(update_fields=['emitted_events', 'finished']) + + # Running the normal post-run task will do nothing at this point + assert bare_job.event_queries_processed is False + with mock.patch('time.sleep'): # for test speedup + save_indirect_host_entries(bare_job.id) + bare_job.refresh_from_db() + assert bare_job.event_queries_processed is False + + # Right away, the fallback processing will not run either + cleanup_and_save_indirect_host_entries_fallback() + bare_job.refresh_from_db() + assert bare_job.event_queries_processed is False + + # After 3 hours have passed... + bare_job.finished = now() - timedelta(hours=3) + + # Create the expected job events + for _ in range(12): + create_registered_event(bare_job) + + bare_job.save(update_fields=['finished']) + + # The fallback task will now process indirect host query data for this job + cleanup_and_save_indirect_host_entries_fallback() + + # Test code to process anyway, events collected or not + save_indirect_host_entries(bare_job.id, wait_for_events=False) + bare_job.refresh_from_db() + assert bare_job.event_queries_processed is True + + +@pytest.mark.django_db +def test_job_id_does_not_exist(): + save_indirect_host_entries(10000001) + + +@pytest.mark.django_db +def test_cleanup_old_audit_records(old_audit_record, new_audit_record): + count_before_cleanup = IndirectManagedNodeAudit.objects.count() + assert count_before_cleanup == 2 + cleanup_and_save_indirect_host_entries_fallback() + count_after_cleanup = IndirectManagedNodeAudit.objects.count() + assert count_after_cleanup == 1 diff --git a/awx/main/tests/functional/tasks/test_tasks_jobs.py b/awx/main/tests/functional/tasks/test_tasks_jobs.py new file mode 100644 index 000000000000..012ee20fdb5e --- /dev/null +++ b/awx/main/tests/functional/tasks/test_tasks_jobs.py @@ -0,0 +1,31 @@ +import pytest + +from awx.main.tasks.jobs import RunJob +from awx.main.models import Job + + +@pytest.mark.django_db +def test_does_not_run_reaped_job(mocker, mock_me): + job = Job.objects.create(status='failed', job_explanation='This job has been reaped.') + mock_run = mocker.patch('awx.main.tasks.jobs.ansible_runner.interface.run') + try: + RunJob().run(job.id) + except Exception: + pass + job.refresh_from_db() + assert job.status == 'failed' + mock_run.assert_not_called() + + +@pytest.mark.django_db +def test_cancel_flag_on_start(jt_linked, caplog): + job = jt_linked.create_unified_job() + job.status = 'waiting' + job.cancel_flag = True + job.save() + + task = RunJob() + task.run(job.id) + + job = Job.objects.get(id=job.id) + assert job.status == 'canceled' diff --git a/awx/main/tests/functional/tasks/test_tasks_system.py b/awx/main/tests/functional/tasks/test_tasks_system.py new file mode 100644 index 000000000000..96ce7aa41347 --- /dev/null +++ b/awx/main/tests/functional/tasks/test_tasks_system.py @@ -0,0 +1,166 @@ +import copy +import json +import logging +import os +import tempfile +import shutil +from unittest import mock + +import pytest + +from awx.main.tasks.system import CleanupImagesAndFiles, execution_node_health_check, inspect_established_receptor_connections, clear_setting_cache +from awx.main.management.commands.dispatcherd import Command +from awx.main.models import Instance, Job, ReceptorAddress, InstanceLink + + +@pytest.mark.django_db +class TestLinkState: + @pytest.fixture(autouse=True) + def configure_settings(self, settings): + settings.IS_K8S = True + + def test_inspect_established_receptor_connections(self): + ''' + Change link state from ADDING to ESTABLISHED + if the receptor status KnownConnectionCosts field + has an entry for the source and target node. + ''' + hop1 = Instance.objects.create(hostname='hop1') + hop2 = Instance.objects.create(hostname='hop2') + hop2addr = ReceptorAddress.objects.create(instance=hop2, address='hop2', port=5678) + InstanceLink.objects.create(source=hop1, target=hop2addr, link_state=InstanceLink.States.ADDING) + + # calling with empty KnownConnectionCosts should not change the link state + inspect_established_receptor_connections({"KnownConnectionCosts": {}}) + assert InstanceLink.objects.get(source=hop1, target=hop2addr).link_state == InstanceLink.States.ADDING + + mesh_state = {"KnownConnectionCosts": {"hop1": {"hop2": 1}}} + inspect_established_receptor_connections(mesh_state) + assert InstanceLink.objects.get(source=hop1, target=hop2addr).link_state == InstanceLink.States.ESTABLISHED + + +@pytest.fixture +def job_folder_factory(request): + def _rf(job_id='1234'): + pdd_path = tempfile.mkdtemp(prefix=f'awx_{job_id}_') + + def test_folder_cleanup(): + if os.path.exists(pdd_path): + shutil.rmtree(pdd_path) + + request.addfinalizer(test_folder_cleanup) + + return pdd_path + + return _rf + + +@pytest.fixture +def mock_job_folder(job_folder_factory): + return job_folder_factory() + + +@pytest.mark.django_db +@pytest.mark.parametrize('node_type', ('control. hybrid')) +def test_no_worker_info_on_AWX_nodes(node_type): + hostname = 'us-south-3-compute.invalid' + Instance.objects.create(hostname=hostname, node_type=node_type) + assert execution_node_health_check(hostname) is None + + +@pytest.mark.django_db +def test_folder_cleanup_stale_file(mock_job_folder, mock_me): + CleanupImagesAndFiles.run() + assert os.path.exists(mock_job_folder) # grace period should protect folder from deletion + + CleanupImagesAndFiles.run(grace_period=0) + assert not os.path.exists(mock_job_folder) # should be deleted + + +@pytest.mark.django_db +def test_folder_cleanup_running_job(mock_job_folder, me_inst): + job = Job.objects.create(id=1234, controller_node=me_inst.hostname, status='running') + CleanupImagesAndFiles.run(grace_period=0) + assert os.path.exists(mock_job_folder) # running job should prevent folder from getting deleted + + job.status = 'failed' + job.save(update_fields=['status']) + CleanupImagesAndFiles.run(grace_period=0) + assert not os.path.exists(mock_job_folder) # job is finished and no grace period, should delete + + +@pytest.mark.django_db +def test_folder_cleanup_multiple_running_jobs(job_folder_factory, me_inst): + jobs = [] + dirs = [] + num_jobs = 3 + + for i in range(num_jobs): + job = Job.objects.create(controller_node=me_inst.hostname, status='running') + dirs.append(job_folder_factory(job.id)) + jobs.append(job) + + CleanupImagesAndFiles.run(grace_period=0) + + assert [os.path.exists(d) for d in dirs] == [True for i in range(num_jobs)] + + +@pytest.mark.django_db +def test_clear_setting_cache_log_level_branch(settings): + settings.LOG_AGGREGATOR_LEVEL = 'DEBUG' + settings.CLUSTER_HOST_ID = 'control-node' + published_messages = [] + + class DummyBroker: + def publish_message(self, channel, message): + published_messages.append((channel, message)) + + def close(self): + pass + + dummy_broker = DummyBroker() + + with mock.patch('dispatcherd.control.get_broker', return_value=dummy_broker) as mock_get_broker: + clear_setting_cache(['LOG_AGGREGATOR_LEVEL']) + + mock_get_broker.assert_called_once() + assert published_messages, 'control command was not sent through the broker' + queue, payload = published_messages[-1] + assert queue == 'control-node' + body = json.loads(payload) + assert body['control'] == 'set_log_level' + assert body['control_data'] == {'level': 'DEBUG'} + + +@pytest.mark.django_db +def test_configure_dispatcher_logging_updates_level(settings): + original_logging_settings = copy.deepcopy(settings.LOGGING) + settings.LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'filters': { + 'dynamic_level_filter': { + '()': 'logging.Filter', + } + }, + 'handlers': { + 'console': { + 'class': 'logging.StreamHandler', + 'filters': ['dynamic_level_filter'], + 'stream': 'ext://sys.stdout', + } + }, + 'loggers': { + 'dispatcherd': { + 'handlers': ['console'], + 'level': 'INFO', + 'propagate': False, + } + }, + } + settings.LOG_AGGREGATOR_LEVEL = 'WARNING' + + Command().configure_dispatcher_logging() + + assert logging.getLogger('dispatcherd').level == logging.WARNING + settings.LOGGING = original_logging_settings diff --git a/awx/main/tests/functional/test_apps.py b/awx/main/tests/functional/test_apps.py new file mode 100644 index 000000000000..a52d4aa723ed --- /dev/null +++ b/awx/main/tests/functional/test_apps.py @@ -0,0 +1,26 @@ +import pytest + +from django.apps import apps + + +@pytest.fixture +def mock_setup_tower_managed_defaults(mocker): + return mocker.patch('awx.main.models.credential.CredentialType.setup_tower_managed_defaults') + + +@pytest.mark.django_db +def test_load_credential_types_feature_migrations_ran(mocker, mock_setup_tower_managed_defaults): + mocker.patch('awx.main.apps.is_database_synchronized', return_value=True) + + apps.get_app_config('main')._load_credential_types_feature() + + mock_setup_tower_managed_defaults.assert_called_once() + + +@pytest.mark.django_db +def test_load_credential_types_feature_migrations_not_ran(mocker, mock_setup_tower_managed_defaults): + mocker.patch('awx.main.apps.is_database_synchronized', return_value=False) + + apps.get_app_config('main')._load_credential_types_feature() + + mock_setup_tower_managed_defaults.assert_not_called() diff --git a/awx/main/tests/functional/test_bulk.py b/awx/main/tests/functional/test_bulk.py new file mode 100644 index 000000000000..6b166cdf2bff --- /dev/null +++ b/awx/main/tests/functional/test_bulk.py @@ -0,0 +1,447 @@ +import pytest + +from uuid import uuid4 + +from awx.api.versioning import reverse + +from awx.main.models.jobs import JobTemplate +from awx.main.models import Organization, Inventory, WorkflowJob, ExecutionEnvironment, Host +from awx.main.scheduler import TaskManager + + +@pytest.mark.django_db +@pytest.mark.parametrize('num_hosts, num_queries', [(1, 15), (10, 15)]) +def test_bulk_host_create_num_queries(organization, inventory, post, get, user, num_hosts, num_queries, django_assert_max_num_queries): + ''' + If I am a... + org admin + inventory admin at org level + admin of a particular inventory + superuser + + Bulk Host create should take under a certain number of queries + ''' + inventory.organization = organization + inventory_admin = user('inventory_admin', False) + org_admin = user('org_admin', False) + org_inv_admin = user('org_admin', False) + superuser = user('admin', True) + for u in [org_admin, org_inv_admin, inventory_admin]: + organization.member_role.members.add(u) + organization.admin_role.members.add(org_admin) + organization.inventory_admin_role.members.add(org_inv_admin) + inventory.admin_role.members.add(inventory_admin) + + for u in [org_admin, inventory_admin, org_inv_admin, superuser]: + hosts = [{'name': uuid4()} for i in range(num_hosts)] + with django_assert_max_num_queries(num_queries): + bulk_host_create_response = post(reverse('api:bulk_host_create'), {'inventory': inventory.id, 'hosts': hosts}, u, expect=201).data + assert len(bulk_host_create_response['hosts']) == len(hosts), f"unexpected number of hosts created for user {u}" + + +@pytest.mark.django_db +def test_bulk_host_create_rbac(organization, inventory, post, get, user): + ''' + If I am a... + org admin + inventory admin at org level + admin of a particular invenotry + ... I can bulk add hosts + + Everyone else cannot + ''' + inventory.organization = organization + inventory_admin = user('inventory_admin', False) + org_admin = user('org_admin', False) + org_inv_admin = user('org_admin', False) + auditor = user('auditor', False) + member = user('member', False) + use_inv_member = user('member', False) + for u in [org_admin, org_inv_admin, auditor, member, inventory_admin, use_inv_member]: + organization.member_role.members.add(u) + organization.admin_role.members.add(org_admin) + organization.inventory_admin_role.members.add(org_inv_admin) + inventory.admin_role.members.add(inventory_admin) + inventory.use_role.members.add(use_inv_member) + organization.auditor_role.members.add(auditor) + + for indx, u in enumerate([org_admin, inventory_admin, org_inv_admin]): + bulk_host_create_response = post( + reverse('api:bulk_host_create'), {'inventory': inventory.id, 'hosts': [{'name': f'foobar-{indx}'}]}, u, expect=201 + ).data + assert len(bulk_host_create_response['hosts']) == 1, f"unexpected number of hosts created for user {u}" + assert Host.objects.filter(inventory__id=inventory.id)[0].name == 'foobar-0' + + for indx, u in enumerate([member, auditor, use_inv_member]): + bulk_host_create_response = post( + reverse('api:bulk_host_create'), {'inventory': inventory.id, 'hosts': [{'name': f'foobar2-{indx}'}]}, u, expect=400 + ).data + assert bulk_host_create_response['__all__'][0] == f'Inventory with id {inventory.id} not found or lack permissions to add hosts.' + + +@pytest.mark.django_db +@pytest.mark.parametrize('num_jobs, num_queries', [(1, 25), (10, 25)]) +def test_bulk_job_launch_queries(job_template, organization, inventory, project, post, get, user, num_jobs, num_queries, django_assert_max_num_queries): + ''' + if I have access to the unified job template + ... I can launch the bulk job + ... and the number of queries should NOT scale with the number of jobs + ''' + normal_user = user('normal_user', False) + org_admin = user('org_admin', False) + jt = JobTemplate.objects.create(name='my-jt', ask_inventory_on_launch=True, project=project, playbook='helloworld.yml') + organization.member_role.members.add(normal_user) + organization.admin_role.members.add(org_admin) + jt.execute_role.members.add(normal_user) + inventory.use_role.members.add(normal_user) + jt.save() + inventory.save() + jobs = [{'unified_job_template': jt.id, 'inventory': inventory.id} for _ in range(num_jobs)] + + # This is not working, we need to figure that out if we want to include tests for more jobs + # with mock.patch('awx.api.serializers.settings.BULK_JOB_MAX_LAUNCH', num_jobs + 1): + with django_assert_max_num_queries(num_queries): + bulk_job_launch_response = post(reverse('api:bulk_job_launch'), {'name': 'Bulk Job Launch', 'jobs': jobs}, normal_user, expect=201).data + + # Run task manager so the workflow job nodes actually spawn + TaskManager().schedule() + + for u in (org_admin, normal_user): + bulk_job = get(bulk_job_launch_response['url'], u, expect=200).data + assert organization.id == bulk_job['summary_fields']['organization']['id'] + resp = get(bulk_job_launch_response['related']['workflow_nodes'], u) + assert resp.data['count'] == num_jobs + for item in resp.data['results']: + assert item["unified_job_template"] == jt.id + assert item["inventory"] == inventory.id + + +@pytest.mark.django_db +def test_bulk_job_launch_no_access_to_job_template(job_template, organization, inventory, project, credential, post, get, user): + ''' + if I don't have access to the unified job templare + ... I can't launch the bulk job + ''' + normal_user = user('normal_user', False) + jt = JobTemplate.objects.create(name='my-jt', inventory=inventory, project=project, playbook='helloworld.yml') + jt.save() + organization.member_role.members.add(normal_user) + bulk_job_launch_response = post( + reverse('api:bulk_job_launch'), {'name': 'Bulk Job Launch', 'jobs': [{'unified_job_template': jt.id}]}, normal_user, expect=400 + ).data + assert bulk_job_launch_response['__all__'][0] == f'Job Templates {{{jt.id}}} not found or you don\'t have permissions to access it' + + +@pytest.mark.django_db +def test_bulk_job_launch_no_org_assigned(job_template, organization, inventory, project, credential, post, get, user): + ''' + if I am not part of any organization... + ... I can't launch the bulk job + ''' + normal_user = user('normal_user', False) + jt = JobTemplate.objects.create(name='my-jt', inventory=inventory, project=project, playbook='helloworld.yml') + jt.save() + jt.execute_role.members.add(normal_user) + bulk_job_launch_response = post( + reverse('api:bulk_job_launch'), {'name': 'Bulk Job Launch', 'jobs': [{'unified_job_template': jt.id}]}, normal_user, expect=400 + ).data + assert bulk_job_launch_response['__all__'][0] == 'User not part of any organization, please assign an organization to assign to the bulk job' + + +@pytest.mark.django_db +def test_bulk_job_launch_multiple_org_assigned(job_template, organization, inventory, project, credential, post, get, user): + ''' + if I am part of multiple organization... + and if I do not provide org at the launch time + ... I can't launch the bulk job + ''' + normal_user = user('normal_user', False) + org1 = Organization.objects.create(name='foo1') + org2 = Organization.objects.create(name='foo2') + org1.member_role.members.add(normal_user) + org2.member_role.members.add(normal_user) + jt = JobTemplate.objects.create(name='my-jt', inventory=inventory, project=project, playbook='helloworld.yml') + jt.save() + jt.execute_role.members.add(normal_user) + bulk_job_launch_response = post( + reverse('api:bulk_job_launch'), {'name': 'Bulk Job Launch', 'jobs': [{'unified_job_template': jt.id}]}, normal_user, expect=400 + ).data + assert bulk_job_launch_response['__all__'][0] == 'User has permission to multiple Organizations, please set one of them in the request' + + +@pytest.mark.django_db +def test_bulk_job_launch_specific_org(job_template, organization, inventory, project, credential, post, get, user): + ''' + if I am part of multiple organization... + and if I provide org at the launch time + ... I can launch the bulk job + ''' + normal_user = user('normal_user', False) + org1 = Organization.objects.create(name='foo1') + org2 = Organization.objects.create(name='foo2') + org1.member_role.members.add(normal_user) + org2.member_role.members.add(normal_user) + jt = JobTemplate.objects.create(name='my-jt', inventory=inventory, project=project, playbook='helloworld.yml') + jt.save() + jt.execute_role.members.add(normal_user) + bulk_job_launch_response = post( + reverse('api:bulk_job_launch'), {'name': 'Bulk Job Launch', 'jobs': [{'unified_job_template': jt.id}], 'organization': org1.id}, normal_user, expect=201 + ).data + bulk_job_id = bulk_job_launch_response['id'] + bulk_job_obj = WorkflowJob.objects.filter(id=bulk_job_id, is_bulk_job=True).first() + assert org1.id == bulk_job_obj.organization.id + + +@pytest.mark.django_db +def test_bulk_job_launch_inventory_no_access(job_template, organization, inventory, project, credential, post, get, user): + ''' + if I don't have access to the inventory... + and if I try to use it at the launch time + ... I can't launch the bulk job + ''' + normal_user = user('normal_user', False) + org1 = Organization.objects.create(name='foo1') + org2 = Organization.objects.create(name='foo2') + jt = JobTemplate.objects.create(name='my-jt', inventory=inventory, project=project, playbook='helloworld.yml') + jt.save() + org1.member_role.members.add(normal_user) + inv = Inventory.objects.create(name='inv1', organization=org2) + jt.execute_role.members.add(normal_user) + bulk_job_launch_response = post( + reverse('api:bulk_job_launch'), {'name': 'Bulk Job Launch', 'jobs': [{'unified_job_template': jt.id, 'inventory': inv.id}]}, normal_user, expect=400 + ).data + assert bulk_job_launch_response['__all__'][0] == f'Inventories {{{inv.id}}} not found or you don\'t have permissions to access it' + + +@pytest.mark.django_db +def test_bulk_job_inventory_prompt(job_template, organization, inventory, project, credential, post, get, user): + ''' + Job template has an inventory set as prompt_on_launch + and if I provide the inventory as a parameter in bulk job + ... job uses that inventory + ''' + normal_user = user('normal_user', False) + org1 = Organization.objects.create(name='foo1') + jt = JobTemplate.objects.create(name='my-jt', ask_inventory_on_launch=True, project=project, playbook='helloworld.yml') + jt.save() + org1.member_role.members.add(normal_user) + inv = Inventory.objects.create(name='inv1', organization=org1) + jt.execute_role.members.add(normal_user) + inv.use_role.members.add(normal_user) + bulk_job_launch_response = post( + reverse('api:bulk_job_launch'), {'name': 'Bulk Job Launch', 'jobs': [{'unified_job_template': jt.id, 'inventory': inv.id}]}, normal_user, expect=201 + ).data + bulk_job_id = bulk_job_launch_response['id'] + node = WorkflowJob.objects.get(id=bulk_job_id).workflow_job_nodes.all().order_by('created') + assert inv.id == node[0].inventory.id + + +@pytest.mark.django_db +def test_bulk_job_set_all_prompt(job_template, organization, inventory, project, credentialtype_ssh, post, get, user): + ''' + Job template has many fields set as prompt_on_launch + and if I provide all those fields as a parameter in bulk job + ... job uses them + ''' + normal_user = user('normal_user', False) + jt = JobTemplate.objects.create( + name='my-jt', + ask_inventory_on_launch=True, + ask_diff_mode_on_launch=True, + ask_job_type_on_launch=True, + ask_verbosity_on_launch=True, + ask_execution_environment_on_launch=True, + ask_forks_on_launch=True, + ask_job_slice_count_on_launch=True, + ask_timeout_on_launch=True, + ask_variables_on_launch=True, + ask_scm_branch_on_launch=True, + ask_limit_on_launch=True, + ask_skip_tags_on_launch=True, + ask_tags_on_launch=True, + project=project, + playbook='helloworld.yml', + ) + jt.save() + organization.member_role.members.add(normal_user) + inv = Inventory.objects.create(name='inv1', organization=organization) + ee = ExecutionEnvironment.objects.create(name='test-ee', image='quay.io/foo/bar') + jt.execute_role.members.add(normal_user) + inv.use_role.members.add(normal_user) + bulk_job_launch_response = post( + reverse('api:bulk_job_launch'), + { + 'name': 'Bulk Job Launch', + 'jobs': [ + { + 'unified_job_template': jt.id, + 'inventory': inv.id, + 'diff_mode': True, + 'job_type': 'check', + 'verbosity': 3, + 'execution_environment': ee.id, + 'forks': 1, + 'job_slice_count': 1, + 'timeout': 200, + 'extra_data': {'prompted_key': 'prompted_val'}, + 'scm_branch': 'non_dev', + 'limit': 'kansas', + 'skip_tags': 'foobar', + 'job_tags': 'untagged', + } + ], + }, + normal_user, + expect=201, + ).data + bulk_job_id = bulk_job_launch_response['id'] + node = WorkflowJob.objects.get(id=bulk_job_id).workflow_job_nodes.all().order_by('created') + assert node[0].inventory.id == inv.id + assert node[0].diff_mode == True + assert node[0].job_type == 'check' + assert node[0].verbosity == 3 + assert node[0].execution_environment.id == ee.id + assert node[0].forks == 1 + assert node[0].job_slice_count == 1 + assert node[0].timeout == 200 + assert node[0].extra_data == {'prompted_key': 'prompted_val'} + assert node[0].scm_branch == 'non_dev' + assert node[0].limit == 'kansas' + assert node[0].skip_tags == 'foobar' + assert node[0].job_tags == 'untagged' + + +@pytest.mark.django_db +@pytest.mark.parametrize('num_hosts, num_queries', [(1, 70), (10, 150), (25, 250)]) +def test_bulk_host_delete_num_queries(organization, inventory, post, get, user, num_hosts, num_queries, django_assert_max_num_queries): + ''' + If I am a... + org admin + inventory admin at org level + admin of a particular inventory + superuser + + Bulk Host delete should take under a certain number of queries + ''' + users_list = setup_admin_users_list(organization, inventory, user) + for u in users_list: + hosts = [{'name': str(uuid4())} for i in range(num_hosts)] + with django_assert_max_num_queries(num_queries): + bulk_host_create_response = post(reverse('api:bulk_host_create'), {'inventory': inventory.id, 'hosts': hosts}, u, expect=201).data + assert len(bulk_host_create_response['hosts']) == len(hosts), f"unexpected number of hosts created for user {u}" + hosts_ids_created = get_inventory_hosts(get, inventory.id, u) + bulk_host_delete_response = post(reverse('api:bulk_host_delete'), {'hosts': hosts_ids_created}, u, expect=201).data + assert len(bulk_host_delete_response['hosts'].keys()) == len(hosts), f"unexpected number of hosts deleted for user {u}" + + +@pytest.mark.django_db +def test_bulk_host_delete_rbac(organization, inventory, post, get, user): + ''' + If I am a... + org admin + inventory admin at org level + admin of a particular invenotry + ... I can bulk delete hosts + + Everyone else cannot + ''' + admin_users_list = setup_admin_users_list(organization, inventory, user) + users_list = setup_none_admin_uses_list(organization, inventory, user) + + for indx, u in enumerate(admin_users_list): + bulk_host_create_response = post( + reverse('api:bulk_host_create'), {'inventory': inventory.id, 'hosts': [{'name': f'foobar-{indx}'}]}, u, expect=201 + ).data + assert len(bulk_host_create_response['hosts']) == 1, f"unexpected number of hosts created for user {u}" + assert Host.objects.filter(inventory__id=inventory.id)[0].name == f'foobar-{indx}' + hosts_ids_created = get_inventory_hosts(get, inventory.id, u) + bulk_host_delete_response = post(reverse('api:bulk_host_delete'), {'hosts': hosts_ids_created}, u, expect=201).data + assert len(bulk_host_delete_response['hosts'].keys()) == 1, f"unexpected number of hosts deleted by user {u}" + + for indx, create_u in enumerate(admin_users_list): + bulk_host_create_response = post( + reverse('api:bulk_host_create'), {'inventory': inventory.id, 'hosts': [{'name': f'foobar2-{indx}'}]}, create_u, expect=201 + ).data + print(bulk_host_create_response) + assert bulk_host_create_response['hosts'][0]['name'] == f'foobar2-{indx}' + hosts_ids_created = get_inventory_hosts(get, inventory.id, create_u) + print(f"Try to delete {hosts_ids_created}") + for delete_u in users_list: + bulk_host_delete_response = post(reverse('api:bulk_host_delete'), {'hosts': hosts_ids_created}, delete_u, expect=403).data + assert "Lack permissions to delete hosts from this inventory." in bulk_host_delete_response['inventories'].values() + + +@pytest.mark.django_db +def test_bulk_host_delete_from_multiple_inv(organization, inventory, post, get, user): + ''' + If I am inventory admin at org level + + Bulk Host delete should be enabled only on my inventory + ''' + num_hosts = 10 + inventory.organization = organization + + # Create second inventory + inv2 = organization.inventories.create(name="second-test-inv") + inv2.organization = organization + admin2_user = user('inventory2_admin', False) + inv2.admin_role.members.add(admin2_user) + + admin_user = user('inventory_admin', False) + inventory.admin_role.members.add(admin_user) + + organization.member_role.members.add(admin_user) + organization.member_role.members.add(admin2_user) + + hosts = [{'name': str(uuid4())} for i in range(num_hosts)] + hosts2 = [{'name': str(uuid4())} for i in range(num_hosts)] + + # create hosts in each of the inventories + bulk_host_create_response = post(reverse('api:bulk_host_create'), {'inventory': inventory.id, 'hosts': hosts}, admin_user, expect=201).data + assert len(bulk_host_create_response['hosts']) == len(hosts), f"unexpected number of hosts created for user {admin_user}" + + bulk_host_create_response2 = post(reverse('api:bulk_host_create'), {'inventory': inv2.id, 'hosts': hosts2}, admin2_user, expect=201).data + assert len(bulk_host_create_response2['hosts']) == len(hosts), f"unexpected number of hosts created for user {admin2_user}" + + # get all hosts ids - from both inventories + hosts_ids_created = get_inventory_hosts(get, inventory.id, admin_user) + hosts_ids_created += get_inventory_hosts(get, inv2.id, admin2_user) + + expected_error = "Lack permissions to delete hosts from this inventory." + # try to delete ALL hosts with admin user of inventory 1. + for inv_name, invadmin in zip([inv2.name, inventory.name], [admin_user, admin2_user]): + bulk_host_delete_response = post(reverse('api:bulk_host_delete'), {'hosts': hosts_ids_created}, invadmin, expect=403).data + result_message = bulk_host_delete_response['inventories'][inv_name] + assert result_message == expected_error, f"deleted hosts without permission by user {invadmin}" + + +def setup_admin_users_list(organization, inventory, user): + inventory.organization = organization + inventory_admin = user('inventory_admin', False) + org_admin = user('org_admin', False) + org_inv_admin = user('org_admin', False) + superuser = user('admin', True) + for u in [org_admin, org_inv_admin, inventory_admin]: + organization.member_role.members.add(u) + organization.admin_role.members.add(org_admin) + organization.inventory_admin_role.members.add(org_inv_admin) + inventory.admin_role.members.add(inventory_admin) + return [inventory_admin, org_inv_admin, superuser, org_admin] + + +def setup_none_admin_uses_list(organization, inventory, user): + inventory.organization = organization + auditor = user('auditor', False) + member = user('member', False) + use_inv_member = user('member', False) + for u in [auditor, member, use_inv_member]: + organization.member_role.members.add(u) + inventory.use_role.members.add(use_inv_member) + organization.auditor_role.members.add(auditor) + return [auditor, member, use_inv_member] + + +def get_inventory_hosts(get, inv_id, use_user): + data = get(reverse('api:inventory_hosts_list', kwargs={'pk': inv_id}), use_user, expect=200).data + results = [host['id'] for host in data['results']] + return results diff --git a/awx/main/tests/functional/test_copy.py b/awx/main/tests/functional/test_copy.py index 0574f9ccbdef..7c156979a8b7 100644 --- a/awx/main/tests/functional/test_copy.py +++ b/awx/main/tests/functional/test_copy.py @@ -43,7 +43,7 @@ def test_job_template_copy( c.save() assert get(reverse('api:job_template_copy', kwargs={'pk': job_template_with_survey_passwords.pk}), alice, expect=200).data['can_copy'] is True jt_copy_pk_alice = post( - reverse('api:job_template_copy', kwargs={'pk': job_template_with_survey_passwords.pk}), {'name': 'new jt name'}, alice, expect=201 + reverse('api:job_template_copy', kwargs={'pk': job_template_with_survey_passwords.pk}), {'name': 'new jt name alice'}, alice, expect=201 ).data['id'] jt_copy_admin = type(job_template_with_survey_passwords).objects.get(pk=jt_copy_pk) @@ -53,7 +53,7 @@ def test_job_template_copy( assert jt_copy_alice.created_by == alice for jt_copy in (jt_copy_admin, jt_copy_alice): - assert jt_copy.name == 'new jt name' + assert jt_copy.name.startswith('new jt name') assert jt_copy.project == project assert jt_copy.inventory == inventory assert jt_copy.playbook == job_template_with_survey_passwords.playbook @@ -123,6 +123,24 @@ def test_inventory_copy(inventory, group_factory, post, get, alice, organization assert set(group_2_2_copy.hosts.all()) == set() +@pytest.mark.django_db +@pytest.mark.parametrize( + "is_admin, can_copy, status", + [ + [True, True, 200], + [False, False, 200], + ], +) +def test_workflow_job_template_copy_access(get, admin_user, alice, workflow_job_template, is_admin, can_copy, status): + url = reverse('api:workflow_job_template_copy', kwargs={'pk': workflow_job_template.pk}) + if is_admin: + response = get(url, user=admin_user, expect=status) + else: + workflow_job_template.organization.auditor_role.members.add(alice) + response = get(url, user=alice, expect=status) + assert response.data['can_copy'] == can_copy + + @pytest.mark.django_db def test_workflow_job_template_copy(workflow_job_template, post, get, admin, organization): ''' diff --git a/awx/main/tests/functional/test_credential.py b/awx/main/tests/functional/test_credential.py index d2937412daa5..2ecc508088a0 100644 --- a/awx/main/tests/functional/test_credential.py +++ b/awx/main/tests/functional/test_credential.py @@ -78,18 +78,22 @@ def test_default_cred_types(): [ 'aim', 'aws', + 'aws_secretsmanager_credential', 'azure_kv', 'azure_rm', + 'bitbucket_dc_token', 'centrify_vault_kv', 'conjur', 'controller', 'galaxy_api_token', 'gce', 'github_token', + 'github_app_lookup', 'gitlab_token', 'gpg_public_key', 'hashivault_kv', 'hashivault_ssh', + 'hcp_terraform', 'insights', 'kubernetes_bearer_token', 'net', @@ -99,6 +103,7 @@ def test_default_cred_types(): 'satellite6', 'scm', 'ssh', + 'terraform', 'thycotic_dsv', 'thycotic_tss', 'vault', @@ -336,3 +341,25 @@ def test_credential_get_input(organization_factory): # verify return values for encrypted secret fields are decrypted assert cred.inputs['vault_password'].startswith('$encrypted$') assert cred.get_input('vault_password') == 'testing321' + + +@pytest.mark.django_db +def test_idempotent_credential_type_setup(): + """ + awx main app ready() calls `setup_tower_managed_defaults()` to register CredentialType(s). + This is problematic in our testing system. pytest_django deviates from the production ready() call path. pytest_django calls our apps ready() function + before migrations run. This is a problem since we interact with tables in the database that do not yet exist. + + Now forget about what you just read because we do not _actually_ want to register CredentialType(s) in our test at all. So then + you would expect this bit of code to spy on `setup_tower_managed_defaults` and assert it was not called BUT registering a spy early + enough is hard. The call to ready() from pytest_django happens via pytest hooks very early https://github.com/pytest-dev/pytest-django/blob/1157a7c5c74f4b4e0f4aca8312f3fe67eb00568e/pytest_django/plugin.py#L266C5-L266C34 + + Instead of ensuring that `setup_tower_managed_defaults()` is explicitly not called, we check it _implicitly_ by observing that no credential type records are created. + """ + assert CredentialType.objects.count() == 0 + CredentialType.setup_tower_managed_defaults() + total = CredentialType.objects.count() + assert total > 0 + + CredentialType.setup_tower_managed_defaults() + assert CredentialType.objects.count() == total diff --git a/awx/main/tests/functional/test_credential_plugins.py b/awx/main/tests/functional/test_credential_plugins.py deleted file mode 100644 index 3ea31fce425d..000000000000 --- a/awx/main/tests/functional/test_credential_plugins.py +++ /dev/null @@ -1,78 +0,0 @@ -import pytest -from unittest import mock -from awx.main.credential_plugins import hashivault - - -def test_imported_azure_cloud_sdk_vars(): - from awx.main.credential_plugins import azure_kv - - assert len(azure_kv.clouds) > 0 - assert all([hasattr(c, 'name') for c in azure_kv.clouds]) - assert all([hasattr(c, 'suffixes') for c in azure_kv.clouds]) - assert all([hasattr(c.suffixes, 'keyvault_dns') for c in azure_kv.clouds]) - - -def test_hashivault_approle_auth(): - kwargs = { - 'role_id': 'the_role_id', - 'secret_id': 'the_secret_id', - } - expected_res = { - 'role_id': 'the_role_id', - 'secret_id': 'the_secret_id', - } - res = hashivault.approle_auth(**kwargs) - assert res == expected_res - - -def test_hashivault_kubernetes_auth(): - kwargs = { - 'kubernetes_role': 'the_kubernetes_role', - } - expected_res = { - 'role': 'the_kubernetes_role', - 'jwt': 'the_jwt', - } - with mock.patch('pathlib.Path') as path_mock: - mock.mock_open(path_mock.return_value.open, read_data='the_jwt') - res = hashivault.kubernetes_auth(**kwargs) - path_mock.assert_called_with('/var/run/secrets/kubernetes.io/serviceaccount/token') - assert res == expected_res - - -def test_hashivault_handle_auth_token(): - kwargs = { - 'token': 'the_token', - } - token = hashivault.handle_auth(**kwargs) - assert token == kwargs['token'] - - -def test_hashivault_handle_auth_approle(): - kwargs = { - 'role_id': 'the_role_id', - 'secret_id': 'the_secret_id', - } - with mock.patch.object(hashivault, 'method_auth') as method_mock: - method_mock.return_value = 'the_token' - token = hashivault.handle_auth(**kwargs) - method_mock.assert_called_with(**kwargs, auth_param=kwargs) - assert token == 'the_token' - - -def test_hashivault_handle_auth_kubernetes(): - kwargs = { - 'kubernetes_role': 'the_kubernetes_role', - } - with mock.patch.object(hashivault, 'method_auth') as method_mock: - with mock.patch('pathlib.Path') as path_mock: - mock.mock_open(path_mock.return_value.open, read_data='the_jwt') - method_mock.return_value = 'the_token' - token = hashivault.handle_auth(**kwargs) - method_mock.assert_called_with(**kwargs, auth_param={'role': 'the_kubernetes_role', 'jwt': 'the_jwt'}) - assert token == 'the_token' - - -def test_hashivault_handle_auth_not_enough_args(): - with pytest.raises(Exception): - hashivault.handle_auth() diff --git a/awx/main/tests/functional/test_dispatch.py b/awx/main/tests/functional/test_dispatch.py index 86e90e50a0f4..7226318a19bf 100644 --- a/awx/main/tests/functional/test_dispatch.py +++ b/awx/main/tests/functional/test_dispatch.py @@ -1,19 +1,12 @@ import datetime -import multiprocessing -import random -import signal -import time from unittest import mock - from django.utils.timezone import now as tz_now import pytest from awx.main.models import Job, WorkflowJob, Instance from awx.main.dispatch import reaper -from awx.main.dispatch.pool import StatefulPoolWorker, WorkerPool, AutoscalePool -from awx.main.dispatch.publish import task -from awx.main.dispatch.worker import BaseWorker, TaskWorker - +from awx.main.tasks import system +from dispatcherd.publish import task ''' Prevent logger. calls from triggering database operations @@ -56,286 +49,9 @@ def multiply(a, b): return a * b -class SimpleWorker(BaseWorker): - def perform_work(self, body, *args): - pass - - -class ResultWriter(BaseWorker): - def perform_work(self, body, result_queue): - result_queue.put(body + '!!!') - - -class SlowResultWriter(BaseWorker): - def perform_work(self, body, result_queue): - time.sleep(3) - super(SlowResultWriter, self).perform_work(body, result_queue) - - -@pytest.mark.usefixtures("disable_database_settings") -class TestPoolWorker: - def setup_method(self, test_method): - self.worker = StatefulPoolWorker(1000, self.tick, tuple()) - - def tick(self): - self.worker.finished.put(self.worker.queue.get()['uuid']) - time.sleep(0.5) - - def test_qsize(self): - assert self.worker.qsize == 0 - for i in range(3): - self.worker.put({'task': 'abc123'}) - assert self.worker.qsize == 3 - - def test_put(self): - assert len(self.worker.managed_tasks) == 0 - assert self.worker.messages_finished == 0 - self.worker.put({'task': 'abc123'}) - - assert len(self.worker.managed_tasks) == 1 - assert self.worker.messages_sent == 1 - - def test_managed_tasks(self): - self.worker.put({'task': 'abc123'}) - self.worker.calculate_managed_tasks() - assert len(self.worker.managed_tasks) == 1 - - self.tick() - self.worker.calculate_managed_tasks() - assert len(self.worker.managed_tasks) == 0 - - def test_current_task(self): - self.worker.put({'task': 'abc123'}) - assert self.worker.current_task['task'] == 'abc123' - - def test_quit(self): - self.worker.quit() - assert self.worker.queue.get() == 'QUIT' - - def test_idle_busy(self): - assert self.worker.idle is True - assert self.worker.busy is False - self.worker.put({'task': 'abc123'}) - assert self.worker.busy is True - assert self.worker.idle is False - - -@pytest.mark.django_db -class TestWorkerPool: - def setup_method(self, test_method): - self.pool = WorkerPool(min_workers=3) - - def teardown_method(self, test_method): - self.pool.stop(signal.SIGTERM) - - def test_worker(self): - self.pool.init_workers(SimpleWorker().work_loop) - assert len(self.pool) == 3 - for worker in self.pool.workers: - assert worker.messages_sent == 0 - assert worker.alive is True - - def test_single_task(self): - self.pool.init_workers(SimpleWorker().work_loop) - self.pool.write(0, 'xyz') - assert self.pool.workers[0].messages_sent == 1 # worker at index 0 handled one task - assert self.pool.workers[1].messages_sent == 0 - assert self.pool.workers[2].messages_sent == 0 - - def test_queue_preference(self): - self.pool.init_workers(SimpleWorker().work_loop) - self.pool.write(2, 'xyz') - assert self.pool.workers[0].messages_sent == 0 - assert self.pool.workers[1].messages_sent == 0 - assert self.pool.workers[2].messages_sent == 1 # worker at index 2 handled one task - - def test_worker_processing(self): - result_queue = multiprocessing.Queue() - self.pool.init_workers(ResultWriter().work_loop, result_queue) - for i in range(10): - self.pool.write(random.choice(range(len(self.pool))), 'Hello, Worker {}'.format(i)) - all_messages = [result_queue.get(timeout=1) for i in range(10)] - all_messages.sort() - assert all_messages == ['Hello, Worker {}!!!'.format(i) for i in range(10)] - - total_handled = sum([worker.messages_sent for worker in self.pool.workers]) - assert total_handled == 10 - - -@pytest.mark.django_db -class TestAutoScaling: - def setup_method(self, test_method): - self.pool = AutoscalePool(min_workers=2, max_workers=10) - - def teardown_method(self, test_method): - self.pool.stop(signal.SIGTERM) - - def test_scale_up(self): - result_queue = multiprocessing.Queue() - self.pool.init_workers(SlowResultWriter().work_loop, result_queue) - - # start with two workers, write an event to each worker and make it busy - assert len(self.pool) == 2 - for i, w in enumerate(self.pool.workers): - w.put('Hello, Worker {}'.format(0)) - assert len(self.pool) == 2 - - # wait for the subprocesses to start working on their tasks and be marked busy - time.sleep(1) - assert self.pool.should_grow - - # write a third message, expect a new worker to spawn because all - # workers are busy - self.pool.write(0, 'Hello, Worker {}'.format(2)) - assert len(self.pool) == 3 - - def test_scale_down(self): - self.pool.init_workers(ResultWriter().work_loop, multiprocessing.Queue()) - - # start with two workers, and scale up to 10 workers - assert len(self.pool) == 2 - for i in range(8): - self.pool.up() - assert len(self.pool) == 10 - - # cleanup should scale down to 8 workers - self.pool.cleanup() - assert len(self.pool) == 2 - - def test_max_scale_up(self): - self.pool.init_workers(ResultWriter().work_loop, multiprocessing.Queue()) - - assert len(self.pool) == 2 - for i in range(25): - self.pool.up() - assert self.pool.max_workers == 10 - assert self.pool.full is True - assert len(self.pool) == 10 - - def test_equal_worker_distribution(self): - # if all workers are busy, spawn new workers *before* adding messages - # to an existing queue - self.pool.init_workers(SlowResultWriter().work_loop, multiprocessing.Queue) - - # start with two workers, write an event to each worker and make it busy - assert len(self.pool) == 2 - for i in range(10): - self.pool.write(0, 'Hello, World!') - assert len(self.pool) == 10 - for w in self.pool.workers: - assert w.busy - assert len(w.managed_tasks) == 1 - - # the queue is full at 10, the _next_ write should put the message into - # a worker's backlog - assert len(self.pool) == 10 - for w in self.pool.workers: - assert w.messages_sent == 1 - self.pool.write(0, 'Hello, World!') - assert len(self.pool) == 10 - assert self.pool.workers[0].messages_sent == 2 - - def test_lost_worker_autoscale(self): - # if a worker exits, it should be replaced automatically up to min_workers - self.pool.init_workers(ResultWriter().work_loop, multiprocessing.Queue()) - - # start with two workers, kill one of them - assert len(self.pool) == 2 - assert not self.pool.should_grow - alive_pid = self.pool.workers[1].pid - self.pool.workers[0].process.terminate() - time.sleep(2) # wait a moment for sigterm - - # clean up and the dead worker - self.pool.cleanup() - assert len(self.pool) == 1 - assert self.pool.workers[0].pid == alive_pid - - # the next queue write should replace the lost worker - self.pool.write(0, 'Hello, Worker') - assert len(self.pool) == 2 - - -@pytest.mark.usefixtures("disable_database_settings") -class TestTaskDispatcher: - @property - def tm(self): - return TaskWorker() - - def test_function_dispatch(self): - result = self.tm.perform_work({'task': 'awx.main.tests.functional.test_dispatch.add', 'args': [2, 2]}) - assert result == 4 - - def test_function_dispatch_must_be_decorated(self): - result = self.tm.perform_work({'task': 'awx.main.tests.functional.test_dispatch.restricted', 'args': [2, 2]}) - assert isinstance(result, ValueError) - assert str(result) == 'awx.main.tests.functional.test_dispatch.restricted is not decorated with @task()' # noqa - - def test_method_dispatch(self): - result = self.tm.perform_work({'task': 'awx.main.tests.functional.test_dispatch.Adder', 'args': [2, 2]}) - assert result == 4 - - def test_method_dispatch_must_be_decorated(self): - result = self.tm.perform_work({'task': 'awx.main.tests.functional.test_dispatch.Restricted', 'args': [2, 2]}) - assert isinstance(result, ValueError) - assert str(result) == 'awx.main.tests.functional.test_dispatch.Restricted is not decorated with @task()' # noqa - - def test_python_function_cannot_be_imported(self): - result = self.tm.perform_work( - { - 'task': 'os.system', - 'args': ['ls'], - } - ) - assert isinstance(result, ValueError) - assert str(result) == 'os.system is not a valid awx task' # noqa - - def test_undefined_function_cannot_be_imported(self): - result = self.tm.perform_work({'task': 'awx.foo.bar'}) - assert isinstance(result, ModuleNotFoundError) - assert str(result) == "No module named 'awx.foo'" # noqa - - -class TestTaskPublisher: - def test_function_callable(self): - assert add(2, 2) == 4 - - def test_method_callable(self): - assert Adder().run(2, 2) == 4 - - def test_function_apply_async(self): - message, queue = add.apply_async([2, 2], queue='foobar') - assert message['args'] == [2, 2] - assert message['kwargs'] == {} - assert message['task'] == 'awx.main.tests.functional.test_dispatch.add' - assert queue == 'foobar' - - def test_method_apply_async(self): - message, queue = Adder.apply_async([2, 2], queue='foobar') - assert message['args'] == [2, 2] - assert message['kwargs'] == {} - assert message['task'] == 'awx.main.tests.functional.test_dispatch.Adder' - assert queue == 'foobar' - - def test_apply_async_queue_required(self): - with pytest.raises(ValueError) as e: - message, queue = add.apply_async([2, 2]) - assert "awx.main.tests.functional.test_dispatch.add: Queue value required and may not be None" == e.value.args[0] - - def test_queue_defined_in_task_decorator(self): - message, queue = multiply.apply_async([2, 2]) - assert queue == 'hard-math' - - def test_queue_overridden_from_task_decorator(self): - message, queue = multiply.apply_async([2, 2], queue='not-so-hard') - assert queue == 'not-so-hard' - - def test_apply_with_callable_queuename(self): - message, queue = add.apply_async([2, 2], queue=lambda: 'called') - assert queue == 'called' - - yesterday = tz_now() - datetime.timedelta(days=1) +minute = tz_now() - datetime.timedelta(seconds=120) +now = tz_now() @pytest.mark.django_db @@ -346,11 +62,6 @@ class TestJobReaper(object): ('running', '', '', None, False), # running, not assigned to the instance ('running', 'awx', '', None, True), # running, has the instance as its execution_node ('running', '', 'awx', None, True), # running, has the instance as its controller_node - ('waiting', '', '', None, False), # waiting, not assigned to the instance - ('waiting', 'awx', '', None, False), # waiting, was edited less than a minute ago - ('waiting', '', 'awx', None, False), # waiting, was edited less than a minute ago - ('waiting', 'awx', '', yesterday, False), # waiting, managed by another node, ignore - ('waiting', '', 'awx', yesterday, True), # waiting, assigned to the controller_node, stale ], ) def test_should_reap(self, status, fail, execution_node, controller_node, modified): @@ -368,7 +79,6 @@ def test_should_reap(self, status, fail, execution_node, controller_node, modifi # (because .save() overwrites it to _now_) Job.objects.filter(id=j.id).update(modified=modified) reaper.reap(i) - reaper.reap_waiting(i) job = Job.objects.first() if fail: assert job.status == 'failed' @@ -377,14 +87,30 @@ def test_should_reap(self, status, fail, execution_node, controller_node, modifi else: assert job.status == status + def test_waiting_job_sent_back_to_pending(self): + this_inst = Instance(hostname='awx') + this_inst.save() + lost_inst = Instance(hostname='lost', node_type=Instance.Types.EXECUTION, node_state=Instance.States.UNAVAILABLE) + lost_inst.save() + job = Job.objects.create(status='waiting', controller_node=lost_inst.hostname, execution_node='lost') + + system._heartbeat_handle_lost_instances([lost_inst], this_inst) + job.refresh_from_db() + + assert job.status == 'pending' + assert job.controller_node == '' + assert job.execution_node == '' + @pytest.mark.parametrize( - 'excluded_uuids, fail', + 'excluded_uuids, fail, started', [ - (['abc123'], False), - ([], True), + (['abc123'], False, None), + ([], False, None), + ([], True, minute), ], ) - def test_do_not_reap_excluded_uuids(self, excluded_uuids, fail): + def test_do_not_reap_excluded_uuids(self, excluded_uuids, fail, started): + """Modified Test to account for ref_time in reap()""" i = Instance(hostname='awx') i.save() j = Job( @@ -395,10 +121,13 @@ def test_do_not_reap_excluded_uuids(self, excluded_uuids, fail): celery_task_id='abc123', ) j.save() + if started: + Job.objects.filter(id=j.id).update(started=started) # if the UUID is excluded, don't reap it - reaper.reap(i, excluded_uuids=excluded_uuids) + reaper.reap(i, excluded_uuids=excluded_uuids, ref_time=now) job = Job.objects.first() + if fail: assert job.status == 'failed' assert 'marked as failed' in job.job_explanation @@ -414,3 +143,20 @@ def test_workflow_does_not_reap(self): reaper.reap(i) assert WorkflowJob.objects.first().status == 'running' + + def test_should_not_reap_new(self): + """ + This test is designed specifically to ensure that jobs that are launched after the dispatcher has provided a list of UUIDs aren't reaped. + It is very racy and this test is designed with that in mind + """ + i = Instance(hostname='awx') + # ref_time is set to 10 seconds in the past to mimic someone launching a job in the heartbeat window. + ref_time = tz_now() - datetime.timedelta(seconds=10) + # creating job at current time + job = Job.objects.create(status='running', controller_node=i.hostname) + reaper.reap(i, ref_time=ref_time) + # explictly refreshing from db to ensure up to date cache + job.refresh_from_db() + assert job.started > ref_time + assert job.status == 'running' + assert job.job_explanation == '' diff --git a/awx/main/tests/functional/test_fixture_factories.py b/awx/main/tests/functional/test_fixture_factories.py index 1af7b6624650..30fa1247ae9a 100644 --- a/awx/main/tests/functional/test_fixture_factories.py +++ b/awx/main/tests/functional/test_fixture_factories.py @@ -50,13 +50,11 @@ def test_org_factory_roles(organization_factory): teams=['team1', 'team2'], users=['team1:foo', 'bar'], projects=['baz', 'bang'], - roles=['team2.member_role:foo', 'team1.admin_role:bar', 'team1.admin_role:team2.admin_role', 'baz.admin_role:foo'], + roles=['team2.member_role:foo', 'team1.admin_role:bar', 'baz.admin_role:foo'], ) - - assert objects.users.bar in objects.teams.team2.admin_role + assert objects.users.bar in objects.teams.team1.admin_role assert objects.users.foo in objects.projects.baz.admin_role assert objects.users.foo in objects.teams.team1.member_role - assert objects.teams.team2.admin_role in objects.teams.team1.admin_role.children.all() @pytest.mark.django_db diff --git a/awx/main/tests/functional/test_ha.py b/awx/main/tests/functional/test_ha.py deleted file mode 100644 index 0b4ced53c218..000000000000 --- a/awx/main/tests/functional/test_ha.py +++ /dev/null @@ -1,19 +0,0 @@ -import pytest - -# AWX -from awx.main.ha import is_ha_environment -from awx.main.models.ha import Instance - - -@pytest.mark.django_db -def test_multiple_instances(): - for i in range(2): - Instance.objects.create(hostname=f'foo{i}', node_type='hybrid') - assert is_ha_environment() - - -@pytest.mark.django_db -def test_db_localhost(): - Instance.objects.create(hostname='foo', node_type='hybrid') - Instance.objects.create(hostname='bar', node_type='execution') - assert is_ha_environment() is False diff --git a/awx/main/tests/functional/test_instance_group_ordering.py b/awx/main/tests/functional/test_instance_group_ordering.py index 42c69ffc7fe0..fb8c0db16858 100644 --- a/awx/main/tests/functional/test_instance_group_ordering.py +++ b/awx/main/tests/functional/test_instance_group_ordering.py @@ -1,6 +1,6 @@ import pytest -from awx.main.models import InstanceGroup +from awx.main.models import InstanceGroup, Inventory @pytest.fixture(scope='function') @@ -38,6 +38,16 @@ def test_instance_group_ordering(source_model): assert source_model.instance_groups.through.objects.count() == 0 +@pytest.mark.django_db +@pytest.mark.parametrize('source_model', ['job_template', 'inventory', 'organization'], indirect=True) +def test_instance_group_bulk_add(source_model): + groups = [InstanceGroup.objects.create(name='host-%d' % i) for i in range(5)] + groups.reverse() + with pytest.raises(RuntimeError) as err: + source_model.instance_groups.add(*groups) + assert 'Ordered many-to-many fields do not support multiple objects' in str(err) + + @pytest.mark.django_db @pytest.mark.parametrize('source_model', ['job_template', 'inventory', 'organization'], indirect=True) def test_instance_group_middle_deletion(source_model): @@ -66,3 +76,33 @@ def test_explicit_ordering(source_model): assert [g.name for g in source_model.instance_groups.all()] == ['host-4', 'host-3', 'host-2', 'host-1', 'host-0'] assert [g.name for g in source_model.instance_groups.order_by('name').all()] == ['host-0', 'host-1', 'host-2', 'host-3', 'host-4'] + + +@pytest.mark.django_db +def test_input_inventories_ordering(): + constructed_inventory = Inventory.objects.create(name='my_constructed', kind='constructed') + input_inventories = [Inventory.objects.create(name='inv-%d' % i) for i in range(5)] + input_inventories.reverse() + for inv in input_inventories: + constructed_inventory.input_inventories.add(inv) + + assert [g.name for g in constructed_inventory.input_inventories.all()] == ['inv-4', 'inv-3', 'inv-2', 'inv-1', 'inv-0'] + assert [(row.position, row.input_inventory.name) for row in constructed_inventory.input_inventories.through.objects.all()] == [ + (0, 'inv-4'), + (1, 'inv-3'), + (2, 'inv-2'), + (3, 'inv-1'), + (4, 'inv-0'), + ] + + constructed_inventory.input_inventories.remove(input_inventories[0]) + assert [g.name for g in constructed_inventory.input_inventories.all()] == ['inv-3', 'inv-2', 'inv-1', 'inv-0'] + assert [(row.position, row.input_inventory.name) for row in constructed_inventory.input_inventories.through.objects.all()] == [ + (0, 'inv-3'), + (1, 'inv-2'), + (2, 'inv-1'), + (3, 'inv-0'), + ] + + constructed_inventory.input_inventories.clear() + assert constructed_inventory.input_inventories.through.objects.count() == 0 diff --git a/awx/main/tests/functional/test_instances.py b/awx/main/tests/functional/test_instances.py index df6d17786819..4ed652179d91 100644 --- a/awx/main/tests/functional/test_instances.py +++ b/awx/main/tests/functional/test_instances.py @@ -94,17 +94,18 @@ def test_instance_dup(org_admin, organization, project, instance_factory, instan ig_all = instance_group_factory("all", instances=[i1, i2, i3]) ig_dup = instance_group_factory("duplicates", instances=[i1]) - project.organization.instance_groups.add(ig_all, ig_dup) + project.organization.instance_groups.add(ig_all) + project.organization.instance_groups.add(ig_dup) actual_num_instances = Instance.objects.count() list_response = get(reverse('api:instance_list'), user=system_auditor) api_num_instances_auditor = list(list_response.data.items())[0][1] + ig_all.read_role.members.add(org_admin) list_response2 = get(reverse('api:instance_list'), user=org_admin) api_num_instances_oa = list(list_response2.data.items())[0][1] assert api_num_instances_auditor == actual_num_instances - # Note: The org_admin will not see the default 'tower' node - # (instance fixture) because it is not in its group, as expected + # Note: The org_admin will not see instances unless at least read_role to the IG has been assigned assert api_num_instances_oa == (actual_num_instances - 1) diff --git a/awx/main/tests/functional/test_inventory_input_constructed.py b/awx/main/tests/functional/test_inventory_input_constructed.py new file mode 100644 index 000000000000..2602cf294777 --- /dev/null +++ b/awx/main/tests/functional/test_inventory_input_constructed.py @@ -0,0 +1,61 @@ +import pytest +from awx.main.models import Inventory +from awx.api.versioning import reverse + + +@pytest.mark.django_db +def test_constructed_inventory_post(post, admin_user, organization): + inv1 = Inventory.objects.create(name='dummy1', kind='constructed', organization=organization) + inv2 = Inventory.objects.create(name='dummy2', kind='constructed', organization=organization) + resp = post( + url=reverse('api:inventory_input_inventories', kwargs={'pk': inv1.pk}), + data={'id': inv2.pk}, + user=admin_user, + expect=400, + ) + assert resp.status_code == 400 + + +@pytest.mark.django_db +def test_add_constructed_inventory_source(post, admin_user, constructed_inventory): + resp = post( + url=reverse('api:inventory_inventory_sources_list', kwargs={'pk': constructed_inventory.pk}), + data={'name': 'dummy1', 'source': 'constructed'}, + user=admin_user, + expect=400, + ) + assert resp.status_code == 400 + + +@pytest.mark.django_db +def test_add_constructed_inventory_host(post, admin_user, constructed_inventory): + resp = post( + url=reverse('api:inventory_hosts_list', kwargs={'pk': constructed_inventory.pk}), + data={'name': 'dummy1'}, + user=admin_user, + expect=400, + ) + assert resp.status_code == 400 + + +@pytest.mark.django_db +def test_add_constructed_inventory_group(post, admin_user, constructed_inventory): + resp = post( + reverse('api:inventory_groups_list', kwargs={'pk': constructed_inventory.pk}), + data={'name': 'group-test'}, + user=admin_user, + expect=400, + ) + assert resp.status_code == 400 + + +@pytest.mark.django_db +def test_edit_constructed_inventory_source(patch, admin_user, inventory_source_factory): + inv_src = inventory_source_factory(name='dummy1', source='constructed') + resp = patch( + reverse('api:inventory_source_detail', kwargs={'pk': inv_src.pk}), + data={'description': inv_src.name}, + user=admin_user, + expect=400, + ) + assert resp.status_code == 400 diff --git a/awx/main/tests/functional/test_inventory_source_injectors.py b/awx/main/tests/functional/test_inventory_source_injectors.py index 97fc8a7c17cc..8f740db72f72 100644 --- a/awx/main/tests/functional/test_inventory_source_injectors.py +++ b/awx/main/tests/functional/test_inventory_source_injectors.py @@ -5,12 +5,13 @@ import re from collections import namedtuple +from awx_plugins.interfaces._temporary_private_container_api import get_incontainer_path + from awx.main.tasks.jobs import RunInventoryUpdate from awx.main.models import InventorySource, Credential, CredentialType, UnifiedJob, ExecutionEnvironment -from awx.main.constants import CLOUD_PROVIDERS, STANDARD_INVENTORY_UPDATE_ENV +from awx.main.constants import STANDARD_INVENTORY_UPDATE_ENV from awx.main.tests import data -from awx.main.utils.execution_environments import to_container_path - +from awx.main.utils.plugins import discover_available_cloud_provider_plugin_names from django.conf import settings DATA = os.path.join(os.path.dirname(data.__file__), 'inventory') @@ -46,6 +47,8 @@ def generate_fake_var(element): def credential_kind(source): """Given the inventory source kind, return expected credential kind""" + if source == 'openshift_virtualization': + return 'kubernetes_bearer_token' return source.replace('ec2', 'aws') @@ -107,12 +110,13 @@ def read_content(private_data_dir, raw_env, inventory_update): for filename in os.listdir(os.path.join(private_data_dir, subdir)): filename_list.append(os.path.join(subdir, filename)) filename_list = sorted(filename_list, key=lambda fn: inverse_env.get(os.path.join(private_data_dir, fn), [fn])[0]) + inventory_content = "" for filename in filename_list: if filename in ('args', 'project'): continue # Ansible runner abs_file_path = os.path.join(private_data_dir, filename) file_aliases[abs_file_path] = filename - runner_path = to_container_path(abs_file_path, private_data_dir) + runner_path = get_incontainer_path(abs_file_path, private_data_dir) if runner_path in inverse_env: referenced_paths.add(abs_file_path) alias = 'file_reference' @@ -121,7 +125,7 @@ def read_content(private_data_dir, raw_env, inventory_update): break alias = 'file_reference_{}'.format(i) else: - raise RuntimeError('Test not able to cope with >10 references by env vars. ' 'Something probably went very wrong.') + raise RuntimeError('Test not able to cope with >10 references by env vars. Something probably went very wrong.') file_aliases[abs_file_path] = alias for env_key in inverse_env[runner_path]: env[env_key] = '{{{{ {} }}}}'.format(alias) @@ -130,6 +134,7 @@ def read_content(private_data_dir, raw_env, inventory_update): dir_contents[abs_file_path] = f.read() # Declare a reference to inventory plugin file if it exists if abs_file_path.endswith('.yml') and 'plugin: ' in dir_contents[abs_file_path]: + inventory_content = dir_contents[abs_file_path] referenced_paths.add(abs_file_path) # used as inventory file elif cache_file_regex.match(abs_file_path): file_aliases[abs_file_path] = 'cache_file' @@ -157,7 +162,11 @@ def read_content(private_data_dir, raw_env, inventory_update): content = {} for abs_file_path, file_content in dir_contents.items(): # assert that all files laid down are used - if abs_file_path not in referenced_paths and abs_file_path not in ignore_files: + if ( + abs_file_path not in referenced_paths + and get_incontainer_path(abs_file_path, private_data_dir) not in inventory_content + and abs_file_path not in ignore_files + ): raise AssertionError( "File {} is not referenced. References and files:\n{}\n{}".format(abs_file_path, json.dumps(env, indent=4), json.dumps(dir_contents, indent=4)) ) @@ -182,15 +191,14 @@ def create_reference_data(source_dir, env, content): json.dump(env, f, indent=4, sort_keys=True) +@mock.patch('awx_plugins.interfaces._temporary_private_licensing_api.detect_server_product_name', return_value='NOT-AWX') @pytest.mark.django_db -@pytest.mark.parametrize('this_kind', CLOUD_PROVIDERS) -def test_inventory_update_injected_content(this_kind, inventory, fake_credential_factory, mock_me): +@pytest.mark.parametrize('this_kind', discover_available_cloud_provider_plugin_names()) +def test_inventory_update_injected_content(product_name, this_kind, inventory, fake_credential_factory, mock_me): ExecutionEnvironment.objects.create(name='Control Plane EE', managed=True) ExecutionEnvironment.objects.create(name='Default Job EE', managed=False) injector = InventorySource.injectors[this_kind] - if injector.plugin_name is None: - pytest.skip('Use of inventory plugin is not enabled for this source') src_vars = dict(base_source_var='value_of_var') src_vars['plugin'] = injector.get_proper_name() @@ -200,7 +208,7 @@ def test_inventory_update_injected_content(this_kind, inventory, fake_credential source_vars=src_vars, ) inventory_source.credentials.add(fake_credential_factory(this_kind)) - inventory_update = inventory_source.create_unified_job() + inventory_update = inventory_source.create_unified_job(_eager_fields={'status': 'waiting'}) task = RunInventoryUpdate() def substitute_run(awx_receptor_job): @@ -214,6 +222,10 @@ def substitute_run(awx_receptor_job): private_data_dir = envvars.pop('AWX_PRIVATE_DATA_DIR') assert envvars.pop('ANSIBLE_INVENTORY_ENABLED') == 'auto' set_files = bool(os.getenv("MAKE_INVENTORY_REFERENCE_FILES", 'false').lower()[0] not in ['f', '0']) + + # Ensure the directory exists before trying to list/read it + os.makedirs(private_data_dir, exist_ok=True) + env, content = read_content(private_data_dir, envvars, inventory_update) # Assert inventory plugin inventory file is in private_data_dir @@ -222,7 +234,7 @@ def substitute_run(awx_receptor_job): len([True for k in content.keys() if k.endswith(inventory_filename)]) > 0 ), f"'{inventory_filename}' file not found in inventory update runtime files {content.keys()}" - env.pop('ANSIBLE_COLLECTIONS_PATHS', None) # collection paths not relevant to this test + env.pop('ANSIBLE_COLLECTIONS_PATH', None) base_dir = os.path.join(DATA, 'plugins') if not os.path.exists(base_dir): os.mkdir(base_dir) @@ -234,7 +246,7 @@ def substitute_run(awx_receptor_job): source_dir = os.path.join(base_dir, this_kind) # this_kind is a global if not os.path.exists(source_dir): - raise FileNotFoundError('Maybe you never made reference files? ' 'MAKE_INVENTORY_REFERENCE_FILES=true py.test ...\noriginal: {}') + raise FileNotFoundError('Maybe you never made reference files? MAKE_INVENTORY_REFERENCE_FILES=true py.test ...\noriginal: {}') files_dir = os.path.join(source_dir, 'files') try: expected_file_list = os.listdir(files_dir) diff --git a/awx/main/tests/functional/test_jobs.py b/awx/main/tests/functional/test_jobs.py index da3b9fd57cd3..7d4a0ed5b7d2 100644 --- a/awx/main/tests/functional/test_jobs.py +++ b/awx/main/tests/functional/test_jobs.py @@ -6,6 +6,7 @@ from awx.main.models import ( Job, Instance, + Host, JobHostSummary, InventoryUpdate, InventorySource, @@ -18,6 +19,9 @@ ExecutionEnvironment, ) from awx.main.tasks.system import cluster_node_heartbeat +from awx.main.utils.db import bulk_update_sorted_by_id + +from django.db import OperationalError from django.test.utils import override_settings @@ -33,9 +37,9 @@ def test_orphan_unified_job_creation(instance, inventory): @pytest.mark.django_db -@mock.patch('awx.main.tasks.system.inspect_execution_nodes', lambda *args, **kwargs: None) -@mock.patch('awx.main.models.ha.get_cpu_effective_capacity', lambda cpu: 8) -@mock.patch('awx.main.models.ha.get_mem_effective_capacity', lambda mem: 62) +@mock.patch('awx.main.tasks.system.inspect_execution_and_hop_nodes', lambda *args, **kwargs: None) +@mock.patch('awx.main.models.ha.get_cpu_effective_capacity', lambda cpu, is_control_node: 8) +@mock.patch('awx.main.models.ha.get_mem_effective_capacity', lambda mem, is_control_node: 62) def test_job_capacity_and_with_inactive_node(): i = Instance.objects.create(hostname='test-1') i.save_health_data('18.0.1', 2, 8000) @@ -46,7 +50,7 @@ def test_job_capacity_and_with_inactive_node(): i.save() with override_settings(CLUSTER_HOST_ID=i.hostname): with mock.patch.object(redis.client.Redis, 'ping', lambda self: True): - cluster_node_heartbeat() + cluster_node_heartbeat(None) i = Instance.objects.get(id=i.id) assert i.capacity == 0 @@ -112,6 +116,63 @@ def test_job_notification_host_data(inventory, machine_credential, project, job_ } +@pytest.mark.django_db +class TestAnsibleFactsSave: + current_call = 0 + + def test_update_hosts_deleted_host(self, inventory): + hosts = [Host.objects.create(inventory=inventory, name=f'foo{i}') for i in range(3)] + for host in hosts: + host.ansible_facts = {'foo': 'bar'} + last_pk = hosts[-1].pk + assert inventory.hosts.count() == 3 + Host.objects.get(pk=last_pk).delete() + assert inventory.hosts.count() == 2 + bulk_update_sorted_by_id(Host, hosts, fields=['ansible_facts']) + assert inventory.hosts.count() == 2 + for host in inventory.hosts.all(): + host.refresh_from_db() + assert host.ansible_facts == {'foo': 'bar'} + + def test_update_hosts_forever_deadlock(self, inventory, mocker): + hosts = [Host.objects.create(inventory=inventory, name=f'foo{i}') for i in range(3)] + for host in hosts: + host.ansible_facts = {'foo': 'bar'} + db_mock = mocker.patch('awx.main.tasks.facts.Host.objects.bulk_update') + db_mock.side_effect = OperationalError('deadlock detected') + with pytest.raises(OperationalError): + bulk_update_sorted_by_id(Host, hosts, fields=['ansible_facts']) + + def fake_bulk_update(self, host_list): + if self.current_call > 2: + return Host.objects.bulk_update(host_list, ['ansible_facts', 'ansible_facts_modified']) + self.current_call += 1 + raise OperationalError('deadlock detected') + + +@pytest.mark.django_db +def test_update_hosts_resolved_deadlock(inventory, mocker): + + hosts = [Host.objects.create(inventory=inventory, name=f'foo{i}') for i in range(3)] + + # Set ansible_facts for each host + for host in hosts: + host.ansible_facts = {'foo': 'bar'} + + bulk_update_sorted_by_id(Host, hosts, fields=['ansible_facts']) + + # Save changes and refresh from DB to ensure the updated facts are saved + for host in hosts: + host.save() # Ensure changes are persisted in the DB + host.refresh_from_db() # Refresh from DB to get latest data + + # Assert that the ansible_facts were updated correctly + for host in inventory.hosts.all(): + assert host.ansible_facts == {'foo': 'bar'} + + bulk_update_sorted_by_id(Host, hosts, fields=['ansible_facts']) + + @pytest.mark.django_db class TestLaunchConfig: def test_null_creation_from_prompts(self): diff --git a/awx/main/tests/functional/test_ldap.py b/awx/main/tests/functional/test_ldap.py deleted file mode 100644 index 2467ff52e38f..000000000000 --- a/awx/main/tests/functional/test_ldap.py +++ /dev/null @@ -1,103 +0,0 @@ -import ldap -import ldif -import pytest -import os -from mockldap import MockLdap - -from awx.api.versioning import reverse - - -@pytest.fixture -def ldap_generator(): - def fn(fname, host='localhost'): - fh = open(os.path.join(os.path.dirname(os.path.realpath(__file__)), fname), 'rb') - ctrl = ldif.LDIFRecordList(fh) - ctrl.parse() - - directory = dict(ctrl.all_records) - - mockldap = MockLdap(directory) - - mockldap.start() - mockldap['ldap://{}/'.format(host)] - - conn = ldap.initialize('ldap://{}/'.format(host)) - - return conn - # mockldap.stop() - - return fn - - -@pytest.fixture -def ldap_settings_generator(): - def fn(prefix='', dc='ansible', host='ldap.ansible.com'): - prefix = '_{}'.format(prefix) if prefix else '' - - data = { - 'AUTH_LDAP_SERVER_URI': 'ldap://{}'.format(host), - 'AUTH_LDAP_BIND_DN': 'cn=eng_user1,ou=people,dc={},dc=com'.format(dc), - 'AUTH_LDAP_BIND_PASSWORD': 'password', - "AUTH_LDAP_USER_SEARCH": ["ou=people,dc={},dc=com".format(dc), "SCOPE_SUBTREE", "(cn=%(user)s)"], - "AUTH_LDAP_TEAM_MAP": { - "LDAP Sales": {"organization": "LDAP Organization", "users": "cn=sales,ou=groups,dc={},dc=com".format(dc), "remove": True}, - "LDAP IT": {"organization": "LDAP Organization", "users": "cn=it,ou=groups,dc={},dc=com".format(dc), "remove": True}, - "LDAP Engineering": {"organization": "LDAP Organization", "users": "cn=engineering,ou=groups,dc={},dc=com".format(dc), "remove": True}, - }, - "AUTH_LDAP_REQUIRE_GROUP": None, - "AUTH_LDAP_USER_ATTR_MAP": {"first_name": "givenName", "last_name": "sn", "email": "mail"}, - "AUTH_LDAP_GROUP_SEARCH": ["dc={},dc=com".format(dc), "SCOPE_SUBTREE", "(objectClass=groupOfNames)"], - "AUTH_LDAP_USER_FLAGS_BY_GROUP": {"is_superuser": "cn=superusers,ou=groups,dc={},dc=com".format(dc)}, - "AUTH_LDAP_ORGANIZATION_MAP": { - "LDAP Organization": { - "admins": "cn=engineering_admins,ou=groups,dc={},dc=com".format(dc), - "remove_admins": False, - "users": [ - "cn=engineering,ou=groups,dc={},dc=com".format(dc), - "cn=sales,ou=groups,dc={},dc=com".format(dc), - "cn=it,ou=groups,dc={},dc=com".format(dc), - ], - "remove_users": False, - } - }, - } - - if prefix: - data_new = dict() - for k, v in data.items(): - k_new = k.replace('AUTH_LDAP', 'AUTH_LDAP{}'.format(prefix)) - data_new[k_new] = v - else: - data_new = data - - return data_new - - return fn - - -# Note: mockldap isn't fully featured. Fancy queries aren't fully baked. -# However, objects returned are solid so they should flow through django ldap middleware nicely. -@pytest.mark.skip(reason="Needs Update - CA") -@pytest.mark.django_db -def test_login(ldap_generator, patch, post, admin, ldap_settings_generator): - auth_url = reverse('api:auth_token_view') - ldap_settings_url = reverse('api:setting_singleton_detail', kwargs={'category_slug': 'ldap'}) - - # Generate mock ldap servers and init with ldap data - ldap_generator("../data/ldap_example.ldif", "ldap.example.com") - ldap_generator("../data/ldap_redhat.ldif", "ldap.redhat.com") - ldap_generator("../data/ldap_ansible.ldif", "ldap.ansible.com") - - ldap_settings_example = ldap_settings_generator(dc='example') - ldap_settings_ansible = ldap_settings_generator(prefix='1', dc='ansible') - ldap_settings_redhat = ldap_settings_generator(prefix='2', dc='redhat') - - # eng_user1 exists in ansible and redhat but not example - patch(ldap_settings_url, user=admin, data=ldap_settings_example, expect=200) - - post(auth_url, data={'username': 'eng_user1', 'password': 'password'}, expect=400) - - patch(ldap_settings_url, user=admin, data=ldap_settings_ansible, expect=200) - patch(ldap_settings_url, user=admin, data=ldap_settings_redhat, expect=200) - - post(auth_url, data={'username': 'eng_user1', 'password': 'password'}, expect=200) diff --git a/awx/main/tests/functional/test_licenses.py b/awx/main/tests/functional/test_licenses.py index 4b8ee7a9189a..aefec6153b3c 100644 --- a/awx/main/tests/functional/test_licenses.py +++ b/awx/main/tests/functional/test_licenses.py @@ -1,5 +1,4 @@ import glob -import json import os from django.conf import settings @@ -12,122 +11,99 @@ from pip._internal.req.constructors import parse_req_from_line -def test_python_and_js_licenses(): - def index_licenses(path): - # Check for GPL (forbidden) and LGPL (need to ship source) - # This is not meant to be an exhaustive check. - def check_license(license_file): - with open(license_file) as f: - data = f.read() - is_lgpl = 'GNU LESSER GENERAL PUBLIC LICENSE' in data.upper() - # The LGPL refers to the GPL in-text - # Case-sensitive for GPL to match license text and not PSF license reference - is_gpl = 'GNU GENERAL PUBLIC LICENSE' in data and not is_lgpl - return (is_gpl, is_lgpl) - - def find_embedded_source_version(path, name): - for entry in os.listdir(path): - # Check variations of '-' and '_' in filenames due to python - for fname in [name, name.replace('-', '_')]: - if entry.startswith(fname) and entry.endswith('.tar.gz'): - v = entry.split(name + '-')[1].split('.tar.gz')[0] - return v - return None - - list = {} - for txt_file in glob.glob('%s/*.txt' % path): - filename = txt_file.split('/')[-1] - name = filename[:-4].lower() - (is_gpl, is_lgpl) = check_license(txt_file) - list[name] = { - 'name': name, - 'filename': filename, - 'gpl': is_gpl, - 'source_required': (is_gpl or is_lgpl), - 'source_version': find_embedded_source_version(path, name), - } - return list - - def read_api_requirements(path): - ret = {} - skip_pbr_license_check = False - for req_file in ['requirements.txt', 'requirements_git.txt']: - fname = '%s/%s' % (path, req_file) - - for reqt in parse_requirements(fname, session=''): - parsed_requirement = parse_req_from_line(reqt.requirement, None) - name = parsed_requirement.requirement.name - version = str(parsed_requirement.requirement.specifier) - if version.startswith('=='): - version = version[2:] - if parsed_requirement.link: - if str(parsed_requirement.link).startswith(('http://', 'https://')): - (name, version) = str(parsed_requirement.requirement).split('==', 1) - else: - (name, version) = parsed_requirement.link.filename.split('@', 1) - if name.endswith('.git'): - name = name[:-4] - if name == 'receptor': - name = 'receptorctl' - if name == 'ansible-runner': - skip_pbr_license_check = True - ret[name] = {'name': name, 'version': version} - if 'pbr' in ret and skip_pbr_license_check: - del ret['pbr'] - return ret - - def read_ui_requirements(path): - def json_deps(jsondata): - ret = {} - deps = jsondata.get('dependencies', {}) - for key in deps.keys(): - key = key.lower() - devonly = deps[key].get('dev', False) - if not devonly: - if key not in ret.keys(): - depname = key.replace('/', '-') - if depname[0] == '@': - depname = depname[1:] - ret[depname] = {'name': depname, 'version': deps[key]['version']} - ret.update(json_deps(deps[key])) - return ret - - with open('%s/package-lock.json' % path) as f: - jsondata = json.load(f) - return json_deps(jsondata) - - def remediate_licenses_and_requirements(licenses, requirements): - errors = [] - items = list(licenses.keys()) - items.sort() - for item in items: - if item not in [r.lower() for r in requirements.keys()] and item != 'awx': - errors.append(" license file %s does not correspond to an existing requirement; it should be removed." % (licenses[item]['filename'],)) - continue - # uWSGI has a linking exception - if licenses[item]['gpl'] and item != 'uwsgi': - errors.append(" license for %s is GPL. This software cannot be used." % (item,)) - if licenses[item]['source_required']: - version = requirements[item]['version'] - if version != licenses[item]['source_version']: - errors.append(" embedded source for %s is %s instead of the required version %s" % (item, licenses[item]['source_version'], version)) - elif licenses[item]['source_version']: - errors.append(" embedded source version %s for %s is included despite not being needed" % (licenses[item]['source_version'], item)) - items = list(requirements.keys()) - items.sort() - for item in items: - if item.lower() not in licenses.keys(): - errors.append(" license for requirement %s is missing" % (item,)) - return errors +def check_license(license_file): + with open(license_file) as f: + data = f.read() + is_lgpl = 'GNU LESSER GENERAL PUBLIC LICENSE' in data.upper() + is_gpl = 'GNU GENERAL PUBLIC LICENSE' in data and not is_lgpl + return is_gpl, is_lgpl + + +def find_embedded_source_version(path, name): + files = os.listdir(path) + tgz_files = [f for f in files if f.endswith('.tar.gz')] + for tgz in tgz_files: + pkg_name = tgz.split('-')[0].split('_')[0] + if pkg_name == name: + return tgz.split('-')[1].split('.tar.gz')[0] + return None + + +def index_licenses(path): + licenses = {} + for txt_file in glob.glob(f'{path}/*.txt'): + filename = os.path.basename(txt_file) + name = filename[:-4].lower() + is_gpl, is_lgpl = check_license(txt_file) + licenses[name] = { + 'name': name, + 'filename': filename, + 'gpl': is_gpl, + 'source_required': is_gpl or is_lgpl, + 'source_version': find_embedded_source_version(path, name), + } + return licenses + + +def parse_requirement(reqt): + parsed_requirement = parse_req_from_line(reqt.requirement, None) + assert parsed_requirement.requirement, reqt.__dict__ + name = parsed_requirement.requirement.name + version = str(parsed_requirement.requirement.specifier) + if version.startswith('=='): + version = version[2:] + if parsed_requirement.link: + if str(parsed_requirement.link).startswith(('http://', 'https://')): + name, version = str(parsed_requirement.requirement).split('==', 1) + else: + name, version = parsed_requirement.link.filename.split('@', 1) + if name.endswith('.git'): + name = name[:-4] + if name == 'receptor': + name = 'receptorctl' + return name, version - base_dir = settings.BASE_DIR - api_licenses = index_licenses('%s/../licenses' % base_dir) - ui_licenses = index_licenses('%s/../licenses/ui' % base_dir) - api_requirements = read_api_requirements('%s/../requirements' % base_dir) - ui_requirements = read_ui_requirements('%s/ui' % base_dir) +def read_api_requirements(path): + requirements = {} + skip_pbr_license_check = False + for req_file in ['requirements.txt', 'requirements_git.txt']: + fname = f'{path}/{req_file}' + for reqt in parse_requirements(fname, session=''): + name, version = parse_requirement(reqt) + if name == 'ansible-runner': + skip_pbr_license_check = True + requirements[name] = {'name': name, 'version': version} + if 'pbr' in requirements and skip_pbr_license_check: + del requirements['pbr'] + return requirements + + +def remediate_licenses_and_requirements(licenses, requirements): errors = [] - errors += remediate_licenses_and_requirements(ui_licenses, ui_requirements) - errors += remediate_licenses_and_requirements(api_licenses, api_requirements) + for item in sorted(licenses.keys()): + if item not in [r.lower() for r in requirements.keys()] and item != 'awx': + errors.append(f" license file {licenses[item]['filename']} does not correspond to an existing requirement; it should be removed.") + continue + if licenses[item]['gpl'] and item != 'uwsgi': + errors.append(f" license for {item} is GPL. This software cannot be used.") + if licenses[item]['source_required']: + version = requirements[item]['version'] + if version != licenses[item]['source_version']: + errors.append(f" embedded source for {item} is {licenses[item]['source_version']} instead of the required version {version}") + elif licenses[item]['source_version']: + errors.append(f" embedded source version {licenses[item]['source_version']} for {item} is included despite not being needed") + for item in sorted(requirements.keys()): + if item.lower() not in licenses.keys(): + errors.append(f" license for requirement {item} is missing") + return errors + + +def test_python_licenses(): + base_dir = settings.BASE_DIR + api_licenses = index_licenses(f'{base_dir}/../licenses') + api_requirements = read_api_requirements(f'{base_dir}/../requirements') + + errors = remediate_licenses_and_requirements(api_licenses, api_requirements) if errors: raise Exception('Included licenses not consistent with requirements:\n%s' % '\n'.join(errors)) diff --git a/awx/main/tests/functional/test_migrations.py b/awx/main/tests/functional/test_migrations.py new file mode 100644 index 000000000000..caa9579f6abb --- /dev/null +++ b/awx/main/tests/functional/test_migrations.py @@ -0,0 +1,226 @@ +import pytest + +from django_test_migrations.plan import all_migrations, nodes_to_tuples +from django.utils.timezone import now + +""" +Most tests that live in here can probably be deleted at some point. They are mainly +for a developer. When AWX versions that users upgrade from falls out of support that +is when migration tests can be deleted. This is also a good time to squash. Squashing +will likely mess with the tests that live here. +The smoke test should be kept in here. The smoke test ensures that our migrations +continue to work when sqlite is the backing database (vs. the default DB of postgres). +""" + + +@pytest.mark.django_db +class TestMigrationSmoke: + def test_happy_path(self, migrator): + """ + This smoke test runs all the migrations. + Example of how to use django-test-migration to invoke particular migration(s) + while weaving in object creation and assertions. + Note that this is more than just an example. It is a smoke test because it runs ALL + the migrations. Our "normal" unit tests subvert the migrations running because it is slow. + """ + migration_nodes = all_migrations('default') + migration_tuples = nodes_to_tuples(migration_nodes) + final_migration = migration_tuples[-1] + migrator.apply_initial_migration(('main', None)) + # I just picked a newish migration at the time of writing this. + # If someone from the future finds themselves here because the are squashing migrations + # it is fine to change the 0180_... below to some other newish migration + intermediate_state = migrator.apply_tested_migration(('main', '0180_add_hostmetric_fields')) + Instance = intermediate_state.apps.get_model('main', 'Instance') + # Create any old object in the database + Instance.objects.create(hostname='foobar', node_type='control') + final_state = migrator.apply_tested_migration(final_migration) + Instance = final_state.apps.get_model('main', 'Instance') + assert Instance.objects.filter(hostname='foobar').count() == 1 + + def test_receptor_address(self, migrator): + old_state = migrator.apply_initial_migration(('main', '0188_add_bitbucket_dc_webhook')) + Instance = old_state.apps.get_model('main', 'Instance') + for i in range(3): + Instance.objects.create(hostname=f'foobar{i}', node_type='hop') + foo = Instance.objects.create(hostname='foo', node_type='execution', listener_port=1234) + bar = Instance.objects.create(hostname='bar', node_type='execution', listener_port=None) + bar.peers.add(foo) + new_state = migrator.apply_tested_migration( + ('main', '0189_inbound_hop_nodes'), + ) + Instance = new_state.apps.get_model('main', 'Instance') + ReceptorAddress = new_state.apps.get_model('main', 'ReceptorAddress') + # We can now test how our migration worked, new field is there: + assert ReceptorAddress.objects.filter(address='foo', port=1234).count() == 1 + assert not ReceptorAddress.objects.filter(address='bar').exists() + bar = Instance.objects.get(hostname='bar') + fooaddr = ReceptorAddress.objects.get(address='foo') + bar_peers = bar.peers.all() + assert len(bar_peers) == 1 + assert fooaddr in bar_peers + + def test_migrate_DAB_RBAC(self, migrator): + old_state = migrator.apply_initial_migration(('main', '0190_alter_inventorysource_source_and_more')) + Organization = old_state.apps.get_model('main', 'Organization') + Team = old_state.apps.get_model('main', 'Team') + User = old_state.apps.get_model('auth', 'User') + org = Organization.objects.create(name='arbitrary-org', created=now(), modified=now()) + user = User.objects.create(username='random-user') + org.read_role.members.add(user) + org.member_role.members.add(user) + + team = Team.objects.create(name='arbitrary-team', organization=org, created=now(), modified=now()) + team.member_role.members.add(user) + + new_state = migrator.apply_tested_migration( + ('main', '0192_custom_roles'), + ) + RoleUserAssignment = new_state.apps.get_model('dab_rbac', 'RoleUserAssignment') + assert RoleUserAssignment.objects.filter(user=user.id, object_id=org.id).exists() + assert RoleUserAssignment.objects.filter(user=user.id, role_definition__name='Organization Member', object_id=org.id).exists() + assert RoleUserAssignment.objects.filter(user=user.id, role_definition__name='Team Member', object_id=team.id).exists() + + # Regression testing for bug that comes from current vs past models mismatch + RoleDefinition = new_state.apps.get_model('dab_rbac', 'RoleDefinition') + assert not RoleDefinition.objects.filter(name='Organization Organization Admin').exists() + # Test special cases in managed role creation + assert not RoleDefinition.objects.filter(name='Organization Team Admin').exists() + assert not RoleDefinition.objects.filter(name='Organization InstanceGroup Admin').exists() + # Test that a removed EE model permission has been deleted + new_state = migrator.apply_tested_migration( + ('main', '0195_EE_permissions'), + ) + DABPermission = new_state.apps.get_model('dab_rbac', 'DABPermission') + assert not DABPermission.objects.filter(codename='view_executionenvironment').exists() + + # Test create a Project with a duplicate name + Organization = new_state.apps.get_model('main', 'Organization') + Project = new_state.apps.get_model('main', 'Project') + WorkflowJobTemplate = new_state.apps.get_model('main', 'WorkflowJobTemplate') + org = Organization.objects.create(name='duplicate-obj-organization', created=now(), modified=now()) + proj_ids = [] + for i in range(3): + proj = Project.objects.create(name='duplicate-project-name', organization=org, created=now(), modified=now()) + proj_ids.append(proj.id) + + # Test create WorkflowJobTemplate with duplicate names + wfjt_ids = [] + for i in range(3): + wfjt = WorkflowJobTemplate.objects.create(name='duplicate-workflow-name', organization=org, created=now(), modified=now()) + wfjt_ids.append(wfjt.id) + + # The uniqueness rules will not apply to InventorySource + Inventory = new_state.apps.get_model('main', 'Inventory') + InventorySource = new_state.apps.get_model('main', 'InventorySource') + inv = Inventory.objects.create(name='migration-test-inv', organization=org, created=now(), modified=now()) + InventorySource.objects.create(name='migration-test-src', source='file', inventory=inv, organization=org, created=now(), modified=now()) + + # Apply migration 0200 which should rename duplicates + new_state = migrator.apply_tested_migration( + ('main', '0200_template_name_constraint'), + ) + + # Get the models from the new state for verification + Project = new_state.apps.get_model('main', 'Project') + WorkflowJobTemplate = new_state.apps.get_model('main', 'WorkflowJobTemplate') + InventorySource = new_state.apps.get_model('main', 'InventorySource') + + for i, proj_id in enumerate(proj_ids): + proj = Project.objects.get(id=proj_id) + if i == 0: + assert proj.name == 'duplicate-project-name' + else: + assert proj.name != 'duplicate-project-name' + assert proj.name.startswith('duplicate-project-name') + + # Verify WorkflowJobTemplate duplicates are renamed + for i, wfjt_id in enumerate(wfjt_ids): + wfjt = WorkflowJobTemplate.objects.get(id=wfjt_id) + if i == 0: + assert wfjt.name == 'duplicate-workflow-name' + else: + assert wfjt.name != 'duplicate-workflow-name' + assert wfjt.name.startswith('duplicate-workflow-name') + + # The inventory source had this field set to avoid the constrains + inv_src = InventorySource.objects.get(name='migration-test-src') + assert inv_src.org_unique is False + for proj in Project.objects.all(): + assert proj.org_unique is True + + # Piggyback test for the new credential types + validate_exists = ['GitHub App Installation Access Token Lookup', 'Terraform backend configuration'] + CredentialType = new_state.apps.get_model('main', 'CredentialType') + # simulate an upgrade by deleting existing types with these names + for expected_name in validate_exists: + ct = CredentialType.objects.filter(name=expected_name).first() + if ct: + ct.delete() + + new_state = migrator.apply_tested_migration( + ('main', '0201_create_managed_creds'), + ) + + CredentialType = new_state.apps.get_model('main', 'CredentialType') + for expected_name in validate_exists: + assert CredentialType.objects.filter( + name=expected_name + ).exists(), f'Could not find {expected_name} credential type name, all names: {list(CredentialType.objects.values_list("name", flat=True))}' + + # Verify the system_administrator role exists + Role = new_state.apps.get_model('main', 'Role') + assert Role.objects.filter( + singleton_name='system_administrator', role_field='system_administrator' + ).exists(), "expected to find a system_administrator singleton role" + + +@pytest.mark.django_db +class TestGithubAppBug: + """ + Tests that `awx-manage createsuperuser` runs successfully after + the `github_app` CredentialType kind is updated to `github_app_lookup` + via the migration. + """ + + def test_after_github_app_kind_migration(self, migrator): + """ + Verifies that `createsuperuser` does not raise a KeyError + after the 0204_squashed_deletions migration (which includes + the `update_github_app_kind` logic) is applied. + """ + # 1. Apply migrations up to the point *before* the 0204_squashed_deletions migration. + # This simulates the state where the problematic CredentialType might exist. + # We use 0203_remove_team_of_teams as the direct predecessor. + old_state = migrator.apply_tested_migration(('main', '0203_remove_team_of_teams')) + + # Get the CredentialType model from the historical state. + CredentialType = old_state.apps.get_model('main', 'CredentialType') + + # Create a CredentialType with the old, problematic 'namespace' value + CredentialType.objects.create( + name='Legacy GitHub App Credential', + kind='external', + namespace='github_app', # The namespace that causes the KeyError in the registry lookup + managed=True, + created=now(), + modified=now(), + ) + + # Apply the migration that includes the fix (0204_squashed_deletions). + new_state = migrator.apply_tested_migration(('main', '0204_squashed_deletions')) + + # Verify that the CredentialType with the old 'kind' no longer exists + # and the 'kind' has been updated to the new value. + CredentialType = new_state.apps.get_model('main', 'CredentialType') # Get CredentialType model from the new state + + # Assertion 1: The CredentialType with the old 'github_app' kind should no longer exist. + assert not CredentialType.objects.filter( + namespace='github_app' + ).exists(), "CredentialType with old 'github_app' kind should no longer exist after migration." + + # Assertion 2: The CredentialType should now exist with the new 'github_app_lookup' kind + # and retain its original name. + assert CredentialType.objects.filter( + namespace='github_app_lookup', name='Legacy GitHub App Credential' + ).exists(), "CredentialType should be updated to 'github_app_lookup' and retain its name." diff --git a/awx/main/tests/functional/test_named_url.py b/awx/main/tests/functional/test_named_url.py index 884ecd7dc0c7..5bf12653ac04 100644 --- a/awx/main/tests/functional/test_named_url.py +++ b/awx/main/tests/functional/test_named_url.py @@ -1,11 +1,6 @@ # -*- coding: utf-8 -*- -from unittest import mock - import pytest -from django.core.exceptions import ImproperlyConfigured -from django.conf import settings - from awx.api.versioning import reverse from awx.main.middleware import URLModificationMiddleware from awx.main.models import ( # noqa @@ -23,25 +18,6 @@ User, WorkflowJobTemplate, ) -from awx.conf import settings_registry - - -def setup_module(module): - # In real-world scenario, named url graph structure is populated by __init__ - # of URLModificationMiddleware. The way Django bootstraps ensures the initialization - # will happen *once and only once*, while the number of initialization is uncontrollable - # in unit test environment. So it is wrapped by try-except block to mute any - # unwanted exceptions. - try: - URLModificationMiddleware(mock.Mock()) - except ImproperlyConfigured: - pass - - -def teardown_module(module): - # settings_registry will be persistent states unless we explicitly clean them up. - settings_registry.unregister('NAMED_URL_FORMATS') - settings_registry.unregister('NAMED_URL_GRAPH_NODES') @pytest.mark.django_db @@ -143,7 +119,7 @@ def test_notification_template(get, admin_user): @pytest.mark.django_db -def test_instance(get, admin_user): +def test_instance(get, admin_user, settings): test_instance = Instance.objects.create(uuid=settings.SYSTEM_UUID, hostname="localhost", capacity=100) url = reverse('api:instance_detail', kwargs={'pk': test_instance.pk}) response = get(url, user=admin_user, expect=200) @@ -227,3 +203,76 @@ def test_403_vs_404(get): get(f'/api/v2/users/{cindy.pk}/', expect=401) get('/api/v2/users/cindy/', expect=404) + + +@pytest.mark.django_db +class TestConvertNamedUrl: + @pytest.mark.parametrize( + "url", + ( + "/api/", + "/api/v2/", + "/api/v2/hosts/", + "/api/v2/hosts/1/", + "/api/v2/organizations/1/inventories/", + "/api/foo/", + "/api/foo/v2/", + "/api/foo/v2/organizations/", + "/api/foo/v2/organizations/1/", + "/api/foo/v2/organizations/1/inventories/", + "/api/foobar/", + "/api/foobar/v2/", + "/api/foobar/v2/organizations/", + "/api/foobar/v2/organizations/1/", + "/api/foobar/v2/organizations/1/inventories/", + "/api/foobar/v2/organizations/1/inventories/", + ), + ) + def test_noop(self, url, settings): + settings.OPTIONAL_API_URLPATTERN_PREFIX = '' + assert URLModificationMiddleware._convert_named_url(url) == url + + settings.OPTIONAL_API_URLPATTERN_PREFIX = 'foo' + assert URLModificationMiddleware._convert_named_url(url) == url + + def test_named_org(self): + test_org = Organization.objects.create(name='test_org') + + assert URLModificationMiddleware._convert_named_url('/api/v2/organizations/test_org/') == f'/api/v2/organizations/{test_org.pk}/' + + def test_named_org_optional_api_urlpattern_prefix_interaction(self, settings): + settings.OPTIONAL_API_URLPATTERN_PREFIX = 'bar' + test_org = Organization.objects.create(name='test_org') + + assert URLModificationMiddleware._convert_named_url('/api/bar/v2/organizations/test_org/') == f'/api/bar/v2/organizations/{test_org.pk}/' + + @pytest.mark.parametrize("prefix", ['', 'bar']) + def test_named_org_not_found(self, prefix, settings): + settings.OPTIONAL_API_URLPATTERN_PREFIX = prefix + if prefix: + prefix += '/' + + assert URLModificationMiddleware._convert_named_url(f'/api/{prefix}v2/organizations/does-not-exist/') == f'/api/{prefix}v2/organizations/0/' + + @pytest.mark.parametrize("prefix", ['', 'bar']) + def test_named_sub_resource(self, prefix, settings): + settings.OPTIONAL_API_URLPATTERN_PREFIX = prefix + test_org = Organization.objects.create(name='test_org') + if prefix: + prefix += '/' + + assert ( + URLModificationMiddleware._convert_named_url(f'/api/{prefix}v2/organizations/test_org/inventories/') + == f'/api/{prefix}v2/organizations/{test_org.pk}/inventories/' + ) + + def test_named_job_template(self): + org = Organization.objects.create(name='test_org') + tpl = JobTemplate.objects.create(name='test_tpl', organization=org) + + # first, cause a '404' - we want to verify that no state from previous requests is carried over when named + # urls are resolved + assert URLModificationMiddleware._convert_named_url('/api/v2/job_templates/test/tpl++test_org/') == '/api/v2/job_templates/test/tpl++test_org/' + + # try to resolve a valid url - it should succeed + assert URLModificationMiddleware._convert_named_url('/api/v2/job_templates/test_tpl++test_org/') == f'/api/v2/job_templates/{tpl.pk}/' diff --git a/awx/main/tests/functional/test_notifications.py b/awx/main/tests/functional/test_notifications.py index 08036db97c90..cf93030ac6ac 100644 --- a/awx/main/tests/functional/test_notifications.py +++ b/awx/main/tests/functional/test_notifications.py @@ -16,8 +16,7 @@ @pytest.mark.django_db def test_get_notification_template_list(get, user, notification_template): url = reverse('api:notification_template_list') - response = get(url, user('admin', True)) - assert response.status_code == 200 + response = get(url, user('admin', True), expect=200) assert len(response.data['results']) == 1 @@ -35,8 +34,8 @@ def test_basic_parameterization(get, post, user, organization): notification_configuration=dict(url="http://localhost", disable_ssl_verification=False, headers={"Test": "Header"}), ), u, + expect=201, ) - assert response.status_code == 201 url = reverse('api:notification_template_detail', kwargs={'pk': response.data['id']}) response = get(url, u) assert 'related' in response.data @@ -69,8 +68,8 @@ def assert_send(self, messages): notification_configuration=dict(account_sid="dummy", account_token="shouldhide", from_number="+19999999999", to_numbers=["9998887777"]), ), u, + expect=201, ) - assert response.status_code == 201 notification_template_actual = NotificationTemplate.objects.get(id=response.data['id']) url = reverse('api:notification_template_detail', kwargs={'pk': response.data['id']}) response = get(url, u) @@ -96,8 +95,8 @@ def test_inherited_notification_templates(get, post, user, organization, project notification_configuration=dict(url="http://localhost", disable_ssl_verification=False, headers={"Test": "Header"}), ), u, + expect=201, ) - assert response.status_code == 201 notification_templates.append(response.data['id']) i = Inventory.objects.create(name='test', organization=organization) i.save() @@ -122,8 +121,7 @@ def test_disallow_delete_when_notifications_pending(delete, user, notification_t u = user('superuser', True) url = reverse('api:notification_template_detail', kwargs={'pk': notification_template.id}) Notification.objects.create(notification_template=notification_template, status='pending') - response = delete(url, user=u) - assert response.status_code == 405 + delete(url, user=u, expect=405) @pytest.mark.django_db @@ -133,9 +131,8 @@ def test_notification_template_list_includes_notification_errors(get, user, noti Notification.objects.create(notification_template=notification_template, status='successful') url = reverse('api:notification_template_list') u = user('superuser', True) - response = get(url, user=u) + response = get(url, user=u, expect=200) - assert response.status_code == 200 notifications = response.data['results'][0]['summary_fields']['recent_notifications'] assert len(notifications) == 3 statuses = [n['status'] for n in notifications] @@ -163,8 +160,8 @@ def test_custom_environment_injection(post, user, organization): notification_configuration=dict(url="https://example.org", disable_ssl_verification=False, http_method="POST", headers={"Test": "Header"}), ), u, + expect=201, ) - assert response.status_code == 201 template = NotificationTemplate.objects.get(pk=response.data['id']) with pytest.raises(ConnectionError), override_settings(AWX_TASK_ENV={'HTTPS_PROXY': '192.168.50.100:1234'}), mock.patch.object( HTTPAdapter, 'send' @@ -218,3 +215,31 @@ def test_webhook_notification_pointed_to_a_redirect_launch_endpoint(post, admin, ) assert n1.send("", n1.messages.get("success").get("body")) == 1 + + +@pytest.mark.django_db +def test_update_notification_template(admin, notification_template): + notification_template.messages['workflow_approval'] = { + "running": { + "message": None, + "body": None, + } + } + notification_template.save() + + workflow_approval_message = { + "approved": { + "message": None, + "body": None, + }, + "running": { + "message": "test-message", + "body": None, + }, + } + notification_template.messages['workflow_approval'] = workflow_approval_message + notification_template.save() + + subevents = sorted(notification_template.messages["workflow_approval"].keys()) + assert subevents == ["approved", "running"] + assert notification_template.messages['workflow_approval'] == workflow_approval_message diff --git a/awx/main/tests/functional/test_policy.py b/awx/main/tests/functional/test_policy.py new file mode 100644 index 000000000000..f265a55e6413 --- /dev/null +++ b/awx/main/tests/functional/test_policy.py @@ -0,0 +1,631 @@ +import json +import os +from unittest import mock + +import pytest +import requests.exceptions +from django.test import override_settings + +from awx.main.models import ( + Job, + Inventory, + Project, + Organization, + JobTemplate, + Credential, + CredentialType, + User, + Team, + Label, + WorkflowJob, + WorkflowJobNode, + InventorySource, +) +from awx.main.exceptions import PolicyEvaluationError +from awx.main.tasks import policy +from awx.main.tasks.policy import JobSerializer, OPA_AUTH_TYPES + + +def _parse_exception_message(exception: PolicyEvaluationError): + pe_plain = str(exception.value) + + assert "This job cannot be executed due to a policy violation or error. See the following details:" in pe_plain + + violation_message = "This job cannot be executed due to a policy violation or error. See the following details:" + return eval(pe_plain.split(violation_message)[1].strip()) + + +@pytest.fixture(autouse=True) +def setup_opa_settings(): + with override_settings( + OPA_HOST='opa.example.com', + ): + yield + + +@pytest.fixture +def opa_client(): + cls_mock = mock.MagicMock(name='OpaClient') + instance_mock = cls_mock.return_value + instance_mock.__enter__.return_value = instance_mock + + with mock.patch('awx.main.tasks.policy.OpaClient', cls_mock): + yield instance_mock + + +@pytest.fixture +def job(): + project: Project = Project.objects.create(name='proj1', scm_type='git', scm_branch='main', scm_url='https://git.example.com/proj1') + inventory: Inventory = Inventory.objects.create(name='inv1', opa_query_path="inventory/response") + org: Organization = Organization.objects.create(name="org1", opa_query_path="organization/response") + jt: JobTemplate = JobTemplate.objects.create(name="jt1", opa_query_path="job_template/response") + job: Job = Job.objects.create(name='job1', extra_vars="{}", inventory=inventory, project=project, organization=org, job_template=jt) + return job + + +@pytest.mark.django_db +def test_job_serializer(): + user: User = User.objects.create(username='user1') + org: Organization = Organization.objects.create(name='org1') + + team: Team = Team.objects.create(name='team1', organization=org) + team.admin_role.members.add(user) + + project: Project = Project.objects.create(name='proj1', scm_type='git', scm_branch='main', scm_url='https://git.example.com/proj1') + inventory: Inventory = Inventory.objects.create(name='inv1', description='Demo inventory') + inventory_source: InventorySource = InventorySource.objects.create(name='inv-src1', source='file', inventory=inventory) + extra_vars = {"FOO": "value1", "BAR": "value2"} + + CredentialType.setup_tower_managed_defaults() + cred_type_ssh: CredentialType = CredentialType.objects.get(kind='ssh') + cred: Credential = Credential.objects.create(name="cred1", description='Demo credential', credential_type=cred_type_ssh, organization=org) + + label: Label = Label.objects.create(name='label1', organization=org) + + job: Job = Job.objects.create( + name='job1', extra_vars=json.dumps(extra_vars), inventory=inventory, project=project, organization=org, created_by=user, launch_type='workflow' + ) + # job.unified_job_node.workflow_job = workflow_job + job.credentials.add(cred) + job.labels.add(label) + + workflow_job: WorkflowJob = WorkflowJob.objects.create(name='wf-job1') + WorkflowJobNode.objects.create(job=job, workflow_job=workflow_job) + + serializer = JobSerializer(instance=job) + + assert serializer.data == { + 'id': job.id, + 'name': 'job1', + 'created': job.created.strftime("%Y-%m-%dT%H:%M:%S.%fZ"), + 'created_by': { + 'id': user.id, + 'username': 'user1', + 'is_superuser': False, + 'teams': [ + {'id': team.id, 'name': 'team1'}, + ], + }, + 'credentials': [ + { + 'id': cred.id, + 'name': 'cred1', + 'description': 'Demo credential', + 'organization': { + 'id': org.id, + 'name': 'org1', + }, + 'credential_type': cred_type_ssh.id, + 'kind': 'ssh', + 'managed': False, + 'kubernetes': False, + 'cloud': False, + }, + ], + 'execution_environment': None, + 'extra_vars': extra_vars, + 'forks': 0, + 'hosts_count': 0, + 'instance_group': None, + 'inventory': { + 'id': inventory.id, + 'name': 'inv1', + 'description': 'Demo inventory', + 'kind': '', + 'total_hosts': 0, + 'total_groups': 0, + 'has_inventory_sources': False, + 'total_inventory_sources': 0, + 'has_active_failures': False, + 'hosts_with_active_failures': 0, + 'inventory_sources': [ + { + 'id': inventory_source.id, + 'name': 'inv-src1', + 'source': 'file', + 'status': 'never updated', + } + ], + }, + 'job_template': None, + 'job_type': 'run', + 'job_type_name': 'job', + 'labels': [ + { + 'id': label.id, + 'name': 'label1', + 'organization': { + 'id': org.id, + 'name': 'org1', + }, + }, + ], + 'launch_type': 'workflow', + 'limit': '', + 'launched_by': {}, + 'organization': { + 'id': org.id, + 'name': 'org1', + }, + 'playbook': '', + 'project': { + 'id': project.id, + 'name': 'proj1', + 'status': 'pending', + 'scm_type': 'git', + 'scm_url': 'https://git.example.com/proj1', + 'scm_branch': 'main', + 'scm_refspec': '', + 'scm_clean': False, + 'scm_track_submodules': False, + 'scm_delete_on_update': False, + }, + 'scm_branch': '', + 'scm_revision': '', + 'workflow_job': { + 'id': workflow_job.id, + 'name': 'wf-job1', + }, + 'workflow_job_template': None, + } + + +@pytest.mark.django_db +def test_evaluate_policy_missing_opa_query_path_field(opa_client): + project: Project = Project.objects.create(name='proj1', scm_type='git', scm_branch='main', scm_url='https://git.example.com/proj1') + inventory: Inventory = Inventory.objects.create(name='inv1') + org: Organization = Organization.objects.create(name="org1") + jt: JobTemplate = JobTemplate.objects.create(name="jt1") + job: Job = Job.objects.create(name='job1', extra_vars="{}", inventory=inventory, project=project, organization=org, job_template=jt) + + response = { + "result": { + "allowed": True, + "violations": [], + } + } + opa_client.query_rule.return_value = response + try: + policy.evaluate_policy(job) + except PolicyEvaluationError as e: + pytest.fail(f"Must not raise PolicyEvaluationError: {e}") + + assert opa_client.query_rule.call_count == 0 + + +@pytest.mark.django_db +def test_evaluate_policy(opa_client, job): + response = { + "result": { + "allowed": True, + "violations": [], + } + } + opa_client.query_rule.return_value = response + try: + policy.evaluate_policy(job) + except PolicyEvaluationError as e: + pytest.fail(f"Must not raise PolicyEvaluationError: {e}") + + opa_client.query_rule.assert_has_calls( + [ + mock.call(input_data=mock.ANY, package_path='organization/response'), + mock.call(input_data=mock.ANY, package_path='inventory/response'), + mock.call(input_data=mock.ANY, package_path='job_template/response'), + ], + any_order=False, + ) + assert opa_client.query_rule.call_count == 3 + + +@pytest.mark.django_db +def test_evaluate_policy_allowed(opa_client, job): + response = { + "result": { + "allowed": True, + "violations": [], + } + } + opa_client.query_rule.return_value = response + try: + policy.evaluate_policy(job) + except PolicyEvaluationError as e: + pytest.fail(f"Must not raise PolicyEvaluationError: {e}") + + assert opa_client.query_rule.call_count == 3 + + +@pytest.mark.django_db +def test_evaluate_policy_not_allowed(opa_client, job): + response = { + "result": { + "allowed": False, + "violations": ["Access not allowed."], + } + } + opa_client.query_rule.return_value = response + + with pytest.raises(PolicyEvaluationError) as pe: + policy.evaluate_policy(job) + + pe_plain = str(pe.value) + assert "Errors:" not in pe_plain + + exception = _parse_exception_message(pe) + + assert exception["Violations"]["Organization"] == ["Access not allowed."] + assert exception["Violations"]["Inventory"] == ["Access not allowed."] + assert exception["Violations"]["Job template"] == ["Access not allowed."] + + assert opa_client.query_rule.call_count == 3 + + +@pytest.mark.django_db +def test_evaluate_policy_not_found(opa_client, job): + response = {} + opa_client.query_rule.return_value = response + + with pytest.raises(PolicyEvaluationError) as pe: + policy.evaluate_policy(job) + + missing_result_property = 'Call to OPA did not return a "result" property. The path refers to an undefined document.' + + exception = _parse_exception_message(pe) + assert exception["Errors"]["Organization"] == missing_result_property + assert exception["Errors"]["Inventory"] == missing_result_property + assert exception["Errors"]["Job template"] == missing_result_property + + assert opa_client.query_rule.call_count == 3 + + +@pytest.mark.django_db +def test_evaluate_policy_server_error(opa_client, job): + http_error_msg = '500 Server Error: Internal Server Error for url: https://opa.example.com:8181/v1/data/job_template/response/invalid' + error_response = { + 'code': 'internal_error', + 'message': ( + '1 error occurred: 1:1: rego_type_error: undefined ref: data.job_template.response.invalid\n\t' + 'data.job_template.response.invalid\n\t' + ' ^\n\t' + ' have: "invalid"\n\t' + ' want (one of): ["allowed" "violations"]' + ), + } + response = mock.Mock() + response.status_code = requests.codes.internal_server_error + response.json.return_value = error_response + + opa_client.query_rule.side_effect = requests.exceptions.HTTPError(http_error_msg, response=response) + + with pytest.raises(PolicyEvaluationError) as pe: + policy.evaluate_policy(job) + + exception = _parse_exception_message(pe) + assert exception["Errors"]["Organization"] == f'Call to OPA failed. Code: internal_error, Message: {error_response["message"]}' + assert exception["Errors"]["Inventory"] == f'Call to OPA failed. Code: internal_error, Message: {error_response["message"]}' + assert exception["Errors"]["Job template"] == f'Call to OPA failed. Code: internal_error, Message: {error_response["message"]}' + + assert opa_client.query_rule.call_count == 3 + + +@pytest.mark.django_db +def test_evaluate_policy_invalid_result(opa_client, job): + response = { + "result": { + "absolutely": "no!", + } + } + opa_client.query_rule.return_value = response + + with pytest.raises(PolicyEvaluationError) as pe: + policy.evaluate_policy(job) + + invalid_result = 'OPA policy returned invalid result.' + + exception = _parse_exception_message(pe) + assert exception["Errors"]["Organization"] == invalid_result + assert exception["Errors"]["Inventory"] == invalid_result + assert exception["Errors"]["Job template"] == invalid_result + + assert opa_client.query_rule.call_count == 3 + + +@pytest.mark.django_db +def test_evaluate_policy_failed_exception(opa_client, job): + error_response = {} + response = mock.Mock() + response.status_code = requests.codes.internal_server_error + response.json.return_value = error_response + + opa_client.query_rule.side_effect = ValueError("Invalid JSON") + + with pytest.raises(PolicyEvaluationError) as pe: + policy.evaluate_policy(job) + + opa_failed_exception = 'Call to OPA failed. Exception: Invalid JSON' + + exception = _parse_exception_message(pe) + assert exception["Errors"]["Organization"] == opa_failed_exception + assert exception["Errors"]["Inventory"] == opa_failed_exception + assert exception["Errors"]["Job template"] == opa_failed_exception + + assert opa_client.query_rule.call_count == 3 + + +@pytest.mark.django_db +@pytest.mark.parametrize( + "settings_kwargs, expected_client_cert, expected_verify, verify_content", + [ + # Case 1: Certificate-based authentication (mTLS) + ( + { + "OPA_HOST": "opa.example.com", + "OPA_SSL": True, + "OPA_AUTH_TYPE": OPA_AUTH_TYPES.CERTIFICATE, + "OPA_AUTH_CLIENT_CERT": "-----BEGIN CERTIFICATE-----\nMIICert\n-----END CERTIFICATE-----", + "OPA_AUTH_CLIENT_KEY": "-----BEGIN PRIVATE KEY-----\nMIIKey\n-----END PRIVATE KEY-----", + "OPA_AUTH_CA_CERT": "-----BEGIN CERTIFICATE-----\nMIICACert\n-----END CERTIFICATE-----", + }, + True, # Client cert should be created + "file", # Verify path should be a file + "-----BEGIN CERTIFICATE-----", # Expected content in verify file + ), + # Case 2: SSL with server verification only + ( + { + "OPA_HOST": "opa.example.com", + "OPA_SSL": True, + "OPA_AUTH_TYPE": OPA_AUTH_TYPES.NONE, + "OPA_AUTH_CA_CERT": "-----BEGIN CERTIFICATE-----\nMIICACert\n-----END CERTIFICATE-----", + }, + False, # No client cert should be created + "file", # Verify path should be a file + "-----BEGIN CERTIFICATE-----", # Expected content in verify file + ), + # Case 3: SSL with system CA store + ( + { + "OPA_HOST": "opa.example.com", + "OPA_SSL": True, + "OPA_AUTH_TYPE": OPA_AUTH_TYPES.NONE, + "OPA_AUTH_CA_CERT": "", # No custom CA cert + }, + False, # No client cert should be created + True, # Verify path should be True (system CA store) + None, # No file to check content + ), + # Case 4: No SSL + ( + { + "OPA_HOST": "opa.example.com", + "OPA_SSL": False, + "OPA_AUTH_TYPE": OPA_AUTH_TYPES.NONE, + }, + False, # No client cert should be created + False, # Verify path should be False (no verification) + None, # No file to check content + ), + ], + ids=[ + "certificate_auth", + "ssl_server_verification", + "ssl_system_ca_store", + "no_ssl", + ], +) +def test_opa_cert_file(settings_kwargs, expected_client_cert, expected_verify, verify_content): + """Parameterized test for the opa_cert_file context manager. + + Tests different configurations: + - Certificate-based authentication (mTLS) + - SSL with server verification only + - SSL with system CA store + - No SSL + """ + with override_settings(**settings_kwargs): + client_cert_path = None + verify_path = None + + with policy.opa_cert_file() as cert_files: + client_cert_path, verify_path = cert_files + + # Check client cert based on expected_client_cert + if expected_client_cert: + assert client_cert_path is not None + with open(client_cert_path, 'r') as f: + content = f.read() + assert "-----BEGIN CERTIFICATE-----" in content + assert "-----BEGIN PRIVATE KEY-----" in content + else: + assert client_cert_path is None + + # Check verify path based on expected_verify + if expected_verify == "file": + assert verify_path is not None + assert os.path.isfile(verify_path) + with open(verify_path, 'r') as f: + content = f.read() + assert verify_content in content + else: + assert verify_path is expected_verify + + # Verify files are deleted after context manager exits + if expected_client_cert: + assert not os.path.exists(client_cert_path), "Client cert file was not deleted" + + if expected_verify == "file": + assert not os.path.exists(verify_path), "CA cert file was not deleted" + + +@pytest.mark.django_db +@override_settings( + OPA_HOST='opa.example.com', + OPA_SSL=False, # SSL disabled + OPA_AUTH_TYPE=OPA_AUTH_TYPES.CERTIFICATE, # But cert auth enabled + OPA_AUTH_CLIENT_CERT="-----BEGIN CERTIFICATE-----\nMIICert\n-----END CERTIFICATE-----", + OPA_AUTH_CLIENT_KEY="-----BEGIN PRIVATE KEY-----\nMIIKey\n-----END PRIVATE KEY-----", +) +def test_evaluate_policy_cert_auth_requires_ssl(): + """Test that policy evaluation raises an error when certificate auth is used without SSL.""" + project = Project.objects.create(name='proj1') + inventory = Inventory.objects.create(name='inv1', opa_query_path="inventory/response") + org = Organization.objects.create(name="org1", opa_query_path="organization/response") + jt = JobTemplate.objects.create(name="jt1", opa_query_path="job_template/response") + job = Job.objects.create(name='job1', extra_vars="{}", inventory=inventory, project=project, organization=org, job_template=jt) + + with pytest.raises(PolicyEvaluationError) as pe: + policy.evaluate_policy(job) + + assert "OPA_AUTH_TYPE=Certificate requires OPA_SSL to be enabled" in str(pe.value) + + +@pytest.mark.django_db +@override_settings( + OPA_HOST='opa.example.com', + OPA_SSL=True, + OPA_AUTH_TYPE=OPA_AUTH_TYPES.CERTIFICATE, + OPA_AUTH_CLIENT_CERT="", # Missing client cert + OPA_AUTH_CLIENT_KEY="", # Missing client key + OPA_AUTH_CA_CERT="", # Missing CA cert +) +def test_evaluate_policy_missing_cert_settings(): + """Test that policy evaluation raises an error when certificate settings are missing.""" + project = Project.objects.create(name='proj1') + inventory = Inventory.objects.create(name='inv1', opa_query_path="inventory/response") + org = Organization.objects.create(name="org1", opa_query_path="organization/response") + jt = JobTemplate.objects.create(name="jt1", opa_query_path="job_template/response") + job = Job.objects.create(name='job1', extra_vars="{}", inventory=inventory, project=project, organization=org, job_template=jt) + + with pytest.raises(PolicyEvaluationError) as pe: + policy.evaluate_policy(job) + + error_msg = str(pe.value) + assert "Following certificate settings are missing for OPA_AUTH_TYPE=Certificate:" in error_msg + assert "OPA_AUTH_CLIENT_CERT" in error_msg + assert "OPA_AUTH_CLIENT_KEY" in error_msg + assert "OPA_AUTH_CA_CERT" in error_msg + + +@pytest.mark.django_db +@override_settings( + OPA_HOST='opa.example.com', + OPA_PORT=8181, + OPA_SSL=True, + OPA_AUTH_TYPE=OPA_AUTH_TYPES.CERTIFICATE, + OPA_AUTH_CLIENT_CERT="-----BEGIN CERTIFICATE-----\nMIICert\n-----END CERTIFICATE-----", + OPA_AUTH_CLIENT_KEY="-----BEGIN PRIVATE KEY-----\nMIIKey\n-----END PRIVATE KEY-----", + OPA_AUTH_CA_CERT="-----BEGIN CERTIFICATE-----\nMIICACert\n-----END CERTIFICATE-----", + OPA_REQUEST_TIMEOUT=2.5, + OPA_REQUEST_RETRIES=3, +) +def test_opa_client_context_manager_mtls(): + """Test that opa_client context manager correctly initializes the OPA client.""" + # Mock the OpaClient class + with mock.patch('awx.main.tasks.policy.OpaClient') as mock_opa_client: + # Setup the mock + mock_instance = mock_opa_client.return_value + mock_instance.__enter__.return_value = mock_instance + mock_instance._session = mock.MagicMock() + + # Use the context manager + with policy.opa_client(headers={'Custom-Header': 'Value'}) as client: + # Verify the client was initialized with the correct parameters + mock_opa_client.assert_called_once_with( + host='opa.example.com', + port=8181, + headers={'Custom-Header': 'Value'}, + ssl=True, + cert=mock.ANY, # We can't check the exact value as it's a temporary file + timeout=2.5, + retries=3, + ) + + # Verify the session properties were set correctly + assert client._session.cert is not None + assert client._session.verify is not None + + # Check the content of the cert file + cert_file_path = client._session.cert + assert os.path.isfile(cert_file_path) + with open(cert_file_path, 'r') as f: + cert_content = f.read() + assert "-----BEGIN CERTIFICATE-----" in cert_content + assert "MIICert" in cert_content + assert "-----BEGIN PRIVATE KEY-----" in cert_content + assert "MIIKey" in cert_content + + # Check the content of the verify file + verify_file_path = client._session.verify + assert os.path.isfile(verify_file_path) + with open(verify_file_path, 'r') as f: + verify_content = f.read() + assert "-----BEGIN CERTIFICATE-----" in verify_content + assert "MIICACert" in verify_content + + # Verify the client is the mocked instance + assert client is mock_instance + + # Store file paths for checking after context exit + cert_path = client._session.cert + verify_path = client._session.verify + + # Verify files are deleted after context manager exits + assert not os.path.exists(cert_path), "Client cert file was not deleted" + assert not os.path.exists(verify_path), "CA cert file was not deleted" + + +@pytest.mark.django_db +@override_settings( + OPA_HOST='opa.example.com', + OPA_SSL=True, + OPA_AUTH_TYPE=OPA_AUTH_TYPES.TOKEN, + OPA_AUTH_TOKEN='secret-token', + OPA_AUTH_CUSTOM_HEADERS={'X-Custom': 'Header'}, +) +def test_opa_client_token_auth(): + """Test that token authentication correctly adds the Authorization header.""" + # Create a job for testing + project = Project.objects.create(name='proj1') + inventory = Inventory.objects.create(name='inv1', opa_query_path="inventory/response") + org = Organization.objects.create(name="org1", opa_query_path="organization/response") + jt = JobTemplate.objects.create(name="jt1", opa_query_path="job_template/response") + job = Job.objects.create(name='job1', extra_vars="{}", inventory=inventory, project=project, organization=org, job_template=jt) + + # Mock the OpaClient class + with mock.patch('awx.main.tasks.policy.opa_client') as mock_opa_client_cm: + # Setup the mock + mock_client = mock.MagicMock() + mock_opa_client_cm.return_value.__enter__.return_value = mock_client + mock_client.query_rule.return_value = { + "result": { + "allowed": True, + "violations": [], + } + } + + # Call evaluate_policy + policy.evaluate_policy(job) + + # Verify opa_client was called with the correct headers + expected_headers = {'X-Custom': 'Header', 'Authorization': 'Bearer secret-token'} + mock_opa_client_cm.assert_called_once_with(headers=expected_headers) diff --git a/awx/main/tests/functional/test_projects.py b/awx/main/tests/functional/test_projects.py index 0459aaab49ae..7d389d1e1623 100644 --- a/awx/main/tests/functional/test_projects.py +++ b/awx/main/tests/functional/test_projects.py @@ -4,7 +4,7 @@ import pytest from awx.api.versioning import reverse -from awx.main.models import Project +from awx.main.models import Project, JobTemplate from django.core.exceptions import ValidationError @@ -334,8 +334,71 @@ def test_team_project_list(get, team_project_list): ) +@pytest.mark.django_db +def test_project_teams_list_multiple_roles_distinct(get, organization_factory): + # test projects with multiple roles on the same team + objects = organization_factory( + 'org1', + superusers=['admin'], + teams=['teamA'], + projects=['proj1'], + roles=[ + 'teamA.member_role:proj1.admin_role', + 'teamA.member_role:proj1.use_role', + 'teamA.member_role:proj1.update_role', + 'teamA.member_role:proj1.read_role', + ], + ) + admin = objects.superusers.admin + proj1 = objects.projects.proj1 + + res = get(reverse('api:project_teams_list', kwargs={'pk': proj1.pk}), admin).data + names = [t['name'] for t in res['results']] + assert names == ['teamA'] + + +@pytest.mark.django_db +def test_project_teams_list_multiple_teams(get, organization_factory): + # test projects with multiple teams + objs = organization_factory( + 'org1', + superusers=['admin'], + teams=['teamA', 'teamB', 'teamC', 'teamD'], + projects=['proj1'], + roles=[ + 'teamA.member_role:proj1.admin_role', + 'teamB.member_role:proj1.update_role', + 'teamC.member_role:proj1.use_role', + 'teamD.member_role:proj1.read_role', + ], + ) + admin = objs.superusers.admin + proj1 = objs.projects.proj1 + + res = get(reverse('api:project_teams_list', kwargs={'pk': proj1.pk}), admin).data + names = sorted([t['name'] for t in res['results']]) + assert names == ['teamA', 'teamB', 'teamC', 'teamD'] + + +@pytest.mark.django_db +def test_project_teams_list_no_direct_assignments(get, organization_factory): + # test projects with no direct team assignments + objects = organization_factory( + 'org1', + superusers=['admin'], + teams=['teamA'], + projects=['proj1'], + roles=[], + ) + admin = objects.superusers.admin + proj1 = objects.projects.proj1 + + res = get(reverse('api:project_teams_list', kwargs={'pk': proj1.pk}), admin).data + assert res['count'] == 0 + + @pytest.mark.parametrize("u,expected_status_code", [('rando', 403), ('org_member', 403), ('org_admin', 201), ('admin', 201)]) -@pytest.mark.django_db() +@pytest.mark.django_db def test_create_project(post, organization, org_admin, org_member, admin, rando, u, expected_status_code): if u == 'rando': u = rando @@ -353,11 +416,12 @@ def test_create_project(post, organization, org_admin, org_member, admin, rando, 'organization': organization.id, }, u, + expect=expected_status_code, ) - print(result.data) - assert result.status_code == expected_status_code if expected_status_code == 201: assert Project.objects.filter(name='Project', organization=organization).exists() + elif expected_status_code == 403: + assert 'do not have permission' in str(result.data['detail']) @pytest.mark.django_db @@ -411,14 +475,14 @@ def test_project_delete(delete, organization, admin_user): @pytest.mark.parametrize( - 'order_by, expected_names, expected_ids', + 'order_by, expected_names', [ - ('name', ['alice project', 'bob project', 'shared project'], [1, 2, 3]), - ('-name', ['shared project', 'bob project', 'alice project'], [3, 2, 1]), + ('name', ['alice project', 'bob project', 'shared project']), + ('-name', ['shared project', 'bob project', 'alice project']), ], ) @pytest.mark.django_db -def test_project_list_ordering_by_name(get, order_by, expected_names, expected_ids, organization_factory): +def test_project_list_ordering_by_name(get, order_by, expected_names, organization_factory): 'ensure sorted order of project list is maintained correctly when the requested order is invalid or not applicable' objects = organization_factory( 'org1', @@ -426,28 +490,44 @@ def test_project_list_ordering_by_name(get, order_by, expected_names, expected_i superusers=['admin'], ) project_names = [] - project_ids = [] # TODO: ask for an order by here that doesn't apply results = get(reverse('api:project_list'), objects.superusers.admin, QUERY_STRING='order_by=%s' % order_by).data['results'] for x in range(len(results)): project_names.append(results[x]['name']) - project_ids.append(results[x]['id']) - assert project_names == expected_names and project_ids == expected_ids + assert project_names == expected_names @pytest.mark.parametrize('order_by', ('name', '-name')) @pytest.mark.django_db -def test_project_list_ordering_with_duplicate_names(get, order_by, organization_factory): +def test_project_list_ordering_with_duplicate_names(get, order_by, admin): # why? because all the '1' mean that all the names are the same, you can't sort based on that, # meaning you have to fall back on the default sort order, which in this case, is ID 'ensure sorted order of project list is maintained correctly when the project names the same' - objects = organization_factory( - 'org1', - projects=['1', '1', '1', '1', '1'], - superusers=['admin'], - ) + from awx.main.models import Organization + + projects = [] + for i in range(5): + projects.append(Project.objects.create(name='1', organization=Organization.objects.create(name=f'org{i}'))) project_ids = {} for x in range(3): - results = get(reverse('api:project_list'), objects.superusers.admin, QUERY_STRING='order_by=%s' % order_by).data['results'] + results = get(reverse('api:project_list'), user=admin, QUERY_STRING='order_by=%s' % order_by).data['results'] project_ids[x] = [proj['id'] for proj in results] - assert project_ids[0] == project_ids[1] == project_ids[2] == [1, 2, 3, 4, 5] + assert project_ids[0] == project_ids[1] == project_ids[2] + assert project_ids[0] == sorted(project_ids[0]) + assert set(project_ids[0]) == set([proj.id for proj in projects]) + + +@pytest.mark.django_db +def test_project_failed_update(post, project, admin, inventory): + """Test to ensure failed projects with update on launch will create launch rather than error""" + jt = JobTemplate.objects.create(project=project, inventory=inventory) + # set project to update on launch and set status to failed + project.update_fields(scm_update_on_launch=True) + project.update() + project.project_updates.last().update_fields(status='failed') + response = post(reverse('api:job_template_launch', kwargs={'pk': jt.pk}), user=admin, expect=201) + assert response.status_code == 201 + # set project to not update on launch and validate still 400's + project.update_fields(scm_update_on_launch=False) + response = post(reverse('api:job_template_launch', kwargs={'pk': jt.pk}), user=admin, expect=400) + assert response.status_code == 400 diff --git a/awx/main/tests/functional/test_python_requirements.py b/awx/main/tests/functional/test_python_requirements.py index d363b91db1f4..089638e5c2fa 100644 --- a/awx/main/tests/functional/test_python_requirements.py +++ b/awx/main/tests/functional/test_python_requirements.py @@ -5,7 +5,38 @@ from django.conf import settings -@pytest.mark.skip(reason="This test needs some love") +def test_bootstrap_consistent(): + with open('Makefile', 'r') as f: + mk_data = f.read() + bootstrap_reqs = None + for line in mk_data.split('\n'): + if line.startswith('VENV_BOOTSTRAP'): + parts = line.split() + bootstrap_reqs = parts[parts.index('?=') + 1 :] + break + else: + raise RuntimeError('Cound not find bootstrap line') + + req_data = None + with open('requirements/requirements.txt', 'r') as f: + req_data = f.read() + + different_requirements = [] + for req in bootstrap_reqs: + boot_req_name, _ = req.split('=', 1) + for line in req_data.split('\n'): + if '=' not in line: + continue + req_name, _ = line.split('=', 1) + if req_name == boot_req_name: + if req != line: + different_requirements.append((req, line)) + break + + assert not different_requirements + + +@pytest.mark.xfail(reason="This test needs some love") def test_env_matches_requirements_txt(): from pip.operations import freeze @@ -33,7 +64,7 @@ def skip_line(line): if skip_line(x): continue x = x.lower() - (pkg_name, pkg_version) = x.split('==') + pkg_name, pkg_version = x.split('==') reqs_actual.append([pkg_name, pkg_version]) reqs_expected = [] @@ -49,7 +80,7 @@ def skip_line(line): Special case pkg_name[pkg_subname]==version For this case, we strip out [pkg_subname] ''' - (pkg_name, pkg_version) = line.split('==') + pkg_name, pkg_version = line.split('==') pkg_name = re.sub(r'\[.*\]', '', pkg_name) reqs_expected.append([pkg_name, pkg_version]) diff --git a/awx/main/tests/functional/test_rbac_core.py b/awx/main/tests/functional/test_rbac_core.py deleted file mode 100644 index 7029bbe54486..000000000000 --- a/awx/main/tests/functional/test_rbac_core.py +++ /dev/null @@ -1,213 +0,0 @@ -import pytest - -from awx.main.models import ( - Role, - Organization, - Project, -) -from awx.main.fields import update_role_parentage_for_instance - - -@pytest.mark.django_db -def test_auto_inheritance_by_children(organization, alice): - A = Role.objects.create() - B = Role.objects.create() - A.members.add(alice) - - assert alice not in organization.admin_role - assert Organization.accessible_objects(alice, 'admin_role').count() == 0 - A.children.add(B) - assert alice not in organization.admin_role - assert Organization.accessible_objects(alice, 'admin_role').count() == 0 - A.children.add(organization.admin_role) - assert alice in organization.admin_role - assert Organization.accessible_objects(alice, 'admin_role').count() == 1 - A.children.remove(organization.admin_role) - assert alice not in organization.admin_role - B.children.add(organization.admin_role) - assert alice in organization.admin_role - B.children.remove(organization.admin_role) - assert alice not in organization.admin_role - assert Organization.accessible_objects(alice, 'admin_role').count() == 0 - - # We've had the case where our pre/post save init handlers in our field descriptors - # end up creating a ton of role objects because of various not-so-obvious issues - assert Role.objects.count() < 50 - - -@pytest.mark.django_db -def test_auto_inheritance_by_parents(organization, alice): - A = Role.objects.create() - B = Role.objects.create() - A.members.add(alice) - - assert alice not in organization.admin_role - B.parents.add(A) - assert alice not in organization.admin_role - organization.admin_role.parents.add(A) - assert alice in organization.admin_role - organization.admin_role.parents.remove(A) - assert alice not in organization.admin_role - organization.admin_role.parents.add(B) - assert alice in organization.admin_role - organization.admin_role.parents.remove(B) - assert alice not in organization.admin_role - - -@pytest.mark.django_db -def test_accessible_objects(organization, alice, bob): - A = Role.objects.create() - A.members.add(alice) - B = Role.objects.create() - B.members.add(alice) - B.members.add(bob) - - assert Organization.accessible_objects(alice, 'admin_role').count() == 0 - assert Organization.accessible_objects(bob, 'admin_role').count() == 0 - A.children.add(organization.admin_role) - assert Organization.accessible_objects(alice, 'admin_role').count() == 1 - assert Organization.accessible_objects(bob, 'admin_role').count() == 0 - - -@pytest.mark.django_db -def test_team_symantics(organization, team, alice): - assert alice not in organization.auditor_role - team.member_role.children.add(organization.auditor_role) - assert alice not in organization.auditor_role - team.member_role.members.add(alice) - assert alice in organization.auditor_role - team.member_role.members.remove(alice) - assert alice not in organization.auditor_role - - -@pytest.mark.django_db -def test_auto_field_adjustments(organization, inventory, team, alice): - 'Ensures the auto role reparenting is working correctly through non m2m fields' - org2 = Organization.objects.create(name='Org 2', description='org 2') - org2.admin_role.members.add(alice) - assert alice not in inventory.admin_role - inventory.organization = org2 - inventory.save() - assert alice in inventory.admin_role - inventory.organization = organization - inventory.save() - assert alice not in inventory.admin_role - # assert False - - -@pytest.mark.django_db -def test_implicit_deletes(alice): - 'Ensures implicit resources and roles delete themselves' - delorg = Organization.objects.create(name='test-org') - child = Role.objects.create() - child.parents.add(delorg.admin_role) - delorg.admin_role.members.add(alice) - - admin_role_id = delorg.admin_role.id - auditor_role_id = delorg.auditor_role.id - - assert child.ancestors.count() > 1 - assert Role.objects.filter(id=admin_role_id).count() == 1 - assert Role.objects.filter(id=auditor_role_id).count() == 1 - n_alice_roles = alice.roles.count() - n_system_admin_children = Role.singleton('system_administrator').children.count() - - delorg.delete() - - assert Role.objects.filter(id=admin_role_id).count() == 0 - assert Role.objects.filter(id=auditor_role_id).count() == 0 - assert alice.roles.count() == (n_alice_roles - 1) - assert Role.singleton('system_administrator').children.count() == (n_system_admin_children - 1) - assert child.ancestors.count() == 1 - assert child.ancestors.all()[0] == child - - -@pytest.mark.django_db -def test_content_object(user): - 'Ensure our content_object stuf seems to be working' - - org = Organization.objects.create(name='test-org') - assert org.admin_role.content_object.id == org.id - - -@pytest.mark.django_db -def test_hierarchy_rebuilding_multi_path(): - 'Tests a subdtle cases around role hierarchy rebuilding when you have multiple paths to the same role of different length' - - X = Role.objects.create() - A = Role.objects.create() - B = Role.objects.create() - C = Role.objects.create() - D = Role.objects.create() - - A.children.add(B) - A.children.add(D) - B.children.add(C) - C.children.add(D) - - assert A.is_ancestor_of(D) - assert X.is_ancestor_of(D) is False - - X.children.add(A) - - assert X.is_ancestor_of(D) is True - - X.children.remove(A) - - # This can be the stickler, the rebuilder needs to ensure that D's role - # hierarchy is built after both A and C are updated. - assert X.is_ancestor_of(D) is False - - -@pytest.mark.django_db -def test_auto_parenting(): - org1 = Organization.objects.create(name='org1') - org2 = Organization.objects.create(name='org2') - - prj1 = Project.objects.create(name='prj1') - prj2 = Project.objects.create(name='prj2') - - assert org1.admin_role.is_ancestor_of(prj1.admin_role) is False - assert org1.admin_role.is_ancestor_of(prj2.admin_role) is False - assert org2.admin_role.is_ancestor_of(prj1.admin_role) is False - assert org2.admin_role.is_ancestor_of(prj2.admin_role) is False - - prj1.organization = org1 - prj1.save() - - assert org1.admin_role.is_ancestor_of(prj1.admin_role) - assert org1.admin_role.is_ancestor_of(prj2.admin_role) is False - assert org2.admin_role.is_ancestor_of(prj1.admin_role) is False - assert org2.admin_role.is_ancestor_of(prj2.admin_role) is False - - prj2.organization = org1 - prj2.save() - - assert org1.admin_role.is_ancestor_of(prj1.admin_role) - assert org1.admin_role.is_ancestor_of(prj2.admin_role) - assert org2.admin_role.is_ancestor_of(prj1.admin_role) is False - assert org2.admin_role.is_ancestor_of(prj2.admin_role) is False - - prj1.organization = org2 - prj1.save() - - assert org1.admin_role.is_ancestor_of(prj1.admin_role) is False - assert org1.admin_role.is_ancestor_of(prj2.admin_role) - assert org2.admin_role.is_ancestor_of(prj1.admin_role) - assert org2.admin_role.is_ancestor_of(prj2.admin_role) is False - - prj2.organization = org2 - prj2.save() - - assert org1.admin_role.is_ancestor_of(prj1.admin_role) is False - assert org1.admin_role.is_ancestor_of(prj2.admin_role) is False - assert org2.admin_role.is_ancestor_of(prj1.admin_role) - assert org2.admin_role.is_ancestor_of(prj2.admin_role) - - -@pytest.mark.django_db -def test_update_parents_keeps_teams(team, project): - project.update_role.parents.add(team.member_role) - assert team.member_role in project.update_role # test prep sanity check - update_role_parentage_for_instance(project) - assert team.member_role in project.update_role # actual assertion diff --git a/awx/main/tests/functional/test_rbac_instance_groups.py b/awx/main/tests/functional/test_rbac_instance_groups.py deleted file mode 100644 index 402040ea21c3..000000000000 --- a/awx/main/tests/functional/test_rbac_instance_groups.py +++ /dev/null @@ -1,87 +0,0 @@ -import pytest - -from awx.main.access import ( - InstanceGroupAccess, - OrganizationAccess, - InventoryAccess, - JobTemplateAccess, -) -from awx.main.models import Organization - - -@pytest.mark.django_db -def test_ig_normal_user_visibility(organization, default_instance_group, user): - u = user('user', False) - assert len(InstanceGroupAccess(u).get_queryset()) == 0 - organization.instance_groups.add(default_instance_group) - organization.member_role.members.add(u) - assert len(InstanceGroupAccess(u).get_queryset()) == 0 - - -@pytest.mark.django_db -def test_ig_admin_user_visibility(organization, default_instance_group, admin, system_auditor, org_admin): - assert len(InstanceGroupAccess(admin).get_queryset()) == 1 - assert len(InstanceGroupAccess(system_auditor).get_queryset()) == 1 - assert len(InstanceGroupAccess(org_admin).get_queryset()) == 0 - organization.instance_groups.add(default_instance_group) - assert len(InstanceGroupAccess(org_admin).get_queryset()) == 1 - - -@pytest.mark.django_db -def test_ig_normal_user_associability(organization, default_instance_group, user): - u = user('user', False) - access = OrganizationAccess(u) - assert not access.can_attach(organization, default_instance_group, 'instance_groups', None) - organization.instance_groups.add(default_instance_group) - organization.member_role.members.add(u) - assert not access.can_attach(organization, default_instance_group, 'instance_groups', None) - - -@pytest.mark.django_db -def test_access_via_two_organizations(rando, default_instance_group): - for org_name in ['org1', 'org2']: - org = Organization.objects.create(name=org_name) - org.instance_groups.add(default_instance_group) - org.admin_role.members.add(rando) - access = InstanceGroupAccess(rando) - assert list(access.get_queryset()) == [default_instance_group] - - -@pytest.mark.django_db -def test_ig_associability(organization, default_instance_group, admin, system_auditor, org_admin, org_member, job_template_factory): - admin_access = OrganizationAccess(admin) - auditor_access = OrganizationAccess(system_auditor) - oadmin_access = OrganizationAccess(org_admin) - omember_access = OrganizationAccess(org_member) - assert admin_access.can_attach(organization, default_instance_group, 'instance_groups', None) - assert not oadmin_access.can_attach(organization, default_instance_group, 'instance_groups', None) - assert not auditor_access.can_attach(organization, default_instance_group, 'instance_groups', None) - assert not omember_access.can_attach(organization, default_instance_group, 'instance_groups', None) - - organization.instance_groups.add(default_instance_group) - - assert admin_access.can_unattach(organization, default_instance_group, 'instance_groups', None) - assert not oadmin_access.can_unattach(organization, default_instance_group, 'instance_groups', None) - assert not auditor_access.can_unattach(organization, default_instance_group, 'instance_groups', None) - assert not omember_access.can_unattach(organization, default_instance_group, 'instance_groups', None) - - objects = job_template_factory('jt', organization=organization, project='p', inventory='i', credential='c') - admin_access = InventoryAccess(admin) - auditor_access = InventoryAccess(system_auditor) - oadmin_access = InventoryAccess(org_admin) - omember_access = InventoryAccess(org_member) - - assert admin_access.can_attach(objects.inventory, default_instance_group, 'instance_groups', None) - assert oadmin_access.can_attach(objects.inventory, default_instance_group, 'instance_groups', None) - assert not auditor_access.can_attach(objects.inventory, default_instance_group, 'instance_groups', None) - assert not omember_access.can_attach(objects.inventory, default_instance_group, 'instance_groups', None) - - admin_access = JobTemplateAccess(admin) - auditor_access = JobTemplateAccess(system_auditor) - oadmin_access = JobTemplateAccess(org_admin) - omember_access = JobTemplateAccess(org_member) - - assert admin_access.can_attach(objects.job_template, default_instance_group, 'instance_groups', None) - assert oadmin_access.can_attach(objects.job_template, default_instance_group, 'instance_groups', None) - assert not auditor_access.can_attach(objects.job_template, default_instance_group, 'instance_groups', None) - assert not omember_access.can_attach(objects.job_template, default_instance_group, 'instance_groups', None) diff --git a/awx/main/tests/functional/test_rbac_migration.py b/awx/main/tests/functional/test_rbac_migration.py deleted file mode 100644 index 5f1b2633e86e..000000000000 --- a/awx/main/tests/functional/test_rbac_migration.py +++ /dev/null @@ -1,75 +0,0 @@ -import pytest - -from django.apps import apps - -from awx.main.migrations import _rbac as rbac -from awx.main.models import UnifiedJobTemplate, InventorySource, Inventory, JobTemplate, Project, Organization, User - - -@pytest.mark.django_db -def test_implied_organization_subquery_inventory(): - orgs = [] - for i in range(3): - orgs.append(Organization.objects.create(name='foo{}'.format(i))) - orgs.append(orgs[0]) - for i in range(4): - org = orgs[i] - if i == 2: - inventory = Inventory.objects.create(name='foo{}'.format(i)) - else: - inventory = Inventory.objects.create(name='foo{}'.format(i), organization=org) - inv_src = InventorySource.objects.create(name='foo{}'.format(i), inventory=inventory, source='ec2') - sources = UnifiedJobTemplate.objects.annotate(test_field=rbac.implicit_org_subquery(UnifiedJobTemplate, InventorySource)) - for inv_src in sources: - assert inv_src.test_field == inv_src.inventory.organization_id - - -@pytest.mark.django_db -def test_implied_organization_subquery_job_template(): - jts = [] - for i in range(5): - if i <= 3: - org = Organization.objects.create(name='foo{}'.format(i)) - else: - org = None - if i <= 4: - proj = Project.objects.create(name='foo{}'.format(i), organization=org) - else: - proj = None - jts.append(JobTemplate.objects.create(name='foo{}'.format(i), project=proj)) - # test case of sharing same org - jts[2].project.organization = jts[3].project.organization - jts[2].save() - ujts = UnifiedJobTemplate.objects.annotate(test_field=rbac.implicit_org_subquery(UnifiedJobTemplate, JobTemplate)) - for jt in ujts: - if not isinstance(jt, JobTemplate): # some are projects - assert jt.test_field is None - else: - if jt.project is None: - assert jt.test_field is None - else: - assert jt.test_field == jt.project.organization_id - - -@pytest.mark.django_db -def test_give_explicit_inventory_permission(): - dual_admin = User.objects.create(username='alice') - inv_admin = User.objects.create(username='bob') - inv_org = Organization.objects.create(name='inv-org') - proj_org = Organization.objects.create(name='proj-org') - - inv_org.admin_role.members.add(inv_admin, dual_admin) - proj_org.admin_role.members.add(dual_admin) - - proj = Project.objects.create(name="test-proj", organization=proj_org) - inv = Inventory.objects.create(name='test-inv', organization=inv_org) - - jt = JobTemplate.objects.create(name='foo', project=proj, inventory=inv) - - assert dual_admin in jt.admin_role - - rbac.restore_inventory_admins(apps, None) - - assert inv_admin in jt.admin_role.members.all() - assert dual_admin not in jt.admin_role.members.all() - assert dual_admin in jt.admin_role diff --git a/awx/main/tests/functional/test_rbac_oauth.py b/awx/main/tests/functional/test_rbac_oauth.py deleted file mode 100644 index c55943adeb35..000000000000 --- a/awx/main/tests/functional/test_rbac_oauth.py +++ /dev/null @@ -1,247 +0,0 @@ -import pytest - -from awx.main.access import ( - OAuth2ApplicationAccess, - OAuth2TokenAccess, - ActivityStreamAccess, -) -from awx.main.models.oauth import ( - OAuth2Application as Application, - OAuth2AccessToken as AccessToken, -) -from awx.main.models import ActivityStream -from awx.api.versioning import reverse - - -@pytest.mark.django_db -class TestOAuth2Application: - @pytest.mark.parametrize( - "user_for_access, can_access_list", - [ - (0, [True, True]), - (1, [True, True]), - (2, [True, True]), - (3, [False, False]), - ], - ) - def test_can_read(self, admin, org_admin, org_member, alice, user_for_access, can_access_list, organization): - user_list = [admin, org_admin, org_member, alice] - access = OAuth2ApplicationAccess(user_list[user_for_access]) - app_creation_user_list = [admin, org_admin] - for user, can_access in zip(app_creation_user_list, can_access_list): - app = Application.objects.create( - name='test app for {}'.format(user.username), - user=user, - client_type='confidential', - authorization_grant_type='password', - organization=organization, - ) - assert access.can_read(app) is can_access - - def test_admin_only_can_read(self, user, organization): - user = user('org-admin', False) - organization.admin_role.members.add(user) - access = OAuth2ApplicationAccess(user) - app = Application.objects.create( - name='test app for {}'.format(user.username), user=user, client_type='confidential', authorization_grant_type='password', organization=organization - ) - assert access.can_read(app) is True - - def test_app_activity_stream(self, org_admin, alice, organization): - app = Application.objects.create( - name='test app for {}'.format(org_admin.username), - user=org_admin, - client_type='confidential', - authorization_grant_type='password', - organization=organization, - ) - access = OAuth2ApplicationAccess(org_admin) - assert access.can_read(app) is True - access = ActivityStreamAccess(org_admin) - activity_stream = ActivityStream.objects.filter(o_auth2_application=app).latest('pk') - assert access.can_read(activity_stream) is True - access = ActivityStreamAccess(alice) - assert access.can_read(app) is False - assert access.can_read(activity_stream) is False - - def test_token_activity_stream(self, org_admin, alice, organization, post): - app = Application.objects.create( - name='test app for {}'.format(org_admin.username), - user=org_admin, - client_type='confidential', - authorization_grant_type='password', - organization=organization, - ) - response = post(reverse('api:o_auth2_application_token_list', kwargs={'pk': app.pk}), {'scope': 'read'}, org_admin, expect=201) - token = AccessToken.objects.get(token=response.data['token']) - access = OAuth2ApplicationAccess(org_admin) - assert access.can_read(app) is True - access = ActivityStreamAccess(org_admin) - activity_stream = ActivityStream.objects.filter(o_auth2_access_token=token).latest('pk') - assert access.can_read(activity_stream) is True - access = ActivityStreamAccess(alice) - assert access.can_read(token) is False - assert access.can_read(activity_stream) is False - - def test_can_edit_delete_app_org_admin(self, admin, org_admin, org_member, alice, organization): - user_list = [admin, org_admin, org_member, alice] - can_access_list = [True, True, False, False] - for user, can_access in zip(user_list, can_access_list): - app = Application.objects.create( - name='test app for {}'.format(user.username), - user=org_admin, - client_type='confidential', - authorization_grant_type='password', - organization=organization, - ) - access = OAuth2ApplicationAccess(user) - assert access.can_change(app, {}) is can_access - assert access.can_delete(app) is can_access - - def test_can_edit_delete_app_admin(self, admin, org_admin, org_member, alice, organization): - user_list = [admin, org_admin, org_member, alice] - can_access_list = [True, True, False, False] - for user, can_access in zip(user_list, can_access_list): - app = Application.objects.create( - name='test app for {}'.format(user.username), - user=admin, - client_type='confidential', - authorization_grant_type='password', - organization=organization, - ) - access = OAuth2ApplicationAccess(user) - assert access.can_change(app, {}) is can_access - assert access.can_delete(app) is can_access - - def test_superuser_can_always_create(self, admin, org_admin, org_member, alice, organization): - access = OAuth2ApplicationAccess(admin) - for user in [admin, org_admin, org_member, alice]: - assert access.can_add( - {'name': 'test app', 'user': user.pk, 'client_type': 'confidential', 'authorization_grant_type': 'password', 'organization': organization.id} - ) - - def test_normal_user_cannot_create(self, admin, org_admin, org_member, alice, organization): - for access_user in [org_member, alice]: - access = OAuth2ApplicationAccess(access_user) - for user in [admin, org_admin, org_member, alice]: - assert not access.can_add( - { - 'name': 'test app', - 'user': user.pk, - 'client_type': 'confidential', - 'authorization_grant_type': 'password', - 'organization': organization.id, - } - ) - - -@pytest.mark.django_db -class TestOAuth2Token: - def test_can_read_change_delete_app_token(self, post, admin, org_admin, org_member, alice, organization): - user_list = [admin, org_admin, org_member, alice] - can_access_list = [True, True, False, False] - app = Application.objects.create( - name='test app for {}'.format(admin.username), - user=admin, - client_type='confidential', - authorization_grant_type='password', - organization=organization, - ) - response = post(reverse('api:o_auth2_application_token_list', kwargs={'pk': app.pk}), {'scope': 'read'}, admin, expect=201) - for user, can_access in zip(user_list, can_access_list): - token = AccessToken.objects.get(token=response.data['token']) - access = OAuth2TokenAccess(user) - assert access.can_read(token) is can_access - assert access.can_change(token, {}) is can_access - assert access.can_delete(token) is can_access - - def test_auditor_can_read(self, post, admin, org_admin, org_member, alice, system_auditor, organization): - user_list = [admin, org_admin, org_member] - can_access_list = [True, True, True] - cannot_access_list = [False, False, False] - app = Application.objects.create( - name='test app for {}'.format(admin.username), - user=admin, - client_type='confidential', - authorization_grant_type='password', - organization=organization, - ) - for user, can_access, cannot_access in zip(user_list, can_access_list, cannot_access_list): - response = post(reverse('api:o_auth2_application_token_list', kwargs={'pk': app.pk}), {'scope': 'read'}, user, expect=201) - token = AccessToken.objects.get(token=response.data['token']) - access = OAuth2TokenAccess(system_auditor) - assert access.can_read(token) is can_access - assert access.can_change(token, {}) is cannot_access - assert access.can_delete(token) is cannot_access - - def test_user_auditor_can_change(self, post, org_member, org_admin, system_auditor, organization): - app = Application.objects.create( - name='test app for {}'.format(org_admin.username), - user=org_admin, - client_type='confidential', - authorization_grant_type='password', - organization=organization, - ) - response = post(reverse('api:o_auth2_application_token_list', kwargs={'pk': app.pk}), {'scope': 'read'}, org_member, expect=201) - token = AccessToken.objects.get(token=response.data['token']) - access = OAuth2TokenAccess(system_auditor) - assert access.can_read(token) is True - assert access.can_change(token, {}) is False - assert access.can_delete(token) is False - dual_user = system_auditor - organization.admin_role.members.add(dual_user) - access = OAuth2TokenAccess(dual_user) - assert access.can_read(token) is True - assert access.can_change(token, {}) is True - assert access.can_delete(token) is True - - def test_can_read_change_delete_personal_token_org_member(self, post, admin, org_admin, org_member, alice): - # Tests who can read a token created by an org-member - user_list = [admin, org_admin, org_member, alice] - can_access_list = [True, False, True, False] - response = post(reverse('api:user_personal_token_list', kwargs={'pk': org_member.pk}), {'scope': 'read'}, org_member, expect=201) - token = AccessToken.objects.get(token=response.data['token']) - for user, can_access in zip(user_list, can_access_list): - access = OAuth2TokenAccess(user) - assert access.can_read(token) is can_access - assert access.can_change(token, {}) is can_access - assert access.can_delete(token) is can_access - - def test_can_read_personal_token_creator(self, post, admin, org_admin, org_member, alice): - # Tests the token's creator can read their tokens - user_list = [admin, org_admin, org_member, alice] - can_access_list = [True, True, True, True] - - for user, can_access in zip(user_list, can_access_list): - response = post(reverse('api:user_personal_token_list', kwargs={'pk': user.pk}), {'scope': 'read', 'application': None}, user, expect=201) - token = AccessToken.objects.get(token=response.data['token']) - access = OAuth2TokenAccess(user) - assert access.can_read(token) is can_access - assert access.can_change(token, {}) is can_access - assert access.can_delete(token) is can_access - - @pytest.mark.parametrize( - "user_for_access, can_access_list", - [ - (0, [True, True]), - (1, [True, True]), - (2, [True, True]), - (3, [False, False]), - ], - ) - def test_can_create(self, post, admin, org_admin, org_member, alice, user_for_access, can_access_list, organization): - user_list = [admin, org_admin, org_member, alice] - for user, can_access in zip(user_list, can_access_list): - app = Application.objects.create( - name='test app for {}'.format(user.username), - user=user, - client_type='confidential', - authorization_grant_type='password', - organization=organization, - ) - post( - reverse('api:o_auth2_application_token_list', kwargs={'pk': app.pk}), - {'scope': 'read'}, - user_list[user_for_access], - expect=201 if can_access else 403, - ) diff --git a/awx/main/tests/functional/test_routing.py b/awx/main/tests/functional/test_routing.py new file mode 100644 index 000000000000..7cb5e9b5874d --- /dev/null +++ b/awx/main/tests/functional/test_routing.py @@ -0,0 +1,90 @@ +import pytest + +from django.contrib.auth.models import AnonymousUser + +from channels.routing import ProtocolTypeRouter +from channels.testing.websocket import WebsocketCommunicator + + +from awx.main.consumers import WebsocketSecretAuthHelper + + +@pytest.fixture +def application(): + # code in routing hits the db on import because .. settings cache + from awx.main.routing import application_func + + yield application_func(ProtocolTypeRouter) + + +@pytest.fixture +def websocket_server_generator(application): + def fn(endpoint): + return WebsocketCommunicator(application, endpoint) + + return fn + + +@pytest.mark.asyncio +@pytest.mark.django_db +class TestWebsocketRelay: + @pytest.fixture + def websocket_relay_secret_generator(self, settings): + def fn(secret, set_broadcast_websocket_secret=False): + secret_backup = settings.BROADCAST_WEBSOCKET_SECRET + settings.BROADCAST_WEBSOCKET_SECRET = 'foobar' + res = ('secret'.encode('utf-8'), WebsocketSecretAuthHelper.construct_secret().encode('utf-8')) + if set_broadcast_websocket_secret is False: + settings.BROADCAST_WEBSOCKET_SECRET = secret_backup + return res + + return fn + + @pytest.fixture + def websocket_relay_secret(self, settings, websocket_relay_secret_generator): + return websocket_relay_secret_generator('foobar', set_broadcast_websocket_secret=True) + + async def test_authorized(self, websocket_server_generator, websocket_relay_secret): + server = websocket_server_generator('/websocket/relay/') + + server.scope['headers'] = (websocket_relay_secret,) + connected, _ = await server.connect() + assert connected is True + + async def test_not_authorized(self, websocket_server_generator): + server = websocket_server_generator('/websocket/relay/') + connected, _ = await server.connect() + assert connected is False, "Connection to the relay websocket without auth. We expected the client to be denied." + + async def test_wrong_secret(self, websocket_server_generator, websocket_relay_secret_generator): + server = websocket_server_generator('/websocket/relay/') + + server.scope['headers'] = (websocket_relay_secret_generator('foobar', set_broadcast_websocket_secret=False),) + connected, _ = await server.connect() + assert connected is False + + +@pytest.mark.asyncio +@pytest.mark.django_db +class TestWebsocketEventConsumer: + async def test_unauthorized_anonymous(self, websocket_server_generator): + server = websocket_server_generator('/websocket/') + + server.scope['user'] = AnonymousUser() + connected, _ = await server.connect() + assert connected is False, "Anonymous user should NOT be allowed to login." + + @pytest.mark.xfail(reason="Ran out of coding time.") + async def test_authorized(self, websocket_server_generator, application, admin): + server = websocket_server_generator('/websocket/') + + """ + I ran out of time. Here is what I was thinking ... + Inject a valid session into the cookies in the header + + server.scope['headers'] = ( + (b'cookie', ...), + ) + """ + connected, _ = await server.connect() + assert connected is True, "User should be allowed in via cookies auth via a session key in the cookies" diff --git a/awx/main/tests/functional/test_tasks.py b/awx/main/tests/functional/test_tasks.py deleted file mode 100644 index c4d0dac4e362..000000000000 --- a/awx/main/tests/functional/test_tasks.py +++ /dev/null @@ -1,89 +0,0 @@ -import pytest -from unittest import mock -import os -import tempfile -import shutil - -from awx.main.tasks.jobs import RunJob -from awx.main.tasks.system import execution_node_health_check, _cleanup_images_and_files, handle_work_error -from awx.main.models import Instance, Job, InventoryUpdate, ProjectUpdate - - -@pytest.fixture -def scm_revision_file(tmpdir_factory): - # Returns path to temporary testing revision file - revision_file = tmpdir_factory.mktemp('revisions').join('revision.txt') - with open(str(revision_file), 'w') as f: - f.write('1234567890123456789012345678901234567890') - return os.path.join(revision_file.dirname, 'revision.txt') - - -@pytest.mark.django_db -@pytest.mark.parametrize('node_type', ('control. hybrid')) -def test_no_worker_info_on_AWX_nodes(node_type): - hostname = 'us-south-3-compute.invalid' - Instance.objects.create(hostname=hostname, node_type=node_type) - assert execution_node_health_check(hostname) is None - - -@pytest.fixture -def mock_job_folder(request): - pdd_path = tempfile.mkdtemp(prefix='awx_123_') - - def test_folder_cleanup(): - if os.path.exists(pdd_path): - shutil.rmtree(pdd_path) - - request.addfinalizer(test_folder_cleanup) - - return pdd_path - - -@pytest.mark.django_db -def test_folder_cleanup_stale_file(mock_job_folder, mock_me): - _cleanup_images_and_files() - assert os.path.exists(mock_job_folder) # grace period should protect folder from deletion - - _cleanup_images_and_files(grace_period=0) - assert not os.path.exists(mock_job_folder) # should be deleted - - -@pytest.mark.django_db -def test_folder_cleanup_running_job(mock_job_folder, mock_me): - me_inst = Instance.objects.create(hostname='local_node', uuid='00000000-0000-0000-0000-000000000000') - with mock.patch.object(Instance.objects, 'me', return_value=me_inst): - job = Job.objects.create(id=123, controller_node=me_inst.hostname, status='running') - _cleanup_images_and_files(grace_period=0) - assert os.path.exists(mock_job_folder) # running job should prevent folder from getting deleted - - job.status = 'failed' - job.save(update_fields=['status']) - _cleanup_images_and_files(grace_period=0) - assert not os.path.exists(mock_job_folder) # job is finished and no grace period, should delete - - -@pytest.mark.django_db -def test_does_not_run_reaped_job(mocker, mock_me): - job = Job.objects.create(status='failed', job_explanation='This job has been reaped.') - mock_run = mocker.patch('awx.main.tasks.jobs.ansible_runner.interface.run') - try: - RunJob().run(job.id) - except Exception: - pass - job.refresh_from_db() - assert job.status == 'failed' - mock_run.assert_not_called() - - -@pytest.mark.django_db -def test_handle_work_error_nested(project, inventory_source): - pu = ProjectUpdate.objects.create(status='failed', project=project, celery_task_id='1234') - iu = InventoryUpdate.objects.create(status='pending', inventory_source=inventory_source, source='scm') - job = Job.objects.create(status='pending') - iu.dependent_jobs.add(pu) - job.dependent_jobs.add(pu, iu) - handle_work_error({'type': 'project_update', 'id': pu.id}) - iu.refresh_from_db() - job.refresh_from_db() - assert iu.job_explanation == f'Previous Task Failed: {{"job_type": "project_update", "job_name": "", "job_id": "{pu.id}"}}' - assert job.job_explanation == f'Previous Task Failed: {{"job_type": "inventory_update", "job_name": "", "job_id": "{iu.id}"}}' diff --git a/awx/main/tests/functional/test_teams.py b/awx/main/tests/functional/test_teams.py deleted file mode 100644 index eda57579cebd..000000000000 --- a/awx/main/tests/functional/test_teams.py +++ /dev/null @@ -1,14 +0,0 @@ -import pytest - - -@pytest.mark.django_db() -def test_admin_not_member(team): - """Test to ensure we don't add admin_role as a parent to team.member_role, as - this creates a cycle with organization administration, which we've decided - to remove support for - - (2016-06-16) I think this might have been resolved. I'm asserting - this to be true in the mean time. - """ - - assert team.admin_role.is_ancestor_of(team.member_role) is True diff --git a/awx/main/tests/live/pytest.ini b/awx/main/tests/live/pytest.ini new file mode 100644 index 000000000000..cc1e9c5a91de --- /dev/null +++ b/awx/main/tests/live/pytest.ini @@ -0,0 +1,3 @@ +# This file is needed to undo the pytest settings from the project root +[pytest] +addopts = -p no:django -p awx.main.tests.live.pytest_django_config diff --git a/awx/main/tests/live/pytest_django_config.py b/awx/main/tests/live/pytest_django_config.py new file mode 100644 index 000000000000..8c4eac2474b5 --- /dev/null +++ b/awx/main/tests/live/pytest_django_config.py @@ -0,0 +1,12 @@ +import django + +from awx import prepare_env + + +def pytest_load_initial_conftests(args): + """Replacement for same-named method in pytest_django plugin + + Instead of setting up a test database, this just sets up Django normally + this will give access to the postgres database as-is, for better and worse""" + prepare_env() + django.setup() diff --git a/awx/main/tests/live/tests/api/test_uniqueness.py b/awx/main/tests/live/tests/api/test_uniqueness.py new file mode 100644 index 000000000000..e32b9416bfef --- /dev/null +++ b/awx/main/tests/live/tests/api/test_uniqueness.py @@ -0,0 +1,77 @@ +import multiprocessing +import json + +import pytest + +import requests +from requests.auth import HTTPBasicAuth + +from django.db import connection + +from awx.main.models import User, JobTemplate + + +def create_in_subprocess(project_id, ready_event, continue_event, admin_auth): + connection.connect() + + print('setting ready event') + ready_event.set() + print('waiting for continue event') + continue_event.wait() + + if JobTemplate.objects.filter(name='test_jt_duplicate_name').exists(): + for jt in JobTemplate.objects.filter(name='test_jt_duplicate_name'): + jt.delete() + assert JobTemplate.objects.filter(name='test_jt_duplicate_name').count() == 0 + + jt_data = {'name': 'test_jt_duplicate_name', 'project': project_id, 'playbook': 'hello_world.yml', 'ask_inventory_on_launch': True} + response = requests.post('http://localhost:8013/api/v2/job_templates/', json=jt_data, auth=admin_auth) + # should either have a conflict or create + assert response.status_code in (400, 201) + print(f'Subprocess got {response.status_code}') + if response.status_code == 400: + print(json.dumps(response.json(), indent=2)) + return response.status_code + + +@pytest.fixture +def admin_for_test(): + user, created = User.objects.get_or_create(username='admin_for_test', defaults={'is_superuser': True}) + if created: + user.set_password('for_test_123!') + user.save() + print(f'Created user {user.username}') + return user + + +@pytest.fixture +def admin_auth(admin_for_test): + return HTTPBasicAuth(admin_for_test.username, 'for_test_123!') + + +def test_jt_duplicate_name(admin_auth, demo_proj): + N_processes = 5 + ready_events = [multiprocessing.Event() for _ in range(N_processes)] + continue_event = multiprocessing.Event() + + processes = [] + for i in range(N_processes): + p = multiprocessing.Process(target=create_in_subprocess, args=(demo_proj.id, ready_events[i], continue_event, admin_auth)) + processes.append(p) + p.start() + + # Assure both processes are connected and have loaded their host list + for e in ready_events: + print('waiting on subprocess ready event') + e.wait() + + # Begin the bulk_update queries + print('setting the continue event for the workers') + continue_event.set() + + # if a Deadloack happens it will probably be surfaced by result here + print('waiting on the workers to finish the creation') + for p in processes: + p.join() + + assert JobTemplate.objects.filter(name='test_jt_duplicate_name').count() == 1 diff --git a/awx/main/tests/live/tests/conftest.py b/awx/main/tests/live/tests/conftest.py new file mode 100644 index 000000000000..4667dc09f104 --- /dev/null +++ b/awx/main/tests/live/tests/conftest.py @@ -0,0 +1,244 @@ +import subprocess +import time +import os +import shutil +import tempfile +import logging + +import pytest + +from django.conf import settings +from django.core.cache import cache + +from awx.api.versioning import reverse + +# These tests are invoked from the awx/main/tests/live/ subfolder +# so any fixtures from higher-up conftest files must be explicitly included +from awx.main.tests.functional.conftest import * # noqa +from awx.main.tests.conftest import load_all_credentials # noqa: F401; pylint: disable=unused-import +from awx.main.tests import data + +from awx.main.models import Project, JobTemplate, Organization, Inventory, WorkflowJob, UnifiedJob +from awx.main.tasks.system import clear_setting_cache + +logger = logging.getLogger(__name__) + + +PROJ_DATA = os.path.join(os.path.dirname(data.__file__), 'projects') + + +def _copy_folders(source_path, dest_path, clear=False): + "folder-by-folder, copy dirs in the source root dir to the destination root dir" + for dirname in os.listdir(source_path): + source_dir = os.path.join(source_path, dirname) + expected_dir = os.path.join(dest_path, dirname) + if clear and os.path.exists(expected_dir): + shutil.rmtree(expected_dir) + if (not os.path.isdir(source_dir)) or os.path.exists(expected_dir): + continue + shutil.copytree(source_dir, expected_dir) + + +GIT_COMMANDS = ( + 'git config --global init.defaultBranch devel; ' + 'git init; ' + 'git config user.email jenkins@ansible.com; ' + 'git config user.name DoneByTest; ' + 'git add .; ' + 'git commit -m "initial commit"' +) + + +@pytest.fixture(scope='session') +def live_tmp_folder(): + path = os.path.join(tempfile.gettempdir(), 'live_tests') + if os.path.exists(path): + shutil.rmtree(path) + os.mkdir(path) + _copy_folders(PROJ_DATA, path) + for dirname in os.listdir(path): + source_dir = os.path.join(path, dirname) + subprocess.run(GIT_COMMANDS, cwd=source_dir, shell=True) + # force invalidation of key before checking it in case it is stale + cache.delete_many(['AWX_ISOLATION_SHOW_PATHS']) + settings._awx_conf_memoizedcache.clear() + if path not in settings.AWX_ISOLATION_SHOW_PATHS: + logger.info(f'Modifying settings.AWX_ISOLATION_SHOW_PATHS for live test: {settings.AWX_ISOLATION_SHOW_PATHS + [path]}') + settings.AWX_ISOLATION_SHOW_PATHS = settings.AWX_ISOLATION_SHOW_PATHS + [path] + cache.delete_many(['AWX_ISOLATION_SHOW_PATHS']) + settings._awx_conf_memoizedcache.clear() + # cache is cleared in test environment, but need to clear in test environment + clear_setting_cache.delay(['AWX_ISOLATION_SHOW_PATHS']) + time.sleep(5.0) # for _awx_conf_memoizedcache to expire on all workers + else: + logger.info(f'Believed that {path} is already in settings.AWX_ISOLATION_SHOW_PATHS: {settings.AWX_ISOLATION_SHOW_PATHS}') + return path + + +def wait_to_leave_status(job, status, timeout=30, sleep_time=0.1): + """Wait until the job does NOT have the specified status with some timeout + + the default timeout is based on the task manager running a 20 second + schedule, and the API does not guarentee working jobs faster than this + """ + start = time.time() + while time.time() - start < timeout: + job.refresh_from_db() + if job.status != status: + return + time.sleep(sleep_time) + raise RuntimeError(f'Job failed to exit {status} in {timeout} seconds. job_explanation={job.job_explanation} tb={job.result_traceback}') + + +def wait_for_events(uj, timeout=2): + start = time.time() + while uj.event_processing_finished is False: + time.sleep(0.2) + uj.refresh_from_db() + if time.time() - start > timeout: + break + + +def unified_job_stdout(uj): + if type(uj) is UnifiedJob: + uj = uj.get_real_instance() + if isinstance(uj, WorkflowJob): + outputs = [] + for node in uj.workflow_job_nodes.all().select_related('job').order_by('id'): + if node.job is None: + continue + outputs.append( + 'workflow node {node_id} job {job_id} output:\n{output}'.format( + node_id=node.id, + job_id=node.job.id, + output=unified_job_stdout(node.job), + ) + ) + return '\n'.join(outputs) + wait_for_events(uj) + return '\n'.join([event.stdout for event in uj.get_event_queryset().order_by('created')]) + + +def wait_for_job(job, final_status='successful', running_timeout=800): + wait_to_leave_status(job, 'pending') + wait_to_leave_status(job, 'waiting') + wait_to_leave_status(job, 'running', timeout=running_timeout) + + assert job.status == final_status, f'Job was not successful id={job.id} status={job.status} tb={job.result_traceback} output=\n{unified_job_stdout(job)}' + + +@pytest.fixture(scope='session') +def default_org(): + org = Organization.objects.filter(name='Default').first() + if org is None: + raise Exception('Tests expect Default org to already be created and it is not') + return org + + +@pytest.fixture(scope='session') +def demo_inv(default_org): + inventory, _ = Inventory.objects.get_or_create(name='Demo Inventory', defaults={'organization': default_org}) + return inventory + + +@pytest.fixture(scope='session') +def demo_proj(default_org): + proj, _ = Project.objects.get_or_create(name='Demo Project', defaults={'organization': default_org}) + return proj + + +@pytest.fixture +def podman_image_generator(): + """ + Generate a tagless podman image from awx base EE + """ + + def fn(): + dockerfile = """ + FROM quay.io/ansible/awx-ee:latest + RUN echo "Hello, Podman!" > /tmp/hello.txt + """ + cmd = ['podman', 'build', '-f', '-'] # Create an image without a tag + subprocess.run(cmd, capture_output=True, input=dockerfile, text=True, check=True) + + return fn + + +@pytest.fixture +def project_factory(post, default_org, admin): + def _rf(scm_url=None, local_path=None, **extra_kwargs): + proj_kwargs = {} + if local_path: + # manual path + project_name = f'Manual roject {local_path}' + proj_kwargs['scm_type'] = '' + proj_kwargs['local_path'] = local_path + elif scm_url: + project_name = f'Project {scm_url}' + proj_kwargs['scm_type'] = 'git' + proj_kwargs['scm_url'] = scm_url + else: + raise RuntimeError('Need to provide scm_url or local_path') + + if extra_kwargs: + proj_kwargs.update(extra_kwargs) + + proj_kwargs['name'] = project_name + proj_kwargs['organization'] = default_org.id + + old_proj = Project.objects.filter(name=project_name).first() + if old_proj: + logger.info(f'Deleting existing project {project_name}') + old_proj.delete() + + result = post( + reverse('api:project_list'), + proj_kwargs, + admin, + expect=201, + ) + proj = Project.objects.get(id=result.data['id']) + return proj + + return _rf + + +@pytest.fixture +def run_job_from_playbook(demo_inv, post, admin, project_factory): + def _rf(test_name, playbook, local_path=None, scm_url=None, jt_params=None, proj=None, wait=True): + jt_name = f'{test_name} JT: {playbook}' + + if not proj: + proj = project_factory(scm_url=scm_url, local_path=local_path) + + old_jt = JobTemplate.objects.filter(name=jt_name).first() + if old_jt: + logger.info(f'Deleting existing JT {jt_name}') + old_jt.delete() + + if proj.current_job: + wait_for_job(proj.current_job) + + assert proj.get_project_path() + assert playbook in proj.playbooks + + jt_data = {'name': jt_name, 'project': proj.id, 'playbook': playbook, 'inventory': demo_inv.id} + if jt_params: + jt_data.update(jt_params) + + result = post( + reverse('api:job_template_list'), + jt_data, + admin, + expect=201, + ) + jt = JobTemplate.objects.get(id=result.data['id']) + job = jt.create_unified_job() + job.signal_start() + + if wait: + wait_for_job(job) + assert job.status == 'successful' + return {'job': job, 'job_template': jt, 'project': proj} + + return _rf diff --git a/awx/main/tests/live/tests/dispatcherd/test_connection_recovery.py b/awx/main/tests/live/tests/dispatcherd/test_connection_recovery.py new file mode 100644 index 000000000000..183d9ca1d5ac --- /dev/null +++ b/awx/main/tests/live/tests/dispatcherd/test_connection_recovery.py @@ -0,0 +1,74 @@ +import time + +from dispatcherd.config import settings +from dispatcherd.factories import get_control_from_settings +from dispatcherd.utils import serialize_task + +from awx.main.models import JobTemplate + +from awx.main.tests.data.sleep_task import sleep_break_connection, advisory_lock_exception +from awx.main.tests.live.tests.conftest import wait_for_job + + +def poll_for_task_finish(task_name): + running_tasks = [1] + start = time.monotonic() + ctl = get_control_from_settings() + while running_tasks: + responses = ctl.control_with_reply('running') + assert len(responses) == 1 + response = responses[0] + response.pop('node_id') + running_tasks = [task_data for task_data in response.values() if task_data['task'] == task_name] + if time.monotonic() - start > 5.0: + assert False, f'Never finished working through tasks: {running_tasks}' + + +def check_jobs_work(): + jt = JobTemplate.objects.get(name='Demo Job Template') + job = jt.create_unified_job() + job.signal_start() + wait_for_job(job) + + +def test_advisory_lock_error_clears(): + """Run a task that has an exception while holding advisory_lock + + This is regression testing for a bug in its exception handling + expected to be fixed by + https://github.com/ansible/django-ansible-base/pull/713 + + This is an "easier" test case than the next, + because it passes just by fixing the DAB case, + and passing this does not generally guarentee that + workers will not be left with a connection in a bad state. + """ + min_workers = settings.service['pool_kwargs']['min_workers'] + + for i in range(min_workers): + advisory_lock_exception.delay() + + task_name = serialize_task(advisory_lock_exception) + poll_for_task_finish(task_name) + + # Jobs should still work even after the breaking task has ran + check_jobs_work() + + +def test_can_recover_connection(): + """Run a task that intentionally times out the worker connection + + If no connection fixing is implemented outside of that task scope, + then subsequent tasks will all error, thus checking that jobs run, + after running the sleep_break_connection task. + """ + min_workers = settings.service['pool_kwargs']['min_workers'] + + for i in range(min_workers): + sleep_break_connection.delay() + + task_name = serialize_task(sleep_break_connection) + poll_for_task_finish(task_name) + + # Jobs should still work even after the breaking task has ran + check_jobs_work() diff --git a/awx/main/tests/live/tests/projects/conftest.py b/awx/main/tests/live/tests/projects/conftest.py new file mode 100644 index 000000000000..39c8b76fbfad --- /dev/null +++ b/awx/main/tests/live/tests/projects/conftest.py @@ -0,0 +1,14 @@ +import pytest +import os + +from django.conf import settings + +from awx.main.tests.live.tests.conftest import _copy_folders, PROJ_DATA + + +@pytest.fixture(scope='session') +def copy_project_folders(): + proj_root = settings.PROJECTS_ROOT + if not os.path.exists(proj_root): + os.mkdir(proj_root) + _copy_folders(PROJ_DATA, proj_root, clear=True) diff --git a/awx/main/tests/live/tests/projects/test_file_projects.py b/awx/main/tests/live/tests/projects/test_file_projects.py new file mode 100644 index 000000000000..616578b13699 --- /dev/null +++ b/awx/main/tests/live/tests/projects/test_file_projects.py @@ -0,0 +1,25 @@ +import os +import subprocess + +import pytest + +from awx.main.tests.live.tests.conftest import wait_for_job + + +def test_git_file_project(live_tmp_folder, run_job_from_playbook): + run_job_from_playbook('test_git_file_project', 'debug.yml', scm_url=f'file://{live_tmp_folder}/debug') + + +@pytest.mark.parametrize('allow_override', [True, False]) +def test_amend_commit(live_tmp_folder, project_factory, allow_override): + proj = project_factory(scm_url=f'file://{live_tmp_folder}/debug', allow_override=allow_override) + assert proj.current_job + wait_for_job(proj.current_job) + assert proj.allow_override is allow_override + + source_dir = os.path.join(live_tmp_folder, 'debug') + subprocess.run('git commit --amend --no-edit', cwd=source_dir, shell=True) + + update = proj.update() + update.signal_start() + wait_for_job(update) diff --git a/awx/main/tests/live/tests/projects/test_manual_project.py b/awx/main/tests/live/tests/projects/test_manual_project.py new file mode 100644 index 000000000000..11aeb76cf8b3 --- /dev/null +++ b/awx/main/tests/live/tests/projects/test_manual_project.py @@ -0,0 +1,2 @@ +def test_manual_project(copy_project_folders, run_job_from_playbook): + run_job_from_playbook('test_manual_project', 'debug.yml', local_path='debug') diff --git a/awx/main/tests/live/tests/projects/test_requirements.py b/awx/main/tests/live/tests/projects/test_requirements.py new file mode 100644 index 000000000000..c0d392996907 --- /dev/null +++ b/awx/main/tests/live/tests/projects/test_requirements.py @@ -0,0 +1,64 @@ +import os +import time + +import pytest + +from django.conf import settings + +from awx.main.tests.live.tests.conftest import wait_for_job, wait_for_events + +from awx.main.models import Project, SystemJobTemplate, Job + + +@pytest.fixture(scope='session') +def project_with_requirements(default_org): + project, _ = Project.objects.get_or_create( + name='project-with-requirements', + scm_url='https://github.com/ansible/test-playbooks.git', + scm_branch="with_requirements", + scm_type='git', + organization=default_org, + ) + start = time.time() + while time.time() - start < 3.0: + if project.current_job or project.last_job or project.last_job_run: + break + assert project.current_job or project.last_job or project.last_job_run, f'Project never updated id={project.id}' + update = project.current_job or project.last_job + if update: + wait_for_job(update) + return project + + +def project_cache_is_populated(project): + proj_cache = os.path.join(project.get_cache_path(), project.cache_id) + return os.path.exists(proj_cache) + + +def test_cache_is_populated_after_cleanup_job(project_with_requirements): + assert project_with_requirements.cache_id is not None # already updated, should be something + cache_path = os.path.join(settings.PROJECTS_ROOT, '.__awx_cache') + assert os.path.exists(cache_path) + + assert project_cache_is_populated(project_with_requirements) + + cleanup_sjt = SystemJobTemplate.objects.get(name='Cleanup Job Details') + cleanup_job = cleanup_sjt.create_unified_job(extra_vars={'days': 0}) + cleanup_job.signal_start() + wait_for_job(cleanup_job) + + project_with_requirements.refresh_from_db() + assert project_with_requirements.cache_id is not None + update = project_with_requirements.update() + wait_for_job(update) + + # Now, we still have a populated cache + assert project_cache_is_populated(project_with_requirements) + + +def test_git_file_collection_requirement(live_tmp_folder, copy_project_folders, run_job_from_playbook): + # this behaves differently, as use_requirements.yml references only the folder, does not include the github name + run_job_from_playbook('test_git_file_collection_requirement', 'use_requirement.yml', scm_url=f'file://{live_tmp_folder}/with_requirements') + job = Job.objects.filter(name__icontains='test_git_file_collection_requirement').order_by('-created').first() + wait_for_events(job) + assert '1234567890' in job.job_events.filter(task='debug variable', event='runner_on_ok').first().stdout diff --git a/awx/main/tests/live/tests/test_ansible_facts.py b/awx/main/tests/live/tests/test_ansible_facts.py new file mode 100644 index 000000000000..f6db48345e79 --- /dev/null +++ b/awx/main/tests/live/tests/test_ansible_facts.py @@ -0,0 +1,64 @@ +import pytest + +from awx.main.tests.live.tests.conftest import wait_for_events + +from awx.main.models import Job, Inventory + + +def assert_facts_populated(name): + job = Job.objects.filter(name__icontains=name).order_by('-created').first() + assert job is not None + wait_for_events(job) + + inventory = job.inventory + assert inventory.hosts.count() > 0 # sanity + for host in inventory.hosts.all(): + assert host.ansible_facts + + +@pytest.fixture +def general_facts_test(live_tmp_folder, run_job_from_playbook): + def _rf(slug, jt_params): + jt_params['use_fact_cache'] = True + standard_kwargs = dict(scm_url=f'file://{live_tmp_folder}/facts', jt_params=jt_params) + + # GATHER FACTS + name = f'test_gather_ansible_facts_{slug}' + run_job_from_playbook(name, 'gather.yml', **standard_kwargs) + assert_facts_populated(name) + + # KEEP FACTS + name = f'test_clear_ansible_facts_{slug}' + run_job_from_playbook(name, 'no_op.yml', **standard_kwargs) + assert_facts_populated(name) + + # CLEAR FACTS + name = f'test_clear_ansible_facts_{slug}' + run_job_from_playbook(name, 'clear.yml', **standard_kwargs) + job = Job.objects.filter(name__icontains=name).order_by('-created').first() + + assert job is not None + wait_for_events(job) + inventory = job.inventory + assert inventory.hosts.count() > 0 # sanity + for host in inventory.hosts.all(): + assert not host.ansible_facts + + return _rf + + +def test_basic_ansible_facts(general_facts_test): + general_facts_test('basic', {}) + + +@pytest.fixture +def sliced_inventory(): + inv, _ = Inventory.objects.get_or_create(name='inventory-to-slice') + if not inv.hosts.exists(): + for i in range(10): + inv.hosts.create(name=f'sliced_host_{i}') + return inv + + +def test_slicing_with_facts(general_facts_test, sliced_inventory): + general_facts_test('sliced', {'job_slice_count': 3, 'inventory': sliced_inventory.id}) diff --git a/awx/main/tests/live/tests/test_cleanup_task.py b/awx/main/tests/live/tests/test_cleanup_task.py new file mode 100644 index 000000000000..e9af90b96196 --- /dev/null +++ b/awx/main/tests/live/tests/test_cleanup_task.py @@ -0,0 +1,82 @@ +import os +import json +import pytest +import tempfile +import subprocess + +from unittest import mock + +from awx.main.tasks.receptor import _convert_args_to_cli, run_until_complete +from awx.main.tasks.system import CleanupImagesAndFiles +from awx.main.models import Instance, JobTemplate + + +def get_podman_images(): + cmd = ['podman', 'images', '--format', 'json'] + return json.loads((subprocess.run(cmd, capture_output=True, text=True, check=True)).stdout) + + +def test_folder_cleanup_multiple_running_jobs_execution_node(request): + demo_jt = JobTemplate.objects.get(name='Demo Job Template') + + jobs = [demo_jt.create_unified_job(_eager_fields={'status': 'running'}) for i in range(3)] + + def delete_jobs(): + for job in jobs: + job.delete() + + request.addfinalizer(delete_jobs) + + job_dirs = [] + job_patterns = [] + for job in jobs: + job_pattern = f'awx_{job.id}_1234' + job_dir = os.path.join(tempfile.gettempdir(), job_pattern) + job_patterns.append(job_pattern) + job_dirs.append(job_dir) + os.mkdir(job_dir) + + inst = Instance.objects.me() + runner_cleanup_kwargs = inst.get_cleanup_task_kwargs(exclude_strings=job_patterns, grace_period=0) + + # We can not call worker_cleanup directly because execution and control nodes are not fungible + args = _convert_args_to_cli(runner_cleanup_kwargs) + remote_command = ' '.join(args) + + subprocess.call('ansible-runner worker ' + remote_command, shell=True) + print('ansible-runner worker ' + remote_command) + + assert [os.path.exists(job_dir) for job_dir in job_dirs] == [True for i in range(3)] + + +@pytest.mark.parametrize( + 'worktype', + ('remote', 'local'), +) +def test_tagless_image(podman_image_generator, worktype: str): + """ + Ensure podman images on Control and Hybrid nodes are deleted during cleanup. + """ + podman_image_generator() + + dangling_image = next((image for image in get_podman_images() if image.get('Dangling', False)), None) + assert dangling_image + + instance_me = Instance.objects.me() + + match worktype: + case 'local': + CleanupImagesAndFiles.run_local(instance_me, image_prune=True) + case 'remote': + with ( + mock.patch( + 'awx.main.tasks.receptor.run_until_complete', lambda *args, **kwargs: run_until_complete(*args, worktype='local', ttl=None, **kwargs) + ), + mock.patch('awx.main.tasks.system.CleanupImagesAndFiles.get_execution_instances', lambda: [Instance.objects.me()]), + ): + CleanupImagesAndFiles.run_remote(instance_me, image_prune=True) + case _: + raise ValueError(f'worktype "{worktype}" not supported.') + + for image in get_podman_images(): + assert image['Id'] != dangling_image['Id'] diff --git a/awx/main/tests/live/tests/test_demo_data.py b/awx/main/tests/live/tests/test_demo_data.py new file mode 100644 index 000000000000..fa9ee5eb978c --- /dev/null +++ b/awx/main/tests/live/tests/test_demo_data.py @@ -0,0 +1,15 @@ +from awx.api.versioning import reverse + +from awx.main.models import JobTemplate, Job + +from awx.main.tests.live.tests.conftest import wait_for_job + + +def test_launch_demo_jt(post, admin): + jt = JobTemplate.objects.get(name='Demo Job Template') + + url = reverse('api:job_template_launch', kwargs={'pk': jt.id}) + + r = post(url=url, data={}, user=admin, expect=201) + job = Job.objects.get(pk=r.data['id']) + wait_for_job(job) diff --git a/awx/main/tests/live/tests/test_devel_image.py b/awx/main/tests/live/tests/test_devel_image.py new file mode 100644 index 000000000000..a77039247cc3 --- /dev/null +++ b/awx/main/tests/live/tests/test_devel_image.py @@ -0,0 +1,10 @@ +import os + +RSYSLOG_CONFIG = '/var/lib/awx/rsyslog/rsyslog.conf' + + +def test_rsyslog_config_readable(): + with open(RSYSLOG_CONFIG, 'r') as f: + content = f.read() + assert '/var/lib/awx/rsyslog' in content + assert oct(os.stat(RSYSLOG_CONFIG).st_mode) == '0o100640' diff --git a/awx/main/tests/live/tests/test_host_update_contention.py b/awx/main/tests/live/tests/test_host_update_contention.py new file mode 100644 index 000000000000..d822fc27c11c --- /dev/null +++ b/awx/main/tests/live/tests/test_host_update_contention.py @@ -0,0 +1,78 @@ +import multiprocessing +import random + +from django.db import connection +from django.utils.timezone import now + +from awx.main.models import Inventory, Host +from awx.main.utils.db import bulk_update_sorted_by_id + + +def worker_delete_target(ready_event, continue_event, field_name): + """Runs the bulk update, will be called in duplicate, in parallel""" + inv = Inventory.objects.get(organization__name='Default', name='test_host_update_contention') + host_list = list(inv.hosts.all()) + # Using random.shuffle for non-security-critical shuffling in a test + random.shuffle(host_list) # NOSONAR + for i, host in enumerate(host_list): + setattr(host, field_name, f'my_var: {i}') + + # ready to do the bulk_update + print('worker has loaded all the hosts needed') + ready_event.set() + # wait for the coordination message + continue_event.wait() + + # NOTE: did not reproduce the bug without batch_size + bulk_update_sorted_by_id(Host, host_list, fields=[field_name], batch_size=100) + print('finished doing the bulk update in worker') + + +def test_host_update_contention(default_org): + inv_kwargs = dict(organization=default_org, name='test_host_update_contention') + + if Inventory.objects.filter(**inv_kwargs).exists(): + inv = Inventory.objects.get(**inv_kwargs).delete() + + inv = Inventory.objects.create(**inv_kwargs) + right_now = now() + hosts = [Host(inventory=inv, name=f'host-{i}', created=right_now, modified=right_now) for i in range(1000)] + print('bulk creating hosts') + Host.objects.bulk_create(hosts) + + # sanity check + for host in hosts: + assert not host.variables + + # Force our worker pool to make their own connection + connection.close() + + ready_events = [multiprocessing.Event() for _ in range(2)] + continue_event = multiprocessing.Event() + + print('spawning processes for concurrent bulk updates') + processes = [] + fields = ['variables', 'ansible_facts'] + for i in range(2): + p = multiprocessing.Process(target=worker_delete_target, args=(ready_events[i], continue_event, fields[i])) + processes.append(p) + p.start() + + # Assure both processes are connected and have loaded their host list + for e in ready_events: + print('waiting on subprocess ready event') + e.wait() + + # Begin the bulk_update queries + print('setting the continue event for the workers') + continue_event.set() + + # if a Deadloack happens it will probably be surfaced by result here + print('waiting on the workers to finish the bulk_update') + for p in processes: + p.join() + + print('checking workers have variables set') + for host in inv.hosts.all(): + assert host.variables.startswith('my_var:') + assert host.ansible_facts.startswith('my_var:') diff --git a/awx/main/tests/live/tests/test_indirect_host_counting.py b/awx/main/tests/live/tests/test_indirect_host_counting.py new file mode 100644 index 000000000000..2843eaeba535 --- /dev/null +++ b/awx/main/tests/live/tests/test_indirect_host_counting.py @@ -0,0 +1,66 @@ +import yaml +import time + +from awx.main.tests.live.tests.conftest import wait_for_events +from awx.main.tasks.host_indirect import build_indirect_host_data, save_indirect_host_entries +from awx.main.models.indirect_managed_node_audit import IndirectManagedNodeAudit +from awx.main.models import Job + + +def test_indirect_host_counting(live_tmp_folder, run_job_from_playbook): + run_job_from_playbook('test_indirect_host_counting', 'run_task.yml', scm_url=f'file://{live_tmp_folder}/test_host_query') + job = Job.objects.filter(name__icontains='test_indirect_host_counting').order_by('-created').first() + wait_for_events(job) # We must wait for events because system tasks iterate on job.job_events.filter(...) + + # Data matches to awx/main/tests/data/projects/host_query/extensions/audit/event_query.yml + # this just does things in-line to be a more localized test for the immediate testing + module_jq_str = '{name: .name, canonical_facts: {host_name: .direct_host_name}, facts: {device_type: .device_type}}' + event_query = {'demo.query.example': {'query': module_jq_str}} + + # Run the task logic directly with local data + results = build_indirect_host_data(job, event_query) + assert len(results) == 1 + host_audit_entry = results[0] + + canonical_facts = {'host_name': 'foo_host_default'} + facts = {'device_type': 'Fake Host'} + + # Asserts on data that will match to the input jq string from above + assert host_audit_entry.canonical_facts == canonical_facts + assert host_audit_entry.facts == facts + + # Test collection of data + assert 'demo.query' in job.installed_collections + assert 'host_query' in job.installed_collections['demo.query'] + hq_text = job.installed_collections['demo.query']['host_query'] + hq_data = yaml.safe_load(hq_text) + assert hq_data == {'demo.query.example': {'query': module_jq_str}} + + assert job.ansible_version + + # Poll for events finishing processing, because background task requires this + for _ in range(10): + if job.job_events.count() >= job.emitted_events: + break + time.sleep(0.2) + else: + raise RuntimeError(f'job id={job.id} never processed events') + + # Task might not run due to race condition, so make it run here + job.refresh_from_db() + if job.event_queries_processed is False: + save_indirect_host_entries.delay(job.id, wait_for_events=False) + + # event_queries_processed only assures the task has started, it might take a minor amount of time to finish + for _ in range(10): + if IndirectManagedNodeAudit.objects.filter(job=job).exists(): + break + time.sleep(0.2) + else: + raise RuntimeError(f'No IndirectManagedNodeAudit records ever populated for job_id={job.id}') + + assert IndirectManagedNodeAudit.objects.filter(job=job).count() == 1 + host_audit = IndirectManagedNodeAudit.objects.filter(job=job).first() + assert host_audit.canonical_facts == canonical_facts + assert host_audit.facts == facts + assert host_audit.organization == job.organization diff --git a/awx/main/tests/live/tests/test_inventory_vars.py b/awx/main/tests/live/tests/test_inventory_vars.py new file mode 100644 index 000000000000..611a8fffd92d --- /dev/null +++ b/awx/main/tests/live/tests/test_inventory_vars.py @@ -0,0 +1,223 @@ +import subprocess +import time +import os.path +from urllib.parse import urlsplit + +import pytest +from unittest import mock + +from awx.main.models.projects import Project +from awx.main.models.organization import Organization +from awx.main.models.inventory import Inventory, InventorySource +from awx.main.tests.live.tests.conftest import wait_for_job + +NAME_PREFIX = "test-ivu" +GIT_REPO_FOLDER = "inventory_vars" + + +def create_new_by_name(model, **kwargs): + """ + Create a new model instance. Delete an existing instance first. + + :param model: The Django model. + :param dict kwargs: The keyword arguments required to create a model + instance. Must contain at least `name`. + :return: The model instance. + """ + name = kwargs["name"] + try: + instance = model.objects.get(name=name) + except model.DoesNotExist: + pass + else: + print(f"FORCE DELETE {name}") + instance.delete() + finally: + instance = model.objects.create(**kwargs) + return instance + + +def wait_for_update(instance, timeout=3.0): + """Wait until the last update of *instance* is finished.""" + start = time.time() + while time.time() - start < timeout: + if instance.current_job or instance.last_job or instance.last_job_run: + break + time.sleep(0.2) + assert instance.current_job or instance.last_job or instance.last_job_run, f'Instance never updated id={instance.id}' + update = instance.current_job or instance.last_job + if update: + wait_for_job(update) + + +def change_source_vars_and_update(invsrc, group_vars): + """ + Change the variables content of an inventory source and update its + inventory. + + Does not return before the inventory update is finished. + + :param invsrc: The inventory source instance. + :param dict group_vars: The variables for various groups. Format:: + + { + : {: , : , ..}, : + {: , : , ..}, .. + } + + :return: None + """ + project = invsrc.source_project + repo_path = urlsplit(project.scm_url).path + filepath = os.path.join(repo_path, invsrc.source_path) + # print(f"change_source_vars_and_update: {project=} {repo_path=} {filepath=}") + with open(filepath, "w") as fp: + for group, variables in group_vars.items(): + fp.write(f"[{group}:vars]\n") + for name, value in variables.items(): + fp.write(f"{name}={value}\n") + subprocess.run('git add .; git commit -m "Update variables in invsrc.source_path"', cwd=repo_path, shell=True) + # Update the project to sync the changed repo contents. + project.update() + wait_for_update(project) + # Update the inventory from the changed source. + invsrc.update() + wait_for_update(invsrc) + + +@pytest.fixture +def organization(): + name = f"{NAME_PREFIX}-org" + instance = create_new_by_name(Organization, name=name, description=f"Description for {name}") + yield instance + instance.delete() + + +@pytest.fixture +def project(organization, live_tmp_folder): + name = f"{NAME_PREFIX}-project" + instance = create_new_by_name( + Project, + name=name, + description=f"Description for {name}", + organization=organization, + scm_url=f"file://{live_tmp_folder}/{GIT_REPO_FOLDER}", + scm_type="git", + ) + yield instance + instance.delete() + + +@pytest.fixture +def inventory(organization): + name = f"{NAME_PREFIX}-inventory" + instance = create_new_by_name( + Inventory, + name=name, + description=f"Description for {name}", + organization=organization, + ) + yield instance + instance.delete() + + +@pytest.fixture +def inventory_source(inventory, project): + name = f"{NAME_PREFIX}-invsrc" + inv_src = InventorySource( + name=name, + source_project=project, + source="scm", + source_path="inventory_var_deleted_in_source.ini", + inventory=inventory, + overwrite_vars=True, + ) + with mock.patch('awx.main.models.unified_jobs.UnifiedJobTemplate.update'): + inv_src.save() + yield inv_src + inv_src.delete() + + +@pytest.fixture +def inventory_source_factory(inventory, project): + """ + Use this fixture if you want to use multiple inventory sources for the same + inventory in your test. + """ + # https://docs.pytest.org/en/stable/how-to/fixtures.html#factories-as-fixtures + + created = [] + # repo_path = f"{live_tmp_folder}/{GIT_REPO_FOLDER}" + + def _factory(inventory_file, name): + # Make sure the inventory file exists before the inventory source + # instance is created. + # + # Note: The current implementation of the inventory source object allows + # to create an instance even when the inventory source file does not + # exist. If this behaviour changes, uncomment the following code block + # and add the fixture `live_tmp_folder` to the factory function + # signature. + # + # inventory_file_path = os.path.join(repo_path, inventory_file) if not + # os.path.isfile(inventory_file_path): with open(inventory_file_path, + # "w") as fp: pass subprocess.run(f'git add .; git commit -m "Create + # {inventory_file_path}"', cwd=repo_path, shell=True) + # + # Create the inventory source instance. + name = f"{NAME_PREFIX}-invsrc-{name}" + inv_src = InventorySource( + name=name, + source_project=project, + source="scm", + source_path=inventory_file, + inventory=inventory, + overwrite_vars=True, + ) + with mock.patch('awx.main.models.unified_jobs.UnifiedJobTemplate.update'): + inv_src.save() + return inv_src + + yield _factory + for instance in created: + instance.delete() + + +def test_inventory_var_deleted_in_source(inventory, inventory_source): + """ + Verify that a variable which is deleted from its (git-)source between two + updates is also deleted from the inventory. + + Verifies https://issues.redhat.com/browse/AAP-17690 + """ + inventory_source.update() + wait_for_update(inventory_source) + assert {"a": "value_a", "b": "value_b"} == Inventory.objects.get(name=inventory.name).variables_dict + # Remove variable `a` from source and verify that it is also removed from + # the inventory variables. + change_source_vars_and_update(inventory_source, {"all": {"b": "value_b"}}) + assert {"b": "value_b"} == Inventory.objects.get(name=inventory.name).variables_dict + + +def test_inventory_vars_with_multiple_sources(inventory, inventory_source_factory): + """ + Verify a sequence of updates from various sources with changing content. + """ + invsrc_a = inventory_source_factory("invsrc_a.ini", "A") + invsrc_b = inventory_source_factory("invsrc_b.ini", "B") + invsrc_c = inventory_source_factory("invsrc_c.ini", "C") + + change_source_vars_and_update(invsrc_a, {"all": {"x": "x_from_a", "y": "y_from_a"}}) + assert {"x": "x_from_a", "y": "y_from_a"} == Inventory.objects.get(name=inventory.name).variables_dict + change_source_vars_and_update(invsrc_b, {"all": {"x": "x_from_b", "y": "y_from_b", "z": "z_from_b"}}) + assert {"x": "x_from_b", "y": "y_from_b", "z": "z_from_b"} == Inventory.objects.get(name=inventory.name).variables_dict + change_source_vars_and_update(invsrc_c, {"all": {"x": "x_from_c", "z": "z_from_c"}}) + assert {"x": "x_from_c", "y": "y_from_b", "z": "z_from_c"} == Inventory.objects.get(name=inventory.name).variables_dict + change_source_vars_and_update(invsrc_b, {"all": {}}) + assert {"x": "x_from_c", "y": "y_from_a", "z": "z_from_c"} == Inventory.objects.get(name=inventory.name).variables_dict + change_source_vars_and_update(invsrc_c, {"all": {"z": "z_from_c"}}) + assert {"x": "x_from_a", "y": "y_from_a", "z": "z_from_c"} == Inventory.objects.get(name=inventory.name).variables_dict + change_source_vars_and_update(invsrc_a, {"all": {}}) + assert {"z": "z_from_c"} == Inventory.objects.get(name=inventory.name).variables_dict + change_source_vars_and_update(invsrc_c, {"all": {}}) + assert {} == Inventory.objects.get(name=inventory.name).variables_dict diff --git a/awx/main/tests/live/tests/test_job_cancel.py b/awx/main/tests/live/tests/test_job_cancel.py new file mode 100644 index 000000000000..6a88d4b9a8e1 --- /dev/null +++ b/awx/main/tests/live/tests/test_job_cancel.py @@ -0,0 +1,40 @@ +import time + +from awx.api.versioning import reverse +from awx.main.models import Job + +from awx.main.tests.live.tests.conftest import wait_for_events + + +def test_cancel_and_delete_job(live_tmp_folder, run_job_from_playbook, post, delete, admin): + res = run_job_from_playbook('test_cancel_and_delete_job', 'sleep.yml', scm_url=f'file://{live_tmp_folder}/debug', wait=False) + job = res['job'] + assert job.status == 'pending' + + # Wait for first event so that we can be sure the job is in-progress first + start = time.time() + timeout = 10.0 + while not job.job_events.exists(): + time.sleep(0.2) + if time.time() - start > timeout: + assert False, f'Did not receive first event for job_id={job.id} in {timeout} seconds' + + # Now cancel the job + url = reverse("api:job_cancel", kwargs={'pk': job.pk}) + post(url, user=admin, expect=202) + + # Job status should change to expected status before infinity + start = time.time() + timeout = 5.0 + job.refresh_from_db() + while job.status != 'canceled': + time.sleep(0.05) + job.refresh_from_db(fields=['status']) + if time.time() - start > timeout: + assert False, f'job_id={job.id} still status={job.status} after {timeout} seconds' + + wait_for_events(job) + url = reverse("api:job_detail", kwargs={'pk': job.pk}) + delete(url, user=admin, expect=204) + + assert not Job.objects.filter(id=job.id).exists() diff --git a/awx/main/tests/live/tests/test_partitions.py b/awx/main/tests/live/tests/test_partitions.py new file mode 100644 index 000000000000..f395eda8e13e --- /dev/null +++ b/awx/main/tests/live/tests/test_partitions.py @@ -0,0 +1,23 @@ +from datetime import timedelta + +from django.utils.timezone import now +from django.db import connection + +from awx.main.utils.common import create_partition, table_exists + + +def test_table_when_it_exists(): + with connection.cursor() as cursor: + assert table_exists(cursor, 'main_job') + + +def test_table_when_it_does_not_exists(): + with connection.cursor() as cursor: + assert not table_exists(cursor, 'main_not_a_table_check') + + +def test_create_partition_race_condition(mocker): + mocker.patch('awx.main.utils.common.table_exists', return_value=False) + + create_partition('main_jobevent', start=now() - timedelta(days=2)) + create_partition('main_jobevent', start=now() - timedelta(days=2)) diff --git a/awx/main/tests/settings_for_test.py b/awx/main/tests/settings_for_test.py new file mode 100644 index 000000000000..5634494c3373 --- /dev/null +++ b/awx/main/tests/settings_for_test.py @@ -0,0 +1,23 @@ +# Python +import uuid + +# Load development settings for base variables. +from awx.settings.development import * # NOQA + +# Some things make decisions based on settings.SETTINGS_MODULE, so this is done for that +SETTINGS_MODULE = 'awx.settings.development' + +# Use SQLite for unit tests instead of PostgreSQL. If the lines below are +# commented out, Django will create the test_awx-dev database in PostgreSQL to +# run unit tests. +CACHES = {'default': {'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 'LOCATION': 'unique-{}'.format(str(uuid.uuid4()))}} +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'awx.sqlite3'), # noqa + 'TEST': { + # Test database cannot be :memory: for inventory tests. + 'NAME': os.path.join(BASE_DIR, 'awx_test.sqlite3') # noqa + }, + } +} diff --git a/awx/main/tests/unit/analytics/test_broadcast_websocket.py b/awx/main/tests/unit/analytics/test_broadcast_websocket.py index cd7f4323b5cc..9aa24e772b2a 100644 --- a/awx/main/tests/unit/analytics/test_broadcast_websocket.py +++ b/awx/main/tests/unit/analytics/test_broadcast_websocket.py @@ -1,6 +1,7 @@ import datetime +from unittest.mock import Mock, patch -from awx.main.analytics.broadcast_websocket import FixedSlidingWindow +from awx.main.analytics.broadcast_websocket import FixedSlidingWindow, RelayWebsocketStatsManager from awx.main.analytics.broadcast_websocket import dt_to_seconds @@ -59,3 +60,70 @@ def test_record_same_minute_render_diff_minute(self): assert 20 - i == fsw.render(self.ts(minute=1, second=i, microsecond=0)), "E. Sliding window where 1 record() should drop from the results each time" assert 0 == fsw.render(self.ts(minute=1, second=20, microsecond=0)), "F. First second one minute after all record() calls" + + +class TestRelayWebsocketStatsManager: + """Test Redis client caching in RelayWebsocketStatsManager.""" + + def test_get_stats_sync_caches_redis_client(self): + """Verify get_stats_sync caches Redis client to avoid creating new connection pools.""" + # Reset class variable + RelayWebsocketStatsManager._redis_client = None + + mock_redis = Mock() + mock_redis.get.return_value = b'' + + with patch('awx.main.analytics.broadcast_websocket.get_redis_client', return_value=mock_redis) as mock_get_client: + # First call should create client + RelayWebsocketStatsManager.get_stats_sync() + assert mock_get_client.call_count == 1 + + # Second call should reuse cached client + RelayWebsocketStatsManager.get_stats_sync() + assert mock_get_client.call_count == 1 # Still 1, not called again + + # Third call should still reuse cached client + RelayWebsocketStatsManager.get_stats_sync() + assert mock_get_client.call_count == 1 + + # Cleanup + RelayWebsocketStatsManager._redis_client = None + + def test_get_stats_sync_returns_parsed_metrics(self): + """Verify get_stats_sync returns parsed metric families from Redis.""" + # Reset class variable + RelayWebsocketStatsManager._redis_client = None + + # Sample Prometheus metrics format + sample_metrics = b'# HELP test_metric A test metric\n# TYPE test_metric gauge\ntest_metric 42\n' + + mock_redis = Mock() + mock_redis.get.return_value = sample_metrics + + with patch('awx.main.analytics.broadcast_websocket.get_redis_client', return_value=mock_redis): + result = list(RelayWebsocketStatsManager.get_stats_sync()) + + # Should return parsed metric families + assert len(result) > 0 + assert mock_redis.get.called + + # Cleanup + RelayWebsocketStatsManager._redis_client = None + + def test_get_stats_sync_handles_empty_redis_data(self): + """Verify get_stats_sync handles empty data from Redis gracefully.""" + # Reset class variable + RelayWebsocketStatsManager._redis_client = None + + mock_redis = Mock() + mock_redis.get.return_value = None # Redis returns None when key doesn't exist + + with patch('awx.main.analytics.broadcast_websocket.get_redis_client', return_value=mock_redis): + result = list(RelayWebsocketStatsManager.get_stats_sync()) + + # Should handle empty data gracefully + assert result == [] + assert mock_redis.get.called + + # Cleanup + RelayWebsocketStatsManager._redis_client = None diff --git a/awx/main/tests/unit/api/serializers/test_job_template_serializers.py b/awx/main/tests/unit/api/serializers/test_job_template_serializers.py index 51e64fd753a1..0a9e31b91cbd 100644 --- a/awx/main/tests/unit/api/serializers/test_job_template_serializers.py +++ b/awx/main/tests/unit/api/serializers/test_job_template_serializers.py @@ -76,15 +76,15 @@ def test_callback_absent(self, get_related_mock_and_run, job_template): class TestJobTemplateSerializerGetSummaryFields: def test_survey_spec_exists(self, test_get_summary_fields, mocker, job_template): job_template.survey_spec = {'name': 'blah', 'description': 'blah blah'} - with mocker.patch.object(JobTemplateSerializer, '_recent_jobs') as mock_rj: - mock_rj.return_value = [] - test_get_summary_fields(JobTemplateSerializer, job_template, 'survey') + mock_rj = mocker.patch.object(JobTemplateSerializer, '_recent_jobs') + mock_rj.return_value = [] + test_get_summary_fields(JobTemplateSerializer, job_template, 'survey') def test_survey_spec_absent(self, get_summary_fields_mock_and_run, mocker, job_template): job_template.survey_spec = None - with mocker.patch.object(JobTemplateSerializer, '_recent_jobs') as mock_rj: - mock_rj.return_value = [] - summary = get_summary_fields_mock_and_run(JobTemplateSerializer, job_template) + mock_rj = mocker.patch.object(JobTemplateSerializer, '_recent_jobs') + mock_rj.return_value = [] + summary = get_summary_fields_mock_and_run(JobTemplateSerializer, job_template) assert 'survey' not in summary def test_copy_edit_standard(self, mocker, job_template_factory): @@ -107,10 +107,10 @@ def test_copy_edit_standard(self, mocker, job_template_factory): view.kwargs = {} serializer.context['view'] = view - with mocker.patch("awx.api.serializers.role_summary_fields_generator", return_value='Can eat pie'): - with mocker.patch("awx.main.access.JobTemplateAccess.can_change", return_value='foobar'): - with mocker.patch("awx.main.access.JobTemplateAccess.can_copy", return_value='foo'): - response = serializer.get_summary_fields(jt_obj) + mocker.patch("awx.api.serializers.role_summary_fields_generator", return_value='Can eat pie') + mocker.patch("awx.main.access.JobTemplateAccess.can_change", return_value='foobar') + mocker.patch("awx.main.access.JobTemplateAccess.can_copy", return_value='foo') + response = serializer.get_summary_fields(jt_obj) assert response['user_capabilities']['copy'] == 'foo' assert response['user_capabilities']['edit'] == 'foobar' diff --git a/awx/main/tests/unit/api/serializers/test_token_serializer.py b/awx/main/tests/unit/api/serializers/test_token_serializer.py deleted file mode 100644 index aa6363d47a10..000000000000 --- a/awx/main/tests/unit/api/serializers/test_token_serializer.py +++ /dev/null @@ -1,8 +0,0 @@ -import pytest - -from awx.api.serializers import OAuth2TokenSerializer - - -@pytest.mark.parametrize('scope, expect', [('', False), ('read', True), ('read read', False), ('write read', True), ('read rainbow', False)]) -def test_invalid_scopes(scope, expect): - assert OAuth2TokenSerializer()._is_valid_scope(scope) is expect diff --git a/awx/main/tests/unit/api/serializers/test_unified_serializers.py b/awx/main/tests/unit/api/serializers/test_unified_serializers.py index 36558f92cb4f..47451d849a03 100644 --- a/awx/main/tests/unit/api/serializers/test_unified_serializers.py +++ b/awx/main/tests/unit/api/serializers/test_unified_serializers.py @@ -39,7 +39,7 @@ def test_unified_job_detail_exclusive_fields(): For each type, assert that the only fields allowed to be exclusive to detail view are the allowed types """ - allowed_detail_fields = frozenset(('result_traceback', 'job_args', 'job_cwd', 'job_env', 'event_processing_finished')) + allowed_detail_fields = frozenset(('result_traceback', 'job_args', 'job_cwd', 'job_env', 'event_processing_finished', 'artifacts')) for cls in UnifiedJob.__subclasses__(): list_serializer = getattr(serializers, '{}ListSerializer'.format(cls.__name__)) detail_serializer = getattr(serializers, '{}Serializer'.format(cls.__name__)) diff --git a/awx/main/tests/unit/api/serializers/test_workflow_serializers.py b/awx/main/tests/unit/api/serializers/test_workflow_serializers.py index 9e7fe51344e0..218395dc6c62 100644 --- a/awx/main/tests/unit/api/serializers/test_workflow_serializers.py +++ b/awx/main/tests/unit/api/serializers/test_workflow_serializers.py @@ -189,8 +189,8 @@ def test_use_db_answer(self, jt, mocker): serializer = WorkflowJobTemplateNodeSerializer() wfjt = WorkflowJobTemplate.objects.create(name='fake-wfjt') serializer.instance = WorkflowJobTemplateNode(workflow_job_template=wfjt, unified_job_template=jt, extra_data={'var1': '$encrypted$foooooo'}) - with mocker.patch('awx.main.models.mixins.decrypt_value', return_value='foo'): - attrs = serializer.validate({'unified_job_template': jt, 'workflow_job_template': wfjt, 'extra_data': {'var1': '$encrypted$'}}) + mocker.patch('awx.main.models.mixins.decrypt_value', return_value='foo') + attrs = serializer.validate({'unified_job_template': jt, 'workflow_job_template': wfjt, 'extra_data': {'var1': '$encrypted$'}}) assert 'survey_passwords' in attrs assert 'var1' in attrs['survey_passwords'] assert attrs['extra_data']['var1'] == '$encrypted$foooooo' diff --git a/awx/main/tests/unit/api/test_fields.py b/awx/main/tests/unit/api/test_fields.py new file mode 100644 index 000000000000..d6b6ae49d266 --- /dev/null +++ b/awx/main/tests/unit/api/test_fields.py @@ -0,0 +1,49 @@ +import pytest +from collections import OrderedDict +from unittest import mock + +from rest_framework.exceptions import ValidationError + +from awx.api.fields import DeprecatedCredentialField + + +class TestDeprecatedCredentialField: + """Test that DeprecatedCredentialField handles unexpected input types gracefully.""" + + def test_dict_value_raises_validation_error(self): + """Passing a dict instead of an integer should return a 400 validation error, not a 500 TypeError.""" + field = DeprecatedCredentialField() + with pytest.raises(ValidationError): + field.to_internal_value({"username": "admin", "password": "secret"}) + + def test_ordered_dict_value_raises_validation_error(self): + """Passing an OrderedDict should return a 400 validation error, not a 500 TypeError.""" + field = DeprecatedCredentialField() + with pytest.raises(ValidationError): + field.to_internal_value(OrderedDict([("username", "admin")])) + + def test_list_value_raises_validation_error(self): + """Passing a list should return a 400 validation error, not a 500 TypeError.""" + field = DeprecatedCredentialField() + with pytest.raises(ValidationError): + field.to_internal_value([1, 2, 3]) + + def test_string_value_raises_validation_error(self): + """Passing a non-numeric string should return a 400 validation error.""" + field = DeprecatedCredentialField() + with pytest.raises(ValidationError): + field.to_internal_value("not_a_number") + + @mock.patch('awx.api.fields.Credential.objects') + def test_valid_integer_value_works(self, mock_cred_objects): + """Passing a valid integer PK should work when the credential exists.""" + mock_cred_objects.get.return_value = mock.MagicMock() + field = DeprecatedCredentialField() + assert field.to_internal_value(42) == 42 + + @mock.patch('awx.api.fields.Credential.objects') + def test_valid_string_integer_value_works(self, mock_cred_objects): + """Passing a numeric string PK should work when the credential exists.""" + mock_cred_objects.get.return_value = mock.MagicMock() + field = DeprecatedCredentialField() + assert field.to_internal_value("42") == 42 diff --git a/awx/main/tests/unit/api/test_filters.py b/awx/main/tests/unit/api/test_filters.py index 7d6501a87161..78cc7401cf15 100644 --- a/awx/main/tests/unit/api/test_filters.py +++ b/awx/main/tests/unit/api/test_filters.py @@ -3,15 +3,12 @@ import pytest # Django -from django.core.exceptions import FieldDoesNotExist +from rest_framework.exceptions import PermissionDenied -from rest_framework.exceptions import PermissionDenied, ParseError +from ansible_base.rest_filters.rest_framework.field_lookup_backend import FieldLookupBackend -from awx.api.filters import FieldLookupBackend, OrderByBackend, get_field_from_path from awx.main.models import ( AdHocCommand, - ActivityStream, - Credential, Job, JobTemplate, SystemJob, @@ -20,94 +17,15 @@ WorkflowJob, WorkflowJobTemplate, WorkflowJobOptions, - InventorySource, - JobEvent, ) -from awx.main.models.oauth import OAuth2Application from awx.main.models.jobs import JobOptions -def test_related(): - field_lookup = FieldLookupBackend() - lookup = '__'.join(['inventory', 'organization', 'pk']) - field, new_lookup = field_lookup.get_field_from_lookup(InventorySource, lookup) - print(field) - print(new_lookup) - - -def test_invalid_filter_key(): - field_lookup = FieldLookupBackend() - # FieldDoesNotExist is caught and converted to ParseError by filter_queryset - with pytest.raises(FieldDoesNotExist) as excinfo: - field_lookup.value_to_python(JobEvent, 'event_data.task_action', 'foo') - assert 'has no field named' in str(excinfo) - - -def test_invalid_field_hop(): - with pytest.raises(ParseError) as excinfo: - get_field_from_path(Credential, 'organization__description__user') - assert 'No related model for' in str(excinfo) - - -def test_invalid_order_by_key(): - field_order_by = OrderByBackend() - with pytest.raises(ParseError) as excinfo: - [f for f in field_order_by._validate_ordering_fields(JobEvent, ('event_data.task_action',))] - assert 'has no field named' in str(excinfo) - - -@pytest.mark.parametrize(u"empty_value", [u'', '']) -def test_empty_in(empty_value): - field_lookup = FieldLookupBackend() - with pytest.raises(ValueError) as excinfo: - field_lookup.value_to_python(JobTemplate, 'project__name__in', empty_value) - assert 'empty value for __in' in str(excinfo.value) - - -@pytest.mark.parametrize(u"valid_value", [u'foo', u'foo,']) -def test_valid_in(valid_value): - field_lookup = FieldLookupBackend() - value, new_lookup, _ = field_lookup.value_to_python(JobTemplate, 'project__name__in', valid_value) - assert 'foo' in value - - -def test_invalid_field(): - invalid_field = u"ヽヾ" - field_lookup = FieldLookupBackend() - with pytest.raises(ValueError) as excinfo: - field_lookup.value_to_python(WorkflowJobTemplate, invalid_field, 'foo') - assert 'is not an allowed field name. Must be ascii encodable.' in str(excinfo.value) - - -def test_valid_iexact(): - field_lookup = FieldLookupBackend() - value, new_lookup, _ = field_lookup.value_to_python(JobTemplate, 'project__name__iexact', 'foo') - assert 'foo' in value - - -def test_invalid_iexact(): - field_lookup = FieldLookupBackend() - with pytest.raises(ValueError) as excinfo: - field_lookup.value_to_python(Job, 'id__iexact', '1') - assert 'is not a text field and cannot be filtered by case-insensitive search' in str(excinfo.value) - - -@pytest.mark.parametrize('lookup_suffix', ['', 'contains', 'startswith', 'in']) -@pytest.mark.parametrize('password_field', Credential.PASSWORD_FIELDS) -def test_filter_on_password_field(password_field, lookup_suffix): - field_lookup = FieldLookupBackend() - lookup = '__'.join(filter(None, [password_field, lookup_suffix])) - with pytest.raises(PermissionDenied) as excinfo: - field, new_lookup = field_lookup.get_field_from_lookup(Credential, lookup) - assert 'not allowed' in str(excinfo.value) - - @pytest.mark.parametrize( 'model, query', [ (User, 'password__icontains'), (User, 'settings__value__icontains'), - (User, 'main_oauth2accesstoken__token__gt'), (UnifiedJob, 'job_args__icontains'), (UnifiedJob, 'job_env__icontains'), (UnifiedJob, 'start_args__icontains'), @@ -119,8 +37,6 @@ def test_filter_on_password_field(password_field, lookup_suffix): (WorkflowJob, 'survey_passwords__icontains'), (JobTemplate, 'survey_spec__icontains'), (WorkflowJobTemplate, 'survey_spec__icontains'), - (ActivityStream, 'o_auth2_application__client_secret__gt'), - (OAuth2Application, 'grant__code__gt'), ], ) def test_filter_sensitive_fields_and_relations(model, query): @@ -128,10 +44,3 @@ def test_filter_sensitive_fields_and_relations(model, query): with pytest.raises(PermissionDenied) as excinfo: field, new_lookup = field_lookup.get_field_from_lookup(model, query) assert 'not allowed' in str(excinfo.value) - - -def test_looping_filters_prohibited(): - field_lookup = FieldLookupBackend() - with pytest.raises(ParseError) as loop_exc: - field_lookup.get_field_from_lookup(Job, 'job_events__job__job_events') - assert 'job_events' in str(loop_exc.value) diff --git a/awx/main/tests/unit/api/test_generics.py b/awx/main/tests/unit/api/test_generics.py index 6f0982bfd847..05cc72cc1935 100644 --- a/awx/main/tests/unit/api/test_generics.py +++ b/awx/main/tests/unit/api/test_generics.py @@ -50,7 +50,7 @@ def test_attach_validate_ok(self, mocker): mock_request = mocker.MagicMock(data=dict(id=1)) serializer = SubListCreateAttachDetachAPIView() - (sub_id, res) = serializer.attach_validate(mock_request) + sub_id, res = serializer.attach_validate(mock_request) assert sub_id == 1 assert res is None @@ -59,12 +59,12 @@ def test_attach_validate_invalid_type(self, mocker): mock_request = mocker.MagicMock(data=dict(id='foobar')) serializer = SubListCreateAttachDetachAPIView() - (sub_id, res) = serializer.attach_validate(mock_request) + sub_id, res = serializer.attach_validate(mock_request) assert type(res) is Response def test_attach_create_and_associate(self, mocker, get_object_or_400, parent_relationship_factory): - (serializer, mock_parent_relationship) = parent_relationship_factory(SubListCreateAttachDetachAPIView, 'wife') + serializer, mock_parent_relationship = parent_relationship_factory(SubListCreateAttachDetachAPIView, 'wife') create_return_value = mocker.MagicMock(status_code=status.HTTP_201_CREATED) serializer.create = mocker.Mock(return_value=create_return_value) @@ -75,7 +75,7 @@ def test_attach_create_and_associate(self, mocker, get_object_or_400, parent_rel mock_parent_relationship.wife.add.assert_called_with(get_object_or_400.return_value) def test_attach_associate_only(self, mocker, get_object_or_400, parent_relationship_factory): - (serializer, mock_parent_relationship) = parent_relationship_factory(SubListCreateAttachDetachAPIView, 'wife') + serializer, mock_parent_relationship = parent_relationship_factory(SubListCreateAttachDetachAPIView, 'wife') serializer.create = mocker.Mock(return_value=mocker.MagicMock()) mock_request = mocker.MagicMock(data=dict(id=1)) @@ -88,7 +88,7 @@ def test_unattach_validate_ok(self, mocker): mock_request = mocker.MagicMock(data=dict(id=1)) serializer = SubListCreateAttachDetachAPIView() - (sub_id, res) = serializer.unattach_validate(mock_request) + sub_id, res = serializer.unattach_validate(mock_request) assert sub_id == 1 assert res is None @@ -97,7 +97,7 @@ def test_unattach_validate_invalid_type(self, mocker): mock_request = mocker.MagicMock(data=dict(id='foobar')) serializer = SubListCreateAttachDetachAPIView() - (sub_id, res) = serializer.unattach_validate(mock_request) + sub_id, res = serializer.unattach_validate(mock_request) assert type(res) is Response @@ -105,13 +105,13 @@ def test_unattach_validate_missing_id(self, mocker): mock_request = mocker.MagicMock(data=dict()) serializer = SubListCreateAttachDetachAPIView() - (sub_id, res) = serializer.unattach_validate(mock_request) + sub_id, res = serializer.unattach_validate(mock_request) assert sub_id is None assert type(res) is Response def test_unattach_by_id_ok(self, mocker, parent_relationship_factory, get_object_or_400): - (serializer, mock_parent_relationship) = parent_relationship_factory(SubListCreateAttachDetachAPIView, 'wife') + serializer, mock_parent_relationship = parent_relationship_factory(SubListCreateAttachDetachAPIView, 'wife') mock_request = mocker.MagicMock() mock_sub = mocker.MagicMock(name="object to unattach") get_object_or_400.return_value = mock_sub @@ -191,16 +191,16 @@ def mock_view(self, parent=None): def test_parent_access_check_failed(self, mocker, mock_organization): mock_access = mocker.MagicMock(__name__='for logger', return_value=False) - with mocker.patch('awx.main.access.BaseAccess.can_read', mock_access): - with pytest.raises(PermissionDenied): - self.mock_view(parent=mock_organization).check_permissions(self.mock_request()) - mock_access.assert_called_once_with(mock_organization) + mocker.patch('awx.main.access.BaseAccess.can_read', mock_access) + with pytest.raises(PermissionDenied): + self.mock_view(parent=mock_organization).check_permissions(self.mock_request()) + mock_access.assert_called_once_with(mock_organization) def test_parent_access_check_worked(self, mocker, mock_organization): mock_access = mocker.MagicMock(__name__='for logger', return_value=True) - with mocker.patch('awx.main.access.BaseAccess.can_read', mock_access): - self.mock_view(parent=mock_organization).check_permissions(self.mock_request()) - mock_access.assert_called_once_with(mock_organization) + mocker.patch('awx.main.access.BaseAccess.can_read', mock_access) + self.mock_view(parent=mock_organization).check_permissions(self.mock_request()) + mock_access.assert_called_once_with(mock_organization) def test_related_search_reverse_FK_field(): diff --git a/awx/main/tests/unit/api/test_logger.py b/awx/main/tests/unit/api/test_logger.py index b56da87da1a7..a3da0d23b829 100644 --- a/awx/main/tests/unit/api/test_logger.py +++ b/awx/main/tests/unit/api/test_logger.py @@ -47,7 +47,7 @@ '\n'.join( [ 'template(name="awx" type="string" string="%rawmsg-after-pri%")\nmodule(load="omhttp")', - 'action(type="omhttp" server="logs-01.loggly.com" serverport="80" usehttps="off" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" action.resumeInterval="5" errorfile="/var/log/tower/rsyslog.err" restpath="inputs/1fd38090-2af1-4e1e-8d80-492899da0f71/tag/http/")', # noqa + 'action(type="omhttp" server="logs-01.loggly.com" serverport="80" usehttps="off" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" action.resumeInterval="5" queue.spoolDirectory="/var/lib/awx" queue.filename="awx-external-logger-action-queue" queue.maxDiskSpace="1g" queue.maxFileSize="100m" queue.type="LinkedList" queue.saveOnShutdown="on" queue.syncqueuefiles="on" queue.checkpointInterval="1000" queue.size="131072" queue.highwaterMark="98304" queue.discardMark="117964" queue.discardSeverity="5" errorfile="/var/log/tower/rsyslog.err" restpath="inputs/1fd38090-2af1-4e1e-8d80-492899da0f71/tag/http/")', # noqa ] ), ), @@ -61,7 +61,7 @@ '\n'.join( [ 'template(name="awx" type="string" string="%rawmsg-after-pri%")', - 'action(type="omfwd" target="localhost" port="9000" protocol="udp" action.resumeRetryCount="-1" action.resumeInterval="5" template="awx")', # noqa + 'action(type="omfwd" target="localhost" port="9000" protocol="udp" action.resumeRetryCount="-1" action.resumeInterval="5" template="awx" queue.spoolDirectory="/var/lib/awx" queue.filename="awx-external-logger-action-queue" queue.maxDiskSpace="1g" queue.maxFileSize="100m" queue.type="LinkedList" queue.saveOnShutdown="on" queue.syncqueuefiles="on" queue.checkpointInterval="1000" queue.size="131072" queue.highwaterMark="98304" queue.discardMark="117964" queue.discardSeverity="5")', # noqa ] ), ), @@ -75,7 +75,7 @@ '\n'.join( [ 'template(name="awx" type="string" string="%rawmsg-after-pri%")', - 'action(type="omfwd" target="localhost" port="9000" protocol="tcp" action.resumeRetryCount="-1" action.resumeInterval="5" template="awx")', # noqa + 'action(type="omfwd" target="localhost" port="9000" protocol="tcp" action.resumeRetryCount="-1" action.resumeInterval="5" template="awx" queue.spoolDirectory="/var/lib/awx" queue.filename="awx-external-logger-action-queue" queue.maxDiskSpace="1g" queue.maxFileSize="100m" queue.type="LinkedList" queue.saveOnShutdown="on" queue.syncqueuefiles="on" queue.checkpointInterval="1000" queue.size="131072" queue.highwaterMark="98304" queue.discardMark="117964" queue.discardSeverity="5")', # noqa ] ), ), @@ -89,7 +89,7 @@ '\n'.join( [ 'template(name="awx" type="string" string="%rawmsg-after-pri%")\nmodule(load="omhttp")', - 'action(type="omhttp" server="yoursplunk" serverport="443" usehttps="on" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" action.resumeInterval="5" errorfile="/var/log/tower/rsyslog.err" restpath="services/collector/event")', # noqa + 'action(type="omhttp" server="yoursplunk" serverport="443" usehttps="on" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" action.resumeInterval="5" queue.spoolDirectory="/var/lib/awx" queue.filename="awx-external-logger-action-queue" queue.maxDiskSpace="1g" queue.maxFileSize="100m" queue.type="LinkedList" queue.saveOnShutdown="on" queue.syncqueuefiles="on" queue.checkpointInterval="1000" queue.size="131072" queue.highwaterMark="98304" queue.discardMark="117964" queue.discardSeverity="5" errorfile="/var/log/tower/rsyslog.err" restpath="services/collector/event")', # noqa ] ), ), @@ -103,7 +103,7 @@ '\n'.join( [ 'template(name="awx" type="string" string="%rawmsg-after-pri%")\nmodule(load="omhttp")', - 'action(type="omhttp" server="yoursplunk" serverport="80" usehttps="off" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" action.resumeInterval="5" errorfile="/var/log/tower/rsyslog.err" restpath="services/collector/event")', # noqa + 'action(type="omhttp" server="yoursplunk" serverport="80" usehttps="off" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" action.resumeInterval="5" queue.spoolDirectory="/var/lib/awx" queue.filename="awx-external-logger-action-queue" queue.maxDiskSpace="1g" queue.maxFileSize="100m" queue.type="LinkedList" queue.saveOnShutdown="on" queue.syncqueuefiles="on" queue.checkpointInterval="1000" queue.size="131072" queue.highwaterMark="98304" queue.discardMark="117964" queue.discardSeverity="5" errorfile="/var/log/tower/rsyslog.err" restpath="services/collector/event")', # noqa ] ), ), @@ -117,7 +117,7 @@ '\n'.join( [ 'template(name="awx" type="string" string="%rawmsg-after-pri%")\nmodule(load="omhttp")', - 'action(type="omhttp" server="yoursplunk" serverport="8088" usehttps="on" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" action.resumeInterval="5" errorfile="/var/log/tower/rsyslog.err" restpath="services/collector/event")', # noqa + 'action(type="omhttp" server="yoursplunk" serverport="8088" usehttps="on" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" action.resumeInterval="5" queue.spoolDirectory="/var/lib/awx" queue.filename="awx-external-logger-action-queue" queue.maxDiskSpace="1g" queue.maxFileSize="100m" queue.type="LinkedList" queue.saveOnShutdown="on" queue.syncqueuefiles="on" queue.checkpointInterval="1000" queue.size="131072" queue.highwaterMark="98304" queue.discardMark="117964" queue.discardSeverity="5" errorfile="/var/log/tower/rsyslog.err" restpath="services/collector/event")', # noqa ] ), ), @@ -131,7 +131,7 @@ '\n'.join( [ 'template(name="awx" type="string" string="%rawmsg-after-pri%")\nmodule(load="omhttp")', - 'action(type="omhttp" server="yoursplunk" serverport="8088" usehttps="on" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" action.resumeInterval="5" errorfile="/var/log/tower/rsyslog.err" restpath="services/collector/event")', # noqa + 'action(type="omhttp" server="yoursplunk" serverport="8088" usehttps="on" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" action.resumeInterval="5" queue.spoolDirectory="/var/lib/awx" queue.filename="awx-external-logger-action-queue" queue.maxDiskSpace="1g" queue.maxFileSize="100m" queue.type="LinkedList" queue.saveOnShutdown="on" queue.syncqueuefiles="on" queue.checkpointInterval="1000" queue.size="131072" queue.highwaterMark="98304" queue.discardMark="117964" queue.discardSeverity="5" errorfile="/var/log/tower/rsyslog.err" restpath="services/collector/event")', # noqa ] ), ), @@ -145,7 +145,7 @@ '\n'.join( [ 'template(name="awx" type="string" string="%rawmsg-after-pri%")\nmodule(load="omhttp")', - 'action(type="omhttp" server="yoursplunk.org" serverport="8088" usehttps="on" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" action.resumeInterval="5" errorfile="/var/log/tower/rsyslog.err" restpath="services/collector/event")', # noqa + 'action(type="omhttp" server="yoursplunk.org" serverport="8088" usehttps="on" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" action.resumeInterval="5" queue.spoolDirectory="/var/lib/awx" queue.filename="awx-external-logger-action-queue" queue.maxDiskSpace="1g" queue.maxFileSize="100m" queue.type="LinkedList" queue.saveOnShutdown="on" queue.syncqueuefiles="on" queue.checkpointInterval="1000" queue.size="131072" queue.highwaterMark="98304" queue.discardMark="117964" queue.discardSeverity="5" errorfile="/var/log/tower/rsyslog.err" restpath="services/collector/event")', # noqa ] ), ), @@ -159,7 +159,7 @@ '\n'.join( [ 'template(name="awx" type="string" string="%rawmsg-after-pri%")\nmodule(load="omhttp")', - 'action(type="omhttp" server="yoursplunk.org" serverport="8088" usehttps="off" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" action.resumeInterval="5" errorfile="/var/log/tower/rsyslog.err" restpath="services/collector/event")', # noqa + 'action(type="omhttp" server="yoursplunk.org" serverport="8088" usehttps="off" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" action.resumeInterval="5" queue.spoolDirectory="/var/lib/awx" queue.filename="awx-external-logger-action-queue" queue.maxDiskSpace="1g" queue.maxFileSize="100m" queue.type="LinkedList" queue.saveOnShutdown="on" queue.syncqueuefiles="on" queue.checkpointInterval="1000" queue.size="131072" queue.highwaterMark="98304" queue.discardMark="117964" queue.discardSeverity="5" errorfile="/var/log/tower/rsyslog.err" restpath="services/collector/event")', # noqa ] ), ), @@ -173,7 +173,7 @@ '\n'.join( [ 'template(name="awx" type="string" string="%rawmsg-after-pri%")\nmodule(load="omhttp")', - 'action(type="omhttp" server="endpoint5.collection.us2.sumologic.com" serverport="443" usehttps="on" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" action.resumeInterval="5" errorfile="/var/log/tower/rsyslog.err" restpath="receiver/v1/http/ZaVnC4dhaV0qoiETY0MrM3wwLoDgO1jFgjOxE6-39qokkj3LGtOroZ8wNaN2M6DtgYrJZsmSi4-36_Up5TbbN_8hosYonLKHSSOSKY845LuLZBCBwStrHQ==")', # noqa + 'action(type="omhttp" server="endpoint5.collection.us2.sumologic.com" serverport="443" usehttps="on" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" action.resumeInterval="5" queue.spoolDirectory="/var/lib/awx" queue.filename="awx-external-logger-action-queue" queue.maxDiskSpace="1g" queue.maxFileSize="100m" queue.type="LinkedList" queue.saveOnShutdown="on" queue.syncqueuefiles="on" queue.checkpointInterval="1000" queue.size="131072" queue.highwaterMark="98304" queue.discardMark="117964" queue.discardSeverity="5" errorfile="/var/log/tower/rsyslog.err" restpath="receiver/v1/http/ZaVnC4dhaV0qoiETY0MrM3wwLoDgO1jFgjOxE6-39qokkj3LGtOroZ8wNaN2M6DtgYrJZsmSi4-36_Up5TbbN_8hosYonLKHSSOSKY845LuLZBCBwStrHQ==")', # noqa ] ), ), diff --git a/awx/main/tests/unit/api/test_schema.py b/awx/main/tests/unit/api/test_schema.py new file mode 100644 index 000000000000..83ade9e16cc9 --- /dev/null +++ b/awx/main/tests/unit/api/test_schema.py @@ -0,0 +1,424 @@ +import copy +import warnings +from unittest.mock import Mock, patch + +from rest_framework.permissions import IsAuthenticated + +from awx.api.schema import ( + CustomAutoSchema, + AuthenticatedSpectacularAPIView, + AuthenticatedSpectacularSwaggerView, + AuthenticatedSpectacularRedocView, + filter_credential_type_schema, +) + + +class TestCustomAutoSchema: + """Unit tests for CustomAutoSchema class.""" + + def test_get_tags_with_swagger_topic(self): + """Test get_tags returns swagger_topic when available.""" + view = Mock() + view.swagger_topic = 'custom_topic' + view.get_serializer = Mock(return_value=Mock()) + + schema = CustomAutoSchema() + schema.view = view + + tags = schema.get_tags() + assert tags == ['Custom_Topic'] + + def test_get_tags_with_serializer_meta_model(self): + """Test get_tags returns model verbose_name_plural from serializer.""" + # Create a mock model with verbose_name_plural + mock_model = Mock() + mock_model._meta.verbose_name_plural = 'test models' + + # Create a mock serializer with Meta.model + mock_serializer = Mock() + mock_serializer.Meta.model = mock_model + + view = Mock(spec=[]) # View without swagger_topic + view.get_serializer = Mock(return_value=mock_serializer) + + schema = CustomAutoSchema() + schema.view = view + + tags = schema.get_tags() + assert tags == ['Test Models'] + + def test_get_tags_with_view_model(self): + """Test get_tags returns model verbose_name_plural from view.""" + # Create a mock model with verbose_name_plural + mock_model = Mock() + mock_model._meta.verbose_name_plural = 'view models' + + view = Mock(spec=['model']) # View without swagger_topic or get_serializer + view.model = mock_model + + schema = CustomAutoSchema() + schema.view = view + + tags = schema.get_tags() + assert tags == ['View Models'] + + def test_get_tags_without_get_serializer(self): + """Test get_tags when view doesn't have get_serializer method.""" + mock_model = Mock() + mock_model._meta.verbose_name_plural = 'test objects' + + view = Mock(spec=['model']) + view.model = mock_model + + schema = CustomAutoSchema() + schema.view = view + + tags = schema.get_tags() + assert tags == ['Test Objects'] + + def test_get_tags_serializer_exception_with_warning(self): + """Test get_tags handles exception in get_serializer with warning.""" + mock_model = Mock() + mock_model._meta.verbose_name_plural = 'fallback models' + + view = Mock(spec=['get_serializer', 'model', '__class__']) + view.__class__.__name__ = 'TestView' + view.get_serializer = Mock(side_effect=Exception('Serializer error')) + view.model = mock_model + + schema = CustomAutoSchema() + schema.view = view + + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + tags = schema.get_tags() + + # Check that a warning was raised + assert len(w) == 1 + assert 'TestView.get_serializer() raised an exception' in str(w[0].message) + + # Should still get tags from view.model + assert tags == ['Fallback Models'] + + def test_get_tags_serializer_without_meta_model(self): + """Test get_tags when serializer doesn't have Meta.model.""" + mock_serializer = Mock(spec=[]) # No Meta attribute + + view = Mock(spec=['get_serializer']) + view.__class__.__name__ = 'NoMetaView' + view.get_serializer = Mock(return_value=mock_serializer) + + schema = CustomAutoSchema() + schema.view = view + + with patch.object(CustomAutoSchema.__bases__[0], 'get_tags', return_value=['Default Tag']) as mock_super: + tags = schema.get_tags() + mock_super.assert_called_once() + assert tags == ['Default Tag'] + + def test_get_tags_fallback_to_super(self): + """Test get_tags falls back to parent class method.""" + view = Mock(spec=['get_serializer']) + view.get_serializer = Mock(return_value=Mock(spec=[])) + + schema = CustomAutoSchema() + schema.view = view + + with patch.object(CustomAutoSchema.__bases__[0], 'get_tags', return_value=['Super Tag']) as mock_super: + tags = schema.get_tags() + mock_super.assert_called_once() + assert tags == ['Super Tag'] + + def test_get_tags_empty_with_warning(self): + """Test get_tags returns 'api' fallback when no tags can be determined.""" + view = Mock(spec=['get_serializer']) + view.__class__.__name__ = 'EmptyView' + view.get_serializer = Mock(return_value=Mock(spec=[])) + + schema = CustomAutoSchema() + schema.view = view + + with patch.object(CustomAutoSchema.__bases__[0], 'get_tags', return_value=[]): + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + tags = schema.get_tags() + + # Check that a warning was raised + assert len(w) == 1 + assert 'Could not determine tags for EmptyView' in str(w[0].message) + + # Should fallback to 'api' + assert tags == ['api'] + + def test_get_tags_swagger_topic_title_case(self): + """Test that swagger_topic is properly title-cased.""" + view = Mock() + view.swagger_topic = 'multi_word_topic' + view.get_serializer = Mock(return_value=Mock()) + + schema = CustomAutoSchema() + schema.view = view + + tags = schema.get_tags() + assert tags == ['Multi_Word_Topic'] + + def test_is_deprecated_true(self): + """Test is_deprecated returns True when view has deprecated=True.""" + view = Mock() + view.deprecated = True + + schema = CustomAutoSchema() + schema.view = view + + assert schema.is_deprecated() is True + + def test_is_deprecated_false(self): + """Test is_deprecated returns False when view has deprecated=False.""" + view = Mock() + view.deprecated = False + + schema = CustomAutoSchema() + schema.view = view + + assert schema.is_deprecated() is False + + def test_is_deprecated_missing_attribute(self): + """Test is_deprecated returns False when view doesn't have deprecated attribute.""" + view = Mock(spec=[]) + + schema = CustomAutoSchema() + schema.view = view + + assert schema.is_deprecated() is False + + def test_get_tags_serializer_meta_without_model(self): + """Test get_tags when serializer has Meta but no model attribute.""" + mock_serializer = Mock() + mock_serializer.Meta = Mock(spec=[]) # Meta exists but no model + + mock_model = Mock() + mock_model._meta.verbose_name_plural = 'backup models' + + view = Mock(spec=['get_serializer', 'model']) + view.get_serializer = Mock(return_value=mock_serializer) + view.model = mock_model + + schema = CustomAutoSchema() + schema.view = view + + tags = schema.get_tags() + # Should fall back to view.model + assert tags == ['Backup Models'] + + def test_get_tags_complex_scenario_exception_recovery(self): + """Test complex scenario where serializer fails but view.model exists.""" + mock_model = Mock() + mock_model._meta.verbose_name_plural = 'recovery models' + + view = Mock(spec=['get_serializer', 'model', '__class__']) + view.__class__.__name__ = 'ComplexView' + view.get_serializer = Mock(side_effect=ValueError('Invalid serializer')) + view.model = mock_model + + schema = CustomAutoSchema() + schema.view = view + + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + tags = schema.get_tags() + + # Should have warned about the exception + assert len(w) == 1 + assert 'ComplexView.get_serializer() raised an exception' in str(w[0].message) + + # But still recovered and got tags from view.model + assert tags == ['Recovery Models'] + + def test_get_tags_priority_order(self): + """Test that get_tags respects priority: swagger_topic > serializer.Meta.model > view.model.""" + # Set up a view with all three options + mock_model_view = Mock() + mock_model_view._meta.verbose_name_plural = 'view models' + + mock_model_serializer = Mock() + mock_model_serializer._meta.verbose_name_plural = 'serializer models' + + mock_serializer = Mock() + mock_serializer.Meta.model = mock_model_serializer + + view = Mock() + view.swagger_topic = 'priority_topic' + view.get_serializer = Mock(return_value=mock_serializer) + view.model = mock_model_view + + schema = CustomAutoSchema() + schema.view = view + + tags = schema.get_tags() + # swagger_topic should take priority + assert tags == ['Priority_Topic'] + + +class TestAuthenticatedSchemaViews: + """Unit tests for authenticated schema view classes.""" + + def test_authenticated_spectacular_api_view_requires_authentication(self): + """Test that AuthenticatedSpectacularAPIView requires authentication.""" + assert IsAuthenticated in AuthenticatedSpectacularAPIView.permission_classes + + def test_authenticated_spectacular_swagger_view_requires_authentication(self): + """Test that AuthenticatedSpectacularSwaggerView requires authentication.""" + assert IsAuthenticated in AuthenticatedSpectacularSwaggerView.permission_classes + + def test_authenticated_spectacular_redoc_view_requires_authentication(self): + """Test that AuthenticatedSpectacularRedocView requires authentication.""" + assert IsAuthenticated in AuthenticatedSpectacularRedocView.permission_classes + + +class TestFilterCredentialTypeSchema: + """Unit tests for filter_credential_type_schema postprocessing hook.""" + + def test_filters_both_schemas_correctly(self): + """Test that both CredentialTypeRequest and PatchedCredentialTypeRequest schemas are filtered.""" + result = { + 'components': { + 'schemas': { + 'CredentialTypeRequest': { + 'properties': { + 'kind': { + 'enum': [ + 'ssh', + 'vault', + 'net', + 'scm', + 'cloud', + 'registry', + 'token', + 'insights', + 'external', + 'kubernetes', + 'galaxy', + 'cryptography', + None, + ], + 'type': 'string', + } + } + }, + 'PatchedCredentialTypeRequest': { + 'properties': { + 'kind': { + 'enum': [ + 'ssh', + 'vault', + 'net', + 'scm', + 'cloud', + 'registry', + 'token', + 'insights', + 'external', + 'kubernetes', + 'galaxy', + 'cryptography', + None, + ], + 'type': 'string', + } + } + }, + } + } + } + + returned = filter_credential_type_schema(result, None, None, None) + + # POST/PUT schema: no None (required field) + assert result['components']['schemas']['CredentialTypeRequest']['properties']['kind']['enum'] == ['cloud', 'net'] + assert result['components']['schemas']['CredentialTypeRequest']['properties']['kind']['description'] == "* `cloud` - Cloud\\n* `net` - Network" + + # PATCH schema: includes None (optional field) + assert result['components']['schemas']['PatchedCredentialTypeRequest']['properties']['kind']['enum'] == ['cloud', 'net', None] + assert result['components']['schemas']['PatchedCredentialTypeRequest']['properties']['kind']['description'] == "* `cloud` - Cloud\\n* `net` - Network" + + # Other properties should be preserved + assert result['components']['schemas']['CredentialTypeRequest']['properties']['kind']['type'] == 'string' + + # Function should return the result + assert returned is result + + def test_handles_empty_result(self): + """Test graceful handling when result dict is empty.""" + result = {} + original = copy.deepcopy(result) + + returned = filter_credential_type_schema(result, None, None, None) + + assert result == original + assert returned is result + + def test_handles_missing_enum(self): + """Test that schemas without enum key are not modified.""" + result = {'components': {'schemas': {'CredentialTypeRequest': {'properties': {'kind': {'type': 'string', 'description': 'Some description'}}}}}} + original = copy.deepcopy(result) + + filter_credential_type_schema(result, None, None, None) + + assert result == original + + def test_filters_only_target_schemas(self): + """Test that only CredentialTypeRequest schemas are modified, not others.""" + result = { + 'components': { + 'schemas': { + 'CredentialTypeRequest': {'properties': {'kind': {'enum': ['ssh', 'cloud', 'net', None]}}}, + 'OtherSchema': {'properties': {'kind': {'enum': ['option1', 'option2']}}}, + } + } + } + + other_schema_before = copy.deepcopy(result['components']['schemas']['OtherSchema']) + + filter_credential_type_schema(result, None, None, None) + + # CredentialTypeRequest should be filtered (no None for required field) + assert result['components']['schemas']['CredentialTypeRequest']['properties']['kind']['enum'] == ['cloud', 'net'] + + # OtherSchema should be unchanged + assert result['components']['schemas']['OtherSchema'] == other_schema_before + + def test_handles_only_one_schema_present(self): + """Test that function works when only one target schema is present.""" + result = {'components': {'schemas': {'CredentialTypeRequest': {'properties': {'kind': {'enum': ['ssh', 'cloud', 'net', None]}}}}}} + + filter_credential_type_schema(result, None, None, None) + + assert result['components']['schemas']['CredentialTypeRequest']['properties']['kind']['enum'] == ['cloud', 'net'] + + def test_handles_missing_properties(self): + """Test graceful handling when schema has no properties key.""" + result = {'components': {'schemas': {'CredentialTypeRequest': {}}}} + original = copy.deepcopy(result) + + filter_credential_type_schema(result, None, None, None) + + assert result == original + + def test_differentiates_required_vs_optional_fields(self): + """Test that CredentialTypeRequest excludes None but PatchedCredentialTypeRequest includes it.""" + result = { + 'components': { + 'schemas': { + 'CredentialTypeRequest': {'properties': {'kind': {'enum': ['ssh', 'vault', 'net', 'scm', 'cloud', 'registry', None]}}}, + 'PatchedCredentialTypeRequest': {'properties': {'kind': {'enum': ['ssh', 'vault', 'net', 'scm', 'cloud', 'registry', None]}}}, + } + } + } + + filter_credential_type_schema(result, None, None, None) + + # POST/PUT schema: no None (required field) + assert result['components']['schemas']['CredentialTypeRequest']['properties']['kind']['enum'] == ['cloud', 'net'] + + # PATCH schema: includes None (optional field) + assert result['components']['schemas']['PatchedCredentialTypeRequest']['properties']['kind']['enum'] == ['cloud', 'net', None] diff --git a/awx/main/tests/unit/api/test_views.py b/awx/main/tests/unit/api/test_views.py index 950ae57af4a7..503ad6e854dd 100644 --- a/awx/main/tests/unit/api/test_views.py +++ b/awx/main/tests/unit/api/test_views.py @@ -50,6 +50,7 @@ def test_get_endpoints(self, mocker): 'activity_stream', 'workflow_job_templates', 'workflow_jobs', + 'analytics', ] view = ApiVersionRootView() ret = view.get(mocker.MagicMock()) @@ -65,7 +66,7 @@ def test_inherited_mixin_unattach(self): mock_request = mock.MagicMock() super(JobTemplateLabelList, view).unattach(mock_request, None, None) - assert mixin_unattach.called_with(mock_request, None, None) + mixin_unattach.assert_called_with(mock_request, None, None) class TestInventoryInventorySourcesUpdate: @@ -107,15 +108,16 @@ def exclude(self, **kwargs): mock_request = mocker.MagicMock() mock_request.user.can_access.return_value = can_access - with mocker.patch.object(InventoryInventorySourcesUpdate, 'get_object', return_value=obj): - with mocker.patch.object(InventoryInventorySourcesUpdate, 'get_serializer_context', return_value=None): - with mocker.patch('awx.api.serializers.InventoryUpdateDetailSerializer') as serializer_class: - serializer = serializer_class.return_value - serializer.to_representation.return_value = {} + mocker.patch.object(InventoryInventorySourcesUpdate, 'get_object', return_value=obj) + mocker.patch.object(InventoryInventorySourcesUpdate, 'get_serializer_context', return_value=None) + serializer_class = mocker.patch('awx.api.serializers.InventoryUpdateDetailSerializer') - view = InventoryInventorySourcesUpdate() - response = view.post(mock_request) - assert response.data == expected + serializer = serializer_class.return_value + serializer.to_representation.return_value = {} + + view = InventoryInventorySourcesUpdate() + response = view.post(mock_request) + assert response.data == expected class TestSurveySpecValidation: diff --git a/awx/main/tests/unit/commands/test_dispatcherctl.py b/awx/main/tests/unit/commands/test_dispatcherctl.py new file mode 100644 index 000000000000..50804577c36e --- /dev/null +++ b/awx/main/tests/unit/commands/test_dispatcherctl.py @@ -0,0 +1,92 @@ +import io + +import pytest + +from django.core.management.base import CommandError + +from awx.main.management.commands import dispatcherctl + + +@pytest.fixture(autouse=True) +def clear_dispatcher_env(monkeypatch, mocker): + monkeypatch.delenv('DISPATCHERD_CONFIG_FILE', raising=False) + mocker.patch.object(dispatcherctl.logging, 'basicConfig') + mocker.patch.object(dispatcherctl, 'connection', mocker.Mock(vendor='postgresql')) + + +def test_dispatcherctl_runs_control_with_generated_config(mocker): + command = dispatcherctl.Command() + command.stdout = io.StringIO() + + data = {'foo': 'bar'} + mocker.patch.object(dispatcherctl, '_build_command_data_from_args', return_value=data) + dispatcher_setup = mocker.patch.object(dispatcherctl, 'dispatcher_setup') + config_data = {'setting': 'value'} + mocker.patch.object(dispatcherctl, 'get_dispatcherd_config', return_value=config_data) + + control = mocker.Mock() + control.control_with_reply.return_value = [{'status': 'ok'}] + mocker.patch.object(dispatcherctl, 'get_control_from_settings', return_value=control) + mocker.patch.object(dispatcherctl.yaml, 'dump', return_value='payload\n') + + command.handle( + command='running', + config=dispatcherctl.DEFAULT_CONFIG_FILE, + expected_replies=1, + log_level='INFO', + ) + + dispatcher_setup.assert_called_once_with(config_data) + control.control_with_reply.assert_called_once_with('running', data=data, expected_replies=1) + assert command.stdout.getvalue() == 'payload\n' + + +def test_dispatcherctl_rejects_custom_config_path(): + command = dispatcherctl.Command() + command.stdout = io.StringIO() + + with pytest.raises(CommandError): + command.handle( + command='running', + config='/tmp/dispatcher.yml', + expected_replies=1, + log_level='INFO', + ) + + +def test_dispatcherctl_rejects_sqlite_db(mocker): + command = dispatcherctl.Command() + command.stdout = io.StringIO() + + mocker.patch.object(dispatcherctl, 'connection', mocker.Mock(vendor='sqlite')) + + with pytest.raises(CommandError, match='sqlite3'): + command.handle( + command='running', + config=dispatcherctl.DEFAULT_CONFIG_FILE, + expected_replies=1, + log_level='INFO', + ) + + +def test_dispatcherctl_raises_when_replies_missing(mocker): + command = dispatcherctl.Command() + command.stdout = io.StringIO() + + mocker.patch.object(dispatcherctl, '_build_command_data_from_args', return_value={}) + mocker.patch.object(dispatcherctl, 'dispatcher_setup') + mocker.patch.object(dispatcherctl, 'get_dispatcherd_config', return_value={}) + control = mocker.Mock() + control.control_with_reply.return_value = [{'status': 'ok'}] + mocker.patch.object(dispatcherctl, 'get_control_from_settings', return_value=control) + mocker.patch.object(dispatcherctl.yaml, 'dump', return_value='- status: ok\n') + + with pytest.raises(CommandError): + command.handle( + command='running', + config=dispatcherctl.DEFAULT_CONFIG_FILE, + expected_replies=2, + log_level='INFO', + ) + + control.control_with_reply.assert_called_once_with('running', data={}, expected_replies=2) diff --git a/awx/main/tests/unit/models/test_credential.py b/awx/main/tests/unit/models/test_credential.py index 0dc8daff3356..81f243ddefd5 100644 --- a/awx/main/tests/unit/models/test_credential.py +++ b/awx/main/tests/unit/models/test_credential.py @@ -4,6 +4,8 @@ from awx.main.models import Credential, CredentialType +from django.apps import apps + @pytest.mark.django_db def test_unique_hash_with_unicode(): @@ -16,3 +18,32 @@ def test_custom_cred_with_empty_encrypted_field(): ct = CredentialType(name='My Custom Cred', kind='custom', inputs={'fields': [{'id': 'some_field', 'label': 'My Field', 'secret': True}]}) cred = Credential(id=4, name='Testing 1 2 3', credential_type=ct, inputs={}) assert cred.encrypt_field('some_field', None) is None + + +@pytest.mark.parametrize( + ( + 'apps', + 'app_config', + ), + [ + ( + apps, + None, + ), + ( + None, + apps.get_app_config('main'), + ), + ], +) +def test__get_credential_type_class(apps, app_config): + ct = CredentialType._get_credential_type_class(apps=apps, app_config=app_config) + assert ct.__name__ == 'CredentialType' + + +def test__get_credential_type_class_invalid_params(): + with pytest.raises(ValueError) as e: + CredentialType._get_credential_type_class(apps=apps, app_config=apps.get_app_config('main')) + + assert type(e.value) is ValueError + assert str(e.value) == 'Expected only apps or app_config to be defined, not both' diff --git a/awx/main/tests/unit/models/test_events.py b/awx/main/tests/unit/models/test_events.py index a38df57fff6c..920b8572ea12 100644 --- a/awx/main/tests/unit/models/test_events.py +++ b/awx/main/tests/unit/models/test_events.py @@ -1,5 +1,5 @@ from datetime import datetime -from django.utils.timezone import utc +from datetime import timezone import pytest from awx.main.models import JobEvent, ProjectUpdateEvent, AdHocCommandEvent, InventoryUpdateEvent, SystemJobEvent @@ -18,7 +18,7 @@ @pytest.mark.parametrize('created', [datetime(2018, 1, 1).isoformat(), datetime(2018, 1, 1)]) def test_event_parse_created(job_identifier, cls, created): event = cls.create_from_data(**{job_identifier: 123, 'created': created}) - assert event.created == datetime(2018, 1, 1).replace(tzinfo=utc) + assert event.created == datetime(2018, 1, 1).replace(tzinfo=timezone.utc) @pytest.mark.parametrize( diff --git a/awx/main/tests/unit/models/test_jobs.py b/awx/main/tests/unit/models/test_jobs.py index 2f030a57c32c..ff1887f34edb 100644 --- a/awx/main/tests/unit/models/test_jobs.py +++ b/awx/main/tests/unit/models/test_jobs.py @@ -1,97 +1,139 @@ # -*- coding: utf-8 -*- import json import os -import time - import pytest from awx.main.models import ( - Job, Inventory, Host, ) +from awx.main.tasks.facts import start_fact_cache, finish_fact_cache + +from django.utils.timezone import now + +from datetime import timedelta + +import time @pytest.fixture -def hosts(inventory): +def ref_time(): + return now() - timedelta(seconds=5) + + +@pytest.fixture +def hosts(ref_time): + inventory = Inventory(id=5) return [ - Host(name='host1', ansible_facts={"a": 1, "b": 2}, inventory=inventory), - Host(name='host2', ansible_facts={"a": 1, "b": 2}, inventory=inventory), - Host(name='host3', ansible_facts={"a": 1, "b": 2}, inventory=inventory), - Host(name=u'Iñtërnâtiônàlizætiøn', ansible_facts={"a": 1, "b": 2}, inventory=inventory), + Host(name='host1', ansible_facts={"a": 1, "b": 2}, ansible_facts_modified=ref_time, inventory=inventory), + Host(name='host2', ansible_facts={"a": 1, "b": 2}, ansible_facts_modified=ref_time, inventory=inventory), + Host(name='host3', ansible_facts={"a": 1, "b": 2}, ansible_facts_modified=ref_time, inventory=inventory), + Host(name=u'Iñtërnâtiônàlizætiøn', ansible_facts={"a": 1, "b": 2}, ansible_facts_modified=ref_time, inventory=inventory), ] -@pytest.fixture -def inventory(): - return Inventory(id=5) +def test_start_job_fact_cache(hosts, tmpdir): + # Create artifacts dir inside tmpdir + artifacts_dir = tmpdir.mkdir("artifacts") + # Assign a mock inventory ID + inventory_id = 42 -@pytest.fixture -def job(mocker, hosts, inventory): - j = Job(inventory=inventory, id=2) - j._get_inventory_hosts = mocker.Mock(return_value=hosts) - return j + # Call the function WITHOUT log_data — the decorator handles it + start_fact_cache(hosts, artifacts_dir=str(artifacts_dir), timeout=0, inventory_id=inventory_id) + + # Fact files are written into artifacts_dir/fact_cache/ + fact_cache_dir = os.path.join(artifacts_dir, 'fact_cache') + + for host in hosts: + filepath = os.path.join(fact_cache_dir, host.name) + assert os.path.exists(filepath) + with open(filepath, 'r', encoding='utf-8') as f: + assert json.load(f) == host.ansible_facts + + +def test_fact_cache_with_invalid_path_traversal(tmpdir): + hosts = [ + Host( + name='../foo', + ansible_facts={"a": 1, "b": 2}, + ), + ] + artifacts_dir = tmpdir.mkdir("artifacts") + inventory_id = 42 + + start_fact_cache(hosts, artifacts_dir=str(artifacts_dir), timeout=0, inventory_id=inventory_id) + + # Fact cache directory (safe location) + fact_cache_dir = os.path.join(artifacts_dir, 'fact_cache') + + # The bad host name should not produce a file + assert not os.path.exists(os.path.join(fact_cache_dir, '../foo')) + # Make sure the fact_cache dir exists and is still empty + assert os.listdir(fact_cache_dir) == [] -def test_start_job_fact_cache(hosts, job, inventory, tmpdir): + +def test_start_job_fact_cache_past_timeout(hosts, tmpdir): fact_cache = os.path.join(tmpdir, 'facts') - last_modified = job.start_job_fact_cache(fact_cache, timeout=0) + start_fact_cache(hosts, fact_cache, timeout=2) + + for host in hosts: + assert not os.path.exists(os.path.join(fact_cache, host.name)) + ret = start_fact_cache(hosts, fact_cache, timeout=2) + assert ret is None + + +def test_start_job_fact_cache_within_timeout(hosts, tmpdir): + artifacts_dir = tmpdir.mkdir("artifacts") + + # The hosts fixture was modified 5s ago, which is less than 7s + start_fact_cache(hosts, str(artifacts_dir), timeout=7) + fact_cache_dir = os.path.join(artifacts_dir, 'fact_cache') for host in hosts: - filepath = os.path.join(fact_cache, host.name) + filepath = os.path.join(fact_cache_dir, host.name) assert os.path.exists(filepath) with open(filepath, 'r') as f: - assert f.read() == json.dumps(host.ansible_facts) - assert os.path.getmtime(filepath) <= last_modified + assert json.load(f) == host.ansible_facts -def test_fact_cache_with_invalid_path_traversal(job, inventory, tmpdir, mocker): - job._get_inventory_hosts = mocker.Mock( - return_value=[ - Host( - name='../foo', - ansible_facts={"a": 1, "b": 2}, - ), - ] - ) - +def test_finish_job_fact_cache_clear(hosts, mocker, ref_time, tmpdir): fact_cache = os.path.join(tmpdir, 'facts') - job.start_job_fact_cache(fact_cache, timeout=0) - # a file called "foo" should _not_ be written outside the facts dir - assert os.listdir(os.path.join(fact_cache, '..')) == ['facts'] + start_fact_cache(hosts, fact_cache, timeout=0) + bulk_update = mocker.patch('awx.main.tasks.facts.bulk_update_sorted_by_id') -def test_finish_job_fact_cache_with_existing_data(job, hosts, inventory, mocker, tmpdir): - fact_cache = os.path.join(tmpdir, 'facts') - last_modified = job.start_job_fact_cache(fact_cache, timeout=0) + # Mock the os.path.exists behavior for host deletion + # Let's assume the fact file for hosts[1] is missing. + mocker.patch('os.path.exists', side_effect=lambda path: hosts[1].name not in path) - bulk_update = mocker.patch('django.db.models.query.QuerySet.bulk_update') + # Simulate one host's fact file getting deleted manually + host_to_delete_filepath = os.path.join(fact_cache, hosts[1].name) - ansible_facts_new = {"foo": "bar"} - filepath = os.path.join(fact_cache, hosts[1].name) - with open(filepath, 'w') as f: - f.write(json.dumps(ansible_facts_new)) - f.flush() - # I feel kind of gross about calling `os.utime` by hand, but I noticed - # that in our container-based dev environment, the resolution for - # `os.stat()` after a file write was over a second, and I don't want to put - # a sleep() in this test - new_modification_time = time.time() + 3600 - os.utime(filepath, (new_modification_time, new_modification_time)) + # Simulate the file being removed by checking existence first, to avoid FileNotFoundError + if os.path.exists(host_to_delete_filepath): + os.remove(host_to_delete_filepath) - job.finish_job_fact_cache(fact_cache, last_modified) + finish_fact_cache(fact_cache) + # Simulate side effects that would normally be applied during bulk update + hosts[1].ansible_facts = {} + hosts[1].ansible_facts_modified = now() + + # Verify facts are preserved for hosts with valid cache files for host in (hosts[0], hosts[2], hosts[3]): assert host.ansible_facts == {"a": 1, "b": 2} - assert host.ansible_facts_modified is None - assert hosts[1].ansible_facts == ansible_facts_new - bulk_update.assert_called_once_with([hosts[1]], ['ansible_facts', 'ansible_facts_modified']) + assert host.ansible_facts_modified == ref_time + assert hosts[1].ansible_facts_modified > ref_time + # Current implementation skips the call entirely if hosts_to_update == [] + bulk_update.assert_not_called() -def test_finish_job_fact_cache_with_bad_data(job, hosts, inventory, mocker, tmpdir): + +def test_finish_job_fact_cache_with_bad_data(hosts, mocker, tmpdir): fact_cache = os.path.join(tmpdir, 'facts') - last_modified = job.start_job_fact_cache(fact_cache, timeout=0) + start_fact_cache(hosts, fact_cache, timeout=0) bulk_update = mocker.patch('django.db.models.query.QuerySet.bulk_update') @@ -103,22 +145,6 @@ def test_finish_job_fact_cache_with_bad_data(job, hosts, inventory, mocker, tmpd new_modification_time = time.time() + 3600 os.utime(filepath, (new_modification_time, new_modification_time)) - job.finish_job_fact_cache(fact_cache, last_modified) + finish_fact_cache(fact_cache) bulk_update.assert_not_called() - - -def test_finish_job_fact_cache_clear(job, hosts, inventory, mocker, tmpdir): - fact_cache = os.path.join(tmpdir, 'facts') - last_modified = job.start_job_fact_cache(fact_cache, timeout=0) - - bulk_update = mocker.patch('django.db.models.query.QuerySet.bulk_update') - - os.remove(os.path.join(fact_cache, hosts[1].name)) - job.finish_job_fact_cache(fact_cache, last_modified) - - for host in (hosts[0], hosts[2], hosts[3]): - assert host.ansible_facts == {"a": 1, "b": 2} - assert host.ansible_facts_modified is None - assert hosts[1].ansible_facts == {} - bulk_update.assert_called_once_with([hosts[1]], ['ansible_facts', 'ansible_facts_modified']) diff --git a/awx/main/tests/unit/models/test_label.py b/awx/main/tests/unit/models/test_label.py index e049a8857867..8017782ffa5c 100644 --- a/awx/main/tests/unit/models/test_label.py +++ b/awx/main/tests/unit/models/test_label.py @@ -11,7 +11,6 @@ WorkflowJobNode, ) - mock_query_set = mock.MagicMock() mock_objects = mock.MagicMock(filter=mock.MagicMock(return_value=mock_query_set)) diff --git a/awx/main/tests/unit/models/test_receptor_address.py b/awx/main/tests/unit/models/test_receptor_address.py new file mode 100644 index 000000000000..f18e1a9018a1 --- /dev/null +++ b/awx/main/tests/unit/models/test_receptor_address.py @@ -0,0 +1,32 @@ +from awx.main.models import ReceptorAddress +import pytest + +ReceptorAddress() + + +@pytest.mark.parametrize( + 'address, protocol, port, websocket_path, expected', + [ + ('foo', 'tcp', 27199, '', 'foo:27199'), + ('bar', 'ws', 6789, '', 'wss://bar:6789'), + ('mal', 'ws', 6789, 'path', 'wss://mal:6789/path'), + ('example.com', 'ws', 443, 'path', 'wss://example.com:443/path'), + ], +) +def test_get_full_address(address, protocol, port, websocket_path, expected): + receptor_address = ReceptorAddress(address=address, protocol=protocol, port=port, websocket_path=websocket_path) + assert receptor_address.get_full_address() == expected + + +@pytest.mark.parametrize( + 'protocol, expected', + [ + ('tcp', 'tcp-peer'), + ('ws', 'ws-peer'), + ('wss', 'ws-peer'), + ('foo', None), + ], +) +def test_get_peer_type(protocol, expected): + receptor_address = ReceptorAddress(protocol=protocol) + assert receptor_address.get_peer_type() == expected diff --git a/awx/main/tests/unit/models/test_survey_models.py b/awx/main/tests/unit/models/test_survey_models.py index 57058930eacc..6d9eb5dec999 100644 --- a/awx/main/tests/unit/models/test_survey_models.py +++ b/awx/main/tests/unit/models/test_survey_models.py @@ -18,7 +18,7 @@ def __call__(self, value): @pytest.mark.survey -class SurveyVariableValidation: +class TestSurveyVariableValidation: def test_survey_answers_as_string(self, job_template_factory): objects = job_template_factory('job-template-with-survey', survey=[{'variable': 'var1', 'type': 'text'}], persisted=False) jt = objects.job_template @@ -57,7 +57,7 @@ def test_job_template_survey_variable_validation(self, job_template_factory): accepted, rejected, errors = obj.accept_or_ignore_variables({"a": 5}) assert rejected == {"a": 5} assert accepted == {} - assert str(errors[0]) == "Value 5 for 'a' expected to be a string." + assert str(errors['variables_needed_to_start'][0]) == "Value 5 for 'a' expected to be a string." def test_job_template_survey_default_variable_validation(self, job_template_factory): objects = job_template_factory( @@ -88,7 +88,7 @@ def test_job_template_survey_default_variable_validation(self, job_template_fact obj.survey_enabled = True accepted, _, errors = obj.accept_or_ignore_variables({"a": 2}) - assert accepted == {{"a": 2.0}} + assert accepted == {"a": 2.0} assert not errors @@ -176,22 +176,22 @@ def test_display_survey_spec_encrypts_default(survey_spec_factory): @pytest.mark.survey @pytest.mark.parametrize( - "question_type,default,min,max,expect_use,expect_value", + "question_type,default,min,max,expect_valid,expect_use,expect_value", [ - ("text", "", 0, 0, True, ''), # default used - ("text", "", 1, 0, False, 'N/A'), # value less than min length - ("password", "", 1, 0, False, 'N/A'), # passwords behave the same as text - ("multiplechoice", "", 0, 0, False, 'N/A'), # historical bug - ("multiplechoice", "zeb", 0, 0, False, 'N/A'), # zeb not in choices - ("multiplechoice", "coffee", 0, 0, True, 'coffee'), - ("multiselect", None, 0, 0, False, 'N/A'), # NOTE: Behavior is arguable, value of [] may be prefered - ("multiselect", "", 0, 0, False, 'N/A'), - ("multiselect", ["zeb"], 0, 0, False, 'N/A'), - ("multiselect", ["milk"], 0, 0, True, ["milk"]), - ("multiselect", ["orange\nmilk"], 0, 0, False, 'N/A'), # historical bug + ("text", "", 0, 0, True, False, 'N/A'), # valid but empty default not sent for optional question + ("text", "", 1, 0, False, False, 'N/A'), # value less than min length + ("password", "", 1, 0, False, False, 'N/A'), # passwords behave the same as text + ("multiplechoice", "", 0, 0, False, False, 'N/A'), # historical bug + ("multiplechoice", "zeb", 0, 0, False, False, 'N/A'), # zeb not in choices + ("multiplechoice", "coffee", 0, 0, True, True, 'coffee'), + ("multiselect", None, 0, 0, False, False, 'N/A'), # NOTE: Behavior is arguable, value of [] may be prefered + ("multiselect", "", 0, 0, False, False, 'N/A'), + ("multiselect", ["zeb"], 0, 0, False, False, 'N/A'), + ("multiselect", ["milk"], 0, 0, True, True, ["milk"]), + ("multiselect", ["orange\nmilk"], 0, 0, False, False, 'N/A'), # historical bug ], ) -def test_optional_survey_question_defaults(survey_spec_factory, question_type, default, min, max, expect_use, expect_value): +def test_optional_survey_question_defaults(survey_spec_factory, question_type, default, min, max, expect_valid, expect_use, expect_value): spec = survey_spec_factory( [ { @@ -208,7 +208,7 @@ def test_optional_survey_question_defaults(survey_spec_factory, question_type, d jt = JobTemplate(name="test-jt", survey_spec=spec, survey_enabled=True) defaulted_extra_vars = jt._update_unified_job_kwargs({}, {}) element = spec['spec'][0] - if expect_use: + if expect_valid: assert jt._survey_element_validation(element, {element['variable']: element['default']}) == [] else: assert jt._survey_element_validation(element, {element['variable']: element['default']}) @@ -218,6 +218,28 @@ def test_optional_survey_question_defaults(survey_spec_factory, question_type, d assert 'c' not in defaulted_extra_vars['extra_vars'] +@pytest.mark.survey +def test_optional_survey_empty_default_with_runtime_extra_var(survey_spec_factory): + """When a user explicitly provides an empty string at runtime for an optional + survey question, the variable should still be included in extra_vars.""" + spec = survey_spec_factory( + [ + { + "required": False, + "default": "", + "choices": "", + "variable": "c", + "min": 0, + "max": 0, + "type": "text", + }, + ] + ) + jt = JobTemplate(name="test-jt", survey_spec=spec, survey_enabled=True) + defaulted_extra_vars = jt._update_unified_job_kwargs({}, {'extra_vars': json.dumps({'c': ''})}) + assert json.loads(defaulted_extra_vars['extra_vars'])['c'] == '' + + @pytest.mark.survey @pytest.mark.parametrize( "question_type,default,maxlen,kwargs,expected", diff --git a/awx/main/tests/unit/models/test_unified_job_unit.py b/awx/main/tests/unit/models/test_unified_job_unit.py index c7f62225c8e1..2fa8807dff74 100644 --- a/awx/main/tests/unit/models/test_unified_job_unit.py +++ b/awx/main/tests/unit/models/test_unified_job_unit.py @@ -1,4 +1,3 @@ -import pytest from unittest import mock from awx.main.models import UnifiedJob, UnifiedJobTemplate, WorkflowJob, WorkflowJobNode, WorkflowApprovalTemplate, Job, User, Project, JobTemplate, Inventory @@ -22,52 +21,6 @@ def test_unified_job_workflow_attributes(): assert job.workflow_job_id == 1 -def mock_on_commit(f): - f() - - -@pytest.fixture -def unified_job(mocker): - mocker.patch.object(UnifiedJob, 'can_cancel', return_value=True) - j = UnifiedJob() - j.status = 'pending' - j.cancel_flag = None - j.save = mocker.MagicMock() - j.websocket_emit_status = mocker.MagicMock() - j.fallback_cancel = mocker.MagicMock() - return j - - -def test_cancel(unified_job): - with mock.patch('awx.main.models.unified_jobs.connection.on_commit', wraps=mock_on_commit): - unified_job.cancel() - - assert unified_job.cancel_flag is True - assert unified_job.status == 'canceled' - assert unified_job.job_explanation == '' - # Note: the websocket emit status check is just reflecting the state of the current code. - # Some more thought may want to go into only emitting canceled if/when the job record - # status is changed to canceled. Unlike, currently, where it's emitted unconditionally. - unified_job.websocket_emit_status.assert_called_with("canceled") - assert [(args, kwargs) for args, kwargs in unified_job.save.call_args_list] == [ - ((), {'update_fields': ['cancel_flag', 'start_args']}), - ((), {'update_fields': ['status']}), - ] - - -def test_cancel_job_explanation(unified_job): - job_explanation = 'giggity giggity' - - with mock.patch('awx.main.models.unified_jobs.connection.on_commit'): - unified_job.cancel(job_explanation=job_explanation) - - assert unified_job.job_explanation == job_explanation - assert [(args, kwargs) for args, kwargs in unified_job.save.call_args_list] == [ - ((), {'update_fields': ['cancel_flag', 'start_args', 'job_explanation']}), - ((), {'update_fields': ['status']}), - ] - - def test_organization_copy_to_jobs(): """ All unified job types should infer their organization from their template organization @@ -107,7 +60,11 @@ def test_job_metavars(self): result_hash['{}_user_id'.format(name)] = 47 result_hash['{}_inventory_id'.format(name)] = 45 result_hash['{}_inventory_name'.format(name)] = 'example-inv' - assert Job(name='fake-job', pk=42, id=42, launch_type='manual', created_by=maker, inventory=inv).awx_meta_vars() == result_hash + result_hash['{}_execution_node'.format(name)] = 'example-exec-node' + assert ( + Job(name='fake-job', pk=42, id=42, launch_type='manual', created_by=maker, inventory=inv, execution_node='example-exec-node').awx_meta_vars() + == result_hash + ) def test_project_update_metavars(self): data = Job( diff --git a/awx/main/tests/unit/models/test_workflow_unit.py b/awx/main/tests/unit/models/test_workflow_unit.py index dc01c3301f6d..7ac2009403de 100644 --- a/awx/main/tests/unit/models/test_workflow_unit.py +++ b/awx/main/tests/unit/models/test_workflow_unit.py @@ -155,35 +155,35 @@ def test_node_getter_and_setters(): class TestWorkflowJobCreate: def test_create_no_prompts(self, wfjt_node_no_prompts, workflow_job_unit, mocker): mock_create = mocker.MagicMock() - with mocker.patch('awx.main.models.WorkflowJobNode.objects.create', mock_create): - wfjt_node_no_prompts.create_workflow_job_node(workflow_job=workflow_job_unit) - mock_create.assert_called_once_with( - all_parents_must_converge=False, - extra_data={}, - survey_passwords={}, - char_prompts=wfjt_node_no_prompts.char_prompts, - inventory=None, - unified_job_template=wfjt_node_no_prompts.unified_job_template, - workflow_job=workflow_job_unit, - identifier=mocker.ANY, - execution_environment=None, - ) + mocker.patch('awx.main.models.WorkflowJobNode.objects.create', mock_create) + wfjt_node_no_prompts.create_workflow_job_node(workflow_job=workflow_job_unit) + mock_create.assert_called_once_with( + all_parents_must_converge=False, + extra_data={}, + survey_passwords={}, + char_prompts=wfjt_node_no_prompts.char_prompts, + inventory=None, + unified_job_template=wfjt_node_no_prompts.unified_job_template, + workflow_job=workflow_job_unit, + identifier=mocker.ANY, + execution_environment=None, + ) def test_create_with_prompts(self, wfjt_node_with_prompts, workflow_job_unit, credential, mocker): mock_create = mocker.MagicMock() - with mocker.patch('awx.main.models.WorkflowJobNode.objects.create', mock_create): - wfjt_node_with_prompts.create_workflow_job_node(workflow_job=workflow_job_unit) - mock_create.assert_called_once_with( - all_parents_must_converge=False, - extra_data={}, - survey_passwords={}, - char_prompts=wfjt_node_with_prompts.char_prompts, - inventory=wfjt_node_with_prompts.inventory, - unified_job_template=wfjt_node_with_prompts.unified_job_template, - workflow_job=workflow_job_unit, - identifier=mocker.ANY, - execution_environment=None, - ) + mocker.patch('awx.main.models.WorkflowJobNode.objects.create', mock_create) + wfjt_node_with_prompts.create_workflow_job_node(workflow_job=workflow_job_unit) + mock_create.assert_called_once_with( + all_parents_must_converge=False, + extra_data={}, + survey_passwords={}, + char_prompts=wfjt_node_with_prompts.char_prompts, + inventory=wfjt_node_with_prompts.inventory, + unified_job_template=wfjt_node_with_prompts.unified_job_template, + workflow_job=workflow_job_unit, + identifier=mocker.ANY, + execution_environment=None, + ) @pytest.mark.django_db diff --git a/awx/main/tests/unit/notifications/test_awssns.py b/awx/main/tests/unit/notifications/test_awssns.py new file mode 100644 index 000000000000..0d18821fe3e3 --- /dev/null +++ b/awx/main/tests/unit/notifications/test_awssns.py @@ -0,0 +1,26 @@ +from unittest import mock +from django.core.mail.message import EmailMessage + +import awx.main.notifications.awssns_backend as awssns_backend + + +def test_send_messages(): + with mock.patch('awx.main.notifications.awssns_backend.AWSSNSBackend._sns_publish') as sns_publish_mock: + aws_region = 'us-east-1' + sns_topic = f"arn:aws:sns:{aws_region}:111111111111:topic-mock" + backend = awssns_backend.AWSSNSBackend(aws_region=aws_region, aws_access_key_id=None, aws_secret_access_key=None, aws_session_token=None) + message = EmailMessage( + 'test subject', + {'body': 'test body'}, + [], + [ + sns_topic, + ], + ) + sent_messages = backend.send_messages( + [ + message, + ] + ) + sns_publish_mock.assert_called_once_with(topic_arn=sns_topic, message=message.body) + assert sent_messages == 1 diff --git a/awx/main/tests/unit/notifications/test_grafana.py b/awx/main/tests/unit/notifications/test_grafana.py index 70750e33150b..d4b9c31aa2d3 100644 --- a/awx/main/tests/unit/notifications/test_grafana.py +++ b/awx/main/tests/unit/notifications/test_grafana.py @@ -13,7 +13,7 @@ def test_send_messages(): m['started'] = dt.datetime.utcfromtimestamp(60).isoformat() m['finished'] = dt.datetime.utcfromtimestamp(120).isoformat() m['subject'] = "test subject" - backend = grafana_backend.GrafanaBackend("testapikey") + backend = grafana_backend.GrafanaBackend("testapikey", dashboardId='', panelId='') message = EmailMessage( m['subject'], {"started": m['started'], "finished": m['finished']}, @@ -43,7 +43,7 @@ def test_send_messages_with_no_verify_ssl(): m['started'] = dt.datetime.utcfromtimestamp(60).isoformat() m['finished'] = dt.datetime.utcfromtimestamp(120).isoformat() m['subject'] = "test subject" - backend = grafana_backend.GrafanaBackend("testapikey", grafana_no_verify_ssl=True) + backend = grafana_backend.GrafanaBackend("testapikey", dashboardId='', panelId='', grafana_no_verify_ssl=True) message = EmailMessage( m['subject'], {"started": m['started'], "finished": m['finished']}, @@ -74,7 +74,7 @@ def test_send_messages_with_dashboardid(dashboardId): m['started'] = dt.datetime.utcfromtimestamp(60).isoformat() m['finished'] = dt.datetime.utcfromtimestamp(120).isoformat() m['subject'] = "test subject" - backend = grafana_backend.GrafanaBackend("testapikey", dashboardId=dashboardId) + backend = grafana_backend.GrafanaBackend("testapikey", dashboardId=dashboardId, panelId='') message = EmailMessage( m['subject'], {"started": m['started'], "finished": m['finished']}, @@ -97,7 +97,7 @@ def test_send_messages_with_dashboardid(dashboardId): assert sent_messages == 1 -@pytest.mark.parametrize("panelId", [42, 0]) +@pytest.mark.parametrize("panelId", ['42', '0']) def test_send_messages_with_panelid(panelId): with mock.patch('awx.main.notifications.grafana_backend.requests') as requests_mock: requests_mock.post.return_value.status_code = 200 @@ -105,7 +105,7 @@ def test_send_messages_with_panelid(panelId): m['started'] = dt.datetime.utcfromtimestamp(60).isoformat() m['finished'] = dt.datetime.utcfromtimestamp(120).isoformat() m['subject'] = "test subject" - backend = grafana_backend.GrafanaBackend("testapikey", dashboardId=None, panelId=panelId) + backend = grafana_backend.GrafanaBackend("testapikey", dashboardId='', panelId=panelId) message = EmailMessage( m['subject'], {"started": m['started'], "finished": m['finished']}, @@ -122,7 +122,7 @@ def test_send_messages_with_panelid(panelId): requests_mock.post.assert_called_once_with( 'https://example.com/api/annotations', headers={'Content-Type': 'application/json', 'Authorization': 'Bearer testapikey'}, - json={'text': 'test subject', 'isRegion': True, 'timeEnd': 120000, 'panelId': panelId, 'time': 60000}, + json={'text': 'test subject', 'isRegion': True, 'timeEnd': 120000, 'panelId': int(panelId), 'time': 60000}, verify=True, ) assert sent_messages == 1 @@ -135,7 +135,7 @@ def test_send_messages_with_bothids(): m['started'] = dt.datetime.utcfromtimestamp(60).isoformat() m['finished'] = dt.datetime.utcfromtimestamp(120).isoformat() m['subject'] = "test subject" - backend = grafana_backend.GrafanaBackend("testapikey", dashboardId=42, panelId=42) + backend = grafana_backend.GrafanaBackend("testapikey", dashboardId='42', panelId='42') message = EmailMessage( m['subject'], {"started": m['started'], "finished": m['finished']}, @@ -158,6 +158,36 @@ def test_send_messages_with_bothids(): assert sent_messages == 1 +def test_send_messages_with_emptyids(): + with mock.patch('awx.main.notifications.grafana_backend.requests') as requests_mock: + requests_mock.post.return_value.status_code = 200 + m = {} + m['started'] = dt.datetime.utcfromtimestamp(60).isoformat() + m['finished'] = dt.datetime.utcfromtimestamp(120).isoformat() + m['subject'] = "test subject" + backend = grafana_backend.GrafanaBackend("testapikey", dashboardId='', panelId='') + message = EmailMessage( + m['subject'], + {"started": m['started'], "finished": m['finished']}, + [], + [ + 'https://example.com', + ], + ) + sent_messages = backend.send_messages( + [ + message, + ] + ) + requests_mock.post.assert_called_once_with( + 'https://example.com/api/annotations', + headers={'Content-Type': 'application/json', 'Authorization': 'Bearer testapikey'}, + json={'text': 'test subject', 'isRegion': True, 'timeEnd': 120000, 'time': 60000}, + verify=True, + ) + assert sent_messages == 1 + + def test_send_messages_with_tags(): with mock.patch('awx.main.notifications.grafana_backend.requests') as requests_mock: requests_mock.post.return_value.status_code = 200 @@ -165,7 +195,7 @@ def test_send_messages_with_tags(): m['started'] = dt.datetime.utcfromtimestamp(60).isoformat() m['finished'] = dt.datetime.utcfromtimestamp(120).isoformat() m['subject'] = "test subject" - backend = grafana_backend.GrafanaBackend("testapikey", dashboardId=None, panelId=None, annotation_tags=["ansible"]) + backend = grafana_backend.GrafanaBackend("testapikey", dashboardId='', panelId='', annotation_tags=["ansible"]) message = EmailMessage( m['subject'], {"started": m['started'], "finished": m['finished']}, diff --git a/awx/main/tests/unit/notifications/test_webhook.py b/awx/main/tests/unit/notifications/test_webhook.py index b2c92c59ab39..4abbf45b70ee 100644 --- a/awx/main/tests/unit/notifications/test_webhook.py +++ b/awx/main/tests/unit/notifications/test_webhook.py @@ -226,3 +226,140 @@ def test_send_messages_with_additional_headers(): allow_redirects=False, ) assert sent_messages == 1 + + +def test_send_messages_with_redirects_ok(): + with mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, mock.patch( + 'awx.main.notifications.webhook_backend.get_awx_http_client_headers' + ) as version_mock: + # First two calls return redirects, third call returns 200 + requests_mock.post.side_effect = [ + mock.Mock(status_code=301, headers={"Location": "http://redirect1.com"}), + mock.Mock(status_code=307, headers={"Location": "http://redirect2.com"}), + mock.Mock(status_code=200), + ] + version_mock.return_value = {'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'} + backend = webhook_backend.WebhookBackend('POST', None) + message = EmailMessage( + 'test subject', + {'text': 'test body'}, + [], + [ + 'http://example.com', + ], + ) + sent_messages = backend.send_messages( + [ + message, + ] + ) + assert requests_mock.post.call_count == 3 + requests_mock.post.assert_called_with( + url='http://redirect2.com', + auth=None, + data=json.dumps({'text': 'test body'}, ensure_ascii=False).encode('utf-8'), + headers={'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'}, + verify=True, + allow_redirects=False, + ) + assert sent_messages == 1 + + +def test_send_messages_with_redirects_blank(): + with mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, mock.patch( + 'awx.main.notifications.webhook_backend.get_awx_http_client_headers' + ) as version_mock, mock.patch('awx.main.notifications.webhook_backend.logger') as logger_mock: + # First call returns a redirect with Location header, second call returns 301 but NO Location header + requests_mock.post.side_effect = [ + mock.Mock(status_code=301, headers={"Location": "http://redirect1.com"}), + mock.Mock(status_code=301, headers={}), # 301 with no Location header + ] + version_mock.return_value = {'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'} + backend = webhook_backend.WebhookBackend('POST', None, fail_silently=True) + message = EmailMessage( + 'test subject', + {'text': 'test body'}, + [], + [ + 'http://example.com', + ], + ) + sent_messages = backend.send_messages( + [ + message, + ] + ) + # Should make 2 requests (initial + 1 redirect attempt) + assert requests_mock.post.call_count == 2 + # The error message should be logged + logger_mock.error.assert_called_once() + error_call_args = logger_mock.error.call_args[0][0] + assert "redirect to a blank URL" in error_call_args + assert sent_messages == 0 + + +def test_send_messages_with_redirects_max_retries_exceeded(): + with mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, mock.patch( + 'awx.main.notifications.webhook_backend.get_awx_http_client_headers' + ) as version_mock, mock.patch('awx.main.notifications.webhook_backend.logger') as logger_mock: + # Return MAX_RETRIES (5) redirect responses to exceed the retry limit + requests_mock.post.side_effect = [ + mock.Mock(status_code=301, headers={"Location": "http://redirect1.com"}), + mock.Mock(status_code=301, headers={"Location": "http://redirect2.com"}), + mock.Mock(status_code=307, headers={"Location": "http://redirect3.com"}), + mock.Mock(status_code=301, headers={"Location": "http://redirect4.com"}), + mock.Mock(status_code=307, headers={"Location": "http://redirect5.com"}), + ] + version_mock.return_value = {'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'} + backend = webhook_backend.WebhookBackend('POST', None, fail_silently=True) + message = EmailMessage( + 'test subject', + {'text': 'test body'}, + [], + [ + 'http://example.com', + ], + ) + sent_messages = backend.send_messages( + [ + message, + ] + ) + # Should make exactly 5 requests (MAX_RETRIES) + assert requests_mock.post.call_count == 5 + # The error message should be logged for exceeding max retries + logger_mock.error.assert_called_once() + error_call_args = logger_mock.error.call_args[0][0] + assert "max number of retries" in error_call_args + assert "[5]" in error_call_args + assert sent_messages == 0 + + +def test_send_messages_with_error_status_code(): + with mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, mock.patch( + 'awx.main.notifications.webhook_backend.get_awx_http_client_headers' + ) as version_mock, mock.patch('awx.main.notifications.webhook_backend.logger') as logger_mock: + # Return a 404 error status code + requests_mock.post.return_value = mock.Mock(status_code=404) + version_mock.return_value = {'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'} + backend = webhook_backend.WebhookBackend('POST', None, fail_silently=True) + message = EmailMessage( + 'test subject', + {'text': 'test body'}, + [], + [ + 'http://example.com', + ], + ) + sent_messages = backend.send_messages( + [ + message, + ] + ) + # Should make exactly 1 request + assert requests_mock.post.call_count == 1 + # The error message should be logged + logger_mock.error.assert_called_once() + error_call_args = logger_mock.error.call_args[0][0] + assert "Error sending webhook notification: 404" in error_call_args + assert sent_messages == 0 diff --git a/awx/main/tests/unit/scheduler/test_dag_simple.py b/awx/main/tests/unit/scheduler/test_dag_simple.py index 4bb141815754..1cea21e92d27 100644 --- a/awx/main/tests/unit/scheduler/test_dag_simple.py +++ b/awx/main/tests/unit/scheduler/test_dag_simple.py @@ -39,6 +39,6 @@ def simple_cycle_1(node_generator): def test_has_cycle(simple_cycle_1): - (g, nodes) = simple_cycle_1 + g, nodes = simple_cycle_1 assert g.has_cycle() is True diff --git a/awx/main/tests/unit/scheduler/test_dag_workflow.py b/awx/main/tests/unit/scheduler/test_dag_workflow.py index a3225b76a3e7..b4681e6b90a8 100644 --- a/awx/main/tests/unit/scheduler/test_dag_workflow.py +++ b/awx/main/tests/unit/scheduler/test_dag_workflow.py @@ -86,13 +86,13 @@ def workflow_dag_root_children(self, wf_node_generator): return (g, wf_root_nodes, wf_leaf_nodes) def test_get_root_nodes(self, workflow_dag_root_children): - (g, wf_root_nodes, ignore) = workflow_dag_root_children + g, wf_root_nodes, ignore = workflow_dag_root_children assert set([n.id for n in wf_root_nodes]) == set([n['node_object'].id for n in g.get_root_nodes()]) class TestDNR: def test_mark_dnr_nodes(self, workflow_dag_1): - (g, nodes) = workflow_dag_1 + g, nodes = workflow_dag_1 r''' 0 @@ -166,7 +166,7 @@ def simple_all_convergence(self, wf_node_generator): return (g, nodes) def test_simple_all_convergence(self, simple_all_convergence): - (g, nodes) = simple_all_convergence + g, nodes = simple_all_convergence dnr_nodes = g.mark_dnr_nodes() assert 0 == len(dnr_nodes), "no nodes should be marked DNR" @@ -197,7 +197,7 @@ def workflow_all_converge_1(self, wf_node_generator): return (g, nodes) def test_all_converge_edge_case_1(self, workflow_all_converge_1): - (g, nodes) = workflow_all_converge_1 + g, nodes = workflow_all_converge_1 dnr_nodes = g.mark_dnr_nodes() assert 2 == len(dnr_nodes), "node[1] and node[2] should be marked DNR" assert nodes[1] == dnr_nodes[0], "Node 1 should be marked DNR" @@ -233,7 +233,7 @@ def workflow_all_converge_2(self, wf_node_generator): return (g, nodes) def test_all_converge_edge_case_2(self, workflow_all_converge_2): - (g, nodes) = workflow_all_converge_2 + g, nodes = workflow_all_converge_2 dnr_nodes = g.mark_dnr_nodes() assert 1 == len(dnr_nodes), "1 and only 1 node should be marked DNR" assert nodes[2] == dnr_nodes[0], "Node 3 should be marked DNR" @@ -268,7 +268,7 @@ def workflow_all_converge_will_run(self, wf_node_generator): return (g, nodes) def test_workflow_all_converge_will_run(self, workflow_all_converge_will_run): - (g, nodes) = workflow_all_converge_will_run + g, nodes = workflow_all_converge_will_run dnr_nodes = g.mark_dnr_nodes() assert 0 == len(dnr_nodes), "No nodes should get marked DNR" @@ -306,7 +306,7 @@ def workflow_all_converge_dnr(self, wf_node_generator): return (g, nodes) def test_workflow_all_converge_while_parent_runs(self, workflow_all_converge_dnr): - (g, nodes) = workflow_all_converge_dnr + g, nodes = workflow_all_converge_dnr dnr_nodes = g.mark_dnr_nodes() assert 0 == len(dnr_nodes), "No nodes should get marked DNR" @@ -315,7 +315,7 @@ def test_workflow_all_converge_while_parent_runs(self, workflow_all_converge_dnr def test_workflow_all_converge_with_incorrect_parent(self, workflow_all_converge_dnr): # Another tick of the scheduler - (g, nodes) = workflow_all_converge_dnr + g, nodes = workflow_all_converge_dnr nodes[1].job.status = 'successful' dnr_nodes = g.mark_dnr_nodes() assert 1 == len(dnr_nodes), "1 and only 1 node should be marked DNR" @@ -326,7 +326,7 @@ def test_workflow_all_converge_with_incorrect_parent(self, workflow_all_converge def test_workflow_all_converge_runs(self, workflow_all_converge_dnr): # Trick the scheduler again to make sure the convergence node acutally runs - (g, nodes) = workflow_all_converge_dnr + g, nodes = workflow_all_converge_dnr nodes[1].job.status = 'failed' dnr_nodes = g.mark_dnr_nodes() assert 0 == len(dnr_nodes), "No nodes should be marked DNR" @@ -375,7 +375,7 @@ def workflow_all_converge_deep_dnr_tree(self, wf_node_generator): return (g, nodes) def test_workflow_all_converge_deep_dnr_tree(self, workflow_all_converge_deep_dnr_tree): - (g, nodes) = workflow_all_converge_deep_dnr_tree + g, nodes = workflow_all_converge_deep_dnr_tree dnr_nodes = g.mark_dnr_nodes() assert 4 == len(dnr_nodes), "All nodes w/ no jobs should be marked DNR" @@ -391,7 +391,7 @@ def test_workflow_all_converge_deep_dnr_tree(self, workflow_all_converge_deep_dn class TestIsWorkflowDone: @pytest.fixture def workflow_dag_2(self, workflow_dag_1): - (g, nodes) = workflow_dag_1 + g, nodes = workflow_dag_1 r''' S0 /\ @@ -416,7 +416,7 @@ def workflow_dag_2(self, workflow_dag_1): @pytest.fixture def workflow_dag_failed(self, workflow_dag_1): - (g, nodes) = workflow_dag_1 + g, nodes = workflow_dag_1 r''' S0 /\ @@ -453,7 +453,7 @@ def workflow_dag_canceled(self, wf_node_generator): @pytest.fixture def workflow_dag_failure(self, workflow_dag_canceled): - (g, nodes) = workflow_dag_canceled + g, nodes = workflow_dag_canceled nodes[0].job.status = 'failed' return (g, nodes) @@ -463,7 +463,7 @@ def test_done(self, workflow_dag_2): assert g.is_workflow_done() is False def test_workflow_done_and_failed(self, workflow_dag_failed): - (g, nodes) = workflow_dag_failed + g, nodes = workflow_dag_failed assert g.is_workflow_done() is True assert g.has_workflow_failed() == ( @@ -477,7 +477,7 @@ def test_workflow_done_and_failed(self, workflow_dag_failed): ) def test_is_workflow_done_no_unified_job_tempalte_end(self, workflow_dag_failed): - (g, nodes) = workflow_dag_failed + g, nodes = workflow_dag_failed nodes[2].unified_job_template = None @@ -492,7 +492,7 @@ def test_is_workflow_done_no_unified_job_tempalte_end(self, workflow_dag_failed) ) def test_is_workflow_done_no_unified_job_tempalte_begin(self, workflow_dag_1): - (g, nodes) = workflow_dag_1 + g, nodes = workflow_dag_1 nodes[0].unified_job_template = None g.mark_dnr_nodes() @@ -508,7 +508,7 @@ def test_is_workflow_done_no_unified_job_tempalte_begin(self, workflow_dag_1): ) def test_canceled_should_fail(self, workflow_dag_canceled): - (g, nodes) = workflow_dag_canceled + g, nodes = workflow_dag_canceled assert g.has_workflow_failed() == ( True, @@ -521,7 +521,7 @@ def test_canceled_should_fail(self, workflow_dag_canceled): ) def test_failure_should_fail(self, workflow_dag_failure): - (g, nodes) = workflow_dag_failure + g, nodes = workflow_dag_failure assert g.has_workflow_failed() == ( True, @@ -555,13 +555,13 @@ def workflow_dag_canceled(self, wf_node_generator): return (g, nodes) def test_cancel_still_runs_children(self, workflow_dag_canceled): - (g, nodes) = workflow_dag_canceled + g, nodes = workflow_dag_canceled g.mark_dnr_nodes() assert set([nodes[1], nodes[2]]) == set(g.bfs_nodes_to_run()) -@pytest.mark.skip(reason="Run manually to re-generate doc images") +@pytest.mark.xfail(reason="Run manually to re-generate doc images") class TestDocsExample: @pytest.fixture def complex_dag(self, wf_node_generator): @@ -587,7 +587,7 @@ def complex_dag(self, wf_node_generator): return (g, nodes) def test_dnr_step(self, complex_dag): - (g, nodes) = complex_dag + g, nodes = complex_dag base_dir = '/awx_devel' g.generate_graphviz_plot(file_name=os.path.join(base_dir, "workflow_step0.gv")) diff --git a/awx/main/tests/unit/settings/test_defaults.py b/awx/main/tests/unit/settings/test_defaults.py index a7f5eeeca8db..10cb5561a7f4 100644 --- a/awx/main/tests/unit/settings/test_defaults.py +++ b/awx/main/tests/unit/settings/test_defaults.py @@ -1,20 +1,19 @@ import pytest from django.conf import settings -from datetime import timedelta @pytest.mark.parametrize( - "job_name,function_path", + "task_name", [ - ('tower_scheduler', 'awx.main.tasks.system.awx_periodic_scheduler'), + 'awx.main.tasks.system.awx_periodic_scheduler', ], ) -def test_CELERYBEAT_SCHEDULE(mocker, job_name, function_path): - assert job_name in settings.CELERYBEAT_SCHEDULE - assert 'schedule' in settings.CELERYBEAT_SCHEDULE[job_name] - assert type(settings.CELERYBEAT_SCHEDULE[job_name]['schedule']) is timedelta - assert settings.CELERYBEAT_SCHEDULE[job_name]['task'] == function_path +def test_DISPATCHER_SCHEDULE(mocker, task_name): + assert task_name in settings.DISPATCHER_SCHEDULE + assert 'schedule' in settings.DISPATCHER_SCHEDULE[task_name] + assert type(settings.DISPATCHER_SCHEDULE[task_name]['schedule']) in (int, float) + assert settings.DISPATCHER_SCHEDULE[task_name]['task'] == task_name # Ensures that the function exists - mocker.patch(function_path) + mocker.patch(task_name) diff --git a/awx/main/tests/unit/settings/test_k8s_resource_setttings.py b/awx/main/tests/unit/settings/test_k8s_resource_setttings.py index a2899a8561fe..65fa45d95a10 100644 --- a/awx/main/tests/unit/settings/test_k8s_resource_setttings.py +++ b/awx/main/tests/unit/settings/test_k8s_resource_setttings.py @@ -36,7 +36,9 @@ def test_SYSTEM_TASK_ABS_MEM_conversion(value, converted_value, mem_capacity): mock_settings.IS_K8S = True assert convert_mem_str_to_bytes(value) == converted_value assert get_corrected_memory(-1) == converted_value - assert get_mem_effective_capacity(-1) == mem_capacity + assert get_mem_effective_capacity(1, is_control_node=True) == mem_capacity + # SYSTEM_TASK_ABS_MEM should not effect memory and capacity for execution nodes + assert get_mem_effective_capacity(2147483648, is_control_node=False) == 20 @pytest.mark.parametrize( @@ -58,4 +60,6 @@ def test_SYSTEM_TASK_ABS_CPU_conversion(value, converted_value, cpu_capacity): mock_settings.SYSTEM_TASK_FORKS_CPU = 4 assert convert_cpu_str_to_decimal_cpu(value) == converted_value assert get_corrected_cpu(-1) == converted_value - assert get_cpu_effective_capacity(-1) == cpu_capacity + assert get_cpu_effective_capacity(-1, is_control_node=True) == cpu_capacity + # SYSTEM_TASK_ABS_CPU should not effect cpu count and capacity for execution nodes + assert get_cpu_effective_capacity(2.0, is_control_node=False) == 8 diff --git a/awx/main/tests/unit/tasks/test_host_indirect_unit.py b/awx/main/tests/unit/tasks/test_host_indirect_unit.py new file mode 100644 index 000000000000..2b128ca6fafe --- /dev/null +++ b/awx/main/tests/unit/tasks/test_host_indirect_unit.py @@ -0,0 +1,56 @@ +import copy + +import pytest + +from awx.main.tasks.host_indirect import get_hashable_form + + +class TestHashableForm: + @pytest.mark.parametrize( + 'data', + [ + {'a': 'b'}, + ['a', 'b'], + ('a', 'b'), + {'a': {'b': 'c'}}, + {'a': ['b', 'c']}, + {'a': ('b', 'c')}, + ['a', ['b', 'c']], + ['a', ('b', 'c')], + ['a', {'b': 'c'}], + ], + ) + def test_compare_equal_data(self, data): + other_data = copy.deepcopy(data) + # A tuple of scalars may be cached so ids could legitimately be the same + if data != ('a', 'b'): + assert id(data) != id(other_data) # sanity + assert id(get_hashable_form(data)) != id(get_hashable_form(data)) + + assert get_hashable_form(data) == get_hashable_form(data) + assert hash(get_hashable_form(data)) == hash(get_hashable_form(data)) + + assert get_hashable_form(data) in {get_hashable_form(data): 1} # test lookup hit + + @pytest.mark.parametrize( + 'data, other_data', + [ + [{'a': 'b'}, {'a': 'c'}], + [{'a': 'b'}, {'a': 'b', 'c': 'd'}], + [['a', 'b'], ['a', 'c']], + [('a', 'b'), ('a', 'c')], + [{'a': {'b': 'c'}}, {'a': {'b': 'd'}}], + [{'a': ['b', 'c']}, {'a': ['b', 'd']}], + [{'a': ('b', 'c')}, {'a': ('b', 'd')}], + [['a', ['b', 'c']], ['a', ['b', 'd']]], + [['a', ('b', 'c')], ['a', ('b', 'd')]], + [['a', {'b': 'c'}], ['a', {'b': 'd'}]], + ], + ) + def test_compare_different_data(self, data, other_data): + assert data != other_data # sanity, otherwise why test this? + assert get_hashable_form(data) != get_hashable_form(other_data) + assert hash(get_hashable_form(data)) != hash(get_hashable_form(other_data)) + + assert get_hashable_form(other_data) not in {get_hashable_form(data): 1} # test lookup miss + assert get_hashable_form(data) not in {get_hashable_form(other_data): 1} diff --git a/awx/main/tests/unit/tasks/test_jobs.py b/awx/main/tests/unit/tasks/test_jobs.py new file mode 100644 index 000000000000..b678add12d1e --- /dev/null +++ b/awx/main/tests/unit/tasks/test_jobs.py @@ -0,0 +1,485 @@ +# -*- coding: utf-8 -*- +import os +import tempfile +import shutil + +import pytest +from unittest import mock + +from awx.main.models import ( + Inventory, + Host, +) + +from django.utils.timezone import now +from django.db.models.query import QuerySet + +from awx.main.models import ( + Job, + Organization, + Project, + JobTemplate, + UnifiedJobTemplate, + InstanceGroup, + ExecutionEnvironment, + ProjectUpdate, + InventoryUpdate, + InventorySource, + AdHocCommand, +) +from awx.main.tasks import jobs +from ansible_base.lib.workload_identity.controller import AutomationControllerJobScope + + +@pytest.fixture +def private_data_dir(): + private_data = tempfile.mkdtemp(prefix='awx_') + for subfolder in ('inventory', 'env'): + runner_subfolder = os.path.join(private_data, subfolder) + os.makedirs(runner_subfolder, exist_ok=True) + yield private_data + shutil.rmtree(private_data, True) + + +@mock.patch('awx.main.tasks.facts.settings') +@mock.patch('awx.main.tasks.jobs.create_partition', return_value=True) +def test_pre_post_run_hook_facts(mock_create_partition, mock_facts_settings, private_data_dir, execution_environment): + # Create mocked inventory and host queryset + inventory = mock.MagicMock(spec=Inventory, pk=1) + host1 = mock.MagicMock(spec=Host, id=1, name='host1', ansible_facts={"a": 1, "b": 2}, ansible_facts_modified=now(), inventory=inventory) + host2 = mock.MagicMock(spec=Host, id=2, name='host2', ansible_facts={"a": 1, "b": 2}, ansible_facts_modified=now(), inventory=inventory) + + # Mock hosts queryset + hosts = [host1, host2] + qs_hosts = mock.MagicMock(spec=QuerySet) + qs_hosts._result_cache = hosts + qs_hosts.only.return_value = hosts + qs_hosts.count.side_effect = lambda: len(qs_hosts._result_cache) + inventory.hosts = qs_hosts + + # Create mocked job object + org = mock.MagicMock(spec=Organization, pk=1) + proj = mock.MagicMock(spec=Project, pk=1, organization=org) + job = mock.MagicMock( + spec=Job, + use_fact_cache=True, + project=proj, + organization=org, + job_slice_number=1, + job_slice_count=1, + inventory=inventory, + execution_environment=execution_environment, + ) + job.get_hosts_for_fact_cache = Job.get_hosts_for_fact_cache.__get__(job) + job.job_env.get = mock.MagicMock(return_value=private_data_dir) + + # Mock RunJob task + mock_facts_settings.ANSIBLE_FACT_CACHE_TIMEOUT = False + task = jobs.RunJob() + task.instance = job + task.update_model = mock.Mock(return_value=job) + task.model.objects.get = mock.Mock(return_value=job) + + # Run pre_run_hook + task.facts_write_time = task.pre_run_hook(job, private_data_dir) + + # Add a third mocked host + host3 = mock.MagicMock(spec=Host, id=3, name='host3', ansible_facts={"added": True}, ansible_facts_modified=now(), inventory=inventory) + qs_hosts._result_cache.append(host3) + assert inventory.hosts.count() == 3 + + # Run post_run_hook + task.runner_callback.artifacts_processed = mock.MagicMock(return_value=True) + task.post_run_hook(job, "success") + + # Verify final host facts + assert qs_hosts._result_cache[2].ansible_facts == {"added": True} + + +@mock.patch('awx.main.tasks.facts.bulk_update_sorted_by_id') +@mock.patch('awx.main.tasks.facts.settings') +@mock.patch('awx.main.tasks.jobs.create_partition', return_value=True) +def test_pre_post_run_hook_facts_deleted_sliced(mock_create_partition, mock_facts_settings, private_data_dir, execution_environment): + # Fully mocked inventory + mock_inventory = mock.MagicMock(spec=Inventory) + + # Create 999 mocked Host instances + hosts = [] + for i in range(999): + host = mock.MagicMock(spec=Host) + host.id = i + host.name = f'host{i}' + host.ansible_facts = {"a": 1, "b": 2} + host.ansible_facts_modified = now() + host.inventory = mock_inventory + hosts.append(host) + + # Mock inventory.hosts behavior + mock_qs_hosts = mock.MagicMock() + mock_qs_hosts.only.return_value = hosts + mock_qs_hosts.count.return_value = 999 + mock_inventory.hosts = mock_qs_hosts + + # Mock Organization and Project + org = mock.MagicMock(spec=Organization) + proj = mock.MagicMock(spec=Project) + proj.organization = org + + # Mock job object + job = mock.MagicMock(spec=Job) + job.use_fact_cache = True + job.project = proj + job.organization = org + job.job_slice_number = 1 + job.job_slice_count = 3 + job.execution_environment = execution_environment + job.inventory = mock_inventory + job.job_env.get.return_value = private_data_dir + + # Bind actual method for host filtering + job.get_hosts_for_fact_cache = Job.get_hosts_for_fact_cache.__get__(job) + + # Mock task instance + mock_facts_settings.ANSIBLE_FACT_CACHE_TIMEOUT = False + task = jobs.RunJob() + task.instance = job + task.update_model = mock.Mock(return_value=job) + task.model.objects.get = mock.Mock(return_value=job) + + # Call pre_run_hook + task.facts_write_time = task.pre_run_hook(job, private_data_dir) + + # Simulate one host deletion + hosts.pop(1) + mock_qs_hosts.count.return_value = 998 + + # Call post_run_hook + task.runner_callback.artifacts_processed = mock.MagicMock(return_value=True) + task.post_run_hook(job, "success") + + # Assert that ansible_facts were preserved + for host in hosts: + assert host.ansible_facts == {"a": 1, "b": 2} + + # Add expected failure cases + failures = [] + for host in hosts: + try: + assert host.ansible_facts == {"a": 1, "b": 2, "unexpected_key": "bad"} + except AssertionError: + failures.append(f"Host named {host.name} has facts {host.ansible_facts}") + + assert len(failures) > 0, f"Failures occurred for the following hosts: {failures}" + + +@mock.patch('awx.main.tasks.facts.bulk_update_sorted_by_id') +@mock.patch('awx.main.tasks.facts.settings') +def test_invalid_host_facts(mock_facts_settings, bulk_update_sorted_by_id, private_data_dir, execution_environment): + inventory = Inventory(pk=1) + mock_inventory = mock.MagicMock(spec=Inventory, wraps=inventory) + mock_inventory._state = mock.MagicMock() + + hosts = [ + Host(id=0, name='host0', ansible_facts={"a": 1, "b": 2}, ansible_facts_modified=now(), inventory=mock_inventory), + Host(id=1, name='host1', ansible_facts={"a": 1, "b": 2, "unexpected_key": "bad"}, ansible_facts_modified=now(), inventory=mock_inventory), + ] + mock_inventory.hosts = hosts + + failures = [] + for host in mock_inventory.hosts: + assert "a" in host.ansible_facts + if "unexpected_key" in host.ansible_facts: + failures.append(host.name) + + mock_facts_settings.SOME_SETTING = True + bulk_update_sorted_by_id(Host, mock_inventory.hosts, fields=['ansible_facts']) + + with pytest.raises(pytest.fail.Exception): + if failures: + pytest.fail(f" {len(failures)} facts cleared failures : {','.join(failures)}") + + +@pytest.mark.parametrize( + "job_attrs,expected_claims", + [ + ( + { + 'id': 100, + 'name': 'Test Job', + 'job_type': 'run', + 'launch_type': 'manual', + 'playbook': 'site.yml', + 'organization': Organization(id=1, name='Test Org'), + 'inventory': Inventory(id=2, name='Test Inventory'), + 'project': Project(id=3, name='Test Project'), + 'execution_environment': ExecutionEnvironment(id=4, name='Test EE'), + 'job_template': JobTemplate(id=5, name='Test Job Template'), + 'unified_job_template': UnifiedJobTemplate(pk=6, id=6, name='Test Unified Job Template'), + 'instance_group': InstanceGroup(id=7, name='Test Instance Group'), + }, + { + AutomationControllerJobScope.CLAIM_JOB_ID: 100, + AutomationControllerJobScope.CLAIM_JOB_NAME: 'Test Job', + AutomationControllerJobScope.CLAIM_JOB_TYPE: 'run', + AutomationControllerJobScope.CLAIM_LAUNCH_TYPE: 'manual', + AutomationControllerJobScope.CLAIM_PLAYBOOK_NAME: 'site.yml', + AutomationControllerJobScope.CLAIM_ORGANIZATION_NAME: 'Test Org', + AutomationControllerJobScope.CLAIM_ORGANIZATION_ID: 1, + AutomationControllerJobScope.CLAIM_INVENTORY_NAME: 'Test Inventory', + AutomationControllerJobScope.CLAIM_INVENTORY_ID: 2, + AutomationControllerJobScope.CLAIM_EXECUTION_ENVIRONMENT_NAME: 'Test EE', + AutomationControllerJobScope.CLAIM_EXECUTION_ENVIRONMENT_ID: 4, + AutomationControllerJobScope.CLAIM_PROJECT_NAME: 'Test Project', + AutomationControllerJobScope.CLAIM_PROJECT_ID: 3, + AutomationControllerJobScope.CLAIM_JOB_TEMPLATE_NAME: 'Test Job Template', + AutomationControllerJobScope.CLAIM_JOB_TEMPLATE_ID: 5, + AutomationControllerJobScope.CLAIM_UNIFIED_JOB_TEMPLATE_NAME: 'Test Unified Job Template', + AutomationControllerJobScope.CLAIM_UNIFIED_JOB_TEMPLATE_ID: 6, + AutomationControllerJobScope.CLAIM_INSTANCE_GROUP_NAME: 'Test Instance Group', + AutomationControllerJobScope.CLAIM_INSTANCE_GROUP_ID: 7, + }, + ), + ( + {'id': 100, 'name': 'Test', 'job_type': 'run', 'launch_type': 'manual', 'organization': Organization(id=1, name='')}, + { + AutomationControllerJobScope.CLAIM_JOB_ID: 100, + AutomationControllerJobScope.CLAIM_JOB_NAME: 'Test', + AutomationControllerJobScope.CLAIM_JOB_TYPE: 'run', + AutomationControllerJobScope.CLAIM_LAUNCH_TYPE: 'manual', + AutomationControllerJobScope.CLAIM_ORGANIZATION_ID: 1, + AutomationControllerJobScope.CLAIM_ORGANIZATION_NAME: '', + AutomationControllerJobScope.CLAIM_PLAYBOOK_NAME: '', + }, + ), + ], +) +def test_populate_claims_for_workload(job_attrs, expected_claims): + job = Job() + + for attr, value in job_attrs.items(): + setattr(job, attr, value) + + claims = jobs.populate_claims_for_workload(job) + assert claims == expected_claims + + +@pytest.mark.parametrize( + "workload_attrs,expected_claims", + [ + ( + { + 'id': 200, + 'name': 'Git Sync', + 'job_type': 'check', + 'launch_type': 'sync', + 'organization': Organization(id=1, name='Test Org'), + 'project': Project(pk=3, id=3, name='Test Project'), + 'unified_job_template': Project(pk=3, id=3, name='Test Project'), + 'execution_environment': ExecutionEnvironment(id=4, name='Test EE'), + 'instance_group': InstanceGroup(id=7, name='Test Instance Group'), + }, + { + AutomationControllerJobScope.CLAIM_JOB_ID: 200, + AutomationControllerJobScope.CLAIM_JOB_NAME: 'Git Sync', + AutomationControllerJobScope.CLAIM_JOB_TYPE: 'check', + AutomationControllerJobScope.CLAIM_LAUNCH_TYPE: 'sync', + AutomationControllerJobScope.CLAIM_LAUNCHED_BY_NAME: 'Test Project', + AutomationControllerJobScope.CLAIM_LAUNCHED_BY_ID: 3, + AutomationControllerJobScope.CLAIM_ORGANIZATION_NAME: 'Test Org', + AutomationControllerJobScope.CLAIM_ORGANIZATION_ID: 1, + AutomationControllerJobScope.CLAIM_PROJECT_NAME: 'Test Project', + AutomationControllerJobScope.CLAIM_PROJECT_ID: 3, + AutomationControllerJobScope.CLAIM_UNIFIED_JOB_TEMPLATE_NAME: 'Test Project', + AutomationControllerJobScope.CLAIM_UNIFIED_JOB_TEMPLATE_ID: 3, + AutomationControllerJobScope.CLAIM_EXECUTION_ENVIRONMENT_NAME: 'Test EE', + AutomationControllerJobScope.CLAIM_EXECUTION_ENVIRONMENT_ID: 4, + AutomationControllerJobScope.CLAIM_INSTANCE_GROUP_NAME: 'Test Instance Group', + AutomationControllerJobScope.CLAIM_INSTANCE_GROUP_ID: 7, + }, + ), + ( + { + 'id': 201, + 'name': 'Minimal Project Update', + 'job_type': 'run', + 'launch_type': 'manual', + }, + { + AutomationControllerJobScope.CLAIM_JOB_ID: 201, + AutomationControllerJobScope.CLAIM_JOB_NAME: 'Minimal Project Update', + AutomationControllerJobScope.CLAIM_JOB_TYPE: 'run', + AutomationControllerJobScope.CLAIM_LAUNCH_TYPE: 'manual', + }, + ), + ], +) +def test_populate_claims_for_project_update(workload_attrs, expected_claims): + project_update = ProjectUpdate() + for attr, value in workload_attrs.items(): + setattr(project_update, attr, value) + + claims = jobs.populate_claims_for_workload(project_update) + assert claims == expected_claims + + +@pytest.mark.parametrize( + "workload_attrs,expected_claims", + [ + ( + { + 'id': 300, + 'name': 'AWS Sync', + 'launch_type': 'scheduled', + 'organization': Organization(id=1, name='Test Org'), + 'inventory': Inventory(id=2, name='AWS Inventory'), + 'unified_job_template': InventorySource(pk=8, id=8, name='AWS Source'), + 'execution_environment': ExecutionEnvironment(id=4, name='Test EE'), + 'instance_group': InstanceGroup(id=7, name='Test Instance Group'), + }, + { + AutomationControllerJobScope.CLAIM_JOB_ID: 300, + AutomationControllerJobScope.CLAIM_JOB_NAME: 'AWS Sync', + AutomationControllerJobScope.CLAIM_LAUNCH_TYPE: 'scheduled', + AutomationControllerJobScope.CLAIM_ORGANIZATION_NAME: 'Test Org', + AutomationControllerJobScope.CLAIM_ORGANIZATION_ID: 1, + AutomationControllerJobScope.CLAIM_INVENTORY_NAME: 'AWS Inventory', + AutomationControllerJobScope.CLAIM_INVENTORY_ID: 2, + AutomationControllerJobScope.CLAIM_UNIFIED_JOB_TEMPLATE_NAME: 'AWS Source', + AutomationControllerJobScope.CLAIM_UNIFIED_JOB_TEMPLATE_ID: 8, + AutomationControllerJobScope.CLAIM_EXECUTION_ENVIRONMENT_NAME: 'Test EE', + AutomationControllerJobScope.CLAIM_EXECUTION_ENVIRONMENT_ID: 4, + AutomationControllerJobScope.CLAIM_INSTANCE_GROUP_NAME: 'Test Instance Group', + AutomationControllerJobScope.CLAIM_INSTANCE_GROUP_ID: 7, + }, + ), + ( + { + 'id': 301, + 'name': 'Minimal Inventory Update', + 'launch_type': 'manual', + }, + { + AutomationControllerJobScope.CLAIM_JOB_ID: 301, + AutomationControllerJobScope.CLAIM_JOB_NAME: 'Minimal Inventory Update', + AutomationControllerJobScope.CLAIM_LAUNCH_TYPE: 'manual', + }, + ), + ], +) +def test_populate_claims_for_inventory_update(workload_attrs, expected_claims): + inventory_update = InventoryUpdate() + for attr, value in workload_attrs.items(): + setattr(inventory_update, attr, value) + + claims = jobs.populate_claims_for_workload(inventory_update) + assert claims == expected_claims + + +@pytest.mark.parametrize( + "workload_attrs,expected_claims", + [ + ( + { + 'id': 400, + 'name': 'Ping All Hosts', + 'job_type': 'run', + 'launch_type': 'manual', + 'organization': Organization(id=1, name='Test Org'), + 'inventory': Inventory(id=2, name='Test Inventory'), + 'execution_environment': ExecutionEnvironment(id=4, name='Test EE'), + 'instance_group': InstanceGroup(id=7, name='Test Instance Group'), + }, + { + AutomationControllerJobScope.CLAIM_JOB_ID: 400, + AutomationControllerJobScope.CLAIM_JOB_NAME: 'Ping All Hosts', + AutomationControllerJobScope.CLAIM_JOB_TYPE: 'run', + AutomationControllerJobScope.CLAIM_LAUNCH_TYPE: 'manual', + AutomationControllerJobScope.CLAIM_ORGANIZATION_NAME: 'Test Org', + AutomationControllerJobScope.CLAIM_ORGANIZATION_ID: 1, + AutomationControllerJobScope.CLAIM_INVENTORY_NAME: 'Test Inventory', + AutomationControllerJobScope.CLAIM_INVENTORY_ID: 2, + AutomationControllerJobScope.CLAIM_EXECUTION_ENVIRONMENT_NAME: 'Test EE', + AutomationControllerJobScope.CLAIM_EXECUTION_ENVIRONMENT_ID: 4, + AutomationControllerJobScope.CLAIM_INSTANCE_GROUP_NAME: 'Test Instance Group', + AutomationControllerJobScope.CLAIM_INSTANCE_GROUP_ID: 7, + }, + ), + ( + { + 'id': 401, + 'name': 'Minimal Ad Hoc', + 'job_type': 'run', + 'launch_type': 'manual', + }, + { + AutomationControllerJobScope.CLAIM_JOB_ID: 401, + AutomationControllerJobScope.CLAIM_JOB_NAME: 'Minimal Ad Hoc', + AutomationControllerJobScope.CLAIM_JOB_TYPE: 'run', + AutomationControllerJobScope.CLAIM_LAUNCH_TYPE: 'manual', + }, + ), + ], +) +def test_populate_claims_for_adhoc_command(workload_attrs, expected_claims): + adhoc_command = AdHocCommand() + for attr, value in workload_attrs.items(): + setattr(adhoc_command, attr, value) + + claims = jobs.populate_claims_for_workload(adhoc_command) + assert claims == expected_claims + + +@mock.patch('awx.main.tasks.jobs.get_workload_identity_client') +def test_retrieve_workload_identity_jwt_returns_jwt_from_client(mock_get_client): + """retrieve_workload_identity_jwt returns the JWT string from the client.""" + mock_client = mock.MagicMock() + mock_response = mock.MagicMock() + mock_response.jwt = 'eyJ.test.jwt' + mock_client.request_workload_jwt.return_value = mock_response + mock_get_client.return_value = mock_client + + unified_job = Job() + unified_job.id = 42 + unified_job.name = 'Test Job' + unified_job.launch_type = 'manual' + unified_job.organization = Organization(id=1, name='Test Org') + unified_job.unified_job_template = None + unified_job.instance_group = None + + result = jobs.retrieve_workload_identity_jwt(unified_job, audience='https://api.example.com', scope='aap_controller_automation_job') + + assert result == 'eyJ.test.jwt' + mock_client.request_workload_jwt.assert_called_once() + call_kwargs = mock_client.request_workload_jwt.call_args[1] + assert call_kwargs['audience'] == 'https://api.example.com' + assert call_kwargs['scope'] == 'aap_controller_automation_job' + assert 'claims' in call_kwargs + assert call_kwargs['claims'][AutomationControllerJobScope.CLAIM_JOB_ID] == 42 + assert call_kwargs['claims'][AutomationControllerJobScope.CLAIM_JOB_NAME] == 'Test Job' + + +@mock.patch('awx.main.tasks.jobs.get_workload_identity_client') +def test_retrieve_workload_identity_jwt_passes_audience_and_scope(mock_get_client): + """retrieve_workload_identity_jwt passes audience and scope to the client.""" + mock_client = mock.MagicMock() + mock_client.request_workload_jwt.return_value = mock.MagicMock(jwt='token') + mock_get_client.return_value = mock_client + + unified_job = mock.MagicMock() + audience = 'custom_audience' + scope = 'custom_scope' + with mock.patch('awx.main.tasks.jobs.populate_claims_for_workload', return_value={'job_id': 1}): + jobs.retrieve_workload_identity_jwt(unified_job, audience=audience, scope=scope) + + mock_client.request_workload_jwt.assert_called_once_with(claims={'job_id': 1}, scope=scope, audience=audience) + + +@mock.patch('awx.main.tasks.jobs.get_workload_identity_client') +def test_retrieve_workload_identity_jwt_raises_when_client_not_configured(mock_get_client): + """retrieve_workload_identity_jwt raises RuntimeError when client is None.""" + mock_get_client.return_value = None + + unified_job = mock.MagicMock() + + with pytest.raises(RuntimeError, match="Workload identity client is not configured"): + jobs.retrieve_workload_identity_jwt(unified_job, audience='test_audience', scope='test_scope') diff --git a/awx/main/tests/unit/tasks/test_signals.py b/awx/main/tests/unit/tasks/test_signals.py index a435b8a66039..f089ea749da9 100644 --- a/awx/main/tests/unit/tasks/test_signals.py +++ b/awx/main/tests/unit/tasks/test_signals.py @@ -1,8 +1,51 @@ import signal +import functools from awx.main.tasks.signals import signal_state, signal_callback, with_signal_handling +def pytest_sigint(): + pytest_sigint.called_count += 1 + + +def pytest_sigterm(): + pytest_sigterm.called_count += 1 + + +def pytest_sigusr1(): + pytest_sigusr1.called_count += 1 + + +def tmp_signals_for_test(func): + """ + When we run our internal signal handlers, it will call the original signal + handlers when its own work is finished. + This would crash the test runners normally, because those methods will + shut down the process. + So this is a decorator to safely replace existing signal handlers + with new signal handlers that do nothing so that tests do not crash. + """ + + @functools.wraps(func) + def wrapper(): + original_sigterm = signal.getsignal(signal.SIGTERM) + original_sigint = signal.getsignal(signal.SIGINT) + original_sigusr1 = signal.getsignal(signal.SIGUSR1) + signal.signal(signal.SIGTERM, pytest_sigterm) + signal.signal(signal.SIGINT, pytest_sigint) + signal.signal(signal.SIGUSR1, pytest_sigusr1) + pytest_sigterm.called_count = 0 + pytest_sigint.called_count = 0 + pytest_sigusr1.called_count = 0 + func() + signal.signal(signal.SIGTERM, original_sigterm) + signal.signal(signal.SIGINT, original_sigint) + signal.signal(signal.SIGUSR1, original_sigusr1) + + return wrapper + + +@tmp_signals_for_test def test_outer_inner_signal_handling(): """ Even if the flag is set in the outer context, its value should persist in the inner context @@ -15,17 +58,24 @@ def f2(): @with_signal_handling def f1(): assert signal_callback() is False - signal_state.set_flag() + signal_state.set_signal_flag(for_signal=signal.SIGTERM) assert signal_callback() f2() original_sigterm = signal.getsignal(signal.SIGTERM) assert signal_callback() is False + assert pytest_sigterm.called_count == 0 + assert pytest_sigint.called_count == 0 + assert pytest_sigusr1.called_count == 0 f1() assert signal_callback() is False assert signal.getsignal(signal.SIGTERM) is original_sigterm + assert pytest_sigterm.called_count == 1 + assert pytest_sigint.called_count == 0 + assert pytest_sigusr1.called_count == 0 +@tmp_signals_for_test def test_inner_outer_signal_handling(): """ Even if the flag is set in the inner context, its value should persist in the outer context @@ -34,7 +84,7 @@ def test_inner_outer_signal_handling(): @with_signal_handling def f2(): assert signal_callback() is False - signal_state.set_flag() + signal_state.set_signal_flag(for_signal=signal.SIGINT) assert signal_callback() @with_signal_handling @@ -45,6 +95,33 @@ def f1(): original_sigterm = signal.getsignal(signal.SIGTERM) assert signal_callback() is False + assert pytest_sigterm.called_count == 0 + assert pytest_sigint.called_count == 0 + assert pytest_sigusr1.called_count == 0 f1() assert signal_callback() is False assert signal.getsignal(signal.SIGTERM) is original_sigterm + assert pytest_sigterm.called_count == 0 + assert pytest_sigint.called_count == 1 + assert pytest_sigusr1.called_count == 0 + + +@tmp_signals_for_test +def test_sigusr1_signal_handling(): + @with_signal_handling + def f1(): + assert signal_callback() is False + signal_state.set_signal_flag(for_signal=signal.SIGUSR1) + assert signal_callback() + + original_sigusr1 = signal.getsignal(signal.SIGUSR1) + assert signal_callback() is False + assert pytest_sigterm.called_count == 0 + assert pytest_sigint.called_count == 0 + assert pytest_sigusr1.called_count == 0 + f1() + assert signal_callback() is False + assert signal.getsignal(signal.SIGUSR1) is original_sigusr1 + assert pytest_sigterm.called_count == 0 + assert pytest_sigint.called_count == 0 + assert pytest_sigusr1.called_count == 1 diff --git a/awx/main/tests/unit/tasks/test_system.py b/awx/main/tests/unit/tasks/test_system.py new file mode 100644 index 000000000000..c567dc48336d --- /dev/null +++ b/awx/main/tests/unit/tasks/test_system.py @@ -0,0 +1,64 @@ +import pytest +from unittest.mock import MagicMock, patch +from awx.main.tasks.system import update_inventory_computed_fields +from awx.main.models import Inventory +from django.db import DatabaseError + + +@pytest.fixture +def mock_logger(): + with patch("awx.main.tasks.system.logger") as logger: + yield logger + + +@pytest.fixture +def mock_inventory(): + return MagicMock(spec=Inventory) + + +def test_update_inventory_computed_fields_existing_inventory(mock_logger, mock_inventory): + # Mocking the Inventory.objects.filter method to return a non-empty queryset + with patch("awx.main.tasks.system.Inventory.objects.filter") as mock_filter: + mock_filter.return_value.exists.return_value = True + mock_filter.return_value.__getitem__.return_value = mock_inventory + + # Mocking the update_computed_fields method + with patch.object(mock_inventory, "update_computed_fields") as mock_update_computed_fields: + update_inventory_computed_fields(1) + + # Assertions + mock_filter.assert_called_once_with(id=1) + mock_update_computed_fields.assert_called_once() + + # You can add more assertions based on your specific requirements + + +def test_update_inventory_computed_fields_missing_inventory(mock_logger): + # Mocking the Inventory.objects.filter method to return an empty queryset + with patch("awx.main.tasks.system.Inventory.objects.filter") as mock_filter: + mock_filter.return_value.exists.return_value = False + + update_inventory_computed_fields(1) + + # Assertions + mock_filter.assert_called_once_with(id=1) + mock_logger.error.assert_called_once_with("Update Inventory Computed Fields failed due to missing inventory: 1") + + +def test_update_inventory_computed_fields_database_error_nosqlstate(mock_logger, mock_inventory): + # Mocking the Inventory.objects.filter method to return a non-empty queryset + with patch("awx.main.tasks.system.Inventory.objects.filter") as mock_filter: + mock_filter.return_value.exists.return_value = True + mock_filter.return_value.__getitem__.return_value = mock_inventory + + # Mocking the update_computed_fields method + with patch.object(mock_inventory, "update_computed_fields") as mock_update_computed_fields: + # Simulating the update_computed_fields method to explicitly raise a DatabaseError + mock_update_computed_fields.side_effect = DatabaseError("Some error") + + update_inventory_computed_fields(1) + + # Assertions + mock_filter.assert_called_once_with(id=1) + mock_update_computed_fields.assert_called_once() + mock_inventory.update_computed_fields.assert_called_once() diff --git a/awx/main/tests/unit/test_access.py b/awx/main/tests/unit/test_access.py index 0059cb498400..08e1e66ab59a 100644 --- a/awx/main/tests/unit/test_access.py +++ b/awx/main/tests/unit/test_access.py @@ -5,7 +5,7 @@ from django.forms.models import model_to_dict from rest_framework.exceptions import ParseError -from awx.main.access import BaseAccess, check_superuser, JobTemplateAccess, WorkflowJobTemplateAccess, SystemJobTemplateAccess, vars_are_encrypted +from awx.main.access import BaseAccess, check_superuser, JobTemplateAccess, WorkflowJobTemplateAccess, vars_are_encrypted from awx.main.models import ( Credential, @@ -239,14 +239,3 @@ def can_copy(self, obj): foo = object() foo_capabilities = foo_access.get_user_capabilities(foo, ['edit', 'copy']) assert foo_capabilities == {'edit': 'bar', 'copy': 'foo'} - - -def test_system_job_template_can_start(mocker): - user = mocker.MagicMock(spec=User, id=1, is_system_auditor=True, is_superuser=False) - assert user.is_system_auditor - access = SystemJobTemplateAccess(user) - assert not access.can_start(None) - - user.is_superuser = True - access = SystemJobTemplateAccess(user) - assert access.can_start(None) diff --git a/awx/main/tests/unit/test_db.py b/awx/main/tests/unit/test_db.py index ce0b8bbeccb8..b1ffbfc0d8c8 100644 --- a/awx/main/tests/unit/test_db.py +++ b/awx/main/tests/unit/test_db.py @@ -9,7 +9,6 @@ import awx from awx.main.db.profiled_pg.base import RecordedQueryLog - QUERY = {'sql': 'SELECT * FROM main_job', 'time': '.01'} EXPLAIN = 'Seq Scan on public.main_job (cost=0.00..1.18 rows=18 width=86)' diff --git a/awx/main/tests/unit/test_redact.py b/awx/main/tests/unit/test_redact.py index c5585ff75cda..f175cbbf7a55 100644 --- a/awx/main/tests/unit/test_redact.py +++ b/awx/main/tests/unit/test_redact.py @@ -36,8 +36,7 @@ TEST_CLEARTEXT.append( { 'uri': uri, - 'text': textwrap.dedent( - """\ + 'text': textwrap.dedent("""\ PLAY [all] ******************************************************************** TASK: [delete project directory before update] ******************************** @@ -59,9 +58,7 @@ localhost : ok=0 changed=0 unreachable=0 failed=1 - """ - % (uri.username, uri.password, str(uri), str(uri)) - ), + """ % (uri.username, uri.password, str(uri), str(uri))), 'host_occurrences': 2, } ) @@ -70,8 +67,7 @@ TEST_CLEARTEXT.append( { 'uri': uri, - 'text': textwrap.dedent( - """\ + 'text': textwrap.dedent("""\ TASK: [update project using git] ** failed: [localhost] => {"cmd": "/usr/bin/git ls-remote https://REDACTED:********", "failed": true, "rc": 128} stderr: error: Couldn't resolve host '@%s' while accessing %s @@ -81,9 +77,7 @@ msg: error: Couldn't resolve host '@%s' while accessing %s fatal: HTTP request failed - """ - % (uri.host, str(uri), uri.host, str(uri)) - ), + """ % (uri.host, str(uri), uri.host, str(uri))), 'host_occurrences': 4, } ) diff --git a/awx/main/tests/unit/test_settings.py b/awx/main/tests/unit/test_settings.py index 19b90099a175..ee517d6a870e 100644 --- a/awx/main/tests/unit/test_settings.py +++ b/awx/main/tests/unit/test_settings.py @@ -1,8 +1,93 @@ -from split_settings.tools import include +LOCAL_SETTINGS = ( + 'ALLOWED_HOSTS', + 'BROADCAST_WEBSOCKET_PORT', + 'BROADCAST_WEBSOCKET_VERIFY_CERT', + 'BROADCAST_WEBSOCKET_PROTOCOL', + 'BROADCAST_WEBSOCKET_SECRET', + 'DATABASES', + 'CACHES', + 'DEBUG', + 'NAMED_URL_GRAPH', + # Platform flags are managed by the platform flags system and have environment-specific defaults + 'FEATURE_INDIRECT_NODE_COUNTING_ENABLED', +) def test_postprocess_auth_basic_enabled(): - locals().update({'__file__': __file__}) + """The final loaded settings should have basic auth enabled.""" + from awx.settings import REST_FRAMEWORK - include('../../../settings/defaults.py', scope=locals()) - assert 'awx.api.authentication.LoggedBasicAuthentication' in locals()['REST_FRAMEWORK']['DEFAULT_AUTHENTICATION_CLASSES'] + assert 'awx.api.authentication.LoggedBasicAuthentication' in REST_FRAMEWORK['DEFAULT_AUTHENTICATION_CLASSES'] + + +def test_default_settings(): + """Ensure that all default settings are present in the snapshot.""" + from django.conf import settings + + for k in dir(settings): + if k not in settings.DEFAULTS_SNAPSHOT or k in LOCAL_SETTINGS: + continue + default_val = getattr(settings.default_settings, k, None) + snapshot_val = settings.DEFAULTS_SNAPSHOT[k] + assert default_val == snapshot_val, f'Setting for {k} does not match snapshot:\nsnapshot: {snapshot_val}\ndefault: {default_val}' + + +def test_django_conf_settings_is_awx_settings(): + """Ensure that the settings loaded from dynaconf are the same as the settings delivered to django.""" + from django.conf import settings + from awx.settings import REST_FRAMEWORK + + assert settings.REST_FRAMEWORK == REST_FRAMEWORK + + +def test_dynaconf_is_awx_settings(): + """Ensure that the settings loaded from dynaconf are the same as the settings delivered to django.""" + from django.conf import settings + from awx.settings import REST_FRAMEWORK + + assert settings.DYNACONF.REST_FRAMEWORK == REST_FRAMEWORK + + +def test_development_settings_can_be_directly_imported(monkeypatch): + """Ensure that the development settings can be directly imported.""" + monkeypatch.setenv('AWX_MODE', 'development') + from django.conf import settings + from awx.settings.development import REST_FRAMEWORK + from awx.settings.development import DEBUG # actually set on defaults.py and not overridden in development.py + + assert settings.REST_FRAMEWORK == REST_FRAMEWORK + assert DEBUG is True + + +def test_merge_application_name(): + """Ensure that the merge_application_name function works as expected.""" + from awx.settings.functions import merge_application_name + + settings = { + "DATABASES__default__ENGINE": "django.db.backends.postgresql", + "CLUSTER_HOST_ID": "test-cluster-host-id", + } + result = merge_application_name(settings)["DATABASES__default__OPTIONS__application_name"] + assert result.startswith("awx-") + assert "test-cluster" in result + + +def test_development_defaults_feature_flags(monkeypatch): + """Ensure that development_defaults.py sets the correct feature flags.""" + monkeypatch.setenv('AWX_MODE', 'development') + + # Import the development_defaults module directly to trigger coverage of the new lines + import importlib.util + import os + + spec = importlib.util.spec_from_file_location("development_defaults", os.path.join(os.path.dirname(__file__), "../../../settings/development_defaults.py")) + development_defaults = importlib.util.module_from_spec(spec) + spec.loader.exec_module(development_defaults) + + # Also import through the development settings to ensure both paths are tested + from awx.settings.development import FEATURE_INDIRECT_NODE_COUNTING_ENABLED + + # Verify the feature flags are set correctly in both the module and settings + assert hasattr(development_defaults, 'FEATURE_INDIRECT_NODE_COUNTING_ENABLED') + assert development_defaults.FEATURE_INDIRECT_NODE_COUNTING_ENABLED is True + assert FEATURE_INDIRECT_NODE_COUNTING_ENABLED is True diff --git a/awx/main/tests/unit/test_tasks.py b/awx/main/tests/unit/test_tasks.py index bfec59b6163c..ce4515b88c4a 100644 --- a/awx/main/tests/unit/test_tasks.py +++ b/awx/main/tests/unit/test_tasks.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -import configparser import json import os import shutil @@ -10,7 +9,8 @@ from unittest import mock import pytest import yaml -import jinja2 + +from awx_plugins.interfaces._temporary_private_container_api import CONTAINER_ROOT from django.conf import settings @@ -37,7 +37,6 @@ from awx.main.tasks import jobs, system, receptor from awx.main.utils import encrypt_field, encrypt_value from awx.main.utils.safe_yaml import SafeLoader -from awx.main.utils.execution_environments import CONTAINER_ROOT from awx.main.utils.licensing import Licenser from awx.main.constants import JOB_VARIABLE_PREFIXES @@ -108,7 +107,7 @@ def job(): @pytest.fixture def adhoc_job(): - return AdHocCommand(pk=1, id=1, inventory=Inventory()) + return AdHocCommand(pk=1, id=1, inventory=Inventory(), status='waiting') @pytest.fixture @@ -137,17 +136,10 @@ def test_send_notifications_not_list(): def test_send_notifications_job_id(mocker): - with mocker.patch('awx.main.models.UnifiedJob.objects.get'): - system.send_notifications([], job_id=1) - assert UnifiedJob.objects.get.called - assert UnifiedJob.objects.get.called_with(id=1) - - -def test_work_success_callback_missing_job(): - task_data = {'type': 'project_update', 'id': 9999} - with mock.patch('django.db.models.query.QuerySet.get') as get_mock: - get_mock.side_effect = ProjectUpdate.DoesNotExist() - assert system.handle_work_success(task_data) is None + mocker.patch('awx.main.models.UnifiedJob.objects.get') + system.send_notifications([], job_id=1) + assert UnifiedJob.objects.get.called + UnifiedJob.objects.get.assert_called_with(id=1) @mock.patch('awx.main.models.UnifiedJob.objects.get') @@ -164,7 +156,7 @@ def test_send_notifications_list(mock_notifications_filter, mock_job_get, mocker assert mock_notifications[0].save.called assert mock_job.notifications.add.called - assert mock_job.notifications.add.called_with(*mock_notifications) + mock_job.notifications.add.assert_called_with(*mock_notifications) @pytest.mark.parametrize( @@ -371,7 +363,7 @@ class TestExtraVarSanitation(TestJobExecution): # are deemed trustable, because they can only be added by users w/ enough # privilege to add/modify a Job Template) - UNSAFE = '{{ lookup(' 'pipe' ',' 'ls -la' ') }}' + UNSAFE = "{{ lookup('pipe', 'ls -la') }}" def test_vars_unsafe_by_default(self, job, private_data_dir, mock_me): job.created_by = User(pk=123, username='angry-spud') @@ -380,8 +372,8 @@ def test_vars_unsafe_by_default(self, job, private_data_dir, mock_me): task = jobs.RunJob() task.build_extra_vars_file(job, private_data_dir) - fd = open(os.path.join(private_data_dir, 'env', 'extravars')) - extra_vars = yaml.load(fd, Loader=SafeLoader) + with open(os.path.join(private_data_dir, 'env', 'extravars')) as fd: + extra_vars = yaml.load(fd, Loader=SafeLoader) # ensure that strings are marked as unsafe for name in JOB_VARIABLE_PREFIXES: @@ -399,8 +391,8 @@ def test_launchtime_vars_unsafe(self, job, private_data_dir, mock_me): task.build_extra_vars_file(job, private_data_dir) - fd = open(os.path.join(private_data_dir, 'env', 'extravars')) - extra_vars = yaml.load(fd, Loader=SafeLoader) + with open(os.path.join(private_data_dir, 'env', 'extravars')) as fd: + extra_vars = yaml.load(fd, Loader=SafeLoader) assert extra_vars['msg'] == self.UNSAFE assert hasattr(extra_vars['msg'], '__UNSAFE__') @@ -410,8 +402,8 @@ def test_nested_launchtime_vars_unsafe(self, job, private_data_dir, mock_me): task.build_extra_vars_file(job, private_data_dir) - fd = open(os.path.join(private_data_dir, 'env', 'extravars')) - extra_vars = yaml.load(fd, Loader=SafeLoader) + with open(os.path.join(private_data_dir, 'env', 'extravars')) as fd: + extra_vars = yaml.load(fd, Loader=SafeLoader) assert extra_vars['msg'] == {'a': [self.UNSAFE]} assert hasattr(extra_vars['msg']['a'][0], '__UNSAFE__') @@ -421,8 +413,8 @@ def test_allowed_jt_extra_vars(self, job, private_data_dir, mock_me): task.build_extra_vars_file(job, private_data_dir) - fd = open(os.path.join(private_data_dir, 'env', 'extravars')) - extra_vars = yaml.load(fd, Loader=SafeLoader) + with open(os.path.join(private_data_dir, 'env', 'extravars')) as fd: + extra_vars = yaml.load(fd, Loader=SafeLoader) assert extra_vars['msg'] == self.UNSAFE assert not hasattr(extra_vars['msg'], '__UNSAFE__') @@ -433,8 +425,8 @@ def test_nested_allowed_vars(self, job, private_data_dir, mock_me): task.build_extra_vars_file(job, private_data_dir) - fd = open(os.path.join(private_data_dir, 'env', 'extravars')) - extra_vars = yaml.load(fd, Loader=SafeLoader) + with open(os.path.join(private_data_dir, 'env', 'extravars')) as fd: + extra_vars = yaml.load(fd, Loader=SafeLoader) assert extra_vars['msg'] == {'a': {'b': [self.UNSAFE]}} assert not hasattr(extra_vars['msg']['a']['b'][0], '__UNSAFE__') @@ -447,8 +439,8 @@ def test_sensitive_values_dont_leak(self, job, private_data_dir, mock_me): task.build_extra_vars_file(job, private_data_dir) - fd = open(os.path.join(private_data_dir, 'env', 'extravars')) - extra_vars = yaml.load(fd, Loader=SafeLoader) + with open(os.path.join(private_data_dir, 'env', 'extravars')) as fd: + extra_vars = yaml.load(fd, Loader=SafeLoader) assert extra_vars['msg'] == 'other-value' assert hasattr(extra_vars['msg'], '__UNSAFE__') @@ -462,13 +454,14 @@ def test_overwritten_jt_extra_vars(self, job, private_data_dir, mock_me): task.build_extra_vars_file(job, private_data_dir) - fd = open(os.path.join(private_data_dir, 'env', 'extravars')) - extra_vars = yaml.load(fd, Loader=SafeLoader) + with open(os.path.join(private_data_dir, 'env', 'extravars')) as fd: + extra_vars = yaml.load(fd, Loader=SafeLoader) assert extra_vars['msg'] == self.UNSAFE assert hasattr(extra_vars['msg'], '__UNSAFE__') class TestGenericRun: + @pytest.mark.django_db(reset_sequences=True) def test_generic_failure(self, patch_Job, execution_environment, mock_me, mock_create_partition): job = Job(status='running', inventory=Inventory(), project=Project(local_path='/projects/_23_foo')) job.websocket_emit_status = mock.Mock() @@ -480,7 +473,7 @@ def test_generic_failure(self, patch_Job, execution_environment, mock_me, mock_c task.model.objects.get = mock.Mock(return_value=job) task.build_private_data_files = mock.Mock(side_effect=OSError()) - with mock.patch('awx.main.tasks.jobs.shutil.copytree'): + with mock.patch('awx.main.tasks.jobs.shutil.copytree'), mock.patch('awx.main.tasks.jobs.evaluate_policy'): with pytest.raises(Exception): task.run(1) @@ -489,26 +482,6 @@ def test_generic_failure(self, patch_Job, execution_environment, mock_me, mock_c assert update_model_call['status'] == 'error' assert update_model_call['emitted_events'] == 0 - def test_cancel_flag(self, job, update_model_wrapper, execution_environment, mock_me, mock_create_partition): - job.status = 'running' - job.cancel_flag = True - job.websocket_emit_status = mock.Mock() - job.send_notification_templates = mock.Mock() - job.execution_environment = execution_environment - - task = jobs.RunJob() - task.instance = job - task.update_model = mock.Mock(wraps=update_model_wrapper) - task.model.objects.get = mock.Mock(return_value=job) - task.build_private_data_files = mock.Mock() - - with mock.patch('awx.main.tasks.jobs.shutil.copytree'): - with pytest.raises(Exception): - task.run(1) - - for c in [mock.call(1, start_args='', status='canceled')]: - assert c in task.update_model.call_args_list - def test_event_count(self, mock_me): task = jobs.RunJob() task.runner_callback.dispatcher = mock.MagicMock() @@ -573,6 +546,7 @@ def test_survey_extra_vars(self, mock_me): private_data_dir, extra_vars, safe_dict = call_args assert extra_vars['super_secret'] == "CLASSIFIED" + @pytest.mark.django_db def test_awx_task_env(self, patch_Job, private_data_dir, execution_environment, mock_me): job = Job(project=Project(), inventory=Inventory()) job.execution_environment = execution_environment @@ -597,6 +571,8 @@ def test_options_jinja_usage(self, adhoc_job, adhoc_update_model_wrapper, mock_m adhoc_job.send_notification_templates = mock.Mock() task = jobs.RunAdHocCommand() + adhoc_job.status = 'running' # to bypass status flip + task.instance = adhoc_job # to bypass fetch task.update_model = mock.Mock(wraps=adhoc_update_model_wrapper) task.model.objects.get = mock.Mock(return_value=adhoc_job) task.build_inventory = mock.Mock() @@ -863,202 +839,6 @@ def test_multi_vault_password_ask(self, private_data_dir, job, mock_me): assert '--vault-id dev@prompt' in ' '.join(args) assert '--vault-id prod@prompt' in ' '.join(args) - @pytest.mark.parametrize("verify", (True, False)) - def test_k8s_credential(self, job, private_data_dir, verify, mock_me): - k8s = CredentialType.defaults['kubernetes_bearer_token']() - inputs = { - 'host': 'https://example.org/', - 'bearer_token': 'token123', - } - if verify: - inputs['verify_ssl'] = True - inputs['ssl_ca_cert'] = 'CERTDATA' - credential = Credential( - pk=1, - credential_type=k8s, - inputs=inputs, - ) - credential.inputs['bearer_token'] = encrypt_field(credential, 'bearer_token') - job.credentials.add(credential) - - env = {} - safe_env = {} - credential.credential_type.inject_credential(credential, env, safe_env, [], private_data_dir) - - assert env['K8S_AUTH_HOST'] == 'https://example.org/' - assert env['K8S_AUTH_API_KEY'] == 'token123' - - if verify: - assert env['K8S_AUTH_VERIFY_SSL'] == 'True' - local_path = to_host_path(env['K8S_AUTH_SSL_CA_CERT'], private_data_dir) - cert = open(local_path, 'r').read() - assert cert == 'CERTDATA' - else: - assert env['K8S_AUTH_VERIFY_SSL'] == 'False' - assert 'K8S_AUTH_SSL_CA_CERT' not in env - - assert safe_env['K8S_AUTH_API_KEY'] == HIDDEN_PASSWORD - - def test_aws_cloud_credential(self, job, private_data_dir, mock_me): - aws = CredentialType.defaults['aws']() - credential = Credential(pk=1, credential_type=aws, inputs={'username': 'bob', 'password': 'secret'}) - credential.inputs['password'] = encrypt_field(credential, 'password') - job.credentials.add(credential) - - env = {} - safe_env = {} - credential.credential_type.inject_credential(credential, env, safe_env, [], private_data_dir) - - assert env['AWS_ACCESS_KEY_ID'] == 'bob' - assert env['AWS_SECRET_ACCESS_KEY'] == 'secret' - assert 'AWS_SECURITY_TOKEN' not in env - assert safe_env['AWS_SECRET_ACCESS_KEY'] == HIDDEN_PASSWORD - - def test_aws_cloud_credential_with_sts_token(self, private_data_dir, job, mock_me): - aws = CredentialType.defaults['aws']() - credential = Credential(pk=1, credential_type=aws, inputs={'username': 'bob', 'password': 'secret', 'security_token': 'token'}) - for key in ('password', 'security_token'): - credential.inputs[key] = encrypt_field(credential, key) - job.credentials.add(credential) - - env = {} - safe_env = {} - credential.credential_type.inject_credential(credential, env, safe_env, [], private_data_dir) - - assert env['AWS_ACCESS_KEY_ID'] == 'bob' - assert env['AWS_SECRET_ACCESS_KEY'] == 'secret' - assert env['AWS_SECURITY_TOKEN'] == 'token' - assert safe_env['AWS_SECRET_ACCESS_KEY'] == HIDDEN_PASSWORD - - @pytest.mark.parametrize("cred_env_var", ['GCE_CREDENTIALS_FILE_PATH', 'GOOGLE_APPLICATION_CREDENTIALS']) - def test_gce_credentials(self, cred_env_var, private_data_dir, job, mock_me): - gce = CredentialType.defaults['gce']() - credential = Credential(pk=1, credential_type=gce, inputs={'username': 'bob', 'project': 'some-project', 'ssh_key_data': self.EXAMPLE_PRIVATE_KEY}) - credential.inputs['ssh_key_data'] = encrypt_field(credential, 'ssh_key_data') - job.credentials.add(credential) - - env = {} - safe_env = {} - credential.credential_type.inject_credential(credential, env, safe_env, [], private_data_dir) - runner_path = env[cred_env_var] - local_path = to_host_path(runner_path, private_data_dir) - json_data = json.load(open(local_path, 'rb')) - assert json_data['type'] == 'service_account' - assert json_data['private_key'] == self.EXAMPLE_PRIVATE_KEY - assert json_data['client_email'] == 'bob' - assert json_data['project_id'] == 'some-project' - - def test_azure_rm_with_tenant(self, private_data_dir, job, mock_me): - azure = CredentialType.defaults['azure_rm']() - credential = Credential( - pk=1, credential_type=azure, inputs={'client': 'some-client', 'secret': 'some-secret', 'tenant': 'some-tenant', 'subscription': 'some-subscription'} - ) - credential.inputs['secret'] = encrypt_field(credential, 'secret') - job.credentials.add(credential) - - env = {} - safe_env = {} - credential.credential_type.inject_credential(credential, env, safe_env, [], private_data_dir) - - assert env['AZURE_CLIENT_ID'] == 'some-client' - assert env['AZURE_SECRET'] == 'some-secret' - assert env['AZURE_TENANT'] == 'some-tenant' - assert env['AZURE_SUBSCRIPTION_ID'] == 'some-subscription' - assert safe_env['AZURE_SECRET'] == HIDDEN_PASSWORD - - def test_azure_rm_with_password(self, private_data_dir, job, mock_me): - azure = CredentialType.defaults['azure_rm']() - credential = Credential( - pk=1, credential_type=azure, inputs={'subscription': 'some-subscription', 'username': 'bob', 'password': 'secret', 'cloud_environment': 'foobar'} - ) - credential.inputs['password'] = encrypt_field(credential, 'password') - job.credentials.add(credential) - - env = {} - safe_env = {} - credential.credential_type.inject_credential(credential, env, safe_env, [], private_data_dir) - - assert env['AZURE_SUBSCRIPTION_ID'] == 'some-subscription' - assert env['AZURE_AD_USER'] == 'bob' - assert env['AZURE_PASSWORD'] == 'secret' - assert env['AZURE_CLOUD_ENVIRONMENT'] == 'foobar' - assert safe_env['AZURE_PASSWORD'] == HIDDEN_PASSWORD - - def test_vmware_credentials(self, private_data_dir, job, mock_me): - vmware = CredentialType.defaults['vmware']() - credential = Credential(pk=1, credential_type=vmware, inputs={'username': 'bob', 'password': 'secret', 'host': 'https://example.org'}) - credential.inputs['password'] = encrypt_field(credential, 'password') - job.credentials.add(credential) - - env = {} - safe_env = {} - credential.credential_type.inject_credential(credential, env, safe_env, [], private_data_dir) - - assert env['VMWARE_USER'] == 'bob' - assert env['VMWARE_PASSWORD'] == 'secret' - assert env['VMWARE_HOST'] == 'https://example.org' - assert safe_env['VMWARE_PASSWORD'] == HIDDEN_PASSWORD - - def test_openstack_credentials(self, private_data_dir, job, mock_me): - task = jobs.RunJob() - task.instance = job - openstack = CredentialType.defaults['openstack']() - credential = Credential( - pk=1, credential_type=openstack, inputs={'username': 'bob', 'password': 'secret', 'project': 'tenant-name', 'host': 'https://keystone.example.org'} - ) - credential.inputs['password'] = encrypt_field(credential, 'password') - job.credentials.add(credential) - - private_data_files, ssh_key_data = task.build_private_data_files(job, private_data_dir) - env = task.build_env(job, private_data_dir, private_data_files=private_data_files) - credential.credential_type.inject_credential(credential, env, {}, [], private_data_dir) - - config_loc = to_host_path(env['OS_CLIENT_CONFIG_FILE'], private_data_dir) - shade_config = open(config_loc, 'r').read() - assert shade_config == '\n'.join( - [ - 'clouds:', - ' devstack:', - ' auth:', - ' auth_url: https://keystone.example.org', - ' password: secret', - ' project_name: tenant-name', - ' username: bob', - ' verify: true', - '', - ] - ) - - @pytest.mark.parametrize("ca_file", [None, '/path/to/some/file']) - def test_rhv_credentials(self, private_data_dir, job, ca_file, mock_me): - rhv = CredentialType.defaults['rhv']() - inputs = { - 'host': 'some-ovirt-host.example.org', - 'username': 'bob', - 'password': 'some-pass', - } - if ca_file: - inputs['ca_file'] = ca_file - credential = Credential(pk=1, credential_type=rhv, inputs=inputs) - credential.inputs['password'] = encrypt_field(credential, 'password') - job.credentials.add(credential) - - env = {} - safe_env = {} - credential.credential_type.inject_credential(credential, env, safe_env, [], private_data_dir) - - config = configparser.ConfigParser() - host_path = to_host_path(env['OVIRT_INI_PATH'], private_data_dir) - config.read(host_path) - assert config.get('ovirt', 'ovirt_url') == 'some-ovirt-host.example.org' - assert config.get('ovirt', 'ovirt_username') == 'bob' - assert config.get('ovirt', 'ovirt_password') == 'some-pass' - if ca_file: - assert config.get('ovirt', 'ovirt_ca_file') == ca_file - else: - with pytest.raises(configparser.NoOptionError): - config.get('ovirt', 'ovirt_ca_file') - @pytest.mark.parametrize( 'authorize, expected_authorize', [ @@ -1067,6 +847,7 @@ def test_rhv_credentials(self, private_data_dir, job, ca_file, mock_me): [None, '0'], ], ) + @pytest.mark.django_db def test_net_credentials(self, authorize, expected_authorize, job, private_data_dir, mock_me): task = jobs.RunJob() task.instance = job @@ -1089,259 +870,10 @@ def test_net_credentials(self, authorize, expected_authorize, job, private_data_ assert env['ANSIBLE_NET_AUTHORIZE'] == expected_authorize if authorize: assert env['ANSIBLE_NET_AUTH_PASS'] == 'authorizeme' - assert open(env['ANSIBLE_NET_SSH_KEYFILE'], 'r').read() == self.EXAMPLE_PRIVATE_KEY + with open(env['ANSIBLE_NET_SSH_KEYFILE'], 'r') as f: + assert f.read() == self.EXAMPLE_PRIVATE_KEY assert safe_env['ANSIBLE_NET_PASSWORD'] == HIDDEN_PASSWORD - def test_custom_environment_injectors_with_jinja_syntax_error(self, private_data_dir, mock_me): - some_cloud = CredentialType( - kind='cloud', - name='SomeCloud', - managed=False, - inputs={'fields': [{'id': 'api_token', 'label': 'API Token', 'type': 'string'}]}, - injectors={'env': {'MY_CLOUD_API_TOKEN': '{{api_token.foo()}}'}}, - ) - credential = Credential(pk=1, credential_type=some_cloud, inputs={'api_token': 'ABC123'}) - - with pytest.raises(jinja2.exceptions.UndefinedError): - credential.credential_type.inject_credential(credential, {}, {}, [], private_data_dir) - - def test_custom_environment_injectors(self, private_data_dir, mock_me): - some_cloud = CredentialType( - kind='cloud', - name='SomeCloud', - managed=False, - inputs={'fields': [{'id': 'api_token', 'label': 'API Token', 'type': 'string'}]}, - injectors={'env': {'MY_CLOUD_API_TOKEN': '{{api_token}}'}}, - ) - credential = Credential(pk=1, credential_type=some_cloud, inputs={'api_token': 'ABC123'}) - - env = {} - credential.credential_type.inject_credential(credential, env, {}, [], private_data_dir) - - assert env['MY_CLOUD_API_TOKEN'] == 'ABC123' - - def test_custom_environment_injectors_with_boolean_env_var(self, private_data_dir, mock_me): - some_cloud = CredentialType( - kind='cloud', - name='SomeCloud', - managed=False, - inputs={'fields': [{'id': 'turbo_button', 'label': 'Turbo Button', 'type': 'boolean'}]}, - injectors={'env': {'TURBO_BUTTON': '{{turbo_button}}'}}, - ) - credential = Credential(pk=1, credential_type=some_cloud, inputs={'turbo_button': True}) - - env = {} - credential.credential_type.inject_credential(credential, env, {}, [], private_data_dir) - - assert env['TURBO_BUTTON'] == str(True) - - def test_custom_environment_injectors_with_reserved_env_var(self, private_data_dir, job, mock_me): - task = jobs.RunJob() - task.instance = job - some_cloud = CredentialType( - kind='cloud', - name='SomeCloud', - managed=False, - inputs={'fields': [{'id': 'api_token', 'label': 'API Token', 'type': 'string'}]}, - injectors={'env': {'JOB_ID': 'reserved'}}, - ) - credential = Credential(pk=1, credential_type=some_cloud, inputs={'api_token': 'ABC123'}) - job.credentials.add(credential) - - env = task.build_env(job, private_data_dir) - - assert env['JOB_ID'] == str(job.pk) - - def test_custom_environment_injectors_with_secret_field(self, private_data_dir, mock_me): - some_cloud = CredentialType( - kind='cloud', - name='SomeCloud', - managed=False, - inputs={'fields': [{'id': 'password', 'label': 'Password', 'type': 'string', 'secret': True}]}, - injectors={'env': {'MY_CLOUD_PRIVATE_VAR': '{{password}}'}}, - ) - credential = Credential(pk=1, credential_type=some_cloud, inputs={'password': 'SUPER-SECRET-123'}) - credential.inputs['password'] = encrypt_field(credential, 'password') - - env = {} - safe_env = {} - credential.credential_type.inject_credential(credential, env, safe_env, [], private_data_dir) - - assert env['MY_CLOUD_PRIVATE_VAR'] == 'SUPER-SECRET-123' - assert 'SUPER-SECRET-123' not in safe_env.values() - assert safe_env['MY_CLOUD_PRIVATE_VAR'] == HIDDEN_PASSWORD - - def test_custom_environment_injectors_with_extra_vars(self, private_data_dir, job, mock_me): - task = jobs.RunJob() - some_cloud = CredentialType( - kind='cloud', - name='SomeCloud', - managed=False, - inputs={'fields': [{'id': 'api_token', 'label': 'API Token', 'type': 'string'}]}, - injectors={'extra_vars': {'api_token': '{{api_token}}'}}, - ) - credential = Credential(pk=1, credential_type=some_cloud, inputs={'api_token': 'ABC123'}) - job.credentials.add(credential) - - args = task.build_args(job, private_data_dir, {}) - credential.credential_type.inject_credential(credential, {}, {}, args, private_data_dir) - extra_vars = parse_extra_vars(args, private_data_dir) - - assert extra_vars["api_token"] == "ABC123" - assert hasattr(extra_vars["api_token"], '__UNSAFE__') - - def test_custom_environment_injectors_with_boolean_extra_vars(self, job, private_data_dir, mock_me): - task = jobs.RunJob() - some_cloud = CredentialType( - kind='cloud', - name='SomeCloud', - managed=False, - inputs={'fields': [{'id': 'turbo_button', 'label': 'Turbo Button', 'type': 'boolean'}]}, - injectors={'extra_vars': {'turbo_button': '{{turbo_button}}'}}, - ) - credential = Credential(pk=1, credential_type=some_cloud, inputs={'turbo_button': True}) - job.credentials.add(credential) - - args = task.build_args(job, private_data_dir, {}) - credential.credential_type.inject_credential(credential, {}, {}, args, private_data_dir) - extra_vars = parse_extra_vars(args, private_data_dir) - - assert extra_vars["turbo_button"] == "True" - return ['successful', 0] - - def test_custom_environment_injectors_with_nested_extra_vars(self, private_data_dir, job, mock_me): - task = jobs.RunJob() - some_cloud = CredentialType( - kind='cloud', - name='SomeCloud', - managed=False, - inputs={'fields': [{'id': 'host', 'label': 'Host', 'type': 'string'}]}, - injectors={'extra_vars': {'auth': {'host': '{{host}}'}}}, - ) - credential = Credential(pk=1, credential_type=some_cloud, inputs={'host': 'example.com'}) - job.credentials.add(credential) - - args = task.build_args(job, private_data_dir, {}) - credential.credential_type.inject_credential(credential, {}, {}, args, private_data_dir) - extra_vars = parse_extra_vars(args, private_data_dir) - - assert extra_vars["auth"]["host"] == "example.com" - - def test_custom_environment_injectors_with_templated_extra_vars_key(self, private_data_dir, job, mock_me): - task = jobs.RunJob() - some_cloud = CredentialType( - kind='cloud', - name='SomeCloud', - managed=False, - inputs={'fields': [{'id': 'environment', 'label': 'Environment', 'type': 'string'}, {'id': 'host', 'label': 'Host', 'type': 'string'}]}, - injectors={'extra_vars': {'{{environment}}_auth': {'host': '{{host}}'}}}, - ) - credential = Credential(pk=1, credential_type=some_cloud, inputs={'environment': 'test', 'host': 'example.com'}) - job.credentials.add(credential) - - args = task.build_args(job, private_data_dir, {}) - credential.credential_type.inject_credential(credential, {}, {}, args, private_data_dir) - extra_vars = parse_extra_vars(args, private_data_dir) - - assert extra_vars["test_auth"]["host"] == "example.com" - - def test_custom_environment_injectors_with_complicated_boolean_template(self, job, private_data_dir, mock_me): - task = jobs.RunJob() - some_cloud = CredentialType( - kind='cloud', - name='SomeCloud', - managed=False, - inputs={'fields': [{'id': 'turbo_button', 'label': 'Turbo Button', 'type': 'boolean'}]}, - injectors={'extra_vars': {'turbo_button': '{% if turbo_button %}FAST!{% else %}SLOW!{% endif %}'}}, - ) - credential = Credential(pk=1, credential_type=some_cloud, inputs={'turbo_button': True}) - job.credentials.add(credential) - - args = task.build_args(job, private_data_dir, {}) - credential.credential_type.inject_credential(credential, {}, {}, args, private_data_dir) - extra_vars = parse_extra_vars(args, private_data_dir) - - assert extra_vars["turbo_button"] == "FAST!" - - def test_custom_environment_injectors_with_secret_extra_vars(self, job, private_data_dir, mock_me): - """ - extra_vars that contain secret field values should be censored in the DB - """ - task = jobs.RunJob() - some_cloud = CredentialType( - kind='cloud', - name='SomeCloud', - managed=False, - inputs={'fields': [{'id': 'password', 'label': 'Password', 'type': 'string', 'secret': True}]}, - injectors={'extra_vars': {'password': '{{password}}'}}, - ) - credential = Credential(pk=1, credential_type=some_cloud, inputs={'password': 'SUPER-SECRET-123'}) - credential.inputs['password'] = encrypt_field(credential, 'password') - job.credentials.add(credential) - - args = task.build_args(job, private_data_dir, {}) - credential.credential_type.inject_credential(credential, {}, {}, args, private_data_dir) - - extra_vars = parse_extra_vars(args, private_data_dir) - assert extra_vars["password"] == "SUPER-SECRET-123" - - def test_custom_environment_injectors_with_file(self, private_data_dir, mock_me): - some_cloud = CredentialType( - kind='cloud', - name='SomeCloud', - managed=False, - inputs={'fields': [{'id': 'api_token', 'label': 'API Token', 'type': 'string'}]}, - injectors={'file': {'template': '[mycloud]\n{{api_token}}'}, 'env': {'MY_CLOUD_INI_FILE': '{{tower.filename}}'}}, - ) - credential = Credential(pk=1, credential_type=some_cloud, inputs={'api_token': 'ABC123'}) - - env = {} - credential.credential_type.inject_credential(credential, env, {}, [], private_data_dir) - - path = to_host_path(env['MY_CLOUD_INI_FILE'], private_data_dir) - assert open(path, 'r').read() == '[mycloud]\nABC123' - - def test_custom_environment_injectors_with_unicode_content(self, private_data_dir, mock_me): - value = 'Iñtërnâtiônàlizætiøn' - some_cloud = CredentialType( - kind='cloud', - name='SomeCloud', - managed=False, - inputs={'fields': []}, - injectors={'file': {'template': value}, 'env': {'MY_CLOUD_INI_FILE': '{{tower.filename}}'}}, - ) - credential = Credential( - pk=1, - credential_type=some_cloud, - ) - - env = {} - credential.credential_type.inject_credential(credential, env, {}, [], private_data_dir) - - path = to_host_path(env['MY_CLOUD_INI_FILE'], private_data_dir) - assert open(path, 'r').read() == value - - def test_custom_environment_injectors_with_files(self, private_data_dir, mock_me): - some_cloud = CredentialType( - kind='cloud', - name='SomeCloud', - managed=False, - inputs={'fields': [{'id': 'cert', 'label': 'Certificate', 'type': 'string'}, {'id': 'key', 'label': 'Key', 'type': 'string'}]}, - injectors={ - 'file': {'template.cert': '[mycert]\n{{cert}}', 'template.key': '[mykey]\n{{key}}'}, - 'env': {'MY_CERT_INI_FILE': '{{tower.filename.cert}}', 'MY_KEY_INI_FILE': '{{tower.filename.key}}'}, - }, - ) - credential = Credential(pk=1, credential_type=some_cloud, inputs={'cert': 'CERT123', 'key': 'KEY123'}) - - env = {} - credential.credential_type.inject_credential(credential, env, {}, [], private_data_dir) - - cert_path = to_host_path(env['MY_CERT_INI_FILE'], private_data_dir) - key_path = to_host_path(env['MY_KEY_INI_FILE'], private_data_dir) - assert open(cert_path, 'r').read() == '[mycert]\nCERT123' - assert open(key_path, 'r').read() == '[mykey]\nKEY123' - def test_multi_cloud(self, private_data_dir, mock_me): gce = CredentialType.defaults['gce']() gce_credential = Credential(pk=1, credential_type=gce, inputs={'username': 'bob', 'project': 'some-project', 'ssh_key_data': self.EXAMPLE_PRIVATE_KEY}) @@ -1363,7 +895,8 @@ def test_multi_cloud(self, private_data_dir, mock_me): # Because this is testing a mix of multiple cloud creds, we are not going to test the GOOGLE_APPLICATION_CREDENTIALS here path = to_host_path(env['GCE_CREDENTIALS_FILE_PATH'], private_data_dir) - json_data = json.load(open(path, 'rb')) + with open(path, 'rb') as f: + json_data = json.load(f) assert json_data['type'] == 'service_account' assert json_data['private_key'] == self.EXAMPLE_PRIVATE_KEY assert json_data['client_email'] == 'bob' @@ -1371,6 +904,7 @@ def test_multi_cloud(self, private_data_dir, mock_me): assert safe_env['AZURE_PASSWORD'] == HIDDEN_PASSWORD + @pytest.mark.django_db def test_awx_task_env(self, settings, private_data_dir, job, mock_me): settings.AWX_TASK_ENV = {'FOO': 'BAR'} task = jobs.RunJob() @@ -1556,6 +1090,70 @@ def test_awx_task_env(self, project_update, settings, private_data_dir, scm_type assert env['FOO'] == 'BAR' +@pytest.mark.django_db +class TestProjectUpdateRefspec(TestJobExecution): + @pytest.fixture + def project_update(self, execution_environment): + org = Organization(pk=1) + proj = Project(pk=1, organization=org, allow_override=True) + project_update = ProjectUpdate(pk=1, project=proj, scm_type='git') + project_update.websocket_emit_status = mock.Mock() + project_update.execution_environment = execution_environment + return project_update + + def test_refspec_with_allow_override_includes_plus_prefix(self, project_update, private_data_dir, mock_me): + """Test that refspec includes + prefix to allow non-fast-forward updates when allow_override is True""" + task = jobs.RunProjectUpdate() + task.instance = project_update + + # Call build_extra_vars_file which sets the refspec + with mock.patch.object(Licenser, 'validate', lambda *args, **kw: {}): + task.build_extra_vars_file(project_update, private_data_dir) + + # Read the extra vars file to check the refspec + with open(os.path.join(private_data_dir, 'env', 'extravars')) as fd: + extra_vars = yaml.load(fd, Loader=SafeLoader) + + # Verify the refspec includes the + prefix for force updates + assert 'scm_refspec' in extra_vars + assert extra_vars['scm_refspec'] == '+refs/heads/*:refs/remotes/origin/*' + + def test_custom_refspec_not_overridden(self, project_update, private_data_dir, mock_me): + """Test that custom user-provided refspec is not overridden""" + task = jobs.RunProjectUpdate() + task.instance = project_update + project_update.scm_refspec = 'refs/pull/*/head:refs/remotes/origin/pr/*' + + with mock.patch.object(Licenser, 'validate', lambda *args, **kw: {}): + task.build_extra_vars_file(project_update, private_data_dir) + + with open(os.path.join(private_data_dir, 'env', 'extravars')) as fd: + extra_vars = yaml.load(fd, Loader=SafeLoader) + + # Custom refspec should be preserved + assert extra_vars['scm_refspec'] == 'refs/pull/*/head:refs/remotes/origin/pr/*' + + def test_no_refspec_without_allow_override(self, execution_environment, private_data_dir, mock_me): + """Test that no refspec is set when allow_override is False""" + org = Organization(pk=1) + proj = Project(pk=1, organization=org, allow_override=False) + project_update = ProjectUpdate(pk=1, project=proj, scm_type='git') + project_update.websocket_emit_status = mock.Mock() + project_update.execution_environment = execution_environment + + task = jobs.RunProjectUpdate() + task.instance = project_update + + with mock.patch.object(Licenser, 'validate', lambda *args, **kw: {}): + task.build_extra_vars_file(project_update, private_data_dir) + + with open(os.path.join(private_data_dir, 'env', 'extravars')) as fd: + extra_vars = yaml.load(fd, Loader=SafeLoader) + + # No refspec should be set + assert 'scm_refspec' not in extra_vars + + class TestInventoryUpdateCredentials(TestJobExecution): @pytest.fixture def inventory_update(self, execution_environment): @@ -1716,7 +1314,8 @@ def run(expected_gce_zone): credential.credential_type.inject_credential(credential, env, safe_env, [], private_data_dir) assert env['GCE_ZONE'] == expected_gce_zone - json_data = json.load(open(env[cred_env_var], 'rb')) + with open(env[cred_env_var], 'rb') as f: + json_data = json.load(f) assert json_data['type'] == 'service_account' assert json_data['private_key'] == self.EXAMPLE_PRIVATE_KEY assert json_data['client_email'] == 'bob' @@ -1745,7 +1344,8 @@ def get_cred(): env = task.build_env(inventory_update, private_data_dir, private_data_files) path = to_host_path(env['OS_CLIENT_CONFIG_FILE'], private_data_dir) - shade_config = open(path, 'r').read() + with open(path, 'r') as f: + shade_config = f.read() assert ( '\n'.join( [ @@ -1908,8 +1508,8 @@ def test_fcntl_ioerror(): @mock.patch('os.open') -@mock.patch('logging.getLogger') -def test_acquire_lock_open_fail_logged(logging_getLogger, os_open, mock_me): +@mock.patch('awx.main.tasks.jobs.logger') +def test_acquire_lock_open_fail_logged(logger_mock, os_open, mock_me): err = OSError() err.errno = 3 err.strerror = 'dummy message' @@ -1919,21 +1519,18 @@ def test_acquire_lock_open_fail_logged(logging_getLogger, os_open, mock_me): os_open.side_effect = err - logger = mock.Mock() - logging_getLogger.return_value = logger - ProjectUpdate = jobs.RunProjectUpdate() with pytest.raises(OSError): ProjectUpdate.acquire_lock(instance) - assert logger.err.called_with("I/O error({0}) while trying to open lock file [{1}]: {2}".format(3, 'this_file_does_not_exist', 'dummy message')) + logger_mock.error.assert_called_with("I/O error({0}) while trying to open lock file [{1}]: {2}".format(3, 'this_file_does_not_exist', 'dummy message')) @mock.patch('os.open') @mock.patch('os.close') -@mock.patch('logging.getLogger') +@mock.patch('awx.main.tasks.jobs.logger') @mock.patch('fcntl.lockf') -def test_acquire_lock_acquisition_fail_logged(fcntl_lockf, logging_getLogger, os_close, os_open, mock_me): +def test_acquire_lock_acquisition_fail_logged(fcntl_lockf, logger_mock, os_close, os_open, mock_me): err = IOError() err.errno = 3 err.strerror = 'dummy message' @@ -1944,16 +1541,15 @@ def test_acquire_lock_acquisition_fail_logged(fcntl_lockf, logging_getLogger, os os_open.return_value = 3 - logger = mock.Mock() - logging_getLogger.return_value = logger - fcntl_lockf.side_effect = err ProjectUpdate = jobs.RunProjectUpdate() with pytest.raises(IOError): ProjectUpdate.acquire_lock(instance) os_close.assert_called_with(3) - assert logger.err.called_with("I/O error({0}) while trying to acquire lock on file [{1}]: {2}".format(3, 'this_file_does_not_exist', 'dummy message')) + logger_mock.error.assert_called_with( + "I/O error({0}) while trying to acquire lock on file [{1}]: {2}".format(3, 'this_file_does_not_exist', 'dummy message') + ) @pytest.mark.parametrize('injector_cls', [cls for cls in ManagedCredentialType.registry.values() if cls.injectors]) @@ -2008,7 +1604,7 @@ def test_project_update_no_ee(mock_me): with pytest.raises(RuntimeError) as e: task.build_env(job, {}) - assert 'The project could not sync because there is no Execution Environment' in str(e.value) + assert 'The ProjectUpdate could not run because there is no Execution Environment' in str(e.value) @pytest.mark.parametrize( diff --git a/awx/main/tests/unit/test_validators.py b/awx/main/tests/unit/test_validators.py index 925ea64335eb..2512ab28af73 100644 --- a/awx/main/tests/unit/test_validators.py +++ b/awx/main/tests/unit/test_validators.py @@ -132,6 +132,25 @@ def test_cert_with_key(): assert not pem_objects[1]['key_enc'] +def test_ssh_key_with_whitespace(): + # Test that SSH keys with leading/trailing whitespace/newlines are properly sanitized + # This addresses issue #14219 where copy-paste can introduce hidden newlines + valid_key_with_whitespace = "\n\n" + TEST_SSH_KEY_DATA + "\n\n" + pem_objects = validate_ssh_private_key(valid_key_with_whitespace) + assert pem_objects[0]['key_type'] == 'rsa' + assert not pem_objects[0]['key_enc'] + + # Test with just leading whitespace + valid_key_leading = "\n\n\n" + TEST_SSH_KEY_DATA + pem_objects = validate_ssh_private_key(valid_key_leading) + assert pem_objects[0]['key_type'] == 'rsa' + + # Test with just trailing whitespace + valid_key_trailing = TEST_SSH_KEY_DATA + "\n\n\n" + pem_objects = validate_ssh_private_key(valid_key_trailing) + assert pem_objects[0]['key_type'] == 'rsa' + + @pytest.mark.parametrize( "var_str", [ diff --git a/awx/main/tests/unit/test_views.py b/awx/main/tests/unit/test_views.py index e9e2c67baf3a..371e44157ab5 100644 --- a/awx/main/tests/unit/test_views.py +++ b/awx/main/tests/unit/test_views.py @@ -10,7 +10,6 @@ from awx.api.views import JobList from awx.api.generics import ListCreateAPIView, SubListAttachDetachAPIView - HTTP_METHOD_NAMES = [ 'get', 'post', @@ -88,6 +87,6 @@ def test_global_creation_always_possible(all_views): creatable_view = View if not creatable or not global_view: continue - assert 'POST' in global_view().allowed_methods, 'Resource {} should be creatable in global list view {}. ' 'Can be created now in {}'.format( + assert 'POST' in global_view().allowed_methods, 'Resource {} should be creatable in global list view {}. Can be created now in {}'.format( model, global_view, creatable_view ) diff --git a/awx/main/tests/unit/utils/test_analytics_proxy.py b/awx/main/tests/unit/utils/test_analytics_proxy.py new file mode 100644 index 000000000000..0a49c33cb97a --- /dev/null +++ b/awx/main/tests/unit/utils/test_analytics_proxy.py @@ -0,0 +1,112 @@ +import pytest +import requests +from unittest import mock + +from awx.main.utils.analytics_proxy import OIDCClient, TokenType, TokenError + +MOCK_TOKEN_RESPONSE = { + 'access_token': 'bob-access-token', + 'expires_in': 500, + 'refresh_expires_in': 900, + 'token_type': 'Bearer', + 'not-before-policy': 6, + 'scope': 'fake-scope1, fake-scope2', +} + + +@pytest.fixture +def oidc_client(): + ''' + oidc client instantiation fixture. + ''' + return OIDCClient( + 'fake-client-id', + 'fake-client-secret', + 'https://my-token-url.com/get/a/token/', + ['api.console'], + ) + + +@pytest.fixture +def token(): + ''' + Create Token class out of example OIDC token response. + ''' + return OIDCClient._json_response_to_token(MOCK_TOKEN_RESPONSE) + + +def test_generate_access_token(oidc_client): + with mock.patch( + 'awx.main.utils.analytics_proxy.requests.post', + return_value=mock.Mock(json=lambda: MOCK_TOKEN_RESPONSE, raise_for_status=mock.Mock(return_value=None)), # No exception raised + ): + oidc_client._generate_access_token() + + assert oidc_client.token + assert oidc_client.token.access_token == 'bob-access-token' + assert oidc_client.token.expires_in == 500 + assert oidc_client.token.refresh_expires_in == 900 + assert oidc_client.token.token_type == TokenType.BEARER + assert oidc_client.token.not_before_policy == 6 + assert oidc_client.token.scope == 'fake-scope1, fake-scope2' + + +def test_token_generation_error(oidc_client): + ''' + Check that TokenError is raised for failure in token generation process + ''' + exception_404 = requests.HTTPError('404 Client Error: Not Found for url') + with mock.patch( + 'awx.main.utils.analytics_proxy.requests.post', + return_value=mock.Mock(status_code=404, json=mock.Mock(return_value={'error': 'Not Found'}), raise_for_status=mock.Mock(side_effect=exception_404)), + ): + with pytest.raises(TokenError) as exc_info: + oidc_client._generate_access_token() + + assert exc_info.value.__cause__ == exception_404 + + +def test_make_request(oidc_client, token): + ''' + Check that make_request makes an http request with a generated token. + ''' + + def fake_generate_access_token(): + oidc_client.token = token + + with ( + mock.patch.object(oidc_client, '_generate_access_token', side_effect=fake_generate_access_token), + mock.patch('awx.main.utils.analytics_proxy.requests.request') as mock_request, + ): + oidc_client.make_request('GET', 'https://does_not_exist.com') + + mock_request.assert_called_with( + 'GET', + 'https://does_not_exist.com', + headers={ + 'Authorization': f'Bearer {token.access_token}', + 'Accept': 'application/json', + }, + ) + + +def test_make_request_existing_token(oidc_client, token): + ''' + Check that make_request does not try and generate a token. + ''' + oidc_client.token = token + + with ( + mock.patch.object(oidc_client, '_generate_access_token', side_effect=RuntimeError('expected not to be called')), + mock.patch('awx.main.utils.analytics_proxy.requests.request') as mock_request, + ): + oidc_client.make_request('GET', 'https://does_not_exist.com') + + mock_request.assert_called_with( + 'GET', + 'https://does_not_exist.com', + headers={ + 'Authorization': f'Bearer {token.access_token}', + 'Accept': 'application/json', + }, + ) diff --git a/awx/main/tests/unit/utils/test_common.py b/awx/main/tests/unit/utils/test_common.py index cc8f65bf9333..b5983497b20a 100644 --- a/awx/main/tests/unit/utils/test_common.py +++ b/awx/main/tests/unit/utils/test_common.py @@ -12,6 +12,8 @@ from rest_framework.exceptions import ParseError +from ansible_base.lib.utils.models import get_type_for_model + from awx.main.utils import common from awx.api.validators import HostnameRegexValidator @@ -106,7 +108,7 @@ def test_set_environ(): # Cases relied on for scheduler dependent jobs list @pytest.mark.parametrize('model,name', TEST_MODELS) def test_get_type_for_model(model, name): - assert common.get_type_for_model(model) == name + assert get_type_for_model(model) == name def test_get_model_for_invalid_type(): @@ -119,6 +121,10 @@ def test_get_model_for_valid_type(model_type, model_class): assert common.get_model_for_type(model_type) == model_class +def test_is_testing(): + assert common.is_testing() is True + + @pytest.mark.parametrize("model_type,model_class", [(name, cls) for cls, name in TEST_MODELS]) def test_get_capacity_type(model_type, model_class): if model_type in ('job', 'ad_hoc_command', 'inventory_update', 'job_template'): @@ -234,7 +240,15 @@ def test_extract_ansible_vars(): ('git', 'https://example.com/bar.git', 'user', 'pw', True, False, 'https://user:pw@example.com/bar.git'), ('git', 'https://example@example.com/bar.git', False, 'something', True, False, 'https://example.com/bar.git'), # Special github/bitbucket cases - ('git', 'notgit@github.com:ansible/awx.git', True, True, True, False, ValueError('Username must be "git" for SSH access to github.com.')), + ( + 'git', + 'notgit@github.com:ansible/awx.git', + True, + True, + True, + False, + ValueError('Username must be "git" for SSH access to github.com.'), + ), ( 'git', 'notgit@bitbucket.org:does-not-exist/example.git', @@ -312,22 +326,18 @@ def test_hostame_regex_validator_default_constructor(self, regex_expr, re_flags) def test_good_call(self, regex_expr, re_flags): h = HostnameRegexValidator(regex=regex_expr, flags=re_flags) - assert (h("192.168.56.101"), None) + assert h("192.168.56.101") is None def test_bad_call(self, regex_expr, re_flags): h = HostnameRegexValidator(regex=regex_expr, flags=re_flags) - try: + with pytest.raises(ValidationError, match=r"^\['illegal characters detected in hostname=@#\$%\)\$#\(TUFAS_DG. Please verify.'\]$"): h("@#$%)$#(TUFAS_DG") - except ValidationError as e: - assert e.message is not None def test_good_call_with_inverse(self, regex_expr, re_flags, inverse_match=True): h = HostnameRegexValidator(regex=regex_expr, flags=re_flags, inverse_match=inverse_match) - try: + with pytest.raises(ValidationError, match=r"^\['Enter a valid value.'\]$"): h("1.2.3.4") - except ValidationError as e: - assert e.message is not None def test_bad_call_with_inverse(self, regex_expr, re_flags, inverse_match=True): h = HostnameRegexValidator(regex=regex_expr, flags=re_flags, inverse_match=inverse_match) - assert (h("@#$%)$#(TUFAS_DG"), None) + assert h("@#$%)$#(TUFAS_DG") is None diff --git a/awx/main/tests/unit/utils/test_execution_environments.py b/awx/main/tests/unit/utils/test_execution_environments.py index 04a8b05f5f72..1e41890e5f86 100644 --- a/awx/main/tests/unit/utils/test_execution_environments.py +++ b/awx/main/tests/unit/utils/test_execution_environments.py @@ -4,8 +4,7 @@ import pytest -from awx.main.utils.execution_environments import to_container_path - +from awx_plugins.interfaces._temporary_private_container_api import get_incontainer_path private_data_dir = '/tmp/pdd_iso/awx_xxx' @@ -22,7 +21,7 @@ ], ) def test_switch_paths(container_path, host_path): - assert to_container_path(host_path, private_data_dir) == container_path + assert get_incontainer_path(host_path, private_data_dir) == container_path def test_symlink_isolation_dir(request): @@ -40,7 +39,7 @@ def remove_folders(): pdd = f'{dst_path}/awx_xxx' - assert to_container_path(f'{pdd}/env/tmp1234', pdd) == '/runner/env/tmp1234' + assert get_incontainer_path(f'{pdd}/env/tmp1234', pdd) == '/runner/env/tmp1234' @pytest.mark.parametrize( @@ -53,4 +52,4 @@ def remove_folders(): ) def test_invalid_host_path(host_path): with pytest.raises(RuntimeError): - to_container_path(host_path, private_data_dir) + get_incontainer_path(host_path, private_data_dir) diff --git a/awx/main/tests/unit/utils/test_filters.py b/awx/main/tests/unit/utils/test_filters.py index ef0abb80d3f1..c2b23de0eea0 100644 --- a/awx/main/tests/unit/utils/test_filters.py +++ b/awx/main/tests/unit/utils/test_filters.py @@ -68,7 +68,9 @@ def __init__(self): @mock.patch('awx.main.utils.filters.get_model', return_value=mockHost()) class TestSmartFilterQueryFromString: - @mock.patch('awx.api.filters.get_fields_from_path', lambda model, path: ([model], path)) # disable field filtering, because a__b isn't a real Host field + @mock.patch( + 'ansible_base.rest_filters.rest_framework.field_lookup_backend.get_fields_from_path', lambda model, path, **kwargs: ([model], path) + ) # disable field filtering, because a__b isn't a real Host field @pytest.mark.parametrize( "filter_string,q_expected", [ @@ -93,7 +95,7 @@ def test_query_generated(self, mock_get_host_model, filter_string, q_expected): @pytest.mark.parametrize( "filter_string", [ - 'ansible_facts__facts__facts__blank=' 'ansible_facts__a__b__c__ space =ggg', + 'ansible_facts__facts__facts__blank=ansible_facts__a__b__c__ space =ggg', ], ) def test_invalid_filter_strings(self, mock_get_host_model, filter_string): @@ -104,7 +106,7 @@ def test_invalid_filter_strings(self, mock_get_host_model, filter_string): @pytest.mark.parametrize( "filter_string", [ - 'created_by__password__icontains=pbkdf2' 'search=foo or created_by__password__icontains=pbkdf2', + 'created_by__password__icontains=pbkdf2search=foo or created_by__password__icontains=pbkdf2', 'created_by__password__icontains=pbkdf2 or search=foo', ], ) @@ -116,8 +118,8 @@ def test_forbidden_filter_string(self, mock_get_host_model, filter_string): @pytest.mark.parametrize( "filter_string,q_expected", [ - (u'(a=abc\u1F5E3def)', Q(**{u"a": u"abc\u1F5E3def"})), - (u'(ansible_facts__a=abc\u1F5E3def)', Q(**{u"ansible_facts__contains": {u"a": u"abc\u1F5E3def"}})), + (u'(a=abc\u1f5e3def)', Q(**{u"a": u"abc\u1f5e3def"})), + (u'(ansible_facts__a=abc\u1f5e3def)', Q(**{u"ansible_facts__contains": {u"a": u"abc\u1f5e3def"}})), ], ) def test_unicode(self, mock_get_host_model, filter_string, q_expected): diff --git a/awx/main/tests/unit/utils/test_inventory_vars.py b/awx/main/tests/unit/utils/test_inventory_vars.py new file mode 100644 index 000000000000..8ba55c900e17 --- /dev/null +++ b/awx/main/tests/unit/utils/test_inventory_vars.py @@ -0,0 +1,110 @@ +""" +Test utility functions and classes for inventory variable handling. +""" + +import pytest + +from awx.main.utils.inventory_vars import InventoryVariable +from awx.main.utils.inventory_vars import InventoryGroupVariables + + +def test_inventory_variable_update_basic(): + """Test basic functionality of an inventory variable.""" + x = InventoryVariable("x") + assert x.has_no_source + x.update(1, 101) + assert str(x) == "1" + x.update(2, 102) + assert str(x) == "2" + x.update(3, 103) + assert str(x) == "3" + x.delete(102) + assert str(x) == "3" + x.delete(103) + assert str(x) == "1" + x.delete(101) + assert x.value is None + assert x.has_no_source + + +@pytest.mark.parametrize( + "updates", # (, , ) + [ + ((101, 1, 1),), + ((101, 1, 1), (101, None, None)), + ((101, 1, 1), (102, 2, 2), (102, None, 1)), + ((101, 1, 1), (102, 2, 2), (101, None, 2), (102, None, None)), + ( + (101, 0, 0), + (101, 1, 1), + (102, 2, 2), + (103, 3, 3), + (102, None, 3), + (103, None, 1), + (101, None, None), + ), + ], +) +def test_inventory_variable_update(updates: tuple[int, int | None, int | None]): + """ + Test if the variable value is set correctly on a sequence of updates. + + For this test, the value `None` implies the deletion of the source. + """ + x = InventoryVariable("x") + for src_id, value, expected_value in updates: + if value is None: + x.delete(src_id) + else: + x.update(value, src_id) + assert x.value == expected_value + + +def test_inventory_group_variables_update_basic(): + """Test basic functionality of an inventory variables update.""" + vars = InventoryGroupVariables(1) + vars.update_from_src({"x": 1, "y": 2}, 101) + assert vars == {"x": 1, "y": 2} + + +@pytest.mark.parametrize( + "updates", # (, : dict, : dict) + [ + ((101, {"x": 1, "y": 1}, {"x": 1, "y": 1}),), + ( + (101, {"x": 1, "y": 1}, {"x": 1, "y": 1}), + (102, {}, {"x": 1, "y": 1}), + ), + ( + (101, {"x": 1, "y": 1}, {"x": 1, "y": 1}), + (102, {"x": 2}, {"x": 2, "y": 1}), + ), + ( + (101, {"x": 1, "y": 1}, {"x": 1, "y": 1}), + (102, {"x": 2, "y": 2}, {"x": 2, "y": 2}), + ), + ( + (101, {"x": 1, "y": 1}, {"x": 1, "y": 1}), + (102, {"x": 2, "z": 2}, {"x": 2, "y": 1, "z": 2}), + ), + ( + (101, {"x": 1, "y": 1}, {"x": 1, "y": 1}), + (102, {"x": 2, "z": 2}, {"x": 2, "y": 1, "z": 2}), + (102, {}, {"x": 1, "y": 1}), + ), + ( + (101, {"x": 1, "y": 1}, {"x": 1, "y": 1}), + (102, {"x": 2, "z": 2}, {"x": 2, "y": 1, "z": 2}), + (103, {"x": 3}, {"x": 3, "y": 1, "z": 2}), + (101, {}, {"x": 3, "z": 2}), + ), + ], +) +def test_inventory_group_variables_update(updates: tuple[int, int | None, int | None]): + """ + Test if the group vars are set correctly on various update sequences. + """ + groupvars = InventoryGroupVariables(2) + for src_id, vars, expected_vars in updates: + groupvars.update_from_src(vars, src_id) + assert groupvars == expected_vars diff --git a/awx/main/tests/unit/utils/test_receptor.py b/awx/main/tests/unit/utils/test_receptor.py index 0a7e182070c7..123044fcad1b 100644 --- a/awx/main/tests/unit/utils/test_receptor.py +++ b/awx/main/tests/unit/utils/test_receptor.py @@ -3,7 +3,7 @@ def test_file_cleanup_scenario(): args = _convert_args_to_cli({'exclude_strings': ['awx_423_', 'awx_582_'], 'file_pattern': '/tmp/awx_*_*'}) - assert ' '.join(args) == 'cleanup --exclude-strings=awx_423_ awx_582_ --file-pattern=/tmp/awx_*_*' + assert ' '.join(args) == 'cleanup --exclude-strings "awx_423_" "awx_582_" --file-pattern=/tmp/awx_*_*' def test_image_cleanup_scenario(): @@ -17,5 +17,6 @@ def test_image_cleanup_scenario(): } ) assert ( - ' '.join(args) == 'cleanup --remove-images=quay.invalid/foo/bar:latest quay.invalid/foo/bar:devel --image-prune --process-isolation-executable=podman' + ' '.join(args) + == 'cleanup --remove-images "quay.invalid/foo/bar:latest" "quay.invalid/foo/bar:devel" --image-prune --process-isolation-executable=podman' ) diff --git a/awx/main/tests/unit/utils/test_redis.py b/awx/main/tests/unit/utils/test_redis.py new file mode 100644 index 000000000000..23e0940fc032 --- /dev/null +++ b/awx/main/tests/unit/utils/test_redis.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2025 Ansible, Inc. +# All Rights Reserved + +from django.test.utils import override_settings + +from awx.main.utils.redis import get_redis_client, get_redis_client_async +from redis.exceptions import BusyLoadingError, ConnectionError, TimeoutError +from redis.backoff import ExponentialBackoff + + +class TestRedisRetryConfiguration: + """Verify Redis retry configuration is applied to connection objects.""" + + def test_retry_configuration_applied_to_client(self, settings): + """Verify all retry settings are applied to the connection pool.""" + # Test sync client + client = get_redis_client() + retry = client.connection_pool.connection_kwargs['retry'] + backoff = retry._backoff + retry_errors = client.connection_pool.connection_kwargs['retry_on_error'] + + # Assert provided values match values on the object + assert retry._retries == settings.REDIS_RETRY_COUNT == 3 + assert isinstance(backoff, ExponentialBackoff) + assert backoff._base == settings.REDIS_BACKOFF_BASE == 0.5 + assert backoff._cap == settings.REDIS_BACKOFF_CAP == 1.0 + assert BusyLoadingError in retry_errors + assert ConnectionError in retry_errors + assert TimeoutError in retry_errors + + # Test async client has same config + client_async = get_redis_client_async() + retry_async = client_async.connection_pool.connection_kwargs['retry'] + backoff_async = retry_async._backoff + retry_errors_async = client_async.connection_pool.connection_kwargs['retry_on_error'] + + assert retry_async._retries == settings.REDIS_RETRY_COUNT + assert backoff_async._base == settings.REDIS_BACKOFF_BASE + assert backoff_async._cap == settings.REDIS_BACKOFF_CAP + assert ConnectionError in retry_errors_async + + @override_settings(REDIS_RETRY_COUNT=5) + def test_override_settings_applied_to_client(self): + """Verify override_settings changes are applied to client object.""" + client = get_redis_client() + retry = client.connection_pool.connection_kwargs['retry'] + + assert retry._retries == 5 + + @override_settings(REDIS_BACKOFF_CAP=2.0, REDIS_BACKOFF_BASE=1.0) + def test_override_backoff_settings_applied_to_client(self): + """Verify override_settings for backoff parameters are applied to client object.""" + client = get_redis_client() + retry = client.connection_pool.connection_kwargs['retry'] + backoff = retry._backoff + + # Assert provided values match values on object + assert backoff._cap == 2.0 + assert backoff._base == 1.0 diff --git a/awx/main/tests/unit/utils/test_reload.py b/awx/main/tests/unit/utils/test_reload.py index 5f8c7b95e35b..2b41a5fef0c1 100644 --- a/awx/main/tests/unit/utils/test_reload.py +++ b/awx/main/tests/unit/utils/test_reload.py @@ -7,15 +7,15 @@ def test_produce_supervisor_command(mocker): mock_process = mocker.MagicMock() mock_process.communicate = communicate_mock Popen_mock = mocker.MagicMock(return_value=mock_process) - with mocker.patch.object(reload.subprocess, 'Popen', Popen_mock): - reload.supervisor_service_command("restart") - reload.subprocess.Popen.assert_called_once_with( - [ - 'supervisorctl', - 'restart', - 'tower-processes:*', - ], - stderr=-1, - stdin=-1, - stdout=-1, - ) + mocker.patch.object(reload.subprocess, 'Popen', Popen_mock) + reload.supervisor_service_command("restart") + reload.subprocess.Popen.assert_called_once_with( + [ + 'supervisorctl', + 'restart', + 'tower-processes:*', + ], + stderr=-1, + stdin=-1, + stdout=-1, + ) diff --git a/awx/main/tests/unit/utils/test_schedule_fast_forward.py b/awx/main/tests/unit/utils/test_schedule_fast_forward.py new file mode 100644 index 000000000000..be1bdae53eff --- /dev/null +++ b/awx/main/tests/unit/utils/test_schedule_fast_forward.py @@ -0,0 +1,176 @@ +import pytest +import datetime +import dateutil + +from django.utils.timezone import now + +from awx.main.models.schedules import _fast_forward_rrule, Schedule +from dateutil.rrule import HOURLY, MINUTELY, MONTHLY + +REF_DT = datetime.datetime(2024, 1, 1, tzinfo=datetime.timezone.utc) + + +@pytest.mark.parametrize( + 'rrulestr', + [ + pytest.param('DTSTART;TZID=America/New_York:20201118T200000 RRULE:FREQ=MINUTELY;INTERVAL=5', id='every-5-min'), + pytest.param('DTSTART;TZID=America/New_York:20201118T200000 RRULE:FREQ=HOURLY;INTERVAL=5', id='every-5-hours'), + pytest.param('DTSTART;TZID=America/New_York:20201118T200000 RRULE:FREQ=YEARLY;INTERVAL=5', id='every-5-years'), + pytest.param( + 'DTSTART;TZID=America/New_York:20201118T200000 RRULE:FREQ=MINUTELY;INTERVAL=5;WKST=SU;BYMONTH=2,3;BYMONTHDAY=18;BYHOUR=5;BYMINUTE=35;BYSECOND=0', + id='every-5-minutes-at-5:35:00-am-on-the-18th-day-of-feb-or-march-with-week-starting-on-sundays', + ), + pytest.param( + 'DTSTART;TZID=America/New_York:20201118T200000 RRULE:FREQ=HOURLY;INTERVAL=5;WKST=SU;BYMONTH=2,3;BYHOUR=5', + id='every-5-hours-at-5-am-in-feb-or-march-with-week-starting-on-sundays', + ), + ], +) +def test_fast_forwarded_rrule_matches_original_occurrence(rrulestr): + ''' + Assert that the resulting fast forwarded date is included in the original rrule + occurrence list + ''' + rruleset = Schedule.rrulestr(rrulestr, ref_dt=REF_DT) + + gen = rruleset.xafter(REF_DT, count=200) + occurrences = [i for i in gen] + + orig_rruleset = dateutil.rrule.rrulestr(rrulestr, forceset=True) + gen = orig_rruleset.xafter(REF_DT, count=200) + orig_occurrences = [i for i in gen] + + assert occurrences == orig_occurrences + + +@pytest.mark.parametrize( + 'ref_dt', + [ + pytest.param(datetime.datetime(2024, 12, 1, 0, 0, tzinfo=datetime.timezone.utc), id='ref-dt-out-of-dst'), + pytest.param(datetime.datetime(2024, 6, 1, 0, 0, tzinfo=datetime.timezone.utc), id='ref-dt-in-dst'), + ], +) +@pytest.mark.parametrize( + 'rrulestr', + [ + pytest.param('DTSTART;TZID=America/New_York:20240118T200000 RRULE:FREQ=MINUTELY;INTERVAL=10', id='rrule-out-of-dst'), + pytest.param('DTSTART;TZID=America/New_York:20240318T000000 RRULE:FREQ=MINUTELY;INTERVAL=10', id='rrule-in-dst'), + pytest.param( + 'DTSTART;TZID=Europe/Lisbon:20230703T005800 RRULE:INTERVAL=10;FREQ=MINUTELY;BYHOUR=9,10,11,12,13,14,15,16,17,18,19,20,21', id='rrule-in-dst-by-hour' + ), + ], +) +def test_fast_forward_across_dst(rrulestr, ref_dt): + ''' + Ensure fast forward works across daylight savings boundaries + "in dst" means between March and November + "out of dst" means between November and March the following year + + Assert that the resulting fast forwarded date is included in the original rrule + occurrence list + ''' + rruleset = Schedule.rrulestr(rrulestr, ref_dt=ref_dt) + + gen = rruleset.xafter(ref_dt, count=200) + occurrences = [i for i in gen] + + orig_rruleset = dateutil.rrule.rrulestr(rrulestr, forceset=True) + gen = orig_rruleset.xafter(ref_dt, count=200) + orig_occurrences = [i for i in gen] + + assert occurrences == orig_occurrences + + +def test_fast_forward_rrule_hours(): + ''' + Generate an rrule for each hour of the day + + Assert that the resulting fast forwarded date is included in the original rrule + occurrence list + ''' + rrulestr_prefix = 'DTSTART;TZID=America/New_York:20201118T200000 RRULE:FREQ=HOURLY;' + for interval in range(1, 24): + rrulestr = f"{rrulestr_prefix}INTERVAL={interval}" + rruleset = Schedule.rrulestr(rrulestr, ref_dt=REF_DT) + + gen = rruleset.xafter(REF_DT, count=200) + occurrences = [i for i in gen] + + orig_rruleset = dateutil.rrule.rrulestr(rrulestr, forceset=True) + gen = orig_rruleset.xafter(REF_DT, count=200) + orig_occurrences = [i for i in gen] + + assert occurrences == orig_occurrences + + +def test_multiple_rrules(): + ''' + Create an rruleset that contains multiple rrules and an exrule + rruleA: freq HOURLY interval 5, dtstart should be fast forwarded + rruleB: freq HOURLY interval 7, dtstart should be fast forwarded + rruleC: freq MONTHLY interval 1, dtstart should not be fast forwarded + exruleA: freq HOURLY interval 5, dtstart should be fast forwarded + ''' + rrulestr = '''DTSTART;TZID=America/New_York:20201118T200000 + RRULE:FREQ=HOURLY;INTERVAL=5 + RRULE:FREQ=HOURLY;INTERVAL=7 + RRULE:FREQ=MONTHLY + EXRULE:FREQ=HOURLY;INTERVAL=5;BYDAY=MO,TU,WE''' + rruleset = Schedule.rrulestr(rrulestr, ref_dt=REF_DT) + + rruleA, rruleB, rruleC = rruleset._rrule + exruleA = rruleset._exrule[0] + + # assert that each rrule has its own dtstart + assert rruleA._dtstart != rruleB._dtstart + assert rruleA._dtstart != rruleC._dtstart + + assert exruleA._dtstart == rruleA._dtstart + + # the new dtstart should be within INTERVAL amount of hours from REF_DT + assert (REF_DT - rruleA._dtstart) < datetime.timedelta(hours=6) + assert (REF_DT - rruleB._dtstart) < datetime.timedelta(hours=8) + assert (REF_DT - exruleA._dtstart) < datetime.timedelta(hours=6) + + # the freq=monthly rrule's dtstart should not have changed + dateutil_rruleset = dateutil.rrule.rrulestr(rrulestr, forceset=True) + assert rruleC._dtstart == dateutil_rruleset._rrule[2]._dtstart + + gen = rruleset.xafter(REF_DT, count=200) + occurrences = [i for i in gen] + + orig_rruleset = dateutil.rrule.rrulestr(rrulestr, forceset=True) + gen = orig_rruleset.xafter(REF_DT, count=200) + orig_occurrences = [i for i in gen] + + assert occurrences == orig_occurrences + + +def test_future_date_does_not_fast_forward(): + dtstart = now() + datetime.timedelta(days=30) + rrule = dateutil.rrule.rrule(freq=HOURLY, interval=7, dtstart=dtstart) + new_rrule = _fast_forward_rrule(rrule, ref_dt=REF_DT) + assert new_rrule == rrule + + +def test_rrule_with_count_does_not_fast_forward(): + rrule = dateutil.rrule.rrule(freq=MINUTELY, interval=5, count=1, dtstart=REF_DT) + + assert rrule == _fast_forward_rrule(rrule, ref_dt=REF_DT) + + +@pytest.mark.parametrize( + ('freq', 'interval'), + [ + pytest.param(MINUTELY, 15.5555, id="freq-MINUTELY-interval-15.5555"), + pytest.param(MONTHLY, 1, id="freq-MONTHLY-interval-1"), + ], +) +def test_does_not_fast_forward(freq, interval): + ''' + Assert a couple of rrules that should not be fast forwarded + ''' + dtstart = REF_DT - datetime.timedelta(days=30) + rrule = dateutil.rrule.rrule(freq=freq, interval=interval, dtstart=dtstart) + + assert rrule == _fast_forward_rrule(rrule, ref_dt=REF_DT) diff --git a/awx/main/tests/unit/utils/test_validate_rh.py b/awx/main/tests/unit/utils/test_validate_rh.py new file mode 100644 index 000000000000..65052bbdefff --- /dev/null +++ b/awx/main/tests/unit/utils/test_validate_rh.py @@ -0,0 +1,154 @@ +from unittest.mock import patch +from awx.main.utils.licensing import Licenser + + +def test_validate_rh_basic_auth_rhsm(): + """ + Assert get_rhsm_subs is called when + - basic_auth=True + - host is subscription.rhsm.redhat.com + """ + licenser = Licenser() + + with patch.object(licenser, 'get_host_from_rhsm_config', return_value='https://subscription.rhsm.redhat.com') as mock_get_host, patch.object( + licenser, 'get_rhsm_subs', return_value=[] + ) as mock_get_rhsm, patch.object(licenser, 'get_satellite_subs') as mock_get_satellite, patch.object( + licenser, 'get_crc_subs' + ) as mock_get_crc, patch.object( + licenser, 'generate_license_options_from_entitlements' + ) as mock_generate: + + licenser.validate_rh('testuser', 'testpass', basic_auth=True) + + # Assert the correct methods were called + mock_get_host.assert_called_once() + mock_get_rhsm.assert_called_once_with('https://subscription.rhsm.redhat.com', 'testuser', 'testpass') + mock_get_satellite.assert_not_called() + mock_get_crc.assert_not_called() + mock_generate.assert_called_once_with([], is_candlepin=True) + + +def test_validate_rh_basic_auth_satellite(): + """ + Assert get_satellite_subs is called when + - basic_auth=True + - custom satellite host + """ + licenser = Licenser() + + with patch.object(licenser, 'get_host_from_rhsm_config', return_value='https://satellite.example.com') as mock_get_host, patch.object( + licenser, 'get_rhsm_subs' + ) as mock_get_rhsm, patch.object(licenser, 'get_satellite_subs', return_value=[]) as mock_get_satellite, patch.object( + licenser, 'get_crc_subs' + ) as mock_get_crc, patch.object( + licenser, 'generate_license_options_from_entitlements' + ) as mock_generate: + + licenser.validate_rh('testuser', 'testpass', basic_auth=True) + + # Assert the correct methods were called + mock_get_host.assert_called_once() + mock_get_rhsm.assert_not_called() + mock_get_satellite.assert_called_once_with('https://satellite.example.com', 'testuser', 'testpass') + mock_get_crc.assert_not_called() + mock_generate.assert_called_once_with([], is_candlepin=True) + + +def test_validate_rh_service_account_crc(): + """ + Assert get_crc_subs is called when + - basic_auth=False + """ + licenser = Licenser() + + with patch('awx.main.utils.licensing.settings') as mock_settings, patch.object(licenser, 'get_host_from_rhsm_config') as mock_get_host, patch.object( + licenser, 'get_rhsm_subs' + ) as mock_get_rhsm, patch.object(licenser, 'get_satellite_subs') as mock_get_satellite, patch.object( + licenser, 'get_crc_subs', return_value=[] + ) as mock_get_crc, patch.object( + licenser, 'generate_license_options_from_entitlements' + ) as mock_generate: + + mock_settings.SUBSCRIPTIONS_RHSM_URL = 'https://console.redhat.com/api/rhsm/v1/subscriptions' + + licenser.validate_rh('client_id', 'client_secret', basic_auth=False) + + # Assert the correct methods were called + mock_get_host.assert_not_called() + mock_get_rhsm.assert_not_called() + mock_get_satellite.assert_not_called() + mock_get_crc.assert_called_once_with('https://console.redhat.com/api/rhsm/v1/subscriptions', 'client_id', 'client_secret') + mock_generate.assert_called_once_with([], is_candlepin=False) + + +def test_validate_rh_missing_user_raises_error(): + """Test validate_rh raises ValueError when user is missing""" + licenser = Licenser() + + with patch.object(licenser, 'get_host_from_rhsm_config', return_value='https://subscription.rhsm.redhat.com'): + try: + licenser.validate_rh(None, 'testpass', basic_auth=True) + assert False, "Expected ValueError to be raised" + except ValueError as e: + assert 'subscriptions_client_id or subscriptions_username is required' in str(e) + + +def test_validate_rh_missing_password_raises_error(): + """Test validate_rh raises ValueError when password is missing""" + licenser = Licenser() + + with patch.object(licenser, 'get_host_from_rhsm_config', return_value='https://subscription.rhsm.redhat.com'): + try: + licenser.validate_rh('testuser', None, basic_auth=True) + assert False, "Expected ValueError to be raised" + except ValueError as e: + assert 'subscriptions_client_secret or subscriptions_password is required' in str(e) + + +def test_validate_rh_no_host_fallback_to_candlepin(): + """Test validate_rh falls back to REDHAT_CANDLEPIN_HOST when no host from config + - basic_auth=True + - no host from config + - REDHAT_CANDLEPIN_HOST is set + """ + licenser = Licenser() + + with patch('awx.main.utils.licensing.settings') as mock_settings, patch.object( + licenser, 'get_host_from_rhsm_config', return_value=None + ) as mock_get_host, patch.object(licenser, 'get_rhsm_subs', return_value=[]) as mock_get_rhsm, patch.object( + licenser, 'get_satellite_subs', return_value=[] + ) as mock_get_satellite, patch.object( + licenser, 'get_crc_subs' + ) as mock_get_crc, patch.object( + licenser, 'generate_license_options_from_entitlements' + ) as mock_generate: + + mock_settings.REDHAT_CANDLEPIN_HOST = 'https://candlepin.example.com' + licenser.validate_rh('testuser', 'testpass', basic_auth=True) + + # Assert the correct methods were called + mock_get_host.assert_called_once() + mock_get_rhsm.assert_not_called() + mock_get_satellite.assert_called_once_with('https://candlepin.example.com', 'testuser', 'testpass') + mock_get_crc.assert_not_called() + mock_generate.assert_called_once_with([], is_candlepin=True) + + +def test_validate_rh_empty_credentials_basic_auth(): + """Test validate_rh with empty string credentials raises ValueError""" + licenser = Licenser() + + with patch.object(licenser, 'get_host_from_rhsm_config', return_value='https://subscription.rhsm.redhat.com'): + # Test empty user + try: + licenser.validate_rh(None, 'testpass', basic_auth=True) + assert False, "Expected ValueError to be raised" + except ValueError as e: + assert 'subscriptions_client_id or subscriptions_username is required' in str(e) + + # Test empty password + try: + licenser.validate_rh('testuser', None, basic_auth=True) + assert False, "Expected ValueError to be raised" + except ValueError as e: + assert 'subscriptions_client_secret or subscriptions_password is required' in str(e) diff --git a/awx/main/utils/__init__.py b/awx/main/utils/__init__.py index 2ffec9d8b617..af7473b0bd9e 100644 --- a/awx/main/utils/__init__.py +++ b/awx/main/utils/__init__.py @@ -3,6 +3,7 @@ # AWX from awx.main.utils.common import * # noqa +from awx.main.utils.redis import get_redis_client, get_redis_client_async # noqa from awx.main.utils.encryption import ( # noqa get_encryption_key, encrypt_field, diff --git a/awx/main/utils/analytics_proxy.py b/awx/main/utils/analytics_proxy.py new file mode 100644 index 000000000000..a6a599942e21 --- /dev/null +++ b/awx/main/utils/analytics_proxy.py @@ -0,0 +1,188 @@ +''' +Proxy requests Analytics requests +''' + +import time + +from enum import Enum + +from typing import Optional, Any + +import requests + +DEFAULT_OIDC_TOKEN_ENDPOINT = 'https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token' + + +class TokenError(requests.RequestException): + ''' + Raised when token generation request fails. + + Useful for differentiating request failure for make_request() vs. + other requests issued to get a token i.e.: + + try: + client = OIDCClient(...) + client.make_request(...) + except TokenError as e: + print(f"Token generation failed due to {e.__cause__}") + except requests.RequestException: + print("API request failed) + ''' + + def __init__(self, message="Token generation request failed", response=None): + super().__init__(message) + self.response = response # Store the response for debugging + + +def _now(reason: str): + ''' + Wrapper for time. Helps with testing. + ''' + return int(time.time()) + + +class TokenType(Enum): + ''' + Access token type as returned by the remote API. + ''' + + BEARER = 'Bearer' + + +class Token: + ''' + Token data generated by OIDC response. + ''' + + access_token: str + expires_in: int + refresh_expires_in: int + token_type: TokenType + not_before_policy: int # not-before-policy + scope: str + + def __init__( + self, + access_token: str, + expires_in: int, + refresh_expires_in: int, + token_type: TokenType, + not_before_policy: int, + scope: str, + ): + self.access_token = access_token + self.expires_in = expires_in + self.refresh_expires_in = refresh_expires_in + self.token_type = token_type + self.not_before_policy = not_before_policy + self.scope = scope + + self._now = _now(reason='token-creation') + + @property + def expires_at(self) -> int: + ''' + Unix timestamp in seconds of when the token expires. + ''' + return self._now + self.expires_in + + def is_expired(self) -> bool: + ''' + Check if the token is expired. + ''' + return _now(reason='token-expiration-check') >= self.expires_at + + +class OIDCClient: + ''' + Wraps requests library make_request() and manages OIDC access token. + ''' + + def __init__( + self, + client_id: str, + client_secret: str, + token_url: str = DEFAULT_OIDC_TOKEN_ENDPOINT, + scopes: list[str] = None, + base_url: str = '', + ) -> None: + self.client_id: str = client_id + self.client_secret: str = client_secret + self.token_url: str = token_url + if scopes is None: + scopes = ['api.console'] + self.scopes = scopes + self.base_url: str = base_url + self.token: Optional[Token] = None + + @classmethod + def _json_response_to_token(cls, json_response: Any) -> Token: + return Token( + access_token=json_response['access_token'], + expires_in=json_response['expires_in'], + refresh_expires_in=json_response['refresh_expires_in'], + token_type=TokenType(json_response['token_type']), + not_before_policy=json_response['not-before-policy'], + scope=json_response['scope'], + ) + + def _generate_access_token(self) -> None: + ''' + Fetches the initial access token using client credentials. + ''' + response = requests.post( + self.token_url, + data={ + 'grant_type': 'client_credentials', + 'client_id': self.client_id, + 'client_secret': self.client_secret, + 'scope': self.scopes, + }, + headers={'Content-Type': 'application/x-www-form-urlencoded'}, + ) + try: + response.raise_for_status() + except requests.RequestException as e: + raise TokenError() from e + self.token = OIDCClient._json_response_to_token(response.json()) + + def _add_headers(self, headers: dict[str, str]) -> None: + ''' + Add token header + ''' + headers.update( + { + 'Authorization': f'Bearer {self.token.access_token}', + 'Accept': 'application/json', + } + ) + + def _make_request(self, method: str, url: str, headers: dict[str, str], **kwargs: Any) -> requests.Response: + ''' + Actually make an API call. + ''' + self._add_headers(headers) + return requests.request(method, url, headers=headers, **kwargs) + + def make_request(self, method: str, endpoint: str, **kwargs: Any) -> requests.Response: + ''' + Makes an authenticated request and refreshes the token if expired. + ''' + has_generated_token = False + + def generate_access_token(): + self._generate_access_token() + return True + + if not self.token or self.token.is_expired(): + has_generated_token = generate_access_token() + + url = f'{self.base_url}{endpoint}' + headers = kwargs.pop('headers', {}) + + response = self._make_request(method, url, headers, **kwargs) + if not has_generated_token and response.status_code == 401: + generate_access_token() + response = self._make_request(method, url, headers, **kwargs) + + return response diff --git a/awx/main/utils/ansible.py b/awx/main/utils/ansible.py index 64530c53007c..cd99b347de8d 100644 --- a/awx/main/utils/ansible.py +++ b/awx/main/utils/ansible.py @@ -48,15 +48,16 @@ def could_be_playbook(project_path, dir_path, filename): # show up. matched = False try: - for n, line in enumerate(codecs.open(playbook_path, 'r', encoding='utf-8', errors='ignore')): - if valid_playbook_re.match(line): - matched = True - break - # Any YAML file can also be encrypted with vault; - # allow these to be used as the main playbook. - elif n == 0 and line.startswith('$ANSIBLE_VAULT;'): - matched = True - break + with codecs.open(playbook_path, 'r', encoding='utf-8', errors='ignore') as f: + for n, line in enumerate(f): + if valid_playbook_re.match(line): + matched = True + break + # Any YAML file can also be encrypted with vault; + # allow these to be used as the main playbook. + elif n == 0 and line.startswith('$ANSIBLE_VAULT;'): + matched = True + break except IOError: return None if not matched: diff --git a/awx/main/utils/common.py b/awx/main/utils/common.py index dedd02f9957b..a02daef16631 100644 --- a/awx/main/utils/common.py +++ b/awx/main/utils/common.py @@ -6,7 +6,7 @@ import json import yaml import logging -import time +import psycopg import os import subprocess import re @@ -17,13 +17,15 @@ import contextlib import tempfile import functools +from importlib.metadata import version as _get_version +from importlib.metadata import entry_points, EntryPoint # Django from django.core.exceptions import ObjectDoesNotExist, FieldDoesNotExist from django.utils.dateparse import parse_datetime from django.utils.translation import gettext_lazy as _ from django.utils.functional import cached_property -from django.db import connection, transaction, ProgrammingError +from django.db import connection, DatabaseError, transaction, ProgrammingError, IntegrityError from django.db.models.fields.related import ForeignObjectRel, ManyToManyField from django.db.models.fields.related_descriptors import ForwardManyToOneDescriptor, ManyToManyDescriptor from django.db.models.query import QuerySet @@ -41,6 +43,9 @@ # AWX from awx.conf.license import get_license +# ansible-runner +from ansible_runner.utils.capacity import get_mem_in_bytes, get_cpu_count + logger = logging.getLogger('awx.main.utils') __all__ = [ @@ -52,12 +57,10 @@ 'get_awx_http_client_headers', 'get_awx_version', 'update_scm_url', - 'get_type_for_model', 'get_model_for_type', 'copy_model_by_class', 'copy_m2m_relationships', 'prefetch_page_capabilities', - 'to_python_boolean', 'datetime_hook', 'ignore_inventory_computed_fields', 'ignore_inventory_group_removal', @@ -80,7 +83,6 @@ 'set_environ', 'IllegalArgumentError', 'get_custom_venv_choices', - 'get_external_account', 'ScheduleTaskManager', 'ScheduleDependencyManager', 'ScheduleWorkflowManager', @@ -90,7 +92,7 @@ 'deepmerge', 'get_event_partition_epoch', 'cleanup_new_process', - 'log_excess_runtime', + 'unified_job_class_to_event_table_name', ] @@ -110,18 +112,6 @@ def get_object_or_400(klass, *args, **kwargs): raise ParseError(*e.args) -def to_python_boolean(value, allow_none=False): - value = str(value) - if value.lower() in ('true', '1', 't'): - return True - elif value.lower() in ('false', '0', 'f'): - return False - elif allow_none and value.lower() in ('none', 'null'): - return None - else: - raise ValueError(_(u'Unable to convert "%s" to boolean') % value) - - def datetime_hook(d): new_d = {} for key, value in d.items(): @@ -150,7 +140,7 @@ def underscore_to_camelcase(s): @functools.cache def is_testing(argv=None): '''Return True if running django or py.test unit tests.''' - if 'PYTEST_CURRENT_TEST' in os.environ.keys(): + if os.environ.get('DJANGO_SETTINGS_MODULE') == 'awx.main.tests.settings_for_test': return True argv = sys.argv if argv is None else argv if len(argv) >= 1 and ('py.test' in argv[0] or 'py/test.py' in argv[0]): @@ -160,6 +150,14 @@ def is_testing(argv=None): return False +def bypass_in_test(func): + def fn(*args, **kwargs): + if not is_testing(): + return func(*args, **kwargs) + + return fn + + class RequireDebugTrueOrTest(logging.Filter): """ Logging filter to output when in DEBUG mode or running tests. @@ -235,9 +233,7 @@ def get_awx_version(): from awx import __version__ try: - import pkg_resources - - return pkg_resources.require('awx')[0].version + return _get_version('awx') except Exception: return __version__ @@ -367,7 +363,7 @@ def get_allowed_fields(obj, serializer_mapping): else: allowed_fields = [x.name for x in obj._meta.fields] - ACTIVITY_STREAM_FIELD_EXCLUSIONS = {'user': ['last_login'], 'oauth2accesstoken': ['last_used'], 'oauth2application': ['client_secret']} + ACTIVITY_STREAM_FIELD_EXCLUSIONS = {'user': ['last_login']} model_name = obj._meta.model_name fields_excluded = ACTIVITY_STREAM_FIELD_EXCLUSIONS.get(model_name, []) # see definition of from_db for CredentialType @@ -569,14 +565,6 @@ def copy_m2m_relationships(obj1, obj2, fields, kwargs=None): dest_field.add(*list(src_field_value.all().values_list('id', flat=True))) -def get_type_for_model(model): - """ - Return type name for a given model class. - """ - opts = model._meta.concrete_model._meta - return camelcase_to_underscore(opts.object_name) - - def get_model_for_type(type_name): """ Return model class for a given type name. @@ -717,7 +705,7 @@ def parse_yaml_or_json(vars_str, silent_failure=True): if silent_failure: return {} raise ParseError( - _('Cannot parse as JSON (error: {json_error}) or ' 'YAML (error: {yaml_error}).').format(json_error=str(json_err), yaml_error=str(yaml_err)) + _('Cannot parse as JSON (error: {json_error}) or YAML (error: {yaml_error}).').format(json_error=str(json_err), yaml_error=str(yaml_err)) ) return vars_dict @@ -768,14 +756,13 @@ def get_corrected_cpu(cpu_count): # formerlly get_cpu_capacity return cpu_count # no correction -def get_cpu_effective_capacity(cpu_count): +def get_cpu_effective_capacity(cpu_count, is_control_node=False): from django.conf import settings - cpu_count = get_corrected_cpu(cpu_count) - settings_forkcpu = getattr(settings, 'SYSTEM_TASK_FORKS_CPU', None) env_forkcpu = os.getenv('SYSTEM_TASK_FORKS_CPU', None) - + if is_control_node: + cpu_count = get_corrected_cpu(cpu_count) if env_forkcpu: forkcpu = int(env_forkcpu) elif settings_forkcpu: @@ -834,6 +821,7 @@ def get_corrected_memory(memory): # Runner returns memory in bytes # so we convert memory from settings to bytes as well. + if env_absmem is not None: return convert_mem_str_to_bytes(env_absmem) elif settings_absmem is not None: @@ -842,14 +830,13 @@ def get_corrected_memory(memory): return memory -def get_mem_effective_capacity(mem_bytes): +def get_mem_effective_capacity(mem_bytes, is_control_node=False): from django.conf import settings - mem_bytes = get_corrected_memory(mem_bytes) - settings_mem_mb_per_fork = getattr(settings, 'SYSTEM_TASK_FORKS_MEM', None) env_mem_mb_per_fork = os.getenv('SYSTEM_TASK_FORKS_MEM', None) - + if is_control_node: + mem_bytes = get_corrected_memory(mem_bytes) if env_mem_mb_per_fork: mem_mb_per_fork = int(env_mem_mb_per_fork) elif settings_mem_mb_per_fork: @@ -1013,9 +1000,15 @@ def getattrd(obj, name, default=NoDefaultProvided): raise -def getattr_dne(obj, name, notfound=ObjectDoesNotExist): +empty = object() + + +def getattr_dne(obj, name, default=empty, notfound=ObjectDoesNotExist): try: - return getattr(obj, name) + if default is empty: + return getattr(obj, name) + else: + return getattr(obj, name, default) except notfound: return None @@ -1089,29 +1082,6 @@ def has_model_field_prefetched(model_obj, field_name): return getattr(getattr(model_obj, field_name, None), 'prefetch_cache_name', '') in getattr(model_obj, '_prefetched_objects_cache', {}) -def get_external_account(user): - from django.conf import settings - - account_type = None - if getattr(settings, 'AUTH_LDAP_SERVER_URI', None): - try: - if user.pk and user.profile.ldap_dn and not user.has_usable_password(): - account_type = "ldap" - except AttributeError: - pass - if ( - getattr(settings, 'SOCIAL_AUTH_GOOGLE_OAUTH2_KEY', None) - or getattr(settings, 'SOCIAL_AUTH_GITHUB_KEY', None) - or getattr(settings, 'SOCIAL_AUTH_GITHUB_ORG_KEY', None) - or getattr(settings, 'SOCIAL_AUTH_GITHUB_TEAM_KEY', None) - or getattr(settings, 'SOCIAL_AUTH_SAML_ENABLED_IDPS', None) - ) and user.social_auth.all(): - account_type = "social" - if (getattr(settings, 'RADIUS_SERVER', None) or getattr(settings, 'TACACSPLUS_HOST', None)) and user.enterprise_auth.all(): - account_type = "enterprise" - return account_type - - class classproperty: def __init__(self, fget=None, fset=None, fdel=None, doc=None): self.fget = fget @@ -1134,7 +1104,11 @@ def create_temporary_fifo(data): path = os.path.join(tempfile.mkdtemp(), next(tempfile._get_candidate_names())) os.mkfifo(path, stat.S_IRUSR | stat.S_IWUSR) - threading.Thread(target=lambda p, d: open(p, 'wb').write(d), args=(path, data)).start() + def tmp_write(path, data): + with open(path, 'wb') as f: + f.write(data) + + threading.Thread(target=tmp_write, args=(path, data)).start() return path @@ -1172,6 +1146,17 @@ def deepmerge(a, b): return b +def table_exists(cursor, table_name): + cursor.execute(f"SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_name = '{table_name}');") + row = cursor.fetchone() + if row is not None: + for val in row: # should only have 1 + if val is True: + logger.debug(f'Event partition table {table_name} already exists') + return True + return False + + def create_partition(tblname, start=None): """Creates new partition table for events. By default it covers the current hour.""" if start is None: @@ -1188,13 +1173,37 @@ def create_partition(tblname, start=None): try: with transaction.atomic(): with connection.cursor() as cursor: + if table_exists(cursor, f"{tblname}_{partition_label}"): + return + cursor.execute( - f'CREATE TABLE IF NOT EXISTS {tblname}_{partition_label} ' - f'PARTITION OF {tblname} ' - f'FOR VALUES FROM (\'{start_timestamp}\') to (\'{end_timestamp}\');' + f'CREATE TABLE {tblname}_{partition_label} (LIKE {tblname} INCLUDING DEFAULTS INCLUDING CONSTRAINTS); ' + f'ALTER TABLE {tblname} ATTACH PARTITION {tblname}_{partition_label} ' + f'FOR VALUES FROM (\'{start_timestamp}\') TO (\'{end_timestamp}\');' ) - except ProgrammingError as e: - logger.debug(f'Caught known error due to existing partition: {e}') + + except (ProgrammingError, IntegrityError) as e: + cause = e.__cause__ + if cause and hasattr(cause, 'sqlstate'): + sqlstate = cause.sqlstate + if sqlstate is None: + raise + sqlstate_cls = psycopg.errors.lookup(sqlstate) + + if sqlstate_cls in (psycopg.errors.DuplicateTable, psycopg.errors.DuplicateObject, psycopg.errors.UniqueViolation): + logger.info(f'Caught known error due to partition creation race: {e}') + else: + logger.error('SQL Error state: {} - {}'.format(sqlstate, sqlstate_cls)) + raise + except DatabaseError as e: + cause = e.__cause__ + if cause and hasattr(cause, 'sqlstate'): + sqlstate = cause.sqlstate + if sqlstate is None: + raise + sqlstate_str = psycopg.errors.lookup(sqlstate) + logger.error('SQL Error state: {} - {}'.format(sqlstate, sqlstate_str)) + raise def cleanup_new_process(func): @@ -1214,32 +1223,44 @@ def wrapper_cleanup_new_process(*args, **kwargs): return wrapper_cleanup_new_process -def log_excess_runtime(func_logger, cutoff=5.0, debug_cutoff=5.0, msg=None, add_log_data=False): - def log_excess_runtime_decorator(func): - @functools.wraps(func) - def _new_func(*args, **kwargs): - start_time = time.time() - log_data = {'name': repr(func.__name__)} +def unified_job_class_to_event_table_name(job_class): + return f'main_{job_class().event_class.__name__.lower()}' - if add_log_data: - return_value = func(*args, log_data=log_data, **kwargs) - else: - return_value = func(*args, **kwargs) - log_data['delta'] = time.time() - start_time - if isinstance(return_value, dict): - log_data.update(return_value) +def load_all_entry_points_for(entry_point_subsections: list[str], /) -> dict[str, EntryPoint]: + return {ep.name: ep for entry_point_category in entry_point_subsections for ep in entry_points(group=f'awx_plugins.{entry_point_category}')} - if msg is None: - record_msg = 'Running {name} took {delta:.2f}s' - else: - record_msg = msg - if log_data['delta'] > cutoff: - func_logger.info(record_msg.format(**log_data)) - elif log_data['delta'] > debug_cutoff: - func_logger.debug(record_msg.format(**log_data)) - return return_value - return _new_func +def get_auto_max_workers(): + """Method we normally rely on to get max_workers + + Uses almost same logic as Instance.local_health_check + The important thing is to be MORE than Instance.capacity + so that the task-manager does not over-schedule this node + + Ideally we would just use the capacity from the database plus reserve workers, + but this poses some bootstrap problems where OCP task containers + register themselves after startup + """ + # Get memory from ansible-runner + total_memory_gb = get_mem_in_bytes() + + # This may replace memory calculation with a user override + corrected_memory = get_corrected_memory(total_memory_gb) + + # Get same number as max forks based on memory, this function takes memory as bytes + mem_capacity = get_mem_effective_capacity(corrected_memory, is_control_node=True) + + # Follow same process for CPU capacity constraint + cpu_count = get_cpu_count() + corrected_cpu = get_corrected_cpu(cpu_count) + cpu_capacity = get_cpu_effective_capacity(corrected_cpu, is_control_node=True) + + # Here is what is different from health checks, + auto_max = max(mem_capacity, cpu_capacity) + + # add magic number of extra workers to ensure + # we have a few extra workers to run the heartbeat + auto_max += 7 - return log_excess_runtime_decorator + return auto_max diff --git a/awx/main/utils/db.py b/awx/main/utils/db.py index 5574d4ea91f2..2078b28d49fb 100644 --- a/awx/main/utils/db.py +++ b/awx/main/utils/db.py @@ -1,20 +1,34 @@ # Copyright (c) 2017 Ansible by Red Hat # All Rights Reserved. -from itertools import chain - - -def get_all_field_names(model): - # Implements compatibility with _meta.get_all_field_names - # See: https://docs.djangoproject.com/en/1.11/ref/models/meta/#migrating-from-the-old-api - return list( - set( - chain.from_iterable( - (field.name, field.attname) if hasattr(field, 'attname') else (field.name,) - for field in model._meta.get_fields() - # For complete backwards compatibility, you may want to exclude - # GenericForeignKey from the results. - if not (field.many_to_one and field.related_model is None) - ) - ) - ) +from awx.settings.application_name import set_application_name + +from django.conf import settings + + +def set_connection_name(function): + set_application_name(settings.DATABASES, settings.CLUSTER_HOST_ID, function=function) + + +def bulk_update_sorted_by_id(model, objects, fields, batch_size=1000): + """ + Perform a sorted bulk update on model instances to avoid database deadlocks. + + This function was introduced to prevent deadlocks observed in the AWX Controller + when concurrent jobs attempt to update different fields on the same `main_hosts` table. + Specifically, deadlocks occurred when one process updated `last_job_id` while another + simultaneously updated `ansible_facts`. + + By sorting updates ID, we ensure a consistent update order, + which helps avoid the row-level locking contention that can lead to deadlocks + in PostgreSQL when multiple processes are involved. + + Returns: + int: The number of rows affected by the update. + """ + objects = [obj for obj in objects if obj.id is not None] + if not objects: + return 0 # Return 0 when nothing is updated + + sorted_objects = sorted(objects, key=lambda obj: obj.id) + return model.objects.bulk_update(sorted_objects, fields, batch_size=batch_size) diff --git a/awx/main/utils/encryption.py b/awx/main/utils/encryption.py index 4272e3e07fc1..d23685d33456 100644 --- a/awx/main/utils/encryption.py +++ b/awx/main/utils/encryption.py @@ -9,7 +9,6 @@ from cryptography.hazmat.backends import default_backend from django.utils.encoding import smart_str, smart_bytes - __all__ = ['get_encryption_key', 'encrypt_field', 'decrypt_field', 'encrypt_value', 'decrypt_value', 'encrypt_dict'] logger = logging.getLogger('awx.main.utils.encryption') diff --git a/awx/main/utils/execution_environments.py b/awx/main/utils/execution_environments.py index 02e6a8b701f6..111b76acc637 100644 --- a/awx/main/utils/execution_environments.py +++ b/awx/main/utils/execution_environments.py @@ -1,13 +1,18 @@ -import os -from pathlib import Path +import logging from django.conf import settings from awx.main.models.execution_environments import ExecutionEnvironment +logger = logging.getLogger(__name__) + def get_control_plane_execution_environment(): - return ExecutionEnvironment.objects.filter(organization=None, managed=True).first() + ee = ExecutionEnvironment.objects.filter(organization=None, managed=True).first() + if ee == None: + logger.error('Failed to find control plane ee, there are no managed EEs without organizations') + raise RuntimeError("Failed to find default control plane EE") + return ee def get_default_execution_environment(): @@ -22,6 +27,7 @@ def get_default_execution_environment(): def get_default_pod_spec(): + job_label: str = settings.AWX_CONTAINER_GROUP_DEFAULT_JOB_LABEL ee = get_default_execution_environment() if ee is None: raise RuntimeError("Unable to find an execution environment.") @@ -29,10 +35,30 @@ def get_default_pod_spec(): return { "apiVersion": "v1", "kind": "Pod", - "metadata": {"namespace": settings.AWX_CONTAINER_GROUP_DEFAULT_NAMESPACE}, + "metadata": {"namespace": settings.AWX_CONTAINER_GROUP_DEFAULT_NAMESPACE, "labels": {job_label: ""}}, "spec": { "serviceAccountName": "default", "automountServiceAccountToken": False, + "affinity": { + "podAntiAffinity": { + "preferredDuringSchedulingIgnoredDuringExecution": [ + { + "weight": 100, + "podAffinityTerm": { + "labelSelector": { + "matchExpressions": [ + { + "key": job_label, + "operator": "Exists", + } + ] + }, + "topologyKey": "kubernetes.io/hostname", + }, + } + ] + } + }, "containers": [ { "image": ee.image, @@ -43,24 +69,3 @@ def get_default_pod_spec(): ], }, } - - -# this is the root of the private data dir as seen from inside -# of the container running a job -CONTAINER_ROOT = '/runner' - - -def to_container_path(path, private_data_dir): - """Given a path inside of the host machine filesystem, - this returns the expected path which would be observed by the job running - inside of the EE container. - This only handles the volume mount from private_data_dir to /runner - """ - if not os.path.isabs(private_data_dir): - raise RuntimeError('The private_data_dir path must be absolute') - # due to how tempfile.mkstemp works, we are probably passed a resolved path, but unresolved private_data_dir - resolved_path = Path(path).resolve() - resolved_pdd = Path(private_data_dir).resolve() - if resolved_pdd != resolved_path and resolved_pdd not in resolved_path.parents: - raise RuntimeError(f'Cannot convert path {resolved_path} unless it is a subdir of {resolved_pdd}') - return str(resolved_path).replace(str(resolved_pdd), CONTAINER_ROOT, 1) diff --git a/awx/main/utils/external_logging.py b/awx/main/utils/external_logging.py index 26f434a4e439..81983b85e678 100644 --- a/awx/main/utils/external_logging.py +++ b/awx/main/utils/external_logging.py @@ -4,6 +4,7 @@ import urllib.parse as urlparse from django.conf import settings +from dispatcherd.publish import task from awx.main.utils.reload import supervisor_service_command @@ -16,10 +17,26 @@ def construct_rsyslog_conf_template(settings=settings): port = getattr(settings, 'LOG_AGGREGATOR_PORT', '') protocol = getattr(settings, 'LOG_AGGREGATOR_PROTOCOL', '') timeout = getattr(settings, 'LOG_AGGREGATOR_TCP_TIMEOUT', 5) - max_disk_space = getattr(settings, 'LOG_AGGREGATOR_MAX_DISK_USAGE_GB', 1) + action_queue_size = getattr(settings, 'LOG_AGGREGATOR_ACTION_QUEUE_SIZE', 131072) + max_disk_space_action_queue = getattr(settings, 'LOG_AGGREGATOR_ACTION_MAX_DISK_USAGE_GB', 1) spool_directory = getattr(settings, 'LOG_AGGREGATOR_MAX_DISK_USAGE_PATH', '/var/lib/awx').rstrip('/') error_log_file = getattr(settings, 'LOG_AGGREGATOR_RSYSLOGD_ERROR_LOG_FILE', '') + queue_options = [ + f'queue.spoolDirectory="{spool_directory}"', + 'queue.filename="awx-external-logger-action-queue"', + f'queue.maxDiskSpace="{max_disk_space_action_queue}g"', # overall disk space for all queue files + 'queue.maxFileSize="100m"', # individual file size + 'queue.type="LinkedList"', + 'queue.saveOnShutdown="on"', + 'queue.syncqueuefiles="on"', # (f)sync when checkpoint occurs + 'queue.checkpointInterval="1000"', # Update disk queue every 1000 messages + f'queue.size="{action_queue_size}"', # max number of messages in queue + f'queue.highwaterMark="{int(action_queue_size * 0.75)}"', # 75% of queue.size + f'queue.discardMark="{int(action_queue_size * 0.9)}"', # 90% of queue.size + 'queue.discardSeverity="5"', # Only discard notice, info, debug if we must discard anything + ] + if not os.access(spool_directory, os.W_OK): spool_directory = '/var/lib/awx' @@ -31,7 +48,6 @@ def construct_rsyslog_conf_template(settings=settings): '$WorkDirectory /var/lib/awx/rsyslog', f'$MaxMessageSize {max_bytes}', '$IncludeConfig /var/lib/awx/rsyslog/conf.d/*.conf', - f'main_queue(queue.spoolDirectory="{spool_directory}" queue.maxdiskspace="{max_disk_space}g" queue.type="Disk" queue.filename="awx-external-logger-backlog")', # noqa 'module(load="imuxsock" SysSock.Use="off")', 'input(type="imuxsock" Socket="' + settings.LOGGING['handlers']['external_logger']['address'] + '" unlink="on" RateLimit.Burst="0")', 'template(name="awx" type="string" string="%rawmsg-after-pri%")', @@ -77,7 +93,7 @@ def escape_quotes(x): 'action.resumeRetryCount="-1"', 'template="awx"', f'action.resumeInterval="{timeout}"', - ] + ] + queue_options if error_log_file: params.append(f'errorfile="{error_log_file}"') if parsed.path: @@ -105,15 +121,25 @@ def escape_quotes(x): params = ' '.join(params) parts.extend(['module(load="omhttp")', f'action({params})']) elif protocol and host and port: - parts.append( - f'action(type="omfwd" target="{host}" port="{port}" protocol="{protocol}" action.resumeRetryCount="-1" action.resumeInterval="{timeout}" template="awx")' # noqa - ) + params = [ + 'type="omfwd"', + f'target="{host}"', + f'port="{port}"', + f'protocol="{protocol}"', + 'action.resumeRetryCount="-1"', + f'action.resumeInterval="{timeout}"', + 'template="awx"', + ] + queue_options + params = ' '.join(params) + parts.append(f'action({params})') + else: parts.append('action(type="omfile" file="/dev/null")') # rsyslog needs *at least* one valid action to start tmpl = '\n'.join(parts) return tmpl +@task(queue='rsyslog_configurer', timeout=600, on_duplicate='queue_one') def reconfigure_rsyslog(): tmpl = construct_rsyslog_conf_template() # Write config to a temp file then move it to preserve atomicity diff --git a/awx/main/utils/filters.py b/awx/main/utils/filters.py index 7f9724329b80..389b1f93c401 100644 --- a/awx/main/utils/filters.py +++ b/awx/main/utils/filters.py @@ -1,5 +1,7 @@ import re from functools import reduce + +from django.core.exceptions import FieldDoesNotExist from pyparsing import ( infixNotation, opAssoc, @@ -161,7 +163,7 @@ def __init__(self, t): else: # detect loops and restrict access to sensitive fields # this import is intentional here to avoid a circular import - from awx.api.filters import FieldLookupBackend + from ansible_base.rest_filters.rest_framework.field_lookup_backend import FieldLookupBackend FieldLookupBackend().get_field_from_lookup(Host, k) kwargs[k] = v @@ -353,7 +355,7 @@ def query_from_string(cls, filter_string): try: res = boolExpr.parseString('(' + filter_string + ')') - except ParseException: + except (ParseException, FieldDoesNotExist): raise RuntimeError(u"Invalid query %s" % filter_string_raw) if len(res) > 0: diff --git a/awx/main/utils/formatters.py b/awx/main/utils/formatters.py index 783278bd9eb7..45ff3f0d955c 100644 --- a/awx/main/utils/formatters.py +++ b/awx/main/utils/formatters.py @@ -3,7 +3,6 @@ from copy import copy import json -import json_log_formatter import logging import traceback import socket @@ -15,15 +14,6 @@ from django.conf import settings -class JobLifeCycleFormatter(json_log_formatter.JSONFormatter): - def json_record(self, message: str, extra: dict, record: logging.LogRecord): - if 'time' not in extra: - extra['time'] = now() - if record.exc_info: - extra['exc_info'] = self.formatException(record.exc_info) - return extra - - class TimeFormatter(logging.Formatter): """ Custom log formatter used for inventory imports @@ -170,6 +160,11 @@ def reformat_data_for_log(self, raw_data, kind=None): data = json.loads(data) data_for_log = {} + # For the job_lifecycle logger, copy some raw data fields directly + for key in ('lifecycle_data', 'organization_id'): + if key in raw_data: + data_for_log[key] = raw_data[key] + if kind == 'job_events' and raw_data.get('python_objects', {}).get('job_event'): job_event = raw_data['python_objects']['job_event'] guid = job_event.event_data.pop('guid', None) @@ -262,8 +257,7 @@ def get_extra_fields(self, record): return fields def format(self, record): - stamp = datetime.utcfromtimestamp(record.created) - stamp = stamp.replace(tzinfo=tzutc()) + stamp = datetime.fromtimestamp(record.created, tz=tzutc()) message = { # Field not included, but exist in related logs # 'path': record.pathname @@ -283,6 +277,7 @@ def format(self, record): message.update(self.get_debug_fields(record)) if settings.LOG_AGGREGATOR_TYPE == 'splunk': - # splunk messages must have a top level "event" key - message = {'event': message} + # splunk messages must have a top level "event" key when using the /services/collector/event receiver. + # The event receiver wont scan an event for a timestamp field therefore a time field must also be supplied containing epoch timestamp + message = {'time': record.created, 'event': message} return self.serialize(message) diff --git a/awx/main/utils/handlers.py b/awx/main/utils/handlers.py index aa32c77e8c7f..f6209c755ec1 100644 --- a/awx/main/utils/handlers.py +++ b/awx/main/utils/handlers.py @@ -2,10 +2,13 @@ # All Rights Reserved. # Python +import base64 import logging +import logging.handlers import sys import traceback -from datetime import datetime +import os +from datetime import datetime, timezone # Django from django.conf import settings @@ -15,6 +18,17 @@ # AWX from awx.main.exceptions import PostRunError +# OTEL +from opentelemetry._logs import set_logger_provider +from opentelemetry.exporter.otlp.proto.grpc._log_exporter import OTLPLogExporter as OTLPGrpcLogExporter +from opentelemetry.exporter.otlp.proto.http._log_exporter import OTLPLogExporter as OTLPHttpLogExporter + +from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler +from opentelemetry.sdk._logs.export import BatchLogRecordProcessor +from opentelemetry.sdk.resources import Resource + +__all__ = ['RSysLogHandler', 'SpecialInventoryHandler', 'ColorHandler'] + class RSysLogHandler(logging.handlers.SysLogHandler): append_nul = False @@ -35,7 +49,7 @@ def handleError(self, record): # because the alternative is blocking the # socket.send() in the Python process, which we definitely don't # want to do) - dt = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S') + dt = datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M:%S') msg = f'{dt} ERROR rsyslogd was unresponsive: ' exc = traceback.format_exc() try: @@ -97,39 +111,71 @@ def emit(self, record): self.event_handler(dispatch_data) -ColorHandler = logging.StreamHandler - if settings.COLOR_LOGS is True: - try: - from logutils.colorize import ColorizingStreamHandler - import colorama - - colorama.deinit() - colorama.init(wrap=False, convert=False, strip=False) - - class ColorHandler(ColorizingStreamHandler): - def colorize(self, line, record): - # comment out this method if you don't like the job_lifecycle - # logs rendered with cyan text - previous_level_map = self.level_map.copy() - if record.name == "awx.analytics.job_lifecycle": - self.level_map[logging.INFO] = (None, 'cyan', True) - msg = super(ColorHandler, self).colorize(line, record) - self.level_map = previous_level_map - return msg - - def format(self, record): - message = logging.StreamHandler.format(self, record) - return '\n'.join([self.colorize(line, record) for line in message.splitlines()]) - - level_map = { - logging.DEBUG: (None, 'green', True), - logging.INFO: (None, None, True), - logging.WARNING: (None, 'yellow', True), - logging.ERROR: (None, 'red', True), - logging.CRITICAL: (None, 'red', True), - } - - except ImportError: - # logutils is only used for colored logs in the dev environment - pass + from logutils.colorize import ColorizingStreamHandler + import colorama + + colorama.deinit() + colorama.init(wrap=False, convert=False, strip=False) + + class ColorHandler(ColorizingStreamHandler): + def colorize(self, line, record): + # comment out this method if you don't like the job_lifecycle + # logs rendered with cyan text + previous_level_map = self.level_map.copy() + if record.name == "awx.analytics.job_lifecycle": + self.level_map[logging.INFO] = (None, 'cyan', True) + msg = super(ColorHandler, self).colorize(line, record) + self.level_map = previous_level_map + return msg + + def format(self, record): + message = logging.StreamHandler.format(self, record) + return '\n'.join([self.colorize(line, record) for line in message.splitlines()]) + + level_map = { + logging.DEBUG: (None, 'green', True), + logging.INFO: (None, None, True), + logging.WARNING: (None, 'yellow', True), + logging.ERROR: (None, 'red', True), + logging.CRITICAL: (None, 'red', True), + } + +else: + ColorHandler = logging.StreamHandler + + +class OTLPHandler(LoggingHandler): + def __init__(self, endpoint=None, protocol='grpc', service_name=None, instance_id=None, auth=None, username=None, password=None): + if not endpoint: + raise ValueError("endpoint required") + + if auth == 'basic' and (username is None or password is None): + raise ValueError("auth type basic requires username and passsword parameters") + + self.endpoint = endpoint + self.service_name = service_name or (sys.argv[1] if len(sys.argv) > 1 else (sys.argv[0] or 'unknown_service')) + self.instance_id = instance_id or os.uname().nodename + + logger_provider = LoggerProvider( + resource=Resource.create( + { + "service.name": self.service_name, + "service.instance.id": self.instance_id, + } + ), + ) + set_logger_provider(logger_provider) + + headers = {} + if auth == 'basic': + secret = f'{username}:{password}' + headers['Authorization'] = "Basic " + base64.b64encode(secret.encode()).decode() + + if protocol == 'grpc': + otlp_exporter = OTLPGrpcLogExporter(endpoint=self.endpoint, insecure=True, headers=headers) + elif protocol == 'http': + otlp_exporter = OTLPHttpLogExporter(endpoint=self.endpoint, headers=headers) + logger_provider.add_log_record_processor(BatchLogRecordProcessor(otlp_exporter)) + + super().__init__(level=logging.NOTSET, logger_provider=logger_provider) diff --git a/awx/main/utils/inventory_vars.py b/awx/main/utils/inventory_vars.py new file mode 100644 index 000000000000..7780a93c73ff --- /dev/null +++ b/awx/main/utils/inventory_vars.py @@ -0,0 +1,276 @@ +import logging +from typing import TypeAlias, Any + +from awx.main.models import InventoryGroupVariablesWithHistory + +var_value: TypeAlias = Any +update_queue: TypeAlias = list[tuple[int, var_value]] + + +logger = logging.getLogger('awx.api.inventory_import') + + +class InventoryVariable: + """ + Represents an inventory variable. + + This class keeps track of the variable updates from different inventory + sources. + """ + + def __init__(self, name: str) -> None: + """ + :param str name: The variable's name. + :return: None + """ + self.name = name + self._update_queue: update_queue = [] + """ + A queue representing updates from inventory sources in the sequence of + occurrence. + + The queue is realized as a list of two-tuples containing variable values + and their originating inventory source. The last item of the list is + considered the top of the queue, and holds the current value of the + variable. + """ + + def reset(self) -> None: + """Reset the variable by deleting its history.""" + self._update_queue = [] + + def load(self, updates: update_queue) -> "InventoryVariable": + """Load internal state from a list.""" + self._update_queue = updates + return self + + def dump(self) -> update_queue: + """Save internal state to a list.""" + return self._update_queue + + def update(self, value: var_value, invsrc_id: int) -> None: + """ + Update the variable with a new value from an inventory source. + + Updating means that this source is moved to the top of the queue + and `value` becomes the new current value. + + :param value: The new value of the variable. + :param int invsrc_id: The inventory source of the new variable value. + :return: None + """ + logger.debug(f"InventoryVariable().update({value}, {invsrc_id}):") + # Move this source to the front of the queue by first deleting a + # possibly existing entry, and then add the new entry to the front. + self.delete(invsrc_id) + self._update_queue.append((invsrc_id, value)) + + def delete(self, invsrc_id: int) -> None: + """ + Delete an inventory source from the variable. + + :param int invsrc_id: The inventory source id. + :return: None + """ + data_index = self._get_invsrc_index(invsrc_id) + # Remove last update from this source, if there was any. + if data_index is not None: + value = self._update_queue.pop(data_index)[1] + logger.debug(f"InventoryVariable().delete({invsrc_id}): {data_index=} {value=}") + + def _get_invsrc_index(self, invsrc_id: int) -> int | None: + """Return the inventory source's position in the queue, or `None`.""" + for i, entry in enumerate(self._update_queue): + if entry[0] == invsrc_id: + return i + return None + + def _get_current_value(self) -> var_value: + """ + Return the current value of the variable, or None if the variable has no + history. + """ + return self._update_queue[-1][1] if self._update_queue else None + + @property + def value(self) -> var_value: + """Read the current value of the variable.""" + return self._get_current_value() + + @property + def has_no_source(self) -> bool: + """True, if the variable is orphan, i.e. no source contains this var anymore.""" + return not self._update_queue + + def __str__(self): + """Return the string representation of the current value.""" + return str(self.value or "") + + +class InventoryGroupVariables(dict): + """ + Represent all inventory variables from one group. + + This dict contains all variables of a inventory group and their current + value under consideration of the inventory source update history. + + Note that variables values cannot be `None`, use the empty string to + indicate that a variable holds no value. See also `InventoryVariable`. + """ + + def __init__(self, id: int) -> None: + """ + :param int id: The id of the group object. + :return: None + """ + super().__init__() + self.id = id + # In _vars we keep all sources for a given variable. This enables us to + # find the current value for a variable, which is the value from the + # latest update which defined this variable. + self._vars: dict[str, InventoryVariable] = {} + + def _sync_vars(self) -> None: + """ + Copy the current values of all variables into the internal dict. + + Call this everytime the `_vars` structure has been modified. + """ + for name, inv_var in self._vars.items(): + self[name] = inv_var.value + + def load_state(self, state: dict[str, update_queue]) -> "InventoryGroupVariables": + """Load internal state from a dict.""" + for name, updates in state.items(): + self._vars[name] = InventoryVariable(name).load(updates) + self._sync_vars() + return self + + def save_state(self) -> dict[str, update_queue]: + """Return internal state as a dict.""" + state = {} + for name, inv_var in self._vars.items(): + state[name] = inv_var.dump() + return state + + def update_from_src( + self, + new_vars: dict[str, var_value], + source_id: int, + overwrite_vars: bool = True, + reset: bool = False, + ) -> None: + """ + Update with variables from an inventory source. + + Delete all variables for this source which are not in the update vars. + + :param dict new_vars: The variables from the inventory source. + :param int invsrc_id: The id of the inventory source for this update. + :param bool overwrite_vars: If `True`, delete this source's history + entry for variables which are not in this update. If `False`, keep + the old updates in the history for such variables. Default is + `True`. + :param bool reset: If `True`, delete the update history for all existing + variables before updating the new vars. Therewith making this update + overwrite all history. Default is `False`. + :return: None + """ + logger.debug(f"InventoryGroupVariables({self.id}).update_from_src({new_vars=}, {source_id=}, {overwrite_vars=}, {reset=}): {self=}") + # Create variables which are newly introduced by this source. + for name in new_vars: + if name not in self._vars: + self._vars[name] = InventoryVariable(name) + # Combine the names of the existing vars and the new vars from this update. + all_var_names = list(set(list(self.keys()) + list(new_vars.keys()))) + # In reset-mode, delete all existing vars and their history before + # updating. + if reset: + for name in all_var_names: + self._vars[name].reset() + # Go through all variables (the existing ones, and the ones added by + # this update), delete this source from variables which are not in this + # update, and update the value of variables which are part of this + # update. + for name in all_var_names: + # Update or delete source from var (if name not in vars). + if name in new_vars: + self._vars[name].update(new_vars[name], source_id) + elif overwrite_vars: + self._vars[name].delete(source_id) + # Delete vars which have no source anymore. + if self._vars[name].has_no_source: + del self._vars[name] + del self[name] + # After the update, refresh the internal dict with the possibly changed + # current values. + self._sync_vars() + logger.debug(f"InventoryGroupVariables({self.id}).update_from_src(): {self=}") + + +def update_group_variables( + group_id: int | None, + newvars: dict, + dbvars: dict | None, + invsrc_id: int, + inventory_id: int, + overwrite_vars: bool = True, + reset: bool = False, +) -> dict[str, var_value]: + """ + Update the inventory variables of one group. + + Merge the new variables into the existing group variables. + + The update can be triggered either by an inventory update via API, or via a + manual edit of the variables field in the awx inventory form. + + TODO: Can we get rid of the dbvars? This is only needed because the new + update-var mechanism needs to be properly initialized if the db already + contains some variables. + + :param int group_id: The inventory group id (pk). For the 'all'-group use + `None`, because this group is not an actual `Group` object in the + database. + :param dict newvars: The variables contained in this update. + :param dict dbvars: The variables which are already stored in the database + for this inventory and this group. Can be `None`. + :param int invsrc_id: The id of the inventory source. Usually this is the + database primary key of the inventory source object, but there is one + special id -1 which is used for the initial update from the database and + for manual updates via the GUI. + :param int inventory_id: The id of the inventory on which this update is + applied. + :param bool overwrite_vars: If `True`, delete variables which were merged + from the same source in a previous update, but are no longer contained + in that source. If `False`, such variables would not be removed from the + group. Default is `True`. + :param bool reset: If `True`, delete all variables from previous updates, + therewith making this update overwrite all history. Default is `False`. + :return: The variables and their current values as a dict. + :rtype: dict + """ + inv_group_vars = InventoryGroupVariables(group_id) + # Restore the existing variables state. + try: + # Get the object for this group from the database. + model = InventoryGroupVariablesWithHistory.objects.get(inventory_id=inventory_id, group_id=group_id) + except InventoryGroupVariablesWithHistory.DoesNotExist: + # If no previous state exists, create a new database object, and + # initialize it with the current group variables. + model = InventoryGroupVariablesWithHistory(inventory_id=inventory_id, group_id=group_id) + if dbvars: + inv_group_vars.update_from_src(dbvars, -1) # Assume -1 as inv_source_id for existing vars. + else: + # Load the group variables state from the database object. + inv_group_vars.load_state(model.variables) + # + logger.debug(f"update_group_variables: before update_from_src {model.variables=}") + # Apply the new inventory update onto the group variables. + inv_group_vars.update_from_src(newvars, invsrc_id, overwrite_vars, reset) + # Save the new variables state. + model.variables = inv_group_vars.save_state() + model.save() + logger.debug(f"update_group_variables: after update_from_src {model.variables=}") + logger.debug(f"update_group_variables({group_id=}, {newvars}): {inv_group_vars}") + return inv_group_vars diff --git a/awx/main/utils/licensing.py b/awx/main/utils/licensing.py index bec953f822df..20417940b8bc 100644 --- a/awx/main/utils/licensing.py +++ b/awx/main/utils/licensing.py @@ -15,7 +15,6 @@ import collections import copy import io -import os import json import logging import re @@ -35,6 +34,11 @@ from django.conf import settings from django.utils.translation import gettext_lazy as _ +# Shared code for the AWX platform +from awx_plugins.interfaces._temporary_private_licensing_api import detect_server_product_name + +from awx.main.constants import SUBSCRIPTION_USAGE_MODEL_UNIQUE_HOSTS +from awx.main.utils.analytics_proxy import OIDCClient MAX_INSTANCES = 9999999 @@ -169,10 +173,17 @@ def _can_aggregate(sub, license): license.setdefault('sku', sub['pool']['productId']) license.setdefault('subscription_name', sub['pool']['productName']) + license.setdefault('subscription_id', sub['pool']['subscriptionId']) + license.setdefault('account_number', sub['pool']['accountNumber']) license.setdefault('pool_id', sub['pool']['id']) license.setdefault('product_name', sub['pool']['productName']) license.setdefault('valid_key', True) - license.setdefault('license_type', 'enterprise') + if sub['pool']['productId'].startswith('S'): + license.setdefault('trial', True) + license.setdefault('license_type', 'trial') + else: + license.setdefault('trial', False) + license.setdefault('license_type', 'enterprise') license.setdefault('satellite', False) # Use the nearest end date endDate = parse_date(sub['endDate']) @@ -184,6 +195,16 @@ def _can_aggregate(sub, license): license['instance_count'] = license.get('instance_count', 0) + instances license['subscription_name'] = re.sub(r'[\d]* Managed Nodes', '%d Managed Nodes' % license['instance_count'], license['subscription_name']) + license['support_level'] = '' + license['usage'] = '' + for attr in sub['pool'].get('productAttributes', []): + if attr.get('name') == 'support_level': + license['support_level'] = attr.get('value') + elif attr.get('name') == 'usage': + license['usage'] = attr.get('value') + elif attr.get('name') == 'ph_product_name' and attr.get('value') == 'RHEL Developer': + license['license_type'] = 'developer' + if not license: logger.error("No valid subscriptions found in manifest") self._attrs.update(license) @@ -198,27 +219,43 @@ def update(self, **kwargs): kwargs['license_date'] = int(kwargs['license_date']) self._attrs.update(kwargs) - def validate_rh(self, user, pw): + def get_host_from_rhsm_config(self): try: host = 'https://' + str(self.config.get("server", "hostname")) except Exception: logger.exception('Cannot access rhsm.conf, make sure subscription manager is installed and configured.') host = None + return host + + def validate_rh(self, user, pw, basic_auth): + # if basic auth is True, host is read from rhsm.conf (subscription.rhsm.redhat.com) + # if basic auth is False, host is settings.SUBSCRIPTIONS_RHSM_URL (console.redhat.com) + # if rhsm.conf is not found, host is settings.REDHAT_CANDLEPIN_HOST (satellite server) + if basic_auth: + host = self.get_host_from_rhsm_config() + if not host: + host = getattr(settings, 'REDHAT_CANDLEPIN_HOST', None) + else: + host = settings.SUBSCRIPTIONS_RHSM_URL + if not host: - host = getattr(settings, 'REDHAT_CANDLEPIN_HOST', None) + raise ValueError('Could not get host url for subscriptions') if not user: - raise ValueError('subscriptions_username is required') + raise ValueError('subscriptions_client_id or subscriptions_username is required') if not pw: - raise ValueError('subscriptions_password is required') + raise ValueError('subscriptions_client_secret or subscriptions_password is required') if host and user and pw: - if 'subscription.rhsm.redhat.com' in host: - json = self.get_rhsm_subs(host, user, pw) + if basic_auth: + if 'subscription.rhsm.redhat.com' in host: + json = self.get_rhsm_subs(host, user, pw) + else: + json = self.get_satellite_subs(host, user, pw) else: - json = self.get_satellite_subs(host, user, pw) - return self.generate_license_options_from_entitlements(json) + json = self.get_crc_subs(host, user, pw) + return self.generate_license_options_from_entitlements(json, is_candlepin=basic_auth) return [] def get_rhsm_subs(self, host, user, pw): @@ -240,6 +277,35 @@ def get_rhsm_subs(self, host, user, pw): json.extend(resp.json()) return json + def get_crc_subs(self, host, client_id, client_secret): + try: + client = OIDCClient(client_id, client_secret) + subs = client.make_request( + 'GET', + host, + verify=True, + timeout=(31, 31), + ) + except requests.RequestException: + logger.warning("Failed to connect to console.redhat.com using Service Account credentials. Falling back to basic auth.") + subs = requests.request( + 'GET', + host, + auth=(client_id, client_secret), + verify=True, + timeout=(31, 31), + ) + subs.raise_for_status() + subs_formatted = [] + for sku in subs.json()['body']: + sku_data = {k: v for k, v in sku.items() if k != 'subscriptions'} + for sub in sku['subscriptions']: + sub_data = sku_data.copy() + sub_data['subscriptions'] = sub + subs_formatted.append(sub_data) + + return subs_formatted + def get_satellite_subs(self, host, user, pw): port = None try: @@ -247,7 +313,7 @@ def get_satellite_subs(self, host, user, pw): port = str(self.config.get("server", "port")) except Exception as e: logger.exception('Unable to read rhsm config to get ca_cert location. {}'.format(str(e))) - verify = getattr(settings, 'REDHAT_CANDLEPIN_VERIFY', True) + verify = True if port: host = ':'.join([host, port]) json = [] @@ -276,7 +342,10 @@ def get_satellite_subs(self, host, user, pw): license['productId'] = sub['product_id'] license['quantity'] = int(sub['quantity']) license['support_level'] = sub['support_level'] + license['usage'] = sub.get('usage') license['subscription_name'] = sub['name'] + license['subscriptionId'] = sub['subscription_id'] + license['accountNumber'] = sub['account_number'] license['id'] = sub['upstream_pool_id'] license['endDate'] = sub['end_date'] license['productName'] = "Red Hat Ansible Automation" @@ -286,11 +355,6 @@ def get_satellite_subs(self, host, user, pw): json.append(license) return json - def is_appropriate_sat_sub(self, sub): - if 'Red Hat Ansible Automation' not in sub['subscription_name']: - return False - return True - def is_appropriate_sub(self, sub): if sub['activeSubscription'] is False: return False @@ -300,47 +364,94 @@ def is_appropriate_sub(self, sub): return True return False - def generate_license_options_from_entitlements(self, json): + def is_appropriate_sat_sub(self, sub): + if 'Red Hat Ansible Automation' not in sub['subscription_name']: + return False + return True + + def generate_license_options_from_entitlements(self, json, is_candlepin=False): from dateutil.parser import parse - ValidSub = collections.namedtuple('ValidSub', 'sku name support_level end_date trial quantity pool_id satellite') + ValidSub = collections.namedtuple( + 'ValidSub', 'sku name support_level end_date trial developer_license quantity satellite subscription_id account_number usage' + ) valid_subs = [] for sub in json: satellite = sub.get('satellite') if satellite: is_valid = self.is_appropriate_sat_sub(sub) - else: + elif is_candlepin: is_valid = self.is_appropriate_sub(sub) + else: + # the list of subs from console.redhat.com and subscriptions.rhsm.redhat.com are already valid based on the query params we provided + is_valid = True if is_valid: try: - end_date = parse(sub.get('endDate')) + if is_candlepin: + end_date = parse(sub.get('endDate')) + else: + end_date = parse(sub['subscriptions']['endDate']) except Exception: continue - now = datetime.utcnow() + now = datetime.now(timezone.utc) now = now.replace(tzinfo=end_date.tzinfo) if end_date < now: # If the sub has a past end date, skip it continue - try: - quantity = int(sub['quantity']) - if quantity == -1: - # effectively, unlimited - quantity = MAX_INSTANCES - except Exception: - continue - sku = sub['productId'] - trial = sku.startswith('S') # i.e.,, SER/SVC - support_level = '' - pool_id = sub['id'] - if satellite: - support_level = sub['support_level'] + developer_license = False + support_level = sub.get('support_level', '') + account_number = '' + usage = sub.get('usage', '') + if is_candlepin: + try: + quantity = int(sub['quantity']) + except Exception: + continue + sku = sub['productId'] + subscription_id = sub['subscriptionId'] + sub_name = sub['productName'] + account_number = sub['accountNumber'] else: - for attr in sub.get('productAttributes', []): - if attr.get('name') == 'support_level': - support_level = attr.get('value') + try: + # Determine total quantity based on capacity name + # if capacity name is Nodes, capacity quantity x subscription quantity + # if capacity name is Sockets, capacity quantity / 2 (minimum of 1) x subscription quantity + if sub['capacity']['name'] == "Nodes": + quantity = int(sub['capacity']['quantity']) * int(sub['subscriptions']['quantity']) + elif sub['capacity']['name'] == "Sockets": + quantity = max(int(sub['capacity']['quantity']) / 2, 1) * int(sub['subscriptions']['quantity']) + else: + continue + except Exception: + continue + sku = sub['sku'] + sub_name = sub['name'] + support_level = sub['serviceLevel'] + subscription_id = sub['subscriptions']['number'] + if sub.get('name') == 'RHEL Developer': + developer_license = True + + if quantity == -1: + # effectively, unlimited + quantity = MAX_INSTANCES + trial = sku.startswith('S') # i.e.,, SER/SVC - valid_subs.append(ValidSub(sku, sub['productName'], support_level, end_date, trial, quantity, pool_id, satellite)) + valid_subs.append( + ValidSub( + sku, + sub_name, + support_level, + end_date, + trial, + developer_license, + quantity, + satellite, + subscription_id, + account_number, + usage, + ) + ) if valid_subs: licenses = [] @@ -349,10 +460,13 @@ def generate_license_options_from_entitlements(self, json): license._attrs['instance_count'] = int(sub.quantity) license._attrs['sku'] = sub.sku license._attrs['support_level'] = sub.support_level + license._attrs['usage'] = sub.usage license._attrs['license_type'] = 'enterprise' if sub.trial: license._attrs['trial'] = True license._attrs['license_type'] = 'trial' + if sub.developer_license: + license._attrs['license_type'] = 'developer' license._attrs['instance_count'] = min(MAX_INSTANCES, license._attrs['instance_count']) human_instances = license._attrs['instance_count'] if human_instances == MAX_INSTANCES: @@ -362,8 +476,11 @@ def generate_license_options_from_entitlements(self, json): license._attrs['satellite'] = satellite license._attrs['valid_key'] = True license.update(license_date=int(sub.end_date.strftime('%s'))) - license.update(pool_id=sub.pool_id) + license.update(subscription_id=sub.subscription_id) + license.update(account_number=sub.account_number) licenses.append(license._attrs.copy()) + # sort by sku + licenses.sort(key=lambda x: x['sku']) return licenses raise ValueError('No valid Red Hat Ansible Automation subscription could be found for this account.') # noqa @@ -382,12 +499,28 @@ def validate(self): current_instances = Host.objects.active_count() license_date = int(attrs.get('license_date', 0) or 0) - automated_instances = HostMetric.objects.count() - first_host = HostMetric.objects.only('first_automation').order_by('first_automation').first() + + subscription_model = getattr(settings, 'SUBSCRIPTION_USAGE_MODEL', '') + if subscription_model == SUBSCRIPTION_USAGE_MODEL_UNIQUE_HOSTS: + automated_instances = HostMetric.active_objects.count() + first_host = HostMetric.active_objects.only('first_automation').order_by('first_automation').first() + attrs['deleted_instances'] = HostMetric.objects.filter(deleted=True).count() + attrs['reactivated_instances'] = HostMetric.active_objects.filter(deleted_counter__gte=1).count() + else: + automated_instances = 0 + first_host = HostMetric.objects.only('first_automation').order_by('first_automation').first() + attrs['deleted_instances'] = 0 + attrs['reactivated_instances'] = 0 + if first_host: automated_since = int(first_host.first_automation.timestamp()) else: - automated_since = int(Instance.objects.order_by('id').first().created.timestamp()) + try: + automated_since = int(Instance.objects.order_by('id').first().created.timestamp()) + except AttributeError: + # In the odd scenario that create_preload_data was not run, there are no hosts + # Then we CAN end up here before any instance has registered + automated_since = int(time.time()) instance_count = int(attrs.get('instance_count', 0)) attrs['current_instances'] = current_instances attrs['automated_instances'] = automated_instances @@ -412,13 +545,9 @@ def get_licenser(*args, **kwargs): from awx.main.utils.licensing import Licenser, OpenLicense try: - if os.path.exists('/var/lib/awx/.tower_version'): - return Licenser(*args, **kwargs) - else: + if detect_server_product_name() == 'AWX': return OpenLicense() + else: + return Licenser(*args, **kwargs) except Exception as e: raise ValueError(_('Error importing License: %s') % e) - - -def server_product_name(): - return 'AWX' if isinstance(get_licenser(), OpenLicense) else 'Red Hat Ansible Automation Platform' diff --git a/awx/main/utils/mem_inventory.py b/awx/main/utils/mem_inventory.py index 7e6e458cb8f1..3167710d8c5d 100644 --- a/awx/main/utils/mem_inventory.py +++ b/awx/main/utils/mem_inventory.py @@ -6,7 +6,6 @@ import logging from collections import OrderedDict - # Logger is used for any data-related messages so that the log level # can be adjusted on command invocation logger = logging.getLogger('awx.main.commands.inventory_import') @@ -253,7 +252,7 @@ def dict_to_mem_data(data, inventory=None): if isinstance(hv, dict): host.variables.update(hv) else: - logger.warning('Expected dict of vars for ' 'host "%s", got %s instead', hk, str(type(hv))) + logger.warning('Expected dict of vars for host "%s", got %s instead', hk, str(type(hv))) group.add_host(host) elif isinstance(hosts, (list, tuple)): for hk in hosts: @@ -262,13 +261,13 @@ def dict_to_mem_data(data, inventory=None): continue group.add_host(host) else: - logger.warning('Expected dict or list of "hosts" for ' 'group "%s", got %s instead', k, str(type(hosts))) + logger.warning('Expected dict or list of "hosts" for group "%s", got %s instead', k, str(type(hosts))) # Process group variables. vars = v.get('vars', {}) if isinstance(vars, dict): group.variables.update(vars) else: - logger.warning('Expected dict of vars for ' 'group "%s", got %s instead', k, str(type(vars))) + logger.warning('Expected dict of vars for group "%s", got %s instead', k, str(type(vars))) # Process child groups. children = v.get('children', []) if isinstance(children, (list, tuple)): @@ -277,7 +276,7 @@ def dict_to_mem_data(data, inventory=None): if child and c != 'ungrouped': group.add_child_group(child) else: - logger.warning('Expected list of children for ' 'group "%s", got %s instead', k, str(type(children))) + logger.warning('Expected list of children for group "%s", got %s instead', k, str(type(children))) # Load host names from a list. elif isinstance(v, (list, tuple)): @@ -288,7 +287,7 @@ def dict_to_mem_data(data, inventory=None): group.add_host(host) else: logger.warning('') - logger.warning('Expected dict or list for group "%s", ' 'got %s instead', k, str(type(v))) + logger.warning('Expected dict or list for group "%s", got %s instead', k, str(type(v))) if k not in ['all', 'ungrouped']: inventory.all_group.add_child_group(group) @@ -299,6 +298,6 @@ def dict_to_mem_data(data, inventory=None): if isinstance(meta_hostvars, dict): v.variables.update(meta_hostvars) else: - logger.warning('Expected dict of vars for ' 'host "%s", got %s instead', k, str(type(meta_hostvars))) + logger.warning('Expected dict of vars for host "%s", got %s instead', k, str(type(meta_hostvars))) return inventory diff --git a/awx/main/utils/migration.py b/awx/main/utils/migration.py new file mode 100644 index 000000000000..10396e7ea358 --- /dev/null +++ b/awx/main/utils/migration.py @@ -0,0 +1,14 @@ +from django.db.migrations.executor import MigrationExecutor +from django.db import connections, DEFAULT_DB_ALIAS + + +def is_database_synchronized(database=DEFAULT_DB_ALIAS): + """_summary_ + Ensure all migrations have ran + https://stackoverflow.com/questions/31838882/check-for-pending-django-migrations + """ + connection = connections[database] + connection.prepare_database() + executor = MigrationExecutor(connection) + targets = executor.loader.graph.leaf_nodes() + return not executor.migration_plan(targets) diff --git a/awx/main/utils/named_url_graph.py b/awx/main/utils/named_url_graph.py index 9d2c0a27c97d..51a85fc68441 100644 --- a/awx/main/utils/named_url_graph.py +++ b/awx/main/utils/named_url_graph.py @@ -5,8 +5,6 @@ # Django from django.db import models from django.conf import settings -from django.contrib.contenttypes.models import ContentType - NAMED_URL_RES_DILIMITER = "++" NAMED_URL_RES_INNER_DILIMITER = "+" @@ -245,6 +243,8 @@ def _generate_configurations(nodes): def _dfs(configuration, model, graph, dead_ends, new_deadends, parents): + from django.contrib.contenttypes.models import ContentType + parents.add(model) fields, fk_names = configuration[model][0][:], configuration[model][1][:] adj_list = [] @@ -306,3 +306,19 @@ def generate_graph(models): def reset_counters(): for node in settings.NAMED_URL_GRAPH.values(): node.counter = 0 + + +def _customize_graph(): + from django.contrib.auth.models import User + from awx.main.models import Instance, Schedule, UnifiedJobTemplate + + for model in [Schedule, UnifiedJobTemplate]: + if model in settings.NAMED_URL_GRAPH: + settings.NAMED_URL_GRAPH[model].remove_bindings() + settings.NAMED_URL_GRAPH.pop(model) + if User not in settings.NAMED_URL_GRAPH: + settings.NAMED_URL_GRAPH[User] = GraphNode(User, ['username'], []) + settings.NAMED_URL_GRAPH[User].add_bindings() + if Instance not in settings.NAMED_URL_GRAPH: + settings.NAMED_URL_GRAPH[Instance] = GraphNode(Instance, ['hostname'], []) + settings.NAMED_URL_GRAPH[Instance].add_bindings() diff --git a/awx/main/utils/pglock.py b/awx/main/utils/pglock.py deleted file mode 100644 index 3d8a00d20a57..000000000000 --- a/awx/main/utils/pglock.py +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (c) 2017 Ansible by Red Hat -# All Rights Reserved. - -from contextlib import contextmanager - -from django_pglocks import advisory_lock as django_pglocks_advisory_lock -from django.db import connection - - -@contextmanager -def advisory_lock(*args, **kwargs): - if connection.vendor == 'postgresql': - with django_pglocks_advisory_lock(*args, **kwargs) as internal_lock: - yield internal_lock - else: - yield True diff --git a/awx/main/utils/plugins.py b/awx/main/utils/plugins.py new file mode 100644 index 000000000000..31fb2d3963b4 --- /dev/null +++ b/awx/main/utils/plugins.py @@ -0,0 +1,87 @@ +# Copyright (c) 2024 Ansible, Inc. +# All Rights Reserved. + +""" +This module contains the code responsible for extracting the lists of dynamically discovered plugins. +""" + +from functools import cache + + +@cache +def discover_available_cloud_provider_plugin_names() -> list[str]: + """ + Return a list of cloud plugin names available in runtime. + + The discovery result is cached since it does not change throughout + the life cycle of the server run. + + :returns: List of plugin cloud names. + :rtype: list[str] + """ + from awx.main.models.inventory import InventorySourceOptions + + plugin_names = list(InventorySourceOptions.injectors.keys()) + + plugin_names.remove('constructed') + + return plugin_names + + +@cache +def compute_cloud_inventory_sources() -> dict[str, str]: + """ + Return a dictionary of cloud provider plugin names + available plus source control management and constructed. + + :returns: Dictionary of plugin cloud names plus source control. + :rtype: dict[str, str] + """ + + plugins = discover_available_cloud_provider_plugin_names() + + return dict(zip(plugins, plugins), scm='scm', constructed='constructed') + + +@cache +def discover_available_cloud_provider_descriptions() -> dict[str, str]: + """ + Return a dictionary of cloud provider plugin descriptions + available. + + :returns: Dictionary of plugin cloud descriptions. + :rtype: dict[str, str] + """ + from awx.main.models.inventory import InventorySourceOptions + + plugin_description_list = [(plugin_name, plugin.plugin_description) for plugin_name, plugin in InventorySourceOptions.injectors.items()] + + plugin_description = dict(plugin_description_list) + + return plugin_description + + +@cache +def load_combined_inventory_source_options() -> dict[str, str]: + """ + Return a dictionary of cloud provider plugin names and 'file'. + + The 'file' entry is included separately since it needs to be consumed directly by the serializer. + + :returns: A dictionary of cloud provider plugin names (as both keys and values) plus the 'file' entry. + :rtype: dict[str, str] + """ + + plugins = compute_cloud_inventory_sources() + + plugin_description = discover_available_cloud_provider_descriptions() + + if 'scm' in plugins: + plugin_description['scm'] = 'Sourced from a Project' + + if 'file' in plugins: + plugin_description['file'] = 'File-based inventory source' + + result = {plugin: plugin_description.get(plugin, plugin) for plugin in plugins} + + return result diff --git a/awx/main/utils/proxy.py b/awx/main/utils/proxy.py new file mode 100644 index 000000000000..0676e8f44ae6 --- /dev/null +++ b/awx/main/utils/proxy.py @@ -0,0 +1,47 @@ +# Copyright (c) 2024 Ansible, Inc. +# All Rights Reserved. + + +# DRF +from rest_framework.request import Request + +""" +Note that these methods operate on request.environ. This data is from uwsgi. +It is the source data from which request.headers (read-only) is constructed. +""" + + +def is_proxy_in_headers(request: Request, proxy_list: list[str], headers: list[str]) -> bool: + """ + Determine if the request went through at least one proxy in the list. + Example: + request.environ = { + "HTTP_X_FOO": "8.8.8.8, 192.168.2.1", + "REMOTE_ADDR": "192.168.2.1", + "REMOTE_HOST": "foobar" + } + proxy_list = ["192.168.2.1"] + headers = ["HTTP_X_FOO", "REMOTE_ADDR", "REMOTE_HOST"] + + The above would return True since 192.168.2.1 is a value for the header HTTP_X_FOO + + request: The DRF/Django request. request.environ dict will be used for searching for proxies + proxy_list: A list of known and trusted proxies may be ip or hostnames + headers: A list of keys for which to consider values that may contain a proxy + """ + + remote_hosts = set() + + for header in headers: + for value in request.environ.get(header, '').split(','): + value = value.strip() + if value: + remote_hosts.add(value) + + return bool(remote_hosts.intersection(set(proxy_list))) + + +def delete_headers_starting_with_http(request: Request, headers: list[str]): + for header in headers: + if header.startswith('HTTP_'): + request.environ.pop(header, None) diff --git a/awx/main/utils/redis.py b/awx/main/utils/redis.py new file mode 100644 index 000000000000..98aa89ba29ce --- /dev/null +++ b/awx/main/utils/redis.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2025 Ansible, Inc. +# All Rights Reserved + +"""Redis client utilities with automatic retry on connection errors.""" + +import redis +import redis.asyncio +from django.conf import settings +from redis.backoff import ExponentialBackoff +from redis.retry import Retry +from redis.exceptions import BusyLoadingError, ConnectionError, TimeoutError + + +def _get_redis_pool_kwargs(): + """ + Get common Redis connection pool kwargs with retry configuration. + + Returns: + dict: Keyword arguments for redis.ConnectionPool.from_url() + """ + retry = Retry(ExponentialBackoff(cap=settings.REDIS_BACKOFF_CAP, base=settings.REDIS_BACKOFF_BASE), retries=settings.REDIS_RETRY_COUNT) + return { + 'retry': retry, + 'retry_on_error': [BusyLoadingError, ConnectionError, TimeoutError], + } + + +def get_redis_client(): + """ + Create a Redis client with automatic retry on connection errors. + + This function creates a Redis connection with built-in retry logic to handle + transient connection failures (like broken pipes, timeouts, etc.) that can occur + during long-running operations. + + Based on PR feedback: https://github.com/ansible/awx/pull/16158#issuecomment-3486839154 + Uses redis-py's built-in retry mechanism instead of custom retry logic. + + Returns: + redis.Redis: A Redis client instance configured with retry logic + + Notes: + - Uses exponential backoff with configurable retries (REDIS_RETRY_COUNT setting) + - Retries on BusyLoadingError, ConnectionError, and TimeoutError + - Requires redis-py 7.0+ + """ + pool = redis.ConnectionPool.from_url( + settings.BROKER_URL, + **_get_redis_pool_kwargs(), + ) + return redis.Redis(connection_pool=pool) + + +def get_redis_client_async(): + """ + Create an async Redis client with automatic retry on connection errors. + + This is the async version of get_redis_client() for use with asyncio code. + + Returns: + redis.asyncio.Redis: An async Redis client instance configured with retry logic + + Notes: + - Uses exponential backoff with configurable retries (REDIS_RETRY_COUNT setting) + - Retries on BusyLoadingError, ConnectionError, and TimeoutError + - Requires redis-py 7.0+ + """ + pool = redis.asyncio.ConnectionPool.from_url( + settings.BROKER_URL, + **_get_redis_pool_kwargs(), + ) + return redis.asyncio.Redis(connection_pool=pool) diff --git a/awx/main/utils/reload.py b/awx/main/utils/reload.py index a7c2a1ed99b5..4306a1ae2fd3 100644 --- a/awx/main/utils/reload.py +++ b/awx/main/utils/reload.py @@ -6,7 +6,6 @@ import logging import os - logger = logging.getLogger('awx.main.utils.reload') @@ -17,7 +16,7 @@ def supervisor_service_command(command, service='*', communicate=True): """ args = ['supervisorctl'] - supervisor_config_path = os.getenv('SUPERVISOR_WEB_CONFIG_PATH', None) + supervisor_config_path = os.getenv('SUPERVISOR_CONFIG_PATH', None) if supervisor_config_path: args.extend(['-c', supervisor_config_path]) diff --git a/awx/main/utils/safe_yaml.py b/awx/main/utils/safe_yaml.py index abf21e3428db..3dbfffc6a177 100644 --- a/awx/main/utils/safe_yaml.py +++ b/awx/main/utils/safe_yaml.py @@ -1,7 +1,6 @@ import re import yaml - __all__ = ['safe_dump', 'SafeLoader'] diff --git a/awx/main/utils/update_model.py b/awx/main/utils/update_model.py index 0b2998561cdf..37f35f7091a0 100644 --- a/awx/main/utils/update_model.py +++ b/awx/main/utils/update_model.py @@ -6,7 +6,6 @@ from awx.main.tasks.signals import signal_callback - logger = logging.getLogger('awx.main.tasks.utils') diff --git a/awx/main/validators.py b/awx/main/validators.py index 751d38060bbf..ad1552996b88 100644 --- a/awx/main/validators.py +++ b/awx/main/validators.py @@ -181,6 +181,8 @@ def validate_ssh_private_key(data): certificates; should handle any valid options for ssh_private_key on a credential. """ + # Strip leading and trailing whitespace/newlines to handle common copy-paste issues + data = data.strip() return validate_pem(data, min_keys=1) diff --git a/awx/main/wsbroadcast.py b/awx/main/wsbroadcast.py deleted file mode 100644 index 2c1f228785f2..000000000000 --- a/awx/main/wsbroadcast.py +++ /dev/null @@ -1,208 +0,0 @@ -import json -import logging -import asyncio - -import aiohttp -from aiohttp import client_exceptions -from asgiref.sync import sync_to_async - -from channels.layers import get_channel_layer - -from django.conf import settings -from django.apps import apps -from django.core.serializers.json import DjangoJSONEncoder - -from awx.main.analytics.broadcast_websocket import ( - BroadcastWebsocketStats, - BroadcastWebsocketStatsManager, -) -import awx.main.analytics.subsystem_metrics as s_metrics - -logger = logging.getLogger('awx.main.wsbroadcast') - - -def wrap_broadcast_msg(group, message: str): - # TODO: Maybe wrap as "group","message" so that we don't need to - # encode/decode as json. - return json.dumps(dict(group=group, message=message), cls=DjangoJSONEncoder) - - -def unwrap_broadcast_msg(payload: dict): - return (payload['group'], payload['message']) - - -@sync_to_async -def get_broadcast_hosts(): - Instance = apps.get_model('main', 'Instance') - instances = ( - Instance.objects.exclude(hostname=Instance.objects.my_hostname()) - .exclude(node_type='execution') - .exclude(node_type='hop') - .order_by('hostname') - .values('hostname', 'ip_address') - .distinct() - ) - return {i['hostname']: i['ip_address'] or i['hostname'] for i in instances} - - -def get_local_host(): - Instance = apps.get_model('main', 'Instance') - return Instance.objects.my_hostname() - - -class WebsocketTask: - def __init__( - self, - name, - event_loop, - stats: BroadcastWebsocketStats, - remote_host: str, - remote_port: int = settings.BROADCAST_WEBSOCKET_PORT, - protocol: str = settings.BROADCAST_WEBSOCKET_PROTOCOL, - verify_ssl: bool = settings.BROADCAST_WEBSOCKET_VERIFY_CERT, - endpoint: str = 'broadcast', - ): - self.name = name - self.event_loop = event_loop - self.stats = stats - self.remote_host = remote_host - self.remote_port = remote_port - self.endpoint = endpoint - self.protocol = protocol - self.verify_ssl = verify_ssl - self.channel_layer = None - self.subsystem_metrics = s_metrics.Metrics(instance_name=name) - - async def run_loop(self, websocket: aiohttp.ClientWebSocketResponse): - raise RuntimeError("Implement me") - - async def connect(self, attempt): - from awx.main.consumers import WebsocketSecretAuthHelper # noqa - - logger.debug(f"Connection from {self.name} to {self.remote_host} attempt number {attempt}.") - - ''' - Can not put get_channel_layer() in the init code because it is in the init - path of channel layers i.e. RedisChannelLayer() calls our init code. - ''' - if not self.channel_layer: - self.channel_layer = get_channel_layer() - - try: - if attempt > 0: - await asyncio.sleep(settings.BROADCAST_WEBSOCKET_RECONNECT_RETRY_RATE_SECONDS) - except asyncio.CancelledError: - logger.warning(f"Connection from {self.name} to {self.remote_host} cancelled") - raise - - uri = f"{self.protocol}://{self.remote_host}:{self.remote_port}/websocket/{self.endpoint}/" - timeout = aiohttp.ClientTimeout(total=10) - - secret_val = WebsocketSecretAuthHelper.construct_secret() - try: - async with aiohttp.ClientSession(headers={'secret': secret_val}, timeout=timeout) as session: - async with session.ws_connect(uri, ssl=self.verify_ssl, heartbeat=20) as websocket: - logger.info(f"Connection from {self.name} to {self.remote_host} established.") - self.stats.record_connection_established() - attempt = 0 - await self.run_loop(websocket) - except asyncio.CancelledError: - # TODO: Check if connected and disconnect - # Possibly use run_until_complete() if disconnect is async - logger.warning(f"Connection from {self.name} to {self.remote_host} cancelled.") - self.stats.record_connection_lost() - raise - except client_exceptions.ClientConnectorError as e: - logger.warning(f"Connection from {self.name} to {self.remote_host} failed: '{e}'.") - except asyncio.TimeoutError: - logger.warning(f"Connection from {self.name} to {self.remote_host} timed out.") - except Exception as e: - # Early on, this is our canary. I'm not sure what exceptions we can really encounter. - logger.exception(f"Connection from {self.name} to {self.remote_host} failed for unknown reason: '{e}'.") - else: - logger.warning(f"Connection from {self.name} to {self.remote_host} list.") - - self.stats.record_connection_lost() - self.start(attempt=attempt + 1) - - def start(self, attempt=0): - self.async_task = self.event_loop.create_task(self.connect(attempt=attempt)) - - def cancel(self): - self.async_task.cancel() - - -class BroadcastWebsocketTask(WebsocketTask): - async def run_loop(self, websocket: aiohttp.ClientWebSocketResponse): - async for msg in websocket: - self.stats.record_message_received() - - if msg.type == aiohttp.WSMsgType.ERROR: - break - elif msg.type == aiohttp.WSMsgType.TEXT: - try: - payload = json.loads(msg.data) - except json.JSONDecodeError: - logmsg = "Failed to decode broadcast message" - if logger.isEnabledFor(logging.DEBUG): - logmsg = "{} {}".format(logmsg, payload) - logger.warning(logmsg) - continue - (group, message) = unwrap_broadcast_msg(payload) - if group == "metrics": - self.subsystem_metrics.store_metrics(message) - continue - await self.channel_layer.group_send(group, {"type": "internal.message", "text": message}) - - -class BroadcastWebsocketManager(object): - def __init__(self): - self.event_loop = asyncio.get_event_loop() - ''' - { - 'hostname1': BroadcastWebsocketTask(), - 'hostname2': BroadcastWebsocketTask(), - 'hostname3': BroadcastWebsocketTask(), - } - ''' - self.broadcast_tasks = dict() - self.local_hostname = get_local_host() - self.stats_mgr = BroadcastWebsocketStatsManager(self.event_loop, self.local_hostname) - - async def run_per_host_websocket(self): - while True: - known_hosts = await get_broadcast_hosts() - future_remote_hosts = known_hosts.keys() - current_remote_hosts = self.broadcast_tasks.keys() - deleted_remote_hosts = set(current_remote_hosts) - set(future_remote_hosts) - new_remote_hosts = set(future_remote_hosts) - set(current_remote_hosts) - - remote_addresses = {k: v.remote_host for k, v in self.broadcast_tasks.items()} - for hostname, address in known_hosts.items(): - if hostname in self.broadcast_tasks and address != remote_addresses[hostname]: - deleted_remote_hosts.add(hostname) - new_remote_hosts.add(hostname) - - if deleted_remote_hosts: - logger.warning(f"Removing {deleted_remote_hosts} from websocket broadcast list") - if new_remote_hosts: - logger.warning(f"Adding {new_remote_hosts} to websocket broadcast list") - - for h in deleted_remote_hosts: - self.broadcast_tasks[h].cancel() - del self.broadcast_tasks[h] - self.stats_mgr.delete_remote_host_stats(h) - - for h in new_remote_hosts: - stats = self.stats_mgr.new_remote_host_stats(h) - broadcast_task = BroadcastWebsocketTask(name=self.local_hostname, event_loop=self.event_loop, stats=stats, remote_host=known_hosts[h]) - broadcast_task.start() - self.broadcast_tasks[h] = broadcast_task - - await asyncio.sleep(settings.BROADCAST_WEBSOCKET_NEW_INSTANCE_POLL_RATE_SECONDS) - - def start(self): - self.stats_mgr.start() - - self.async_task = self.event_loop.create_task(self.run_per_host_websocket()) - return self.async_task diff --git a/awx/main/wsrelay.py b/awx/main/wsrelay.py new file mode 100644 index 000000000000..9e55e3e2c83a --- /dev/null +++ b/awx/main/wsrelay.py @@ -0,0 +1,376 @@ +import json +import logging +import asyncio +from typing import Dict +from copy import deepcopy + +import ipaddress + +import aiohttp +from aiohttp import client_exceptions +import redis + +from channels.layers import get_channel_layer + +from django.conf import settings +from django.apps import apps + +import psycopg + +from awx.main.analytics.broadcast_websocket import ( + RelayWebsocketStats, + RelayWebsocketStatsManager, +) + +logger = logging.getLogger('awx.main.wsrelay') + + +def wrap_broadcast_msg(group, message: str): + # TODO: Maybe wrap as "group","message" so that we don't need to + # encode/decode as json. + return dict(group=group, message=message) + + +def get_local_host(): + Instance = apps.get_model('main', 'Instance') + return Instance.objects.my_hostname() + + +class WebsocketRelayConnection: + def __init__( + self, + name, + stats: RelayWebsocketStats, + remote_host: str, + remote_port: int = settings.BROADCAST_WEBSOCKET_PORT, + protocol: str = settings.BROADCAST_WEBSOCKET_PROTOCOL, + verify_ssl: bool = settings.BROADCAST_WEBSOCKET_VERIFY_CERT, + ): + self.name = name + self.stats = stats + self.remote_host = remote_host + self.remote_port = remote_port + self.protocol = protocol + self.verify_ssl = verify_ssl + self.channel_layer = None + self.producers = dict() + self.connected = False + + async def run_loop(self, websocket: aiohttp.ClientWebSocketResponse): + raise RuntimeError("Implement me") + + async def connect(self): + from awx.main.consumers import WebsocketSecretAuthHelper # noqa + + logger.debug(f"Connection attempt from {self.name} to {self.remote_host}") + + ''' + Can not put get_channel_layer() in the init code because it is in the init + path of channel layers i.e. RedisChannelLayer() calls our init code. + ''' + if not self.channel_layer: + self.channel_layer = get_channel_layer() + + # figure out if what we have is an ipaddress, IPv6 Addresses must have brackets added for uri + uri_hostname = self.remote_host + try: + # Throws ValueError if self.remote_host is a hostname like example.com, not an IPv4 or IPv6 ip address + if isinstance(ipaddress.ip_address(uri_hostname), ipaddress.IPv6Address): + uri_hostname = f"[{uri_hostname}]" + except ValueError: + pass + + uri = f"{self.protocol}://{uri_hostname}:{self.remote_port}/websocket/relay/" + timeout = aiohttp.ClientTimeout(total=10) + + secret_val = WebsocketSecretAuthHelper.construct_secret() + try: + async with aiohttp.ClientSession(headers={'secret': secret_val}, timeout=timeout) as session: + async with session.ws_connect(uri, ssl=self.verify_ssl, heartbeat=20) as websocket: + logger.info(f"Connection from {self.name} to {self.remote_host} established.") + self.stats.record_connection_established() + self.connected = True + await self.run_connection(websocket) + except asyncio.CancelledError: + # TODO: Check if connected and disconnect + # Possibly use run_until_complete() if disconnect is async + logger.warning(f"Connection from {self.name} to {self.remote_host} canceled.") + except client_exceptions.ClientConnectorError as e: + logger.warning(f"Connection from {self.name} to {self.remote_host} failed: '{e}'.", exc_info=True) + except asyncio.TimeoutError: + logger.warning(f"Connection from {self.name} to {self.remote_host} timed out.") + except Exception as e: + # Early on, this is our canary. I'm not sure what exceptions we can really encounter. + logger.warning(f"Connection from {self.name} to {self.remote_host} failed for unknown reason: '{e}'.", exc_info=True) + else: + logger.debug(f"Connection from {self.name} to {self.remote_host} lost, but no exception was raised.") + finally: + self.connected = False + self.stats.record_connection_lost() + + def start(self): + self.async_task = asyncio.get_running_loop().create_task( + self.connect(), + name=f"WebsocketRelayConnection.connect.{self.name}", + ) + return self.async_task + + def cancel(self): + self.async_task.cancel() + + async def run_connection(self, websocket: aiohttp.ClientWebSocketResponse): + # create a dedicated subsystem metric producer to handle local subsystem + # metrics messages + # the "metrics" group is not subscribed to in the typical fashion, so we + # just explicitly create it + producer = asyncio.get_running_loop().create_task( + self.run_producer("metrics", websocket, "metrics"), + name="WebsocketRelayConnection.run_producer.metrics", + ) + self.producers["metrics"] = {"task": producer, "subscriptions": {"metrics"}} + async for msg in websocket: + self.stats.record_message_received() + + if msg.type == aiohttp.WSMsgType.ERROR: + break + elif msg.type == aiohttp.WSMsgType.TEXT: + try: + payload = json.loads(msg.data) + except json.JSONDecodeError: + logmsg = "Failed to decode message from web node" + if logger.isEnabledFor(logging.DEBUG): + logmsg = "{} {}".format(logmsg, payload) + logger.warning(logmsg) + continue + + if payload.get("type") == "consumer.subscribe": + for group in payload['groups']: + name = f"{self.remote_host}-{group}" + origin_channel = payload['origin_channel'] + if not self.producers.get(name): + producer = asyncio.get_running_loop().create_task( + self.run_producer(name, websocket, group), + name=f"WebsocketRelayConnection.run_producer.{name}", + ) + self.producers[name] = {"task": producer, "subscriptions": {origin_channel}} + logger.debug(f"Producer {name} started.") + else: + self.producers[name]["subscriptions"].add(origin_channel) + logger.debug(f"Connection from {self.name} to {self.remote_host} added subscription to {group}.") + + if payload.get("type") == "consumer.unsubscribe": + for group in payload['groups']: + name = f"{self.remote_host}-{group}" + origin_channel = payload['origin_channel'] + try: + self.producers[name]["subscriptions"].remove(origin_channel) + logger.debug(f"Unsubscribed {origin_channel} from {name}") + except KeyError: + logger.warning(f"Producer {name} not found.") + + async def run_producer(self, name, websocket, group): + try: + logger.info(f"Starting producer for {name}") + + consumer_channel = await self.channel_layer.new_channel() + await self.channel_layer.group_add(group, consumer_channel) + logger.debug(f"Producer {name} added to group {group} and is now awaiting messages.") + + while True: + try: + msg = await asyncio.wait_for(self.channel_layer.receive(consumer_channel), timeout=10) + if not msg.get("needs_relay"): + # This is added in by emit_channel_notification(). It prevents us from looping + # in the event that we are sharing a redis with a web instance. We'll see the + # message once (it'll have needs_relay=True), we'll delete that, and then forward + # the message along. The web instance will add it back to the same channels group, + # but it won't have needs_relay=True, so we'll ignore it. + continue + + # We need to copy the message because we're going to delete the needs_relay key + # and we don't want to modify the original message because other producers may + # still need to act on it. It seems weird, but it's necessary. + msg = dict(msg) + del msg["needs_relay"] + except asyncio.TimeoutError: + current_subscriptions = self.producers[name]["subscriptions"] + if len(current_subscriptions) == 0: + logger.info(f"Producer {name} has no subscribers, shutting down.") + return + + continue + except redis.exceptions.ConnectionError: + logger.info(f"Producer {name} lost connection to Redis, shutting down.") + return + + await websocket.send_json(wrap_broadcast_msg(group, msg)) + except ConnectionResetError: + # This can be hit when a web node is scaling down and we try to write to it. + # There's really nothing to do in this case and it's a fairly typical thing to happen. + # We'll log it as debug, but it's not really a problem. + logger.debug(f"Producer {name} connection reset.") + pass + except Exception: + # Note, this is very intentional and important since we do not otherwise + # ever check the result of this future. Without this line you will not see an error if + # something goes wrong in here. + logger.exception(f"Event relay producer {name} crashed") + finally: + await self.channel_layer.group_discard(group, consumer_channel) + del self.producers[name] + + +class WebSocketRelayManager(object): + def __init__(self): + self.local_hostname = get_local_host() + self.relay_connections = dict() + # hostname -> ip + self.known_hosts: Dict[str, str] = dict() + + async def on_ws_heartbeat(self, conn): + await conn.execute("LISTEN web_ws_heartbeat") + async for notif in conn.notifies(): + if notif is None: + continue + try: + if not notif.payload or notif.channel != "web_ws_heartbeat": + logger.warning(f"Unexpected channel or missing payload. {notif.channel}, {notif.payload}") + continue + + try: + payload = json.loads(notif.payload) + except json.JSONDecodeError: + logmsg = "Failed to decode message from pg_notify channel `web_ws_heartbeat`" + if logger.isEnabledFor(logging.DEBUG): + logmsg = "{} {}".format(logmsg, payload) + logger.warning(logmsg) + continue + + # Skip if the message comes from the same host we are running on + # In this case, we'll be sharing a redis, no need to relay. + if payload.get("hostname") == self.local_hostname: + hostname = payload.get("hostname") + logger.debug(f"Received a heartbeat request for {hostname}. Skipping as we use redis for local host.") + continue + + action = payload.get("action") + + if action in ("online", "offline"): + hostname = payload.get("hostname") + ip = payload.get("ip") or hostname # try back to hostname if ip isn't supplied + if ip is None: + logger.warning(f"Received invalid {action} ws_heartbeat, missing hostname and ip: {payload}") + continue + logger.debug(f"Web host {hostname} ({ip}) {action} heartbeat received.") + + if action == "online": + self.known_hosts[hostname] = ip + elif action == "offline": + await self.cleanup_offline_host(hostname) + except Exception as e: + # This catch-all is the same as the one above. asyncio will eat the exception + # but we want to know about it. + logger.exception(f"on_ws_heartbeat exception: {e}") + + async def cleanup_offline_host(self, hostname): + """ + Given a hostname, try to cancel its task/connection and remove it from + the list of hosts we know about. + If the host isn't in the list, assume that it was already deleted and + don't error. + """ + if hostname in self.relay_connections: + self.relay_connections[hostname].cancel() + + # Wait for the task to actually run its cancel/completion logic + # otherwise it might get GC'd too early when we del it below. + # Being GC'd too early could generate a scary message in logs: + # "Task was destroyed but it is pending!" + try: + await asyncio.wait_for(self.relay_connections[hostname].async_task, timeout=10) + except asyncio.TimeoutError: + logger.warning(f"Tried to cancel relay connection for {hostname} but it timed out during cleanup.") + except asyncio.CancelledError: + # Handle the case where the task was already canceled by the time we got here. + pass + + del self.relay_connections[hostname] + + if hostname in self.known_hosts: + del self.known_hosts[hostname] + + try: + self.stats_mgr.delete_remote_host_stats(hostname) + except KeyError: + pass + + async def run(self): + self.stats_mgr = RelayWebsocketStatsManager(self.local_hostname) + self.stats_mgr.start() + + database_conf = deepcopy(settings.DATABASES['default']) + database_conf['OPTIONS'] = deepcopy(database_conf.get('OPTIONS', {})) + + for k, v in settings.LISTENER_DATABASES.get('default', {}).items(): + if k != 'OPTIONS': + database_conf[k] = v + for k, v in settings.LISTENER_DATABASES.get('default', {}).get('OPTIONS', {}).items(): + database_conf['OPTIONS'][k] = v + + if 'PASSWORD' in database_conf: + database_conf['OPTIONS']['password'] = database_conf.pop('PASSWORD') + + async_conn = await psycopg.AsyncConnection.connect( + dbname=database_conf['NAME'], + host=database_conf['HOST'], + user=database_conf['USER'], + port=database_conf['PORT'], + **database_conf.get("OPTIONS", {}), + ) + + await async_conn.set_autocommit(True) + on_ws_heartbeat_task = asyncio.get_running_loop().create_task( + self.on_ws_heartbeat(async_conn), + name="WebSocketRelayManager.on_ws_heartbeat", + ) + + # Establishes a websocket connection to /websocket/relay on all API servers + while True: + if on_ws_heartbeat_task.done(): + raise Exception("on_ws_heartbeat_task has exited") + + future_remote_hosts = self.known_hosts.keys() + current_remote_hosts = self.relay_connections.keys() + deleted_remote_hosts = set(current_remote_hosts) - set(future_remote_hosts) + new_remote_hosts = set(future_remote_hosts) - set(current_remote_hosts) + + # This loop handles if we get an advertisement from a host we already know about but + # the advertisement has a different IP than we are currently connected to. + for hostname, address in self.known_hosts.items(): + if hostname not in self.relay_connections: + # We've picked up a new hostname that we don't know about yet. + continue + + if address != self.relay_connections[hostname].remote_host: + deleted_remote_hosts.add(hostname) + new_remote_hosts.add(hostname) + + # Delete any hosts with closed connections + for hostname, relay_conn in self.relay_connections.items(): + if not relay_conn.connected: + deleted_remote_hosts.add(hostname) + + if deleted_remote_hosts: + logger.info(f"Removing {deleted_remote_hosts} from websocket broadcast list") + await asyncio.gather(*[self.cleanup_offline_host(h) for h in deleted_remote_hosts]) + + if new_remote_hosts: + logger.info(f"Adding {new_remote_hosts} to websocket broadcast list") + + for h in new_remote_hosts: + stats = self.stats_mgr.new_remote_host_stats(h) + relay_connection = WebsocketRelayConnection(name=self.local_hostname, stats=stats, remote_host=self.known_hosts[h]) + relay_connection.start() + self.relay_connections[h] = relay_connection + + await asyncio.sleep(settings.BROADCAST_WEBSOCKET_NEW_INSTANCE_POLL_RATE_SECONDS) diff --git a/awx/playbooks/action_plugins/insights.py b/awx/playbooks/action_plugins/insights.py index 0d9bf6abd7ff..2d6b563c292f 100644 --- a/awx/playbooks/action_plugins/insights.py +++ b/awx/playbooks/action_plugins/insights.py @@ -9,6 +9,8 @@ from ansible.plugins.action import ActionBase +DEFAULT_OIDC_ENDPOINT = 'https://sso.redhat.com/auth/realms/redhat-external' + class ActionModule(ActionBase): def save_playbook(self, proj_path, remediation, content): @@ -34,31 +36,78 @@ def write_version(self, proj_path, etag): with open(file_path, 'w') as f: f.write(etag) + def _obtain_auth_token(self, oidc_endpoint, client_id, client_secret): + if oidc_endpoint.endswith('/'): + oidc_endpoint = oidc_endpoint[:-1] + main_url = oidc_endpoint + '/.well-known/openid-configuration' + response = requests.get(url=main_url, headers={'Accept': 'application/json'}) + data = {} + if response.status_code != 200: + data['failed'] = True + data['msg'] = 'Expected {} to return a status code of 200 but returned status code "{}" instead with content "{}".'.format( + main_url, response.status_code, response.content + ) + return data + + auth_url = response.json().get('token_endpoint', None) + data = { + 'grant_type': 'client_credentials', + 'scope': 'api.console', + 'client_id': client_id, + 'client_secret': client_secret, + } + response = requests.post(url=auth_url, data=data) + + if response.status_code != 200: + data['failed'] = True + data['msg'] = 'Expected {} to return a status code of 200 but returned status code "{}" instead with content "{}".'.format( + auth_url, response.status_code, response.content + ) + else: + data['token'] = response.json().get('access_token', None) + data['token_type'] = response.json().get('token_type', None) + return data + def run(self, tmp=None, task_vars=None): self._supports_check_mode = False + session = requests.Session() result = super(ActionModule, self).run(tmp, task_vars) insights_url = self._task.args.get('insights_url', None) - username = self._task.args.get('username', None) - password = self._task.args.get('password', None) proj_path = self._task.args.get('project_path', None) license = self._task.args.get('awx_license_type', None) awx_version = self._task.args.get('awx_version', None) + authentication = self._task.args.get('authentication', None) + username = self._task.args.get('username', None) + password = self._task.args.get('password', None) + client_id = self._task.args.get('client_id', None) + client_secret = self._task.args.get('client_secret', None) + + session.headers.update( + { + 'Content-Type': 'application/json', + 'User-Agent': '{} {} ({})'.format('AWX' if license == 'open' else 'Red Hat Ansible Automation Platform', awx_version, license), + } + ) + + if authentication == 'service_account' or (client_id and client_secret): + data = self._obtain_auth_token(DEFAULT_OIDC_ENDPOINT, client_id, client_secret) + if 'token' not in data: + result['failed'] = data['failed'] + result['msg'] = data['msg'] + return result + session.headers.update({'Authorization': f'{data["token_type"]} {data["token"]}'}) + elif authentication == 'basic' or (username and password): + session.auth = requests.auth.HTTPBasicAuth(username, password) - session = requests.Session() - session.auth = requests.auth.HTTPBasicAuth(username, password) - headers = { - 'Content-Type': 'application/json', - 'User-Agent': '{} {} ({})'.format('AWX' if license == 'open' else 'Red Hat Ansible Automation Platform', awx_version, license), - } url = '/api/remediations/v1/remediations' while url: - res = session.get('{}{}'.format(insights_url, url), headers=headers, timeout=120) + res = session.get('{}{}'.format(insights_url, url), timeout=120) if res.status_code != 200: result['failed'] = True - result['msg'] = 'Expected {} to return a status code of 200 but returned status ' 'code "{}" instead with content "{}".'.format( + result['msg'] = 'Expected {} to return a status code of 200 but returned status code "{}" instead with content "{}".'.format( url, res.status_code, res.content ) return result @@ -87,7 +136,7 @@ def run(self, tmp=None, task_vars=None): continue elif res.status_code != 200: result['failed'] = True - result['msg'] = 'Expected {} to return a status code of 200 but returned status ' 'code "{}" instead with content "{}".'.format( + result['msg'] = 'Expected {} to return a status code of 200 but returned status code "{}" instead with content "{}".'.format( playbook_url, res.status_code, res.content ) return result diff --git a/awx/playbooks/library/indirect_instance_count.py b/awx/playbooks/library/indirect_instance_count.py new file mode 100644 index 000000000000..497178abc799 --- /dev/null +++ b/awx/playbooks/library/indirect_instance_count.py @@ -0,0 +1,93 @@ +# (C) 2012, Michael DeHaan, +# (c) 2017 Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = ''' + callback: host_query + type: notification + short_description: for demo of indirect host data and counting, this produces collection data + version_added: historical + description: + - Saves collection data to artifacts folder + requirements: + - Whitelist in configuration + - Set AWX_ISOLATED_DATA_DIR, AWX will do this +''' + +import os +import json +from importlib.resources import files + +from ansible.plugins.callback import CallbackBase + +# NOTE: in Ansible 1.2 or later general logging is available without +# this plugin, just set ANSIBLE_LOG_PATH as an environment variable +# or log_path in the DEFAULTS section of your ansible configuration +# file. This callback is an example of per hosts logging for those +# that want it. + + +# Taken from https://github.com/ansible/ansible/blob/devel/lib/ansible/cli/galaxy.py#L1624 + +from ansible.cli.galaxy import with_collection_artifacts_manager +from ansible.release import __version__ + +from ansible.galaxy.collection import find_existing_collections +from ansible.utils.collection_loader import AnsibleCollectionConfig +import ansible.constants as C + + +@with_collection_artifacts_manager +def list_collections(artifacts_manager=None): + artifacts_manager.require_build_metadata = False + + default_collections_path = set(C.COLLECTIONS_PATHS) + collections_search_paths = default_collections_path | set(AnsibleCollectionConfig.collection_paths) + collections = list(find_existing_collections(list(collections_search_paths), artifacts_manager, dedupe=False)) + return collections + + +class CallbackModule(CallbackBase): + """ + logs playbook results, per host, in /var/log/ansible/hosts + """ + + CALLBACK_VERSION = 2.0 + CALLBACK_TYPE = 'notification' + CALLBACK_NAME = 'indirect_instance_count' + CALLBACK_NEEDS_WHITELIST = True + + TIME_FORMAT = "%b %d %Y %H:%M:%S" + MSG_FORMAT = "%(now)s - %(category)s - %(data)s\n\n" + + def v2_playbook_on_stats(self, stats): + artifact_dir = os.getenv('AWX_ISOLATED_DATA_DIR') + if not artifact_dir: + raise RuntimeError('Only suitable in AWX, did not find private_data_dir') + + collections_print = {} + # Loop over collections, from ansible-core these are Candidate objects + for candidate in list_collections(): + collection_print = { + 'version': candidate.ver, + } + + query_file = files(f'ansible_collections.{candidate.namespace}.{candidate.name}') / 'extensions' / 'audit' / 'event_query.yml' + if query_file.exists(): + with query_file.open('r') as f: + collection_print['host_query'] = f.read() + + collections_print[candidate.fqcn] = collection_print + + ansible_data = {'installed_collections': collections_print, 'ansible_version': __version__} + + write_path = os.path.join(artifact_dir, 'ansible_data.json') + with open(write_path, "w") as fd: + fd.write(json.dumps(ansible_data, indent=2)) + + super().v2_playbook_on_stats(stats) diff --git a/awx/playbooks/project_update.yml b/awx/playbooks/project_update.yml index 2067e76043cb..1cdf046106e2 100644 --- a/awx/playbooks/project_update.yml +++ b/awx/playbooks/project_update.yml @@ -19,48 +19,58 @@ # awx_version: Current running version of the awx or tower as a string # awx_license_type: "open" for AWX; else presume Tower # gpg_pubkey: the GPG public key to use for validation, when enabled +# client_id: Red Hat service account client ID; required for the 'service_account' authentication method used against the Insights API +# client_secret: Red Hat service account client secret; required for the 'service_account' authentication method used against the Insights API +# authentication: The authentication method to use against the Insights API +# client_id and client_secret are required for the 'service_account' authentication method +# scm_username and scm_password are required for the 'basic' authentication method - hosts: localhost gather_facts: false connection: local name: Update source tree if necessary tasks: - - - name: delete project directory before update - command: "find -delete" # volume mounted, cannot delete folder itself + - name: Delete project directory before update + ansible.builtin.shell: set -o pipefail && find . -delete -print | tail -2 # volume mounted, cannot delete folder itself + register: reg + changed_when: reg.stdout_lines | length > 1 args: chdir: "{{ project_path }}" tags: - delete - - block: - - name: update project using git - git: - dest: "{{project_path|quote}}" - repo: "{{scm_url}}" - version: "{{scm_branch|quote}}" - refspec: "{{scm_refspec|default(omit)}}" - force: "{{scm_clean}}" - track_submodules: "{{scm_track_submodules|default(omit)}}" - accept_hostkey: "{{scm_accept_hostkey|default(omit)}}" + - name: Update project using git + tags: + - update_git + block: + - name: Update project using git + ansible.builtin.git: + dest: "{{ project_path | quote }}" + repo: "{{ scm_url }}" + version: "{{ scm_branch | quote }}" + refspec: "{{ scm_refspec | default(omit) }}" + force: "{{ scm_clean }}" + track_submodules: "{{ scm_track_submodules | default(omit) }}" + accept_hostkey: "{{ scm_accept_hostkey | default(omit) }}" register: git_result - name: Set the git repository version - set_fact: + ansible.builtin.set_fact: scm_version: "{{ git_result['after'] }}" when: "'after' in git_result" - tags: - - update_git - - block: - - name: update project using svn - subversion: - dest: "{{project_path|quote}}" - repo: "{{scm_url|quote}}" - revision: "{{scm_branch|quote}}" - force: "{{scm_clean}}" - username: "{{scm_username|default(omit)}}" - password: "{{scm_password|default(omit)}}" + - name: Update project using svn + tags: + - update_svn + block: + - name: Update project using svn + ansible.builtin.subversion: + dest: "{{ project_path | quote }}" + repo: "{{ scm_url | quote }}" + revision: "{{ scm_branch | quote }}" + force: "{{ scm_clean }}" + username: "{{ scm_username | default(omit) }}" + password: "{{ scm_password | default(omit) }}" # must be in_place because folder pre-existing, because it is mounted in_place: true environment: @@ -68,85 +78,93 @@ register: svn_result - name: Set the svn repository version - set_fact: + ansible.builtin.set_fact: scm_version: "{{ svn_result['after'] }}" when: "'after' in svn_result" - - name: parse subversion version string properly - set_fact: - scm_version: "{{scm_version|regex_replace('^.*Revision: ([0-9]+).*$', '\\1')}}" - tags: - - update_svn + - name: Parse subversion version string properly + ansible.builtin.set_fact: + scm_version: "{{ scm_version | regex_replace('^.*Revision: ([0-9]+).*$', '\\1') }}" - - block: + + - name: Project update for Insights + tags: + - update_insights + block: - name: Ensure the project directory is present - file: - dest: "{{project_path|quote}}" + ansible.builtin.file: + dest: "{{ project_path | quote }}" state: directory + mode: '0755' - name: Fetch Insights Playbook(s) insights: - insights_url: "{{insights_url}}" - username: "{{scm_username}}" - password: "{{scm_password}}" - project_path: "{{project_path}}" - awx_license_type: "{{awx_license_type}}" - awx_version: "{{awx_version}}" + insights_url: "{{ insights_url }}" + username: "{{ scm_username | default(omit) }}" + password: "{{ scm_password | default(omit) }}" + project_path: "{{ project_path }}" + awx_license_type: "{{ awx_license_type }}" + awx_version: "{{ awx_version }}" + client_id: "{{ client_id | default(omit) }}" + client_secret: "{{ client_secret | default(omit) }}" + authentication: "{{ authentication | default(omit) }}" register: results - name: Save Insights Version - set_fact: - scm_version: "{{results.version}}" + ansible.builtin.set_fact: + scm_version: "{{ results.version }}" when: results is defined - tags: - - update_insights - - block: + + - name: Update project using archive + tags: + - update_archive + block: - name: Ensure the project archive directory is present - file: - dest: "{{ project_path|quote }}/.archive" + ansible.builtin.file: + dest: "{{ project_path | quote }}/.archive" state: directory + mode: '0755' - name: Get archive from url - get_url: - url: "{{ scm_url|quote }}" - dest: "{{ project_path|quote }}/.archive/" - url_username: "{{ scm_username|default(omit) }}" - url_password: "{{ scm_password|default(omit) }}" + ansible.builtin.get_url: + url: "{{ scm_url | quote }}" + dest: "{{ project_path | quote }}/.archive/" + url_username: "{{ scm_username | default(omit) }}" + url_password: "{{ scm_password | default(omit) }}" force_basic_auth: true + mode: '0755' register: get_archive - name: Unpack archive project_archive: src: "{{ get_archive.dest }}" - project_path: "{{ project_path|quote }}" + project_path: "{{ project_path | quote }}" force: "{{ scm_clean }}" when: get_archive.changed or scm_clean register: unarchived - name: Find previous archives - find: - paths: "{{ project_path|quote }}/.archive/" + ansible.builtin.find: + paths: "{{ project_path | quote }}/.archive/" excludes: - - "{{ get_archive.dest|basename }}" + - "{{ get_archive.dest | basename }}" when: unarchived.changed register: previous_archive - name: Remove previous archives - file: + ansible.builtin.file: path: "{{ item.path }}" state: absent loop: "{{ previous_archive.files }}" - when: previous_archive.files|default([]) + when: previous_archive.files | default([]) - name: Set scm_version to archive sha1 checksum - set_fact: + ansible.builtin.set_fact: scm_version: "{{ get_archive.checksum_src }}" - tags: - - update_archive - name: Repository Version - debug: + ansible.builtin.debug: msg: "Repository Version {{ scm_version }}" tags: - update_git @@ -179,64 +197,94 @@ connection: local name: Install content with ansible-galaxy command if necessary vars: - galaxy_task_env: # configure in settings - additional_collections_env: - # These environment variables are used for installing collections, in addition to galaxy_task_env - # setting the collections paths silences warnings - ANSIBLE_COLLECTIONS_PATHS: "{{projects_root}}/.__awx_cache/{{local_path}}/stage/requirements_collections" + galaxy_task_env: # configured in settings + # additional_galaxy_env contains environment variables are used for installing roles and collections and will take precedence over items in galaxy_task_env + additional_galaxy_env: + # These paths control where ansible-galaxy installs collections and roles on top the filesystem + ANSIBLE_COLLECTIONS_PATH: "{{ projects_root }}/.__awx_cache/{{ local_path }}/stage/requirements_collections" + ANSIBLE_ROLES_PATH: "{{ projects_root }}/.__awx_cache/{{ local_path }}/stage/requirements_roles" # Put the local tmp directory in same volume as collection destination # otherwise, files cannot be moved accross volumes and will cause error - ANSIBLE_LOCAL_TEMP: "{{projects_root}}/.__awx_cache/{{local_path}}/stage/tmp" + ANSIBLE_LOCAL_TEMP: "{{ projects_root }}/.__awx_cache/{{ local_path }}/stage/tmp" tasks: - - name: Check content sync settings + when: not roles_enabled | bool and not collections_enabled | bool + tags: + - install_roles + - install_collections block: - - debug: + - name: Warn about disabled content sync + ansible.builtin.debug: msg: > Collection and role syncing disabled. Check the AWX_ROLES_ENABLED and AWX_COLLECTIONS_ENABLED settings and Galaxy credentials on the project's organization. + - name: End play due to disabled content sync + ansible.builtin.meta: end_play - - meta: end_play + - block: + - name: Fetch galaxy roles from roles/requirements.(yml/yaml) + ansible.builtin.command: + cmd: "ansible-galaxy role install -r {{ req_file }} {{ verbosity }}" + register: galaxy_result + vars: + req_file: "{{ lookup('ansible.builtin.first_found', req_candidates, skip=True) }}" + req_candidates: + files: + - "{{ project_path | quote }}/roles/requirements.yml" + - "{{ project_path | quote }}/roles/requirements.yaml" + skip: True + changed_when: "'was installed successfully' in galaxy_result.stdout" + when: + - roles_enabled | bool + - req_file + tags: + - install_roles - when: not roles_enabled|bool and not collections_enabled|bool - tags: - - install_roles - - install_collections + - name: Fetch galaxy collections from collections/requirements.(yml/yaml) + ansible.builtin.command: + cmd: "ansible-galaxy collection install -r {{ req_file }} {{ verbosity }}" + register: galaxy_collection_result + vars: + req_file: "{{ lookup('ansible.builtin.first_found', req_candidates, skip=True) }}" + req_candidates: + files: + - "{{ project_path | quote }}/collections/requirements.yml" + - "{{ project_path | quote }}/collections/requirements.yaml" + skip: True + changed_when: "'Nothing to do.' not in galaxy_collection_result.stdout" + when: + - "ansible_version.full is version_compare('2.9', '>=')" + - collections_enabled | bool + - req_file + tags: + - install_collections - - name: fetch galaxy roles from requirements.(yml/yaml) - command: > - ansible-galaxy role install -r {{ item }} - --roles-path {{projects_root}}/.__awx_cache/{{local_path}}/stage/requirements_roles - {{ ' -' + 'v' * ansible_verbosity if ansible_verbosity else '' }} - args: - chdir: "{{project_path|quote}}" - register: galaxy_result - with_fileglob: - - "{{project_path|quote}}/roles/requirements.yaml" - - "{{project_path|quote}}/roles/requirements.yml" - changed_when: "'was installed successfully' in galaxy_result.stdout" - environment: "{{ galaxy_task_env }}" - when: roles_enabled|bool - tags: - - install_roles + # requirements.yml in project root can be either "old" (roles only) or "new" (collections+roles) format + - name: Fetch galaxy roles and collections from requirements.(yml/yaml) + ansible.builtin.command: + cmd: "ansible-galaxy install -r {{ req_file }} {{ verbosity }}" + register: galaxy_combined_result + vars: + req_file: "{{ lookup('ansible.builtin.first_found', req_candidates, skip=True) }}" + req_candidates: + files: + - "{{ project_path | quote }}/requirements.yaml" + - "{{ project_path | quote }}/requirements.yml" + skip: True + changed_when: "'Nothing to do.' not in galaxy_combined_result.stdout" + when: + - "ansible_version.full is version_compare('2.10', '>=')" + - collections_enabled | bool + - roles_enabled | bool + - req_file + tags: + - install_collections + - install_roles + module_defaults: + ansible.builtin.command: + chdir: "{{ project_path | quote }}" - - name: fetch galaxy collections from collections/requirements.(yml/yaml) - command: > - ansible-galaxy collection install -r {{ item }} - --collections-path {{projects_root}}/.__awx_cache/{{local_path}}/stage/requirements_collections - {{ ' -' + 'v' * ansible_verbosity if ansible_verbosity else '' }} - args: - chdir: "{{project_path|quote}}" - register: galaxy_collection_result - with_fileglob: - - "{{project_path|quote}}/collections/requirements.yaml" - - "{{project_path|quote}}/collections/requirements.yml" - - "{{project_path|quote}}/requirements.yaml" - - "{{project_path|quote}}/requirements.yml" - changed_when: "'Installing ' in galaxy_collection_result.stdout" - environment: "{{ additional_collections_env | combine(galaxy_task_env) }}" - when: - - "ansible_version.full is version_compare('2.9', '>=')" - - collections_enabled|bool - tags: - - install_collections + # We combine our additional_galaxy_env into galaxy_task_env so that our values are preferred over anything a user would set + environment: "{{ galaxy_task_env | combine(additional_galaxy_env) }}" + vars: + verbosity: "{{ (ansible_verbosity) | ternary('-'+'v'*ansible_verbosity, '') }}" diff --git a/awx/resource_api.py b/awx/resource_api.py new file mode 100644 index 000000000000..10c2eac4ed51 --- /dev/null +++ b/awx/resource_api.py @@ -0,0 +1,42 @@ +from ansible_base.resource_registry.registry import ParentResource, ResourceConfig, ServiceAPIConfig, SharedResource +from ansible_base.rbac.models import RoleDefinition + +from ansible_base.resource_registry.shared_types import ( + FeatureFlagType, + RoleDefinitionType, + OrganizationType, + TeamType, + UserType, +) +from ansible_base.feature_flags.models import AAPFlag +from awx.main import models + + +class APIConfig(ServiceAPIConfig): + service_type = "awx" + + +RESOURCE_LIST = ( + ResourceConfig( + models.Organization, + shared_resource=SharedResource(serializer=OrganizationType, is_provider=False), + ), + ResourceConfig( + models.User, + shared_resource=SharedResource(serializer=UserType, is_provider=False), + name_field="username", + ), + ResourceConfig( + models.Team, + shared_resource=SharedResource(serializer=TeamType, is_provider=False), + parent_resources=[ParentResource(model=models.Organization, field_name="organization")], + ), + ResourceConfig( + RoleDefinition, + shared_resource=SharedResource(serializer=RoleDefinitionType, is_provider=False), + ), + ResourceConfig( + AAPFlag, + shared_resource=SharedResource(serializer=FeatureFlagType, is_provider=False), + ), +) diff --git a/awx/settings/__init__.py b/awx/settings/__init__.py index e484e62be15d..2332863d7bb1 100644 --- a/awx/settings/__init__.py +++ b/awx/settings/__init__.py @@ -1,2 +1,74 @@ # Copyright (c) 2015 Ansible, Inc. # All Rights Reserved. +import os +import copy +from ansible_base.lib.dynamic_config import ( + factory, + export, + load_envvars, + load_python_file_with_injected_context, + load_standard_settings_files, +) +from .functions import ( + assert_production_settings, + merge_application_name, + add_backwards_compatibility, + load_extra_development_files, +) + +add_backwards_compatibility() + +# Create a the standard DYNACONF instance which will come with DAB defaults +# This loads defaults.py and environment specific file e.g: development_defaults.py +DYNACONF = factory( + __name__, + "AWX", + environments=("development", "production", "quiet", "kube"), + settings_files=["defaults.py"], +) + +# Store snapshot before loading any custom config file +DYNACONF.set( + "DEFAULTS_SNAPSHOT", + copy.deepcopy(DYNACONF.as_dict(internal=False)), + loader_identifier="awx.settings:DEFAULTS_SNAPSHOT", +) + +############################################################################################# +# Settings loaded before this point will be allowed to be overridden by the database settings +# Any settings loaded after this point will be marked as as a read_only database setting +############################################################################################# + +# Load extra settings files from the following directories +# /etc/tower/conf.d/ and /etc/tower/ +# this is the legacy location, kept for backwards compatibility +settings_dir = os.environ.get('AWX_SETTINGS_DIR', '/etc/tower/conf.d/') +settings_files_path = os.path.join(settings_dir, '*.py') +settings_file_path = os.environ.get('AWX_SETTINGS_FILE', '/etc/tower/settings.py') +load_python_file_with_injected_context(settings_files_path, settings=DYNACONF) +load_python_file_with_injected_context(settings_file_path, settings=DYNACONF) + +# Load extra settings files from the following directories +# /etc/ansible-automation-platform/{settings,flags,.secrets}.yaml +# and /etc/ansible-automation-platform/awx/{settings,flags,.secrets}.yaml +# this is the new standard location for all services +load_standard_settings_files(DYNACONF) + +# Load optional development only settings files +load_extra_development_files(DYNACONF) + +# Check at least one setting file has been loaded in production mode +assert_production_settings(DYNACONF, settings_dir, settings_file_path) + +# Load envvars at the end to allow them to override everything loaded so far +load_envvars(DYNACONF) + +# This must run after all custom settings are loaded +DYNACONF.update( + merge_application_name(DYNACONF), + loader_identifier="awx.settings:merge_application_name", + merge=True, +) + +# Update django.conf.settings with DYNACONF values +export(__name__, DYNACONF) diff --git a/awx/settings/application_name.py b/awx/settings/application_name.py new file mode 100644 index 000000000000..ac7e40553e00 --- /dev/null +++ b/awx/settings/application_name.py @@ -0,0 +1,36 @@ +import os +import sys + + +def get_service_name(argv): + ''' + Return best-effort guess as to the name of this service + ''' + for arg in argv: + if arg == '-m': + continue + if 'python' in arg: + continue + if 'manage' in arg: + continue + if arg.startswith('run_'): + return arg[len('run_') :] + return arg + + +def get_application_name(CLUSTER_HOST_ID, function=''): + if function: + function = f'_{function}' + return f'awx-{os.getpid()}-{get_service_name(sys.argv)}{function}-{CLUSTER_HOST_ID}'[:63] + + +def set_application_name(DATABASES, CLUSTER_HOST_ID, function=''): + """In place modification of DATABASES to set the application name for the connection.""" + # If settings files were not properly passed DATABASES could be {} at which point we don't need to set the app name. + if not DATABASES or 'default' not in DATABASES: + return + + if 'sqlite3' in DATABASES['default']['ENGINE']: + return + options_dict = DATABASES['default'].setdefault('OPTIONS', dict()) + options_dict['application_name'] = get_application_name(CLUSTER_HOST_ID, function) diff --git a/awx/settings/defaults.py b/awx/settings/defaults.py index 4d18540bcda6..f52e2ea13353 100644 --- a/awx/settings/defaults.py +++ b/awx/settings/defaults.py @@ -1,23 +1,12 @@ # Copyright (c) 2015 Ansible, Inc. # All Rights Reserved. +# Python import base64 import os import re # noqa -import sys import tempfile import socket -from datetime import timedelta - - -if "pytest" in sys.modules: - from unittest import mock - - with mock.patch('__main__.__builtins__.dir', return_value=[]): - import ldap -else: - import ldap - DEBUG = True SQL_DEBUG = DEBUG @@ -42,6 +31,18 @@ } } +# Special database overrides for dispatcher connections listening to pg_notify +LISTENER_DATABASES = { + 'default': { + 'OPTIONS': { + 'keepalives': 1, + 'keepalives_idle': 5, + 'keepalives_interval': 5, + 'keepalives_count': 5, + }, + } +} + # Whether or not the deployment is a K8S-based deployment # In K8S-based deployments, instances have zero capacity - all playbook # automation is intended to flow through defined Container Groups that @@ -51,6 +52,7 @@ AWX_CONTAINER_GROUP_K8S_API_TIMEOUT = 10 AWX_CONTAINER_GROUP_DEFAULT_NAMESPACE = os.getenv('MY_POD_NAMESPACE', 'default') +AWX_CONTAINER_GROUP_DEFAULT_JOB_LABEL = os.getenv('AWX_CONTAINER_GROUP_DEFAULT_JOB_LABEL', 'ansible_job') # Timeout when waiting for pod to enter running state. If the pod is still in pending state , it will be terminated. Valid time units are "s", "m", "h". Example : "5m" , "10s". AWX_CONTAINER_GROUP_POD_PENDING_TIMEOUT = "2h" @@ -77,13 +79,12 @@ # to load the internationalization machinery. USE_I18N = True -# If you set this to False, Django will not format dates, numbers and -# calendars according to the current locale -USE_L10N = True - USE_TZ = True -STATICFILES_DIRS = [os.path.join(BASE_DIR, 'ui', 'build', 'static'), os.path.join(BASE_DIR, 'static')] +STATICFILES_DIRS = [ + os.path.join(BASE_DIR, 'ui', 'build'), + os.path.join(BASE_DIR, 'static'), +] # Absolute filesystem path to the directory where static file are collected via # the collectstatic command. @@ -103,6 +104,7 @@ MEDIA_URL = '/media/' LOGIN_URL = '/api/login/' +LOGOUT_ALLOWED_HOSTS = None # Absolute filesystem path to the directory to host projects (with playbooks). # This directory should not be web-accessible. @@ -116,9 +118,6 @@ # Absolute filesystem path to the directory to store logs LOG_ROOT = '/var/log/tower/' -# The heartbeat file for the scheduler -SCHEDULE_METADATA_LOCATION = os.path.join(BASE_DIR, '.tower_cycle') - # Django gettext files path: locale//LC_MESSAGES/django.po, django.mo LOCALE_PATHS = (os.path.join(BASE_DIR, 'locale'),) @@ -129,6 +128,16 @@ # Note: This setting may be overridden by database settings. SCHEDULE_MAX_JOBS = 10 +# Bulk API related settings +# Maximum number of jobs that can be launched in 1 bulk job +BULK_JOB_MAX_LAUNCH = 100 + +# Maximum number of host that can be created in 1 bulk host create +BULK_HOST_MAX_CREATE = 100 + +# Maximum number of host that can be deleted in 1 bulk host delete +BULK_HOST_MAX_DELETE = 250 + SITE_ID = 1 # Make this unique, and don't share it with anybody. @@ -156,6 +165,11 @@ # REMOTE_HOST_HEADERS will be trusted unconditionally') PROXY_IP_ALLOWED_LIST = [] +# If we are behind a reverse proxy/load balancer, use this setting to +# allow the scheme://addresses from which Tower should trust csrf requests from +# If this setting is an empty list (the default), we will only trust ourself +CSRF_TRUSTED_ORIGINS = [] + CUSTOM_VENV_PATHS = [] # Warning: this is a placeholder for a database setting @@ -203,7 +217,7 @@ # The number of seconds to buffer callback receiver bulk # writes in memory before flushing via JobEvent.objects.bulk_create() -JOB_EVENT_BUFFER_SECONDS = 0.1 +JOB_EVENT_BUFFER_SECONDS = 1 # The interval at which callback receiver statistics should be # recorded @@ -215,6 +229,9 @@ # The number of job events to migrate per-transaction when moving from int -> bigint JOB_EVENT_MIGRATION_CHUNK_SIZE = 1000000 +# The prefix of the redis key that stores metrics +SUBSYSTEM_METRICS_REDIS_KEY_PREFIX = "awx_metrics" + # Histogram buckets for the callback_receiver_batch_events_insert_db metric SUBSYSTEM_METRICS_BATCH_INSERT_BUCKETS = [10, 50, 150, 350, 650, 2000] @@ -235,6 +252,7 @@ # We have the grace period so the task manager can bail out before the timeout. TASK_MANAGER_TIMEOUT = 300 TASK_MANAGER_TIMEOUT_GRACE_PERIOD = 60 +TASK_MANAGER_LOCK_TIMEOUT = TASK_MANAGER_TIMEOUT + TASK_MANAGER_TIMEOUT_GRACE_PERIOD # Number of seconds _in addition to_ the task manager timeout a job can stay # in waiting without being reaped @@ -251,6 +269,9 @@ # Note: This setting may be overridden by database settings. SESSION_COOKIE_AGE = 1800 +# Option to change userLoggedIn cookie SameSite policy. +USER_COOKIE_SAMESITE = 'Lax' + # Name of the cookie that contains the session information. # Note: Changing this value may require changes to any clients. SESSION_COOKIE_NAME = 'awx_sessionid' @@ -283,14 +304,21 @@ 'django.template.context_processors.static', 'django.template.context_processors.tz', 'django.contrib.messages.context_processors.messages', + 'django.template.context_processors.request', 'awx.ui.context_processors.csp', 'awx.ui.context_processors.version', - 'social_django.context_processors.backends', - 'social_django.context_processors.login_redirect', ], 'builtins': ['awx.main.templatetags.swagger'], + 'libraries': { + "ansible_base.lib.templatetags.requests": "ansible_base.lib.templatetags.requests", + "ansible_base.lib.templatetags.util": "ansible_base.lib.templatetags.util", + }, }, - 'DIRS': [os.path.join(BASE_DIR, 'templates'), os.path.join(BASE_DIR, 'ui', 'build'), os.path.join(BASE_DIR, 'ui', 'public')], + 'DIRS': [ + os.path.join(BASE_DIR, 'templates'), + os.path.join(BASE_DIR, 'ui', 'public'), + os.path.join(BASE_DIR, 'ui', 'build', 'awx'), + ], }, ] @@ -308,22 +336,26 @@ # According to channels 4.0 docs you install daphne instead of channels now 'daphne', 'django.contrib.staticfiles', - 'oauth2_provider', 'rest_framework', 'django_extensions', 'polymorphic', - 'taggit', - 'social_django', 'django_guid', 'corsheaders', 'awx.conf', 'awx.main', 'awx.api', 'awx.ui', - 'awx.sso', 'solo', + 'ansible_base.rest_filters', + 'ansible_base.jwt_consumer', + 'ansible_base.resource_registry', + 'ansible_base.rbac', + 'ansible_base.feature_flags', + 'ansible_base.api_documentation', + 'flags', ] + INTERNAL_IPS = ('127.0.0.1',) MAX_PAGE_SIZE = 200 @@ -331,17 +363,11 @@ 'DEFAULT_PAGINATION_CLASS': 'awx.api.pagination.Pagination', 'PAGE_SIZE': 25, 'DEFAULT_AUTHENTICATION_CLASSES': ( - 'awx.api.authentication.LoggedOAuth2Authentication', + 'ansible_base.jwt_consumer.awx.auth.AwxJWTAuthentication', 'awx.api.authentication.SessionAuthentication', 'awx.api.authentication.LoggedBasicAuthentication', ), 'DEFAULT_PERMISSION_CLASSES': ('awx.api.permissions.ModelAccessPermission',), - 'DEFAULT_FILTER_BACKENDS': ( - 'awx.api.filters.TypeFilterBackend', - 'awx.api.filters.FieldLookupBackend', - 'rest_framework.filters.SearchFilter', - 'awx.api.filters.OrderByBackend', - ), 'DEFAULT_PARSER_CLASSES': ('awx.api.parsers.JSONParser',), 'DEFAULT_RENDERER_CLASSES': ('awx.api.renderers.DefaultJSONRenderer', 'awx.api.renderers.BrowsableAPIRenderer'), 'DEFAULT_METADATA_CLASS': 'awx.api.metadata.Metadata', @@ -349,65 +375,15 @@ 'VIEW_DESCRIPTION_FUNCTION': 'awx.api.generics.get_view_description', 'NON_FIELD_ERRORS_KEY': '__all__', 'DEFAULT_VERSION': 'v2', - # For swagger schema generation + # For OpenAPI schema generation with drf-spectacular # see https://github.com/encode/django-rest-framework/pull/6532 - 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.AutoSchema', + 'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema', # 'URL_FORMAT_OVERRIDE': None, } -AUTHENTICATION_BACKENDS = ( - 'awx.sso.backends.LDAPBackend', - 'awx.sso.backends.LDAPBackend1', - 'awx.sso.backends.LDAPBackend2', - 'awx.sso.backends.LDAPBackend3', - 'awx.sso.backends.LDAPBackend4', - 'awx.sso.backends.LDAPBackend5', - 'awx.sso.backends.RADIUSBackend', - 'awx.sso.backends.TACACSPlusBackend', - 'social_core.backends.google.GoogleOAuth2', - 'social_core.backends.github.GithubOAuth2', - 'social_core.backends.github.GithubOrganizationOAuth2', - 'social_core.backends.github.GithubTeamOAuth2', - 'social_core.backends.github_enterprise.GithubEnterpriseOAuth2', - 'social_core.backends.github_enterprise.GithubEnterpriseOrganizationOAuth2', - 'social_core.backends.github_enterprise.GithubEnterpriseTeamOAuth2', - 'social_core.backends.open_id_connect.OpenIdConnectAuth', - 'social_core.backends.azuread.AzureADOAuth2', - 'awx.sso.backends.SAMLAuth', - 'awx.main.backends.AWXModelBackend', -) - - -# Django OAuth Toolkit settings -OAUTH2_PROVIDER_APPLICATION_MODEL = 'main.OAuth2Application' -OAUTH2_PROVIDER_ACCESS_TOKEN_MODEL = 'main.OAuth2AccessToken' -OAUTH2_PROVIDER_REFRESH_TOKEN_MODEL = 'oauth2_provider.RefreshToken' - -OAUTH2_PROVIDER = {'ACCESS_TOKEN_EXPIRE_SECONDS': 31536000000, 'AUTHORIZATION_CODE_EXPIRE_SECONDS': 600, 'REFRESH_TOKEN_EXPIRE_SECONDS': 2628000} -ALLOW_OAUTH2_FOR_EXTERNAL_USERS = False - -# LDAP server (default to None to skip using LDAP authentication). -# Note: This setting may be overridden by database settings. -AUTH_LDAP_SERVER_URI = None - -# Disable LDAP referrals by default (to prevent certain LDAP queries from -# hanging with AD). -# Note: This setting may be overridden by database settings. -AUTH_LDAP_CONNECTION_OPTIONS = {ldap.OPT_REFERRALS: 0, ldap.OPT_NETWORK_TIMEOUT: 30} +# SWAGGER_SETTINGS removed - migrated to drf-spectacular (see SPECTACULAR_SETTINGS below) -# Radius server settings (default to empty string to skip using Radius auth). -# Note: These settings may be overridden by database settings. -RADIUS_SERVER = '' -RADIUS_PORT = 1812 -RADIUS_SECRET = '' - -# TACACS+ settings (default host to empty string to skip using TACACS+ auth). -# Note: These settings may be overridden by database settings. -TACACSPLUS_HOST = '' -TACACSPLUS_PORT = 49 -TACACSPLUS_SECRET = '' -TACACSPLUS_SESSION_TIMEOUT = 5 -TACACSPLUS_AUTH_PROTOCOL = 'ascii' +AUTHENTICATION_BACKENDS = ('awx.main.backends.AWXModelBackend',) # Enable / Disable HTTP Basic Authentication used in the API browser # Note: Session limits are not enforced when using HTTP Basic Authentication. @@ -437,113 +413,46 @@ EXECUTION_NODE_REMEDIATION_CHECKS = 60 * 30 # once every 30 minutes check if an execution node errors have been resolved # Amount of time dispatcher will try to reconnect to database for jobs and consuming new work -DISPATCHER_DB_DOWNTOWN_TOLLERANCE = 40 +DISPATCHER_DB_DOWNTIME_TOLERANCE = 40 BROKER_URL = 'unix:///var/run/redis/redis.sock' -CELERYBEAT_SCHEDULE = { - 'tower_scheduler': {'task': 'awx.main.tasks.system.awx_periodic_scheduler', 'schedule': timedelta(seconds=30), 'options': {'expires': 20}}, - 'cluster_heartbeat': { +REDIS_RETRY_COUNT = 3 # Number of retries for Redis connection errors +REDIS_BACKOFF_CAP = 1.0 # Maximum backoff delay in seconds for Redis retries +REDIS_BACKOFF_BASE = 0.5 # Base for exponential backoff calculation for Redis retries + +DISPATCHER_SCHEDULE = { + 'awx.main.tasks.system.awx_periodic_scheduler': {'task': 'awx.main.tasks.system.awx_periodic_scheduler', 'schedule': 30, 'options': {'expires': 20}}, + 'awx.main.tasks.system.cluster_node_heartbeat': { 'task': 'awx.main.tasks.system.cluster_node_heartbeat', - 'schedule': timedelta(seconds=CLUSTER_NODE_HEARTBEAT_PERIOD), + 'schedule': CLUSTER_NODE_HEARTBEAT_PERIOD, 'options': {'expires': 50}, }, - 'gather_analytics': {'task': 'awx.main.tasks.system.gather_analytics', 'schedule': timedelta(minutes=5)}, - 'task_manager': {'task': 'awx.main.scheduler.tasks.task_manager', 'schedule': timedelta(seconds=20), 'options': {'expires': 20}}, - 'dependency_manager': {'task': 'awx.main.scheduler.tasks.dependency_manager', 'schedule': timedelta(seconds=20), 'options': {'expires': 20}}, - 'k8s_reaper': {'task': 'awx.main.tasks.system.awx_k8s_reaper', 'schedule': timedelta(seconds=60), 'options': {'expires': 50}}, - 'receptor_reaper': {'task': 'awx.main.tasks.system.awx_receptor_workunit_reaper', 'schedule': timedelta(seconds=60)}, - 'send_subsystem_metrics': {'task': 'awx.main.analytics.analytics_tasks.send_subsystem_metrics', 'schedule': timedelta(seconds=20)}, - 'cleanup_images': {'task': 'awx.main.tasks.system.cleanup_images_and_files', 'schedule': timedelta(hours=3)}, + 'awx.main.tasks.system.gather_analytics': {'task': 'awx.main.tasks.system.gather_analytics', 'schedule': 300}, + 'awx.main.scheduler.tasks.task_manager': {'task': 'awx.main.scheduler.tasks.task_manager', 'schedule': 20, 'options': {'expires': 20}}, + 'awx.main.scheduler.tasks.dependency_manager': {'task': 'awx.main.scheduler.tasks.dependency_manager', 'schedule': 20, 'options': {'expires': 20}}, + 'awx.main.tasks.system.awx_k8s_reaper': {'task': 'awx.main.tasks.system.awx_k8s_reaper', 'schedule': 60, 'options': {'expires': 50}}, + 'awx.main.tasks.system.awx_receptor_workunit_reaper': {'task': 'awx.main.tasks.system.awx_receptor_workunit_reaper', 'schedule': 60}, + 'awx.main.analytics.analytics_tasks.send_subsystem_metrics': {'task': 'awx.main.analytics.analytics_tasks.send_subsystem_metrics', 'schedule': 20}, + 'awx.main.tasks.system.cleanup_images_and_files': {'task': 'awx.main.tasks.system.cleanup_images_and_files', 'schedule': 10800}, + 'awx.main.tasks.host_metrics.cleanup_host_metrics': {'task': 'awx.main.tasks.host_metrics.cleanup_host_metrics', 'schedule': 12600}, + 'awx.main.tasks.host_metrics.host_metric_summary_monthly': {'task': 'awx.main.tasks.host_metrics.host_metric_summary_monthly', 'schedule': 14400}, + 'awx.main.tasks.system.periodic_resource_sync': {'task': 'awx.main.tasks.system.periodic_resource_sync', 'schedule': 900}, + 'awx.main.tasks.host_indirect.cleanup_and_save_indirect_host_entries_fallback': { + 'task': 'awx.main.tasks.host_indirect.cleanup_and_save_indirect_host_entries_fallback', + 'schedule': 3600, + }, } # Django Caching Configuration DJANGO_REDIS_IGNORE_EXCEPTIONS = True -CACHES = {'default': {'BACKEND': 'django_redis.cache.RedisCache', 'LOCATION': 'unix:/var/run/redis/redis.sock?db=1'}} - -# Social Auth configuration. -SOCIAL_AUTH_STRATEGY = 'social_django.strategy.DjangoStrategy' -SOCIAL_AUTH_STORAGE = 'social_django.models.DjangoStorage' -SOCIAL_AUTH_USER_MODEL = 'auth.User' - -_SOCIAL_AUTH_PIPELINE_BASE = ( - 'social_core.pipeline.social_auth.social_details', - 'social_core.pipeline.social_auth.social_uid', - 'social_core.pipeline.social_auth.auth_allowed', - 'social_core.pipeline.social_auth.social_user', - 'social_core.pipeline.user.get_username', - 'social_core.pipeline.social_auth.associate_by_email', - 'social_core.pipeline.user.create_user', - 'awx.sso.social_base_pipeline.check_user_found_or_created', - 'social_core.pipeline.social_auth.associate_user', - 'social_core.pipeline.social_auth.load_extra_data', - 'awx.sso.social_base_pipeline.set_is_active_for_new_user', - 'social_core.pipeline.user.user_details', - 'awx.sso.social_base_pipeline.prevent_inactive_login', -) -SOCIAL_AUTH_PIPELINE = _SOCIAL_AUTH_PIPELINE_BASE + ('awx.sso.social_pipeline.update_user_orgs', 'awx.sso.social_pipeline.update_user_teams') -SOCIAL_AUTH_SAML_PIPELINE = _SOCIAL_AUTH_PIPELINE_BASE + ('awx.sso.saml_pipeline.populate_user', 'awx.sso.saml_pipeline.update_user_flags') -SAML_AUTO_CREATE_OBJECTS = True - -SOCIAL_AUTH_LOGIN_URL = '/' -SOCIAL_AUTH_LOGIN_REDIRECT_URL = '/sso/complete/' -SOCIAL_AUTH_LOGIN_ERROR_URL = '/sso/error/' -SOCIAL_AUTH_INACTIVE_USER_URL = '/sso/inactive/' - -SOCIAL_AUTH_RAISE_EXCEPTIONS = False -SOCIAL_AUTH_USERNAME_IS_FULL_EMAIL = False -# SOCIAL_AUTH_SLUGIFY_USERNAMES = True -SOCIAL_AUTH_CLEAN_USERNAMES = True - -SOCIAL_AUTH_SANITIZE_REDIRECTS = True -SOCIAL_AUTH_REDIRECT_IS_HTTPS = False +CACHES = {'default': {'BACKEND': 'awx.main.cache.AWXRedisCache', 'LOCATION': 'unix:///var/run/redis/redis.sock?db=1'}} -# Note: These settings may be overridden by database settings. -SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = '' -SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = '' -SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = ['profile'] - -SOCIAL_AUTH_GITHUB_KEY = '' -SOCIAL_AUTH_GITHUB_SECRET = '' -SOCIAL_AUTH_GITHUB_SCOPE = ['user:email', 'read:org'] - -SOCIAL_AUTH_GITHUB_ORG_KEY = '' -SOCIAL_AUTH_GITHUB_ORG_SECRET = '' -SOCIAL_AUTH_GITHUB_ORG_NAME = '' -SOCIAL_AUTH_GITHUB_ORG_SCOPE = ['user:email', 'read:org'] - -SOCIAL_AUTH_GITHUB_TEAM_KEY = '' -SOCIAL_AUTH_GITHUB_TEAM_SECRET = '' -SOCIAL_AUTH_GITHUB_TEAM_ID = '' -SOCIAL_AUTH_GITHUB_TEAM_SCOPE = ['user:email', 'read:org'] - -SOCIAL_AUTH_GITHUB_ENTERPRISE_KEY = '' -SOCIAL_AUTH_GITHUB_ENTERPRISE_SECRET = '' -SOCIAL_AUTH_GITHUB_ENTERPRISE_SCOPE = ['user:email', 'read:org'] - -SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_KEY = '' -SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_SECRET = '' -SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_NAME = '' -SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_SCOPE = ['user:email', 'read:org'] - -SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_KEY = '' -SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_SECRET = '' -SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ID = '' -SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_SCOPE = ['user:email', 'read:org'] - -SOCIAL_AUTH_AZUREAD_OAUTH2_KEY = '' -SOCIAL_AUTH_AZUREAD_OAUTH2_SECRET = '' - -SOCIAL_AUTH_SAML_SP_ENTITY_ID = '' -SOCIAL_AUTH_SAML_SP_PUBLIC_CERT = '' -SOCIAL_AUTH_SAML_SP_PRIVATE_KEY = '' -SOCIAL_AUTH_SAML_ORG_INFO = {} -SOCIAL_AUTH_SAML_TECHNICAL_CONTACT = {} -SOCIAL_AUTH_SAML_SUPPORT_CONTACT = {} -SOCIAL_AUTH_SAML_ENABLED_IDPS = {} - -SOCIAL_AUTH_SAML_ORGANIZATION_ATTR = {} -SOCIAL_AUTH_SAML_TEAM_ATTR = {} -SOCIAL_AUTH_SAML_USER_FLAGS_BY_ATTR = {} +ROLE_SINGLETON_USER_RELATIONSHIP = '' +ROLE_SINGLETON_TEAM_RELATIONSHIP = '' + +# We want to short-circuit RBAC methods to get permission to system admins and auditors +ROLE_BYPASS_SUPERUSER_FLAGS = ['is_superuser'] +ROLE_BYPASS_ACTION_FLAGS = {'view': 'is_system_auditor'} # Any ANSIBLE_* settings will be passed to the task runner subprocess # environment @@ -612,6 +521,10 @@ # Automatically remove nodes that have missed their heartbeats after some time AWX_AUTO_DEPROVISION_INSTANCES = False + +# If True, allow users to be assigned to roles that were created via JWT +ALLOW_LOCAL_ASSIGNING_JWT_ROLES = True + # Enable Pendo on the UI, possible values are 'off', 'anonymous', and 'detailed' # Note: This setting may be overridden by database settings. PENDO_TRACKING_STATE = "off" @@ -669,6 +582,12 @@ VMWARE_VALIDATE_CERTS = False +# ----------------- +# -- VMware ESXi -- +# ----------------- +# TODO: Verify matches with AAP-53978 solution in awx-plugins +VMWARE_ESXI_EXCLUDE_EMPTY_GROUPS = True + # --------------------------- # -- Google Compute Engine -- # --------------------------- @@ -712,10 +631,10 @@ # --------------------- # ----- Foreman ----- # --------------------- -SATELLITE6_ENABLED_VAR = 'foreman_enabled' +SATELLITE6_ENABLED_VAR = 'foreman_enabled,foreman.enabled' SATELLITE6_ENABLED_VALUE = 'True' SATELLITE6_EXCLUDE_EMPTY_GROUPS = True -SATELLITE6_INSTANCE_ID_VAR = 'foreman_id' +SATELLITE6_INSTANCE_ID_VAR = 'foreman_id,foreman.id' # SATELLITE6_GROUP_PREFIX and SATELLITE6_GROUP_PATTERNS defined in source vars # ---------------- @@ -726,6 +645,19 @@ INSIGHTS_INSTANCE_ID_VAR = 'insights_id' INSIGHTS_EXCLUDE_EMPTY_GROUPS = False +# ---------------- +# -- Terraform State -- +# ---------------- +# TERRAFORM_ENABLED_VAR = +# TERRAFORM_ENABLED_VALUE = +TERRAFORM_INSTANCE_ID_VAR = 'id' +TERRAFORM_EXCLUDE_EMPTY_GROUPS = True + +# ------------------------ +# OpenShift Virtualization +# ------------------------ +OPENSHIFT_VIRTUALIZATION_EXCLUDE_EMPTY_GROUPS = True + # --------------------- # ----- Custom ----- # --------------------- @@ -742,6 +674,13 @@ SCM_EXCLUDE_EMPTY_GROUPS = False # SCM_INSTANCE_ID_VAR = +# ---------------- +# -- Constructed -- +# ---------------- +CONSTRUCTED_INSTANCE_ID_VAR = 'remote_tower_id' + +CONSTRUCTED_EXCLUDE_EMPTY_GROUPS = False + # --------------------- # -- Activity Stream -- # --------------------- @@ -758,31 +697,26 @@ DISABLE_LOCAL_AUTH = False # Note: This setting may be overridden by database settings. -TOWER_URL_BASE = "https://towerhost" +TOWER_URL_BASE = "https://platformhost" INSIGHTS_URL_BASE = "https://example.org" INSIGHTS_AGENT_MIME = 'application/example' # See https://github.com/ansible/awx-facts-playbooks INSIGHTS_SYSTEM_ID_FILE = '/etc/redhat-access-insights/machine-id' - -TOWER_SETTINGS_MANIFEST = {} +INSIGHTS_CERT_PATH = "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem" # Settings related to external logger configuration LOG_AGGREGATOR_ENABLED = False LOG_AGGREGATOR_TCP_TIMEOUT = 5 LOG_AGGREGATOR_VERIFY_CERT = True LOG_AGGREGATOR_LEVEL = 'INFO' -LOG_AGGREGATOR_MAX_DISK_USAGE_GB = 1 +LOG_AGGREGATOR_ACTION_QUEUE_SIZE = 131072 +LOG_AGGREGATOR_ACTION_MAX_DISK_USAGE_GB = 1 # Action queue LOG_AGGREGATOR_MAX_DISK_USAGE_PATH = '/var/lib/awx' LOG_AGGREGATOR_RSYSLOGD_DEBUG = False LOG_AGGREGATOR_RSYSLOGD_ERROR_LOG_FILE = '/var/log/tower/rsyslog.err' API_400_ERROR_LOG_FORMAT = 'status {status_code} received by user {user_name} attempting to access {url_path} from {remote_addr}' -# The number of retry attempts for websocket session establishment -# If you're encountering issues establishing websockets in a cluster, -# raising this value can help -CHANNEL_LAYER_RECEIVE_MAX_RETRY = 10 - ASGI_APPLICATION = "awx.main.routing.application" CHANNEL_LAYERS = { @@ -806,7 +740,6 @@ 'json': {'()': 'awx.main.utils.formatters.LogstashFormatter'}, 'timed_import': {'()': 'awx.main.utils.formatters.TimeFormatter', 'format': '%(relativeSeconds)9.3f %(levelname)-8s %(message)s'}, 'dispatcher': {'format': '%(asctime)s %(levelname)-8s [%(guid)s] %(name)s PID:%(process)d %(message)s'}, - 'job_lifecycle': {'()': 'awx.main.utils.formatters.JobLifeCycleFormatter'}, }, # Extended below based on install scenario. You probably don't want to add something directly here. # See 'handler_config' below. @@ -827,10 +760,12 @@ 'address': '/var/run/awx-rsyslog/rsyslog.sock', 'filters': ['external_log_enabled', 'dynamic_level_filter', 'guid'], }, + 'otel': {'class': 'logging.NullHandler'}, }, 'loggers': { 'django': {'handlers': ['console']}, 'django.request': {'handlers': ['console', 'file', 'tower_warnings'], 'level': 'WARNING'}, + 'ansible_base': {'handlers': ['console', 'file', 'tower_warnings']}, 'daphne': {'handlers': ['console', 'file', 'tower_warnings'], 'level': 'INFO'}, 'rest_framework.request': {'handlers': ['console', 'file', 'tower_warnings'], 'level': 'WARNING', 'propagate': False}, 'py.warnings': {'handlers': ['console']}, @@ -838,25 +773,28 @@ 'awx.conf': {'handlers': ['null'], 'level': 'WARNING'}, 'awx.conf.settings': {'handlers': ['null'], 'level': 'WARNING'}, 'awx.main': {'handlers': ['null']}, - 'awx.main.commands.run_callback_receiver': {'handlers': ['callback_receiver']}, # level handled by dynamic_level_filter + 'awx.main.commands.run_callback_receiver': {'handlers': ['callback_receiver'], 'level': 'INFO'}, # very noisey debug-level logs 'awx.main.dispatch': {'handlers': ['dispatcher']}, 'awx.main.consumers': {'handlers': ['console', 'file', 'tower_warnings'], 'level': 'INFO'}, - 'awx.main.wsbroadcast': {'handlers': ['wsbroadcast']}, + 'awx.main.rsyslog_configurer': {'handlers': ['rsyslog_configurer']}, + 'awx.main.cache_clear': {'handlers': ['cache_clear']}, + 'awx.main.ws_heartbeat': {'handlers': ['ws_heartbeat']}, + 'awx.main.wsrelay': {'handlers': ['wsrelay']}, 'awx.main.commands.inventory_import': {'handlers': ['inventory_import'], 'propagate': False}, - 'awx.main.tasks': {'handlers': ['task_system', 'external_logger'], 'propagate': False}, - 'awx.main.analytics': {'handlers': ['task_system', 'external_logger'], 'level': 'INFO', 'propagate': False}, - 'awx.main.scheduler': {'handlers': ['task_system', 'external_logger'], 'propagate': False}, + 'awx.main.tasks': {'handlers': ['task_system', 'external_logger', 'console'], 'propagate': False}, + 'awx.main.analytics': {'handlers': ['task_system', 'external_logger', 'console'], 'level': 'INFO', 'propagate': False}, + 'awx.main.scheduler': {'handlers': ['task_system', 'external_logger', 'console'], 'propagate': False}, 'awx.main.access': {'level': 'INFO'}, # very verbose debug-level logs 'awx.main.signals': {'level': 'INFO'}, # very verbose debug-level logs 'awx.api.permissions': {'level': 'INFO'}, # very verbose debug-level logs 'awx.analytics': {'handlers': ['external_logger'], 'level': 'INFO', 'propagate': False}, - 'awx.analytics.broadcast_websocket': {'handlers': ['console', 'file', 'wsbroadcast', 'external_logger'], 'level': 'INFO', 'propagate': False}, + 'awx.analytics.broadcast_websocket': {'handlers': ['console', 'file', 'wsrelay', 'external_logger'], 'level': 'INFO', 'propagate': False}, 'awx.analytics.performance': {'handlers': ['console', 'file', 'tower_warnings', 'external_logger'], 'level': 'DEBUG', 'propagate': False}, - 'awx.analytics.job_lifecycle': {'handlers': ['console', 'job_lifecycle'], 'level': 'DEBUG', 'propagate': False}, - 'django_auth_ldap': {'handlers': ['console', 'file', 'tower_warnings'], 'level': 'DEBUG'}, + 'awx.analytics.job_lifecycle': {'handlers': ['console', 'job_lifecycle', 'external_logger'], 'level': 'DEBUG', 'propagate': False}, 'social': {'handlers': ['console', 'file', 'tower_warnings'], 'level': 'DEBUG'}, 'system_tracking_migrations': {'handlers': ['console', 'file', 'tower_warnings'], 'level': 'DEBUG'}, 'rbac_migrations': {'handlers': ['console', 'file', 'tower_warnings'], 'level': 'DEBUG'}, + 'dispatcherd': {'handlers': ['dispatcher', 'console'], 'level': 'INFO'}, }, } @@ -868,10 +806,13 @@ 'tower_warnings': {'filename': 'tower.log'}, 'callback_receiver': {'filename': 'callback_receiver.log'}, 'dispatcher': {'filename': 'dispatcher.log', 'formatter': 'dispatcher'}, - 'wsbroadcast': {'filename': 'wsbroadcast.log'}, + 'wsrelay': {'filename': 'wsrelay.log'}, 'task_system': {'filename': 'task_system.log'}, 'rbac_migrations': {'filename': 'tower_rbac_migrations.log'}, - 'job_lifecycle': {'filename': 'job_lifecycle.log', 'formatter': 'job_lifecycle'}, + 'job_lifecycle': {'filename': 'job_lifecycle.log'}, + 'rsyslog_configurer': {'filename': 'rsyslog_configurer.log'}, + 'cache_clear': {'filename': 'cache_clear.log'}, + 'ws_heartbeat': {'filename': 'ws_heartbeat.log'}, } # If running on a VM, we log to files. When running in a container, we log to stdout. @@ -926,14 +867,25 @@ # Allow ansible-runner to store env folder (may contain sensitive information) AWX_RUNNER_OMIT_ENV_FILES = True -# Allow ansible-runner to save ansible output (may cause performance issues) +# Allow ansible-runner to save ansible output +# (changing to False may cause performance issues) AWX_RUNNER_SUPPRESS_OUTPUT_FILE = True +# https://github.com/ansible/ansible-runner/pull/1191/files +# Interval in seconds between the last message and keep-alive messages that +# ansible-runner will send +AWX_RUNNER_KEEPALIVE_SECONDS = 0 + # Delete completed work units in receptor RECEPTOR_RELEASE_WORK = True +RECEPTOR_KEEP_WORK_ON_ERROR = False + +# K8S only. Use receptor_log_level on AWX spec to set this properly +RECEPTOR_LOG_LEVEL = 'info' MIDDLEWARE = [ 'django_guid.middleware.guid_middleware', + 'ansible_base.lib.middleware.logging.log_request.LogTracebackMiddleware', 'awx.main.middleware.SettingsCacheMiddleware', 'awx.main.middleware.TimingMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', @@ -945,7 +897,7 @@ 'django.contrib.auth.middleware.AuthenticationMiddleware', 'awx.main.middleware.DisableLocalAuthMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', - 'awx.sso.middleware.SocialAuthMiddleware', + 'awx.main.middleware.OptionalURLPrefixPath', 'crum.CurrentRequestUserMiddleware', 'awx.main.middleware.URLModificationMiddleware', 'awx.main.middleware.SessionTimeoutMiddleware', @@ -977,6 +929,9 @@ # How often websocket process will generate stats BROADCAST_WEBSOCKET_STATS_POLL_RATE_SECONDS = 5 +# How often should web instances advertise themselves? +BROADCAST_WEBSOCKET_BEACON_FROM_WEB_RATE_SECONDS = 15 + DJANGO_GUID = {'GUID_HEADER_NAME': 'X-API-Request-Id'} # Name of the default task queue @@ -1003,3 +958,184 @@ # This is overridden downstream via /etc/tower/conf.d/cluster_host_id.py CLUSTER_HOST_ID = socket.gethostname() + +# License compliance for total host count. Possible values: +# - '': No model - Subscription not counted from Host Metrics +# - 'unique_managed_hosts': Compliant = automated - deleted hosts (using /api/v2/host_metrics/) +SUBSCRIPTION_USAGE_MODEL = '' + +# Default URL and query params for obtaining valid AAP subscriptions +SUBSCRIPTIONS_RHSM_URL = 'https://console.redhat.com/api/rhsm/v2/products?include=providedProducts&oids=480&status=Active' + +# Host metrics cleanup - last time of the task/command run +CLEANUP_HOST_METRICS_LAST_TS = None +# Host metrics cleanup - minimal interval between two cleanups in days +CLEANUP_HOST_METRICS_INTERVAL = 30 # days +# Host metrics cleanup - soft-delete HostMetric records with last_automation < [threshold] (in months) +CLEANUP_HOST_METRICS_SOFT_THRESHOLD = 12 # months +# Host metrics cleanup +# - delete HostMetric record with deleted=True and last_deleted < [threshold] +# - also threshold for computing HostMetricSummaryMonthly (command/scheduled task) +CLEANUP_HOST_METRICS_HARD_THRESHOLD = 36 # months + +# Host metric summary monthly task - last time of run +HOST_METRIC_SUMMARY_TASK_LAST_TS = None +HOST_METRIC_SUMMARY_TASK_INTERVAL = 7 # days + + +# TODO: cmeyers, replace with with register pattern +# The register pattern is particularly nice for this because we need +# to know the process to start the thread that will be the server. +# The registration location should be the same location as we would +# call MetricsServer.start() +# Note: if we don't get to this TODO, then at least create constants +# for the services strings below. +# TODO: cmeyers, break this out into a separate django app so other +# projects can take advantage. + +METRICS_SERVICE_CALLBACK_RECEIVER = 'callback_receiver' +METRICS_SERVICE_DISPATCHER = 'dispatcherd' +METRICS_SERVICE_WEBSOCKETS = 'websockets' + +METRICS_SUBSYSTEM_CONFIG = { + 'server': { + METRICS_SERVICE_CALLBACK_RECEIVER: { + 'port': 8014, + }, + METRICS_SERVICE_DISPATCHER: { + 'port': 8015, + }, + METRICS_SERVICE_WEBSOCKETS: { + 'port': 8016, + }, + } +} + +# django-ansible-base +ANSIBLE_BASE_TEAM_MODEL = 'main.Team' +ANSIBLE_BASE_ORGANIZATION_MODEL = 'main.Organization' +ANSIBLE_BASE_RESOURCE_CONFIG_MODULE = 'awx.resource_api' + +# Defaults to be overridden by DAB +SPECTACULAR_SETTINGS = { + 'TITLE': 'AWX API', + 'DESCRIPTION': 'AWX API Documentation', + 'VERSION': 'v2', + 'OAS_VERSION': '3.0.3', # Set OpenAPI Specification version to 3.0.3 + 'SERVE_INCLUDE_SCHEMA': False, + 'SCHEMA_PATH_PREFIX': r'/api/v[0-9]', + 'DEFAULT_GENERATOR_CLASS': 'drf_spectacular.generators.SchemaGenerator', + 'SCHEMA_COERCE_PATH_PK_SUFFIX': True, + 'CONTACT': {'email': 'ansible-community@redhat.com'}, + 'LICENSE': {'name': 'Apache License'}, + 'TERMS_OF_SERVICE': 'https://www.google.com/policies/terms/', + # Use our custom schema class that handles swagger_topic and deprecated views + 'DEFAULT_SCHEMA_CLASS': 'awx.api.schema.CustomAutoSchema', + 'COMPONENT_SPLIT_REQUEST': True, + # Postprocessing hook to filter CredentialType enum values + 'POSTPROCESSING_HOOKS': ['awx.api.schema.filter_credential_type_schema'], + 'SWAGGER_UI_SETTINGS': { + 'deepLinking': True, + 'persistAuthorization': True, + 'displayOperationId': True, + }, + # Resolve enum naming collisions with meaningful names + 'ENUM_NAME_OVERRIDES': { + # Status field collisions + 'Status4e1Enum': 'UnifiedJobStatusEnum', + 'Status876Enum': 'JobStatusEnum', + # Job type field collisions + 'JobType8b8Enum': 'JobTemplateJobTypeEnum', + 'JobType95bEnum': 'AdHocCommandJobTypeEnum', + 'JobType963Enum': 'ProjectUpdateJobTypeEnum', + # Verbosity field collisions + 'Verbosity481Enum': 'JobVerbosityEnum', + 'Verbosity8cfEnum': 'InventoryUpdateVerbosityEnum', + # Event field collision + 'Event4d3Enum': 'JobEventEnum', + # Kind field collision + 'Kind362Enum': 'InventoryKindEnum', + }, +} +OAUTH2_PROVIDER = {} + +# Add a postfix to the API URL patterns +# example if set to '' API pattern will be /api +# example if set to 'controller' API pattern will be /api AND /api/controller +OPTIONAL_API_URLPATTERN_PREFIX = '' + +# Add a postfix to the UI URL patterns for UI URL generated by the API +# example if set to '' UI URL generated by the API for jobs would be $TOWER_URL/jobs +# example if set to 'execution' UI URL generated by the API for jobs would be $TOWER_URL/execution/jobs +OPTIONAL_UI_URL_PREFIX = '' + +# Use AWX base view, to give 401 on unauthenticated requests +ANSIBLE_BASE_CUSTOM_VIEW_PARENT = 'awx.api.generics.APIView' + +# If we have a resource server defined, apply local changes to that server +RESOURCE_SERVER_SYNC_ENABLED = True + +# Settings for the ansible_base RBAC system + +# This has been moved to data migration code +ANSIBLE_BASE_ROLE_PRECREATE = {} + +# Name for auto-created roles that give users permissions to what they create +ANSIBLE_BASE_ROLE_CREATOR_NAME = '{cls.__name__} Creator' + +# Use the new Gateway RBAC system for evaluations? You should. We will remove the old system soon. +ANSIBLE_BASE_ROLE_SYSTEM_ACTIVATED = True + +# Permissions a user will get when creating a new item +ANSIBLE_BASE_CREATOR_DEFAULTS = ['change', 'delete', 'execute', 'use', 'adhoc', 'approve', 'update', 'view'] + +# Temporary, for old roles API compatibility, save child permissions at organization level +ANSIBLE_BASE_CACHE_PARENT_PERMISSIONS = True + +# Currently features are enabled to keep compatibility with old system, except custom roles +ANSIBLE_BASE_ALLOW_TEAM_ORG_ADMIN = False +# ANSIBLE_BASE_ALLOW_CUSTOM_ROLES = True +ANSIBLE_BASE_ALLOW_TEAM_PARENTS = False +ANSIBLE_BASE_ALLOW_CUSTOM_TEAM_ROLES = False +ANSIBLE_BASE_ALLOW_SINGLETON_USER_ROLES = True +ANSIBLE_BASE_ALLOW_SINGLETON_TEAM_ROLES = False # System auditor has always been restricted to users +ANSIBLE_BASE_ALLOW_SINGLETON_ROLES_API = False # Do not allow creating user-defined system-wide roles + +# system username for django-ansible-base +SYSTEM_USERNAME = None + +# For indirect host query processing +# if a job is not immediently confirmed to have all events processed +# it will be eligable for processing after this number of minutes +INDIRECT_HOST_QUERY_FALLBACK_MINUTES = 60 + +# If an error happens in event collection, give up after this time +INDIRECT_HOST_QUERY_FALLBACK_GIVEUP_DAYS = 3 + +# Maximum age for indirect host audit records +# Older records will be cleaned up +INDIRECT_HOST_AUDIT_RECORD_MAX_AGE_DAYS = 7 + +# setting for Policy as Code feature +FEATURE_POLICY_AS_CODE_ENABLED = False + +OPA_HOST = '' # The hostname used to connect to the OPA server. If empty, policy enforcement will be disabled. +OPA_PORT = 8181 # The port used to connect to the OPA server. Defaults to 8181. +OPA_SSL = False # Enable or disable the use of SSL to connect to the OPA server. Defaults to false. + +OPA_AUTH_TYPE = 'None' # The authentication type that will be used to connect to the OPA server: "None", "Token", or "Certificate". +OPA_AUTH_TOKEN = '' # The token for authentication to the OPA server. Required when OPA_AUTH_TYPE is "Token". If an authorization header is defined in OPA_AUTH_CUSTOM_HEADERS, it will be overridden by OPA_AUTH_TOKEN. +OPA_AUTH_CLIENT_CERT = '' # The content of the client certificate file for mTLS authentication to the OPA server. Required when OPA_AUTH_TYPE is "Certificate". +OPA_AUTH_CLIENT_KEY = '' # The content of the client key for mTLS authentication to the OPA server. Required when OPA_AUTH_TYPE is "Certificate". +OPA_AUTH_CA_CERT = '' # The content of the CA certificate for mTLS authentication to the OPA server. Required when OPA_AUTH_TYPE is "Certificate". +OPA_AUTH_CUSTOM_HEADERS = {} # Optional custom headers included in requests to the OPA server. Defaults to empty dictionary ({}). +OPA_REQUEST_TIMEOUT = 1.5 # The number of seconds after which the connection to the OPA server will time out. Defaults to 1.5 seconds. +OPA_REQUEST_RETRIES = 2 # The number of retry attempts for connecting to the OPA server. Default is 2. + +# feature flags +FEATURE_INDIRECT_NODE_COUNTING_ENABLED = False + +# Dispatcher worker lifetime. If set to None, workers will never be retired +# based on age. Note workers will finish their last task before retiring if +# they are busy when they reach retirement age. +WORKER_MAX_LIFETIME_SECONDS = 14400 # seconds diff --git a/awx/settings/development.py b/awx/settings/development.py index 1be4b7295619..5b630c49841a 100644 --- a/awx/settings/development.py +++ b/awx/settings/development.py @@ -1,122 +1,13 @@ -# Copyright (c) 2015 Ansible, Inc. -# All Rights Reserved. - -# Development settings for AWX project. - -# Python +# This file exists for backwards compatibility only +# the current way of running AWX is to point settings to +# awx/settings/__init__.py as the entry point for the settings +# that is done by exporting: export DJANGO_SETTINGS_MODULE=awx.settings import os -import socket -import copy -import sys -import traceback -import uuid - -# Centos-7 doesn't include the svg mime type -# /usr/lib64/python/mimetypes.py -import mimetypes - -# Django Split Settings -from split_settings.tools import optional, include - -# Load default settings. -from .defaults import * # NOQA - -# awx-manage shell_plus --notebook -NOTEBOOK_ARGUMENTS = ['--NotebookApp.token=', '--ip', '0.0.0.0', '--port', '8888', '--allow-root', '--no-browser'] - -# print SQL queries in shell_plus -SHELL_PLUS_PRINT_SQL = False - -# show colored logs in the dev environment -# to disable this, set `COLOR_LOGS = False` in awx/settings/local_settings.py -LOGGING['handlers']['console']['()'] = 'awx.main.utils.handlers.ColorHandler' # noqa -# task system does not propagate to AWX, so color log these too -LOGGING['handlers']['task_system'] = LOGGING['handlers']['console'].copy() # noqa -COLOR_LOGS = True - -ALLOWED_HOSTS = ['*'] - -mimetypes.add_type("image/svg+xml", ".svg", True) -mimetypes.add_type("image/svg+xml", ".svgz", True) - -# Disallow sending session cookies over insecure connections -SESSION_COOKIE_SECURE = False - -# Disallow sending csrf cookies over insecure connections -CSRF_COOKIE_SECURE = False - -# Disable Pendo on the UI for development/test. -# Note: This setting may be overridden by database settings. -PENDO_TRACKING_STATE = "off" -INSIGHTS_TRACKING_STATE = False - -# debug toolbar and swagger assume that requirements/requirements_dev.txt are installed - -INSTALLED_APPS += ['rest_framework_swagger', 'debug_toolbar'] # NOQA - -MIDDLEWARE = ['debug_toolbar.middleware.DebugToolbarMiddleware'] + MIDDLEWARE # NOQA - -DEBUG_TOOLBAR_CONFIG = {'ENABLE_STACKTRACES': True} - -# Configure a default UUID for development only. -SYSTEM_UUID = '00000000-0000-0000-0000-000000000000' -INSTALL_UUID = '00000000-0000-0000-0000-000000000000' - -# Store a snapshot of default settings at this point before loading any -# customizable config files. -DEFAULTS_SNAPSHOT = {} -this_module = sys.modules[__name__] -for setting in dir(this_module): - if setting == setting.upper(): - DEFAULTS_SNAPSHOT[setting] = copy.deepcopy(getattr(this_module, setting)) - -# If there is an `/etc/tower/settings.py`, include it. -# If there is a `/etc/tower/conf.d/*.py`, include them. -include(optional('/etc/tower/settings.py'), scope=locals()) -include(optional('/etc/tower/conf.d/*.py'), scope=locals()) - -BASE_VENV_PATH = "/var/lib/awx/venv/" -AWX_VENV_PATH = os.path.join(BASE_VENV_PATH, "awx") - -# Use SQLite for unit tests instead of PostgreSQL. If the lines below are -# commented out, Django will create the test_awx-dev database in PostgreSQL to -# run unit tests. -if "pytest" in sys.modules: - CACHES = {'default': {'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 'LOCATION': 'unique-{}'.format(str(uuid.uuid4()))}} - DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': os.path.join(BASE_DIR, 'awx.sqlite3'), # noqa - 'TEST': { - # Test database cannot be :memory: for inventory tests. - 'NAME': os.path.join(BASE_DIR, 'awx_test.sqlite3') # noqa - }, - } - } - -CLUSTER_HOST_ID = socket.gethostname() - -AWX_CALLBACK_PROFILE = True -# ======================!!!!!!! FOR DEVELOPMENT ONLY !!!!!!!================================= -# Disable normal scheduled/triggered task managers (DependencyManager, TaskManager, WorkflowManager). -# Allows user to trigger task managers directly for debugging and profiling purposes. -# Only works in combination with settings.SETTINGS_MODULE == 'awx.settings.development' -AWX_DISABLE_TASK_MANAGERS = False -# ======================!!!!!!! FOR DEVELOPMENT ONLY !!!!!!!================================= +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "awx.settings") +os.environ.setdefault("AWX_MODE", "development") -if 'sqlite3' not in DATABASES['default']['ENGINE']: # noqa - DATABASES['default'].setdefault('OPTIONS', dict()).setdefault('application_name', f'{CLUSTER_HOST_ID}-{os.getpid()}-{" ".join(sys.argv)}'[:63]) # noqa +from ansible_base.lib.dynamic_config import export +from . import DYNACONF # noqa -# If any local_*.py files are present in awx/settings/, use them to override -# default settings for development. If not present, we can still run using -# only the defaults. -# this needs to stay at the bottom of this file -try: - if os.getenv('AWX_KUBE_DEVEL', False): - include(optional('development_kube.py'), scope=locals()) - else: - include(optional('local_*.py'), scope=locals()) -except ImportError: - traceback.print_exc() - sys.exit(1) +export(__name__, DYNACONF) diff --git a/awx/settings/development_defaults.py b/awx/settings/development_defaults.py new file mode 100644 index 000000000000..49cb1a68b6bc --- /dev/null +++ b/awx/settings/development_defaults.py @@ -0,0 +1,71 @@ +# Copyright (c) 2015 Ansible, Inc. +# All Rights Reserved. + +# Development settings for AWX project. + +# Python +import os +import socket + +# Centos-7 doesn't include the svg mime type +# /usr/lib64/python/mimetypes.py +import mimetypes + +# awx-manage shell_plus --notebook +NOTEBOOK_ARGUMENTS = ['--NotebookApp.token=', '--ip', '0.0.0.0', '--port', '9888', '--allow-root', '--no-browser'] + +# print SQL queries in shell_plus +SHELL_PLUS_PRINT_SQL = False + +# show colored logs in the dev environment +# to disable this, set `COLOR_LOGS = False` in awx/settings/local_settings.py +COLOR_LOGS = True +LOGGING__handlers__console = '@merge {"()": "awx.main.utils.handlers.ColorHandler"}' + +ALLOWED_HOSTS = ['*'] + +mimetypes.add_type("image/svg+xml", ".svg", True) +mimetypes.add_type("image/svg+xml", ".svgz", True) + +# Disallow sending session cookies over insecure connections +SESSION_COOKIE_SECURE = False + +# Disallow sending csrf cookies over insecure connections +CSRF_COOKIE_SECURE = False + +# Disable Pendo on the UI for development/test. +# Note: This setting may be overridden by database settings. +PENDO_TRACKING_STATE = "off" +INSIGHTS_TRACKING_STATE = False + +# debug toolbar and swagger assume that requirements/requirements_dev.txt are installed +INSTALLED_APPS = "@merge drf_spectacular,debug_toolbar" +MIDDLEWARE = "@insert 0 debug_toolbar.middleware.DebugToolbarMiddleware" + +DEBUG_TOOLBAR_CONFIG = {'ENABLE_STACKTRACES': True} + +# drf-spectacular settings for API schema generation +# SPECTACULAR_SETTINGS moved to defaults.py so it's available in all environments + +# Configure a default UUID for development only. +SYSTEM_UUID = '00000000-0000-0000-0000-000000000000' +INSTALL_UUID = '00000000-0000-0000-0000-000000000000' + +# Ansible base virtualenv paths and enablement +# only used for deprecated fields and management commands for them +BASE_VENV_PATH = os.path.realpath("/var/lib/awx/venv") + +CLUSTER_HOST_ID = socket.gethostname() + +AWX_CALLBACK_PROFILE = True + +# ======================!!!!!!! FOR DEVELOPMENT ONLY !!!!!!!================================= +# Disable normal scheduled/triggered task managers (DependencyManager, TaskManager, WorkflowManager). +# Allows user to trigger task managers directly for debugging and profiling purposes. +# Only works in combination with settings.SETTINGS_MODULE == 'awx.settings.development' +AWX_DISABLE_TASK_MANAGERS = False + +# Needed for launching runserver in debug mode +# ======================!!!!!!! FOR DEVELOPMENT ONLY !!!!!!!================================= + +FEATURE_INDIRECT_NODE_COUNTING_ENABLED = True diff --git a/awx/settings/development_kube.py b/awx/settings/development_kube.py index c30a7fe025fe..e6ba6170c6d7 100644 --- a/awx/settings/development_kube.py +++ b/awx/settings/development_kube.py @@ -1,4 +1,13 @@ -BROADCAST_WEBSOCKET_SECRET = '🤖starscream🤖' -BROADCAST_WEBSOCKET_PORT = 8052 -BROADCAST_WEBSOCKET_VERIFY_CERT = False -BROADCAST_WEBSOCKET_PROTOCOL = 'http' +# This file exists for backwards compatibility only +# the current way of running AWX is to point settings to +# awx/settings/__init__.py as the entry point for the settings +# that is done by exporting: export DJANGO_SETTINGS_MODULE=awx.settings +import os + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "awx.settings") +os.environ.setdefault("AWX_MODE", "development,kube") + +from ansible_base.lib.dynamic_config import export +from . import DYNACONF # noqa + +export(__name__, DYNACONF) diff --git a/awx/settings/development_quiet.py b/awx/settings/development_quiet.py index c47e78b69d86..5fea2756e908 100644 --- a/awx/settings/development_quiet.py +++ b/awx/settings/development_quiet.py @@ -1,15 +1,13 @@ -# Copyright (c) 2015 Ansible, Inc. -# All Rights Reserved. +# This file exists for backwards compatibility only +# the current way of running AWX is to point settings to +# awx/settings/__init__.py as the entry point for the settings +# that is done by exporting: export DJANGO_SETTINGS_MODULE=awx.settings +import os -# Development settings for AWX project, but with DEBUG disabled +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "awx.settings") +os.environ.setdefault("AWX_MODE", "development,quiet") -# Load development settings. -from defaults import * # NOQA +from ansible_base.lib.dynamic_config import export +from . import DYNACONF # noqa -# Load development settings. -from development import * # NOQA - -# Disable capturing DEBUG -DEBUG = False -TEMPLATE_DEBUG = DEBUG -SQL_DEBUG = DEBUG +export(__name__, DYNACONF) diff --git a/awx/settings/functions.py b/awx/settings/functions.py new file mode 100644 index 000000000000..70be9befdbae --- /dev/null +++ b/awx/settings/functions.py @@ -0,0 +1,86 @@ +import os +from ansible_base.lib.dynamic_config import load_python_file_with_injected_context +from dynaconf import Dynaconf +from .application_name import get_application_name + + +def merge_application_name(settings): + """Return a dynaconf merge dict to set the application name for the connection.""" + data = {} + if "sqlite3" not in settings.get("DATABASES__default__ENGINE", ""): + data["DATABASES__default__OPTIONS__application_name"] = get_application_name(settings.get("CLUSTER_HOST_ID")) + return data + + +def add_backwards_compatibility(): + """Add backwards compatibility for AWX_MODE. + + Before dynaconf integration the usage of AWX settings was supported to be just + DJANGO_SETTINGS_MODULE=awx.settings.production or DJANGO_SETTINGS_MODULE=awx.settings.development + (development_quiet and development_kube were also supported). + + With dynaconf the DJANGO_SETTINGS_MODULE should be set always to "awx.settings" as the only entry point + for settings and then "AWX_MODE" can be set to any of production,development,quiet,kube + or a combination of them separated by comma. + + E.g: + + export DJANGO_SETTINGS_MODULE=awx.settings + export AWX_MODE=production + awx-manage [command] + dynaconf [command] + + If pointing `DJANGO_SETTINGS_MODULE` to `awx.settings.production` or `awx.settings.development` then + this function will set `AWX_MODE` to the correct value. + """ + django_settings_module = os.getenv("DJANGO_SETTINGS_MODULE", "awx.settings") + if django_settings_module == "awx.settings": + return + + current_mode = os.getenv("AWX_MODE", "") + for _module_name in ["development", "production", "development_quiet", "development_kube"]: + if django_settings_module == f"awx.settings.{_module_name}": + _mode = current_mode.split(",") + if "development_" in _module_name and "development" not in current_mode: + _mode.append("development") + _mode_fragment = _module_name.replace("development_", "") + if _mode_fragment not in _mode: + _mode.append(_mode_fragment) + os.environ["AWX_MODE"] = ",".join(_mode) + + +def load_extra_development_files(settings: Dynaconf): + """Load optional development only settings files.""" + if not settings.is_development_mode: + return + + if settings.get_environ("AWX_KUBE_DEVEL"): + load_python_file_with_injected_context("kube_defaults.py", settings=settings) + else: + load_python_file_with_injected_context("local_*.py", settings=settings) + + +def assert_production_settings(settings: Dynaconf, settings_dir: str, settings_file_path: str): # pragma: no cover + """Ensure at least one setting file has been loaded in production mode. + Current systems will require /etc/tower/settings.py and + new systems will require /etc/ansible-automation-platform/*.yaml + """ + if "production" not in settings.current_env.lower(): + return + + required_settings_paths = [ + os.path.dirname(settings_file_path), + "/etc/ansible-automation-platform/", + settings_dir, + ] + + for path in required_settings_paths: + if any([path in os.path.dirname(f) for f in settings._loaded_files]): + break + else: + from django.core.exceptions import ImproperlyConfigured # noqa + + msg = 'No AWX configuration found at %s.' % required_settings_paths + msg += '\nDefine the AWX_SETTINGS_FILE environment variable to ' + msg += 'specify an alternate path.' + raise ImproperlyConfigured(msg) diff --git a/awx/settings/kube_defaults.py b/awx/settings/kube_defaults.py new file mode 100644 index 000000000000..c30a7fe025fe --- /dev/null +++ b/awx/settings/kube_defaults.py @@ -0,0 +1,4 @@ +BROADCAST_WEBSOCKET_SECRET = '🤖starscream🤖' +BROADCAST_WEBSOCKET_PORT = 8052 +BROADCAST_WEBSOCKET_VERIFY_CERT = False +BROADCAST_WEBSOCKET_PROTOCOL = 'http' diff --git a/awx/settings/production.py b/awx/settings/production.py index 3dce95deb08f..bcf483b118cf 100644 --- a/awx/settings/production.py +++ b/awx/settings/production.py @@ -1,105 +1,13 @@ -# Copyright (c) 2015 Ansible, Inc. -# All Rights Reserved. - -# Production settings for AWX project. - -# Python +# This file exists for backwards compatibility only +# the current way of running AWX is to point settings to +# awx/settings/__init__.py as the entry point for the settings +# that is done by exporting: export DJANGO_SETTINGS_MODULE=awx.settings import os -import copy -import errno -import sys -import traceback - -# Django Split Settings -from split_settings.tools import optional, include - -# Load default settings. -from .defaults import * # NOQA - -DEBUG = False -TEMPLATE_DEBUG = DEBUG -SQL_DEBUG = DEBUG - -# Clear database settings to force production environment to define them. -DATABASES = {} - -# Clear the secret key to force production environment to define it. -SECRET_KEY = None - -# Hosts/domain names that are valid for this site; required if DEBUG is False -# See https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts -ALLOWED_HOSTS = [] - -# The heartbeat file for the scheduler -SCHEDULE_METADATA_LOCATION = '/var/lib/awx/.tower_cycle' - -# Ansible base virtualenv paths and enablement -BASE_VENV_PATH = os.path.realpath("/var/lib/awx/venv") - -# Base virtualenv paths and enablement -AWX_VENV_PATH = os.path.join(BASE_VENV_PATH, "awx") - -# Very important that this is editable (not read_only) in the API -AWX_ISOLATION_SHOW_PATHS = [ - '/etc/pki/ca-trust:/etc/pki/ca-trust:O', - '/usr/share/pki:/usr/share/pki:O', -] - -# Store a snapshot of default settings at this point before loading any -# customizable config files. -# -############################################################################################### -# -# Any settings defined after this point will be marked as as a read_only database setting -# -################################################################################################ -DEFAULTS_SNAPSHOT = {} -this_module = sys.modules[__name__] -for setting in dir(this_module): - if setting == setting.upper(): - DEFAULTS_SNAPSHOT[setting] = copy.deepcopy(getattr(this_module, setting)) - -# Load settings from any .py files in the global conf.d directory specified in -# the environment, defaulting to /etc/tower/conf.d/. -settings_dir = os.environ.get('AWX_SETTINGS_DIR', '/etc/tower/conf.d/') -settings_files = os.path.join(settings_dir, '*.py') - -# Load remaining settings from the global settings file specified in the -# environment, defaulting to /etc/tower/settings.py. -settings_file = os.environ.get('AWX_SETTINGS_FILE', '/etc/tower/settings.py') - -# Attempt to load settings from /etc/tower/settings.py first, followed by -# /etc/tower/conf.d/*.py. -try: - include(settings_file, optional(settings_files), scope=locals()) -except ImportError: - traceback.print_exc() - sys.exit(1) -except IOError: - from django.core.exceptions import ImproperlyConfigured - included_file = locals().get('__included_file__', '') - if not included_file or included_file == settings_file: - # The import doesn't always give permission denied, so try to open the - # settings file directly. - try: - e = None - open(settings_file) - except IOError: - pass - if e and e.errno == errno.EACCES: - SECRET_KEY = 'permission-denied' - LOGGING = {} - else: - msg = 'No AWX configuration found at %s.' % settings_file - msg += '\nDefine the AWX_SETTINGS_FILE environment variable to ' - msg += 'specify an alternate path.' - raise ImproperlyConfigured(msg) - else: - raise +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "awx.settings") +os.environ.setdefault("AWX_MODE", "production") -# The below runs AFTER all of the custom settings are imported. +from ansible_base.lib.dynamic_config import export +from . import DYNACONF # noqa -DATABASES.setdefault('default', dict()).setdefault('OPTIONS', dict()).setdefault( - 'application_name', f'{CLUSTER_HOST_ID}-{os.getpid()}-{" ".join(sys.argv)}'[:63] # NOQA -) # noqa +export(__name__, DYNACONF) diff --git a/awx/settings/production_defaults.py b/awx/settings/production_defaults.py new file mode 100644 index 000000000000..190779ef286e --- /dev/null +++ b/awx/settings/production_defaults.py @@ -0,0 +1,32 @@ +# Copyright (c) 2015 Ansible, Inc. +# All Rights Reserved. + +# Production settings for AWX project. + +import os + +DEBUG = False +TEMPLATE_DEBUG = DEBUG +SQL_DEBUG = DEBUG + +# Clear database settings to force production environment to define them. +DATABASES = {} + +# Clear the secret key to force production environment to define it. +SECRET_KEY = None + +# Hosts/domain names that are valid for this site; required if DEBUG is False +# See https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts +ALLOWED_HOSTS = [] + +# Ansible base virtualenv paths and enablement +# only used for deprecated fields and management commands for them +BASE_VENV_PATH = os.path.realpath("/var/lib/awx/venv") + +# Very important that this is editable (not read_only) in the API +AWX_ISOLATION_SHOW_PATHS = [ + '/etc/pki/ca-trust:/etc/pki/ca-trust:O', + '/usr/share/pki:/usr/share/pki:O', +] + +del os diff --git a/awx/settings/quiet_defaults.py b/awx/settings/quiet_defaults.py new file mode 100644 index 000000000000..1cb21720f7dd --- /dev/null +++ b/awx/settings/quiet_defaults.py @@ -0,0 +1,8 @@ +# Copyright (c) 2015 Ansible, Inc. +# All Rights Reserved. +# Development settings for AWX project, but with DEBUG disabled + +# Disable capturing DEBUG +DEBUG = False +TEMPLATE_DEBUG = DEBUG +SQL_DEBUG = DEBUG diff --git a/awx/sso/__init__.py b/awx/sso/__init__.py deleted file mode 100644 index e484e62be15d..000000000000 --- a/awx/sso/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# Copyright (c) 2015 Ansible, Inc. -# All Rights Reserved. diff --git a/awx/sso/apps.py b/awx/sso/apps.py deleted file mode 100644 index 6203ca6d6a11..000000000000 --- a/awx/sso/apps.py +++ /dev/null @@ -1,8 +0,0 @@ -# Django -from django.apps import AppConfig -from django.utils.translation import gettext_lazy as _ - - -class SSOConfig(AppConfig): - name = 'awx.sso' - verbose_name = _('Single Sign-On') diff --git a/awx/sso/backends.py b/awx/sso/backends.py deleted file mode 100644 index c55f24e7de3d..000000000000 --- a/awx/sso/backends.py +++ /dev/null @@ -1,446 +0,0 @@ -# Copyright (c) 2015 Ansible, Inc. -# All Rights Reserved. - -# Python -from collections import OrderedDict -import logging -import uuid - -import ldap - -# Django -from django.dispatch import receiver -from django.contrib.auth.models import User -from django.conf import settings as django_settings -from django.core.signals import setting_changed -from django.utils.encoding import force_str - -# django-auth-ldap -from django_auth_ldap.backend import LDAPSettings as BaseLDAPSettings -from django_auth_ldap.backend import LDAPBackend as BaseLDAPBackend -from django_auth_ldap.backend import populate_user -from django.core.exceptions import ImproperlyConfigured - -# radiusauth -from radiusauth.backends import RADIUSBackend as BaseRADIUSBackend - -# tacacs+ auth -import tacacs_plus - -# social -from social_core.backends.saml import OID_USERID -from social_core.backends.saml import SAMLAuth as BaseSAMLAuth -from social_core.backends.saml import SAMLIdentityProvider as BaseSAMLIdentityProvider - -# Ansible Tower -from awx.sso.models import UserEnterpriseAuth -from awx.sso.common import create_org_and_teams, reconcile_users_org_team_mappings - -logger = logging.getLogger('awx.sso.backends') - - -class LDAPSettings(BaseLDAPSettings): - defaults = dict(list(BaseLDAPSettings.defaults.items()) + list({'ORGANIZATION_MAP': {}, 'TEAM_MAP': {}, 'GROUP_TYPE_PARAMS': {}}.items())) - - def __init__(self, prefix='AUTH_LDAP_', defaults={}): - super(LDAPSettings, self).__init__(prefix, defaults) - - # If a DB-backed setting is specified that wipes out the - # OPT_NETWORK_TIMEOUT, fall back to a sane default - if ldap.OPT_NETWORK_TIMEOUT not in getattr(self, 'CONNECTION_OPTIONS', {}): - options = getattr(self, 'CONNECTION_OPTIONS', {}) - options[ldap.OPT_NETWORK_TIMEOUT] = 30 - self.CONNECTION_OPTIONS = options - - # when specifying `.set_option()` calls for TLS in python-ldap, the - # *order* in which you invoke them *matters*, particularly in Python3, - # where dictionary insertion order is persisted - # - # specifically, it is *critical* that `ldap.OPT_X_TLS_NEWCTX` be set *last* - # this manual sorting puts `OPT_X_TLS_NEWCTX` *after* other TLS-related - # options - # - # see: https://github.com/python-ldap/python-ldap/issues/55 - newctx_option = self.CONNECTION_OPTIONS.pop(ldap.OPT_X_TLS_NEWCTX, None) - self.CONNECTION_OPTIONS = OrderedDict(self.CONNECTION_OPTIONS) - if newctx_option is not None: - self.CONNECTION_OPTIONS[ldap.OPT_X_TLS_NEWCTX] = newctx_option - - -class LDAPBackend(BaseLDAPBackend): - - """ - Custom LDAP backend for AWX. - """ - - settings_prefix = 'AUTH_LDAP_' - - def __init__(self, *args, **kwargs): - self._dispatch_uid = uuid.uuid4() - super(LDAPBackend, self).__init__(*args, **kwargs) - setting_changed.connect(self._on_setting_changed, dispatch_uid=self._dispatch_uid) - - def _on_setting_changed(self, sender, **kwargs): - # If any AUTH_LDAP_* setting changes, force settings to be reloaded for - # this backend instance. - if kwargs.get('setting', '').startswith(self.settings_prefix): - self._settings = None - - def _get_settings(self): - if self._settings is None: - self._settings = LDAPSettings(self.settings_prefix) - return self._settings - - def _set_settings(self, settings): - self._settings = settings - - settings = property(_get_settings, _set_settings) - - def authenticate(self, request, username, password): - if self.settings.START_TLS and ldap.OPT_X_TLS_REQUIRE_CERT in self.settings.CONNECTION_OPTIONS: - # with python-ldap, if you want to set connection-specific TLS - # parameters, you must also specify OPT_X_TLS_NEWCTX = 0 - # see: https://stackoverflow.com/a/29722445 - # see: https://stackoverflow.com/a/38136255 - self.settings.CONNECTION_OPTIONS[ldap.OPT_X_TLS_NEWCTX] = 0 - - if not self.settings.SERVER_URI: - return None - try: - user = User.objects.get(username=username) - if user and (not user.profile or not user.profile.ldap_dn): - return None - except User.DoesNotExist: - pass - - try: - for setting_name, type_ in [('GROUP_SEARCH', 'LDAPSearch'), ('GROUP_TYPE', 'LDAPGroupType')]: - if getattr(self.settings, setting_name) is None: - raise ImproperlyConfigured("{} must be an {} instance.".format(setting_name, type_)) - ldap_user = super(LDAPBackend, self).authenticate(request, username, password) - # If we have an LDAP user and that user we found has an ldap_user internal object and that object has a bound connection - # Then we can try and force an unbind to close the sticky connection - if ldap_user and ldap_user.ldap_user and ldap_user.ldap_user._connection_bound: - logger.debug("Forcing LDAP connection to close") - try: - ldap_user.ldap_user._connection.unbind_s() - ldap_user.ldap_user._connection_bound = False - except Exception: - logger.exception(f"Got unexpected LDAP exception when forcing LDAP disconnect for user {ldap_user}, login will still proceed") - return ldap_user - except Exception: - logger.exception("Encountered an error authenticating to LDAP") - return None - - def get_user(self, user_id): - if not self.settings.SERVER_URI: - return None - return super(LDAPBackend, self).get_user(user_id) - - # Disable any LDAP based authorization / permissions checking. - - def has_perm(self, user, perm, obj=None): - return False - - def has_module_perms(self, user, app_label): - return False - - def get_all_permissions(self, user, obj=None): - return set() - - def get_group_permissions(self, user, obj=None): - return set() - - -class LDAPBackend1(LDAPBackend): - settings_prefix = 'AUTH_LDAP_1_' - - -class LDAPBackend2(LDAPBackend): - settings_prefix = 'AUTH_LDAP_2_' - - -class LDAPBackend3(LDAPBackend): - settings_prefix = 'AUTH_LDAP_3_' - - -class LDAPBackend4(LDAPBackend): - settings_prefix = 'AUTH_LDAP_4_' - - -class LDAPBackend5(LDAPBackend): - settings_prefix = 'AUTH_LDAP_5_' - - -def _decorate_enterprise_user(user, provider): - user.set_unusable_password() - user.save() - enterprise_auth, _ = UserEnterpriseAuth.objects.get_or_create(user=user, provider=provider) - return enterprise_auth - - -def _get_or_set_enterprise_user(username, password, provider): - created = False - try: - user = User.objects.prefetch_related('enterprise_auth').get(username=username) - except User.DoesNotExist: - user = User(username=username) - enterprise_auth = _decorate_enterprise_user(user, provider) - logger.debug("Created enterprise user %s via %s backend." % (username, enterprise_auth.get_provider_display())) - created = True - if created or user.is_in_enterprise_category(provider): - return user - logger.warning("Enterprise user %s already defined in Tower." % username) - - -class RADIUSBackend(BaseRADIUSBackend): - """ - Custom Radius backend to verify license status - """ - - def authenticate(self, request, username, password): - if not django_settings.RADIUS_SERVER: - return None - return super(RADIUSBackend, self).authenticate(request, username, password) - - def get_user(self, user_id): - if not django_settings.RADIUS_SERVER: - return None - user = super(RADIUSBackend, self).get_user(user_id) - if not user.has_usable_password(): - return user - - def get_django_user(self, username, password=None, groups=[], is_staff=False, is_superuser=False): - return _get_or_set_enterprise_user(force_str(username), force_str(password), 'radius') - - -class TACACSPlusBackend(object): - """ - Custom TACACS+ auth backend for AWX - """ - - def authenticate(self, request, username, password): - if not django_settings.TACACSPLUS_HOST: - return None - try: - # Upstream TACACS+ client does not accept non-string, so convert if needed. - auth = tacacs_plus.TACACSClient( - django_settings.TACACSPLUS_HOST, - django_settings.TACACSPLUS_PORT, - django_settings.TACACSPLUS_SECRET, - timeout=django_settings.TACACSPLUS_SESSION_TIMEOUT, - ).authenticate(username, password, authen_type=tacacs_plus.TAC_PLUS_AUTHEN_TYPES[django_settings.TACACSPLUS_AUTH_PROTOCOL]) - except Exception as e: - logger.exception("TACACS+ Authentication Error: %s" % str(e)) - return None - if auth.valid: - return _get_or_set_enterprise_user(username, password, 'tacacs+') - - def get_user(self, user_id): - if not django_settings.TACACSPLUS_HOST: - return None - try: - return User.objects.get(pk=user_id) - except User.DoesNotExist: - return None - - -class TowerSAMLIdentityProvider(BaseSAMLIdentityProvider): - """ - Custom Identity Provider to make attributes to what we expect. - """ - - def get_user_permanent_id(self, attributes): - uid = attributes[self.conf.get('attr_user_permanent_id', OID_USERID)] - if isinstance(uid, str): - return uid - return uid[0] - - def get_attr(self, attributes, conf_key, default_attribute): - """ - Get the attribute 'default_attribute' out of the attributes, - unless self.conf[conf_key] overrides the default by specifying - another attribute to use. - """ - key = self.conf.get(conf_key, default_attribute) - value = attributes[key] if key in attributes else None - # In certain implementations (like https://pagure.io/ipsilon) this value is a string, not a list - if isinstance(value, (list, tuple)): - value = value[0] - if conf_key in ('attr_first_name', 'attr_last_name', 'attr_username', 'attr_email') and value is None: - logger.warning( - "Could not map user detail '%s' from SAML attribute '%s'; " "update SOCIAL_AUTH_SAML_ENABLED_IDPS['%s']['%s'] with the correct SAML attribute.", - conf_key[5:], - key, - self.name, - conf_key, - ) - return str(value) if value is not None else value - - -class SAMLAuth(BaseSAMLAuth): - """ - Custom SAMLAuth backend to verify license status - """ - - def get_idp(self, idp_name): - idp_config = self.setting('ENABLED_IDPS')[idp_name] - return TowerSAMLIdentityProvider(idp_name, **idp_config) - - def authenticate(self, request, *args, **kwargs): - if not all( - [ - django_settings.SOCIAL_AUTH_SAML_SP_ENTITY_ID, - django_settings.SOCIAL_AUTH_SAML_SP_PUBLIC_CERT, - django_settings.SOCIAL_AUTH_SAML_SP_PRIVATE_KEY, - django_settings.SOCIAL_AUTH_SAML_ORG_INFO, - django_settings.SOCIAL_AUTH_SAML_TECHNICAL_CONTACT, - django_settings.SOCIAL_AUTH_SAML_SUPPORT_CONTACT, - django_settings.SOCIAL_AUTH_SAML_ENABLED_IDPS, - ] - ): - return None - user = super(SAMLAuth, self).authenticate(request, *args, **kwargs) - # Comes from https://github.com/omab/python-social-auth/blob/v0.2.21/social/backends/base.py#L91 - if getattr(user, 'is_new', False): - enterprise_auth = _decorate_enterprise_user(user, 'saml') - logger.debug("Created enterprise user %s from %s backend." % (user.username, enterprise_auth.get_provider_display())) - elif user and not user.is_in_enterprise_category('saml'): - return None - if user: - logger.debug("Enterprise user %s already created in Tower." % user.username) - return user - - def get_user(self, user_id): - if not all( - [ - django_settings.SOCIAL_AUTH_SAML_SP_ENTITY_ID, - django_settings.SOCIAL_AUTH_SAML_SP_PUBLIC_CERT, - django_settings.SOCIAL_AUTH_SAML_SP_PRIVATE_KEY, - django_settings.SOCIAL_AUTH_SAML_ORG_INFO, - django_settings.SOCIAL_AUTH_SAML_TECHNICAL_CONTACT, - django_settings.SOCIAL_AUTH_SAML_SUPPORT_CONTACT, - django_settings.SOCIAL_AUTH_SAML_ENABLED_IDPS, - ] - ): - return None - return super(SAMLAuth, self).get_user(user_id) - - -def _update_m2m_from_groups(ldap_user, opts, remove=True): - """ - Hepler function to evaluate the LDAP team/org options to determine if LDAP user should - be a member of the team/org based on their ldap group dns. - - Returns: - True - User should be added - False - User should be removed - None - Users membership should not be changed - """ - if opts is None: - return None - elif not opts: - pass - elif isinstance(opts, bool) and opts is True: - return True - else: - if isinstance(opts, str): - opts = [opts] - # If any of the users groups matches any of the list options - for group_dn in opts: - if not isinstance(group_dn, str): - continue - if ldap_user._get_groups().is_member_of(group_dn): - return True - if remove: - return False - return None - - -@receiver(populate_user, dispatch_uid='populate-ldap-user') -def on_populate_user(sender, **kwargs): - """ - Handle signal from LDAP backend to populate the user object. Update user - organization/team memberships according to their LDAP groups. - """ - user = kwargs['user'] - ldap_user = kwargs['ldap_user'] - backend = ldap_user.backend - - # Boolean to determine if we should force an user update - # to avoid duplicate SQL update statements - force_user_update = False - - # Prefetch user's groups to prevent LDAP queries for each org/team when - # checking membership. - ldap_user._get_groups().get_group_dns() - - # If the LDAP user has a first or last name > $maxlen chars, truncate it - for field in ('first_name', 'last_name'): - max_len = User._meta.get_field(field).max_length - field_len = len(getattr(user, field)) - if field_len > max_len: - setattr(user, field, getattr(user, field)[:max_len]) - force_user_update = True - logger.warning('LDAP user {} has {} > max {} characters'.format(user.username, field, max_len)) - - org_map = getattr(backend.settings, 'ORGANIZATION_MAP', {}) - team_map = getattr(backend.settings, 'TEAM_MAP', {}) - orgs_list = list(org_map.keys()) - team_map = {} - for team_name, team_opts in team_map.items(): - if not team_opts.get('organization', None): - # You can't save the LDAP config in the UI w/o an org (or '' or null as the org) so if we somehow got this condition its an error - logger.error("Team named {} in LDAP team map settings is invalid due to missing organization".format(team_name)) - continue - team_map[team_name] = team_opts['organization'] - - create_org_and_teams(orgs_list, team_map, 'LDAP') - - # Compute in memory what the state is of the different LDAP orgs - org_roles_and_ldap_attributes = {'admin_role': 'admins', 'auditor_role': 'auditors', 'member_role': 'users'} - desired_org_states = {} - for org_name, org_opts in org_map.items(): - remove = bool(org_opts.get('remove', True)) - desired_org_states[org_name] = {} - for org_role_name in org_roles_and_ldap_attributes.keys(): - ldap_name = org_roles_and_ldap_attributes[org_role_name] - opts = org_opts.get(ldap_name, None) - remove = bool(org_opts.get('remove_{}'.format(ldap_name), remove)) - desired_org_states[org_name][org_role_name] = _update_m2m_from_groups(ldap_user, opts, remove) - - # If everything returned None (because there was no configuration) we can remove this org from our map - # This will prevent us from loading the org in the next query - if all(desired_org_states[org_name][org_role_name] is None for org_role_name in org_roles_and_ldap_attributes.keys()): - del desired_org_states[org_name] - - # Compute in memory what the state is of the different LDAP teams - desired_team_states = {} - for team_name, team_opts in team_map.items(): - if 'organization' not in team_opts: - continue - users_opts = team_opts.get('users', None) - remove = bool(team_opts.get('remove', True)) - state = _update_m2m_from_groups(ldap_user, users_opts, remove) - if state is not None: - organization = team_opts['organization'] - if organization not in desired_team_states: - desired_team_states[organization] = {} - desired_team_states[organization][team_name] = {'member_role': state} - - # Check if user.profile is available, otherwise force user.save() - try: - _ = user.profile - except ValueError: - force_user_update = True - finally: - if force_user_update: - user.save() - - # Update user profile to store LDAP DN. - profile = user.profile - if profile.ldap_dn != ldap_user.dn: - profile.ldap_dn = ldap_user.dn - profile.save() - - reconcile_users_org_team_mappings(user, desired_org_states, desired_team_states, 'LDAP') diff --git a/awx/sso/common.py b/awx/sso/common.py deleted file mode 100644 index 4d601bb22e43..000000000000 --- a/awx/sso/common.py +++ /dev/null @@ -1,171 +0,0 @@ -# Copyright (c) 2022 Ansible, Inc. -# All Rights Reserved. - -import logging - -from django.contrib.contenttypes.models import ContentType -from django.db.utils import IntegrityError -from awx.main.models import Organization, Team - -logger = logging.getLogger('awx.sso.common') - - -def get_orgs_by_ids(): - existing_orgs = {} - for org_id, org_name in Organization.objects.all().values_list('id', 'name'): - existing_orgs[org_name] = org_id - return existing_orgs - - -def reconcile_users_org_team_mappings(user, desired_org_states, desired_team_states, source): - # - # Arguments: - # user - a user object - # desired_org_states: { '': { '': or None } } - # desired_team_states: { '': { '': { '': or None } } } - # source - a text label indicating the "authentication adapter" for debug messages - # - # This function will load the users existing roles and then based on the desired states modify the users roles - # True indicates the user needs to be a member of the role - # False indicates the user should not be a member of the role - # None means this function should not change the users membership of a role - # - - content_types = [] - reconcile_items = [] - if desired_org_states: - content_types.append(ContentType.objects.get_for_model(Organization)) - reconcile_items.append(('organization', desired_org_states)) - if desired_team_states: - content_types.append(ContentType.objects.get_for_model(Team)) - reconcile_items.append(('team', desired_team_states)) - - if not content_types: - # If both desired states were empty we can simply return because there is nothing to reconcile - return - - # users_roles is a flat set of IDs - users_roles = set(user.roles.filter(content_type__in=content_types).values_list('pk', flat=True)) - - for object_type, desired_states in reconcile_items: - roles = [] - # Get a set of named tuples for the org/team name plus all of the roles we got above - if object_type == 'organization': - for sub_dict in desired_states.values(): - for role_name in sub_dict: - if sub_dict[role_name] is None: - continue - if role_name not in roles: - roles.append(role_name) - model_roles = Organization.objects.filter(name__in=desired_states.keys()).values_list('name', *roles, named=True) - else: - team_names = [] - for teams_dict in desired_states.values(): - team_names.extend(teams_dict.keys()) - for sub_dict in teams_dict.values(): - for role_name in sub_dict: - if sub_dict[role_name] is None: - continue - if role_name not in roles: - roles.append(role_name) - model_roles = Team.objects.filter(name__in=team_names).values_list('name', 'organization__name', *roles, named=True) - - for row in model_roles: - for role_name in roles: - if object_type == 'organization': - desired_state = desired_states.get(row.name, {}) - else: - desired_state = desired_states.get(row.organization__name, {}).get(row.name, {}) - - if desired_state.get(role_name, None) is None: - # The mapping was not defined for this [org/team]/role so we can just pass - continue - - # If somehow the auth adapter knows about an items role but that role is not defined in the DB we are going to print a pretty error - # This is your classic safety net that we should never hit; but here you are reading this comment... good luck and Godspeed. - role_id = getattr(row, role_name, None) - if role_id is None: - logger.error("{} adapter wanted to manage role {} of {} {} but that role is not defined".format(source, role_name, object_type, row.name)) - continue - - if desired_state[role_name]: - # The desired state was the user mapped into the object_type, if the user was not mapped in map them in - if role_id not in users_roles: - logger.debug("{} adapter adding user {} to {} {} as {}".format(source, user.username, object_type, row.name, role_name)) - user.roles.add(role_id) - else: - # The desired state was the user was not mapped into the org, if the user has the permission remove it - if role_id in users_roles: - logger.debug("{} adapter removing user {} permission of {} from {} {}".format(source, user.username, role_name, object_type, row.name)) - user.roles.remove(role_id) - - -def create_org_and_teams(org_list, team_map, adapter, can_create=True): - # - # org_list is a set of organization names - # team_map is a dict of {: } - # - # Move this junk into save of the settings for performance later, there is no need to do that here - # with maybe the exception of someone defining this in settings before the server is started? - # ============================================================================================================== - - if not can_create: - logger.debug(f"Adapter {adapter} is not allowed to create orgs/teams") - return - - # Get all of the IDs and names of orgs in the DB and create any new org defined in LDAP that does not exist in the DB - existing_orgs = get_orgs_by_ids() - - # Parse through orgs and teams provided and create a list of unique items we care about creating - all_orgs = list(set(org_list)) - all_teams = [] - for team_name in team_map: - org_name = team_map[team_name] - if org_name: - if org_name not in all_orgs: - all_orgs.append(org_name) - # We don't have to test if this is in all_teams because team_map is already a hash - all_teams.append(team_name) - else: - # The UI should prevent this condition so this is just a double check to prevent a stack trace.... - # although the rest of the login process might stack later on - logger.error("{} adapter is attempting to create a team {} but it does not have an org".format(adapter, team_name)) - - for org_name in all_orgs: - if org_name and org_name not in existing_orgs: - logger.info("{} adapter is creating org {}".format(adapter, org_name)) - try: - new_org = get_or_create_org_with_default_galaxy_cred(name=org_name) - except IntegrityError: - # Another thread must have created this org before we did so now we need to get it - new_org = get_or_create_org_with_default_galaxy_cred(name=org_name) - # Add the org name to the existing orgs since we created it and we may need it to build the teams below - existing_orgs[org_name] = new_org.id - - # Do the same for teams - existing_team_names = list(Team.objects.all().values_list('name', flat=True)) - for team_name in all_teams: - if team_name not in existing_team_names: - logger.info("{} adapter is creating team {} in org {}".format(adapter, team_name, team_map[team_name])) - try: - Team.objects.create(name=team_name, organization_id=existing_orgs[team_map[team_name]]) - except IntegrityError: - # If another process got here before us that is ok because we don't need the ID from this team or anything - pass - # End move some day - # ============================================================================================================== - - -def get_or_create_org_with_default_galaxy_cred(**kwargs): - from awx.main.models import Organization, Credential - - (org, org_created) = Organization.objects.get_or_create(**kwargs) - if org_created: - logger.debug("Created org {} (id {}) from {}".format(org.name, org.id, kwargs)) - public_galaxy_credential = Credential.objects.filter(managed=True, name='Ansible Galaxy').first() - if public_galaxy_credential is not None: - org.galaxy_credentials.add(public_galaxy_credential) - logger.debug("Added default Ansible Galaxy credential to org") - else: - logger.debug("Could not find default Ansible Galaxy credential to add to org") - return org diff --git a/awx/sso/conf.py b/awx/sso/conf.py deleted file mode 100644 index a835399a3dc7..000000000000 --- a/awx/sso/conf.py +++ /dev/null @@ -1,1614 +0,0 @@ -# Python -import collections -import urllib.parse as urlparse - -# Django -from django.conf import settings -from django.urls import reverse -from django.utils.translation import gettext_lazy as _ - -# Django REST Framework -from rest_framework import serializers - -# AWX -from awx.conf import register, register_validate, fields -from awx.sso.fields import ( - AuthenticationBackendsField, - LDAPConnectionOptionsField, - LDAPDNField, - LDAPDNWithUserField, - LDAPGroupTypeField, - LDAPGroupTypeParamsField, - LDAPOrganizationMapField, - LDAPSearchField, - LDAPSearchUnionField, - LDAPServerURIField, - LDAPTeamMapField, - LDAPUserAttrMapField, - LDAPUserFlagsField, - SAMLContactField, - SAMLEnabledIdPsField, - SAMLOrgAttrField, - SAMLOrgInfoField, - SAMLSecurityField, - SAMLTeamAttrField, - SAMLUserFlagsAttrField, - SocialOrganizationMapField, - SocialTeamMapField, -) -from awx.main.validators import validate_private_key, validate_certificate -from awx.sso.validators import validate_ldap_bind_dn, validate_tacacsplus_disallow_nonascii # noqa - - -class SocialAuthCallbackURL(object): - def __init__(self, provider): - self.provider = provider - - def __call__(self): - path = reverse('social:complete', args=(self.provider,)) - return urlparse.urljoin(settings.TOWER_URL_BASE, path) - - -SOCIAL_AUTH_ORGANIZATION_MAP_HELP_TEXT = _( - '''\ -Mapping to organization admins/users from social auth accounts. This setting -controls which users are placed into which organizations based on their -username and email address. Configuration details are available in the -documentation.\ -''' -) - -# FIXME: /regex/gim (flags) - -SOCIAL_AUTH_ORGANIZATION_MAP_PLACEHOLDER = collections.OrderedDict( - [ - ('Default', collections.OrderedDict([('users', True)])), - ('Test Org', collections.OrderedDict([('admins', ['admin@example.com']), ('auditors', ['auditor@example.com']), ('users', True)])), - ( - 'Test Org 2', - collections.OrderedDict( - [ - ('admins', ['admin@example.com', r'/^tower-[^@]+*?@.*$/']), - ('remove_admins', True), - ('users', r'/^[^@].*?@example\.com$/i'), - ('remove_users', True), - ] - ), - ), - ] -) - -SOCIAL_AUTH_TEAM_MAP_HELP_TEXT = _( - '''\ -Mapping of team members (users) from social auth accounts. Configuration -details are available in the documentation.\ -''' -) - -SOCIAL_AUTH_TEAM_MAP_PLACEHOLDER = collections.OrderedDict( - [ - ('My Team', collections.OrderedDict([('organization', 'Test Org'), ('users', [r'/^[^@]+?@test\.example\.com$/']), ('remove', True)])), - ('Other Team', collections.OrderedDict([('organization', 'Test Org 2'), ('users', r'/^[^@]+?@test2\.example\.com$/i'), ('remove', False)])), - ] -) - -############################################################################### -# AUTHENTICATION BACKENDS DYNAMIC SETTING -############################################################################### - -register( - 'AUTHENTICATION_BACKENDS', - field_class=AuthenticationBackendsField, - label=_('Authentication Backends'), - help_text=_('List of authentication backends that are enabled based on ' 'license features and other authentication settings.'), - read_only=True, - depends_on=AuthenticationBackendsField.get_all_required_settings(), - category=_('Authentication'), - category_slug='authentication', -) - -register( - 'SOCIAL_AUTH_ORGANIZATION_MAP', - field_class=SocialOrganizationMapField, - allow_null=True, - default=None, - label=_('Social Auth Organization Map'), - help_text=SOCIAL_AUTH_ORGANIZATION_MAP_HELP_TEXT, - category=_('Authentication'), - category_slug='authentication', - placeholder=SOCIAL_AUTH_ORGANIZATION_MAP_PLACEHOLDER, -) - -register( - 'SOCIAL_AUTH_TEAM_MAP', - field_class=SocialTeamMapField, - allow_null=True, - default=None, - label=_('Social Auth Team Map'), - help_text=SOCIAL_AUTH_TEAM_MAP_HELP_TEXT, - category=_('Authentication'), - category_slug='authentication', - placeholder=SOCIAL_AUTH_TEAM_MAP_PLACEHOLDER, -) - -register( - 'SOCIAL_AUTH_USER_FIELDS', - field_class=fields.StringListField, - allow_null=True, - default=None, - label=_('Social Auth User Fields'), - help_text=_( - 'When set to an empty list `[]`, this setting prevents new user ' - 'accounts from being created. Only users who have previously ' - 'logged in using social auth or have a user account with a ' - 'matching email address will be able to login.' - ), - category=_('Authentication'), - category_slug='authentication', - placeholder=['username', 'email'], -) - -############################################################################### -# LDAP AUTHENTICATION SETTINGS -############################################################################### - - -def _register_ldap(append=None): - append_str = '_{}'.format(append) if append else '' - - register( - 'AUTH_LDAP{}_SERVER_URI'.format(append_str), - field_class=LDAPServerURIField, - allow_blank=True, - default='', - label=_('LDAP Server URI'), - help_text=_( - 'URI to connect to LDAP server, such as "ldap://ldap.example.com:389" ' - '(non-SSL) or "ldaps://ldap.example.com:636" (SSL). Multiple LDAP ' - 'servers may be specified by separating with spaces or commas. LDAP ' - 'authentication is disabled if this parameter is empty.' - ), - category=_('LDAP'), - category_slug='ldap', - placeholder='ldaps://ldap.example.com:636', - ) - - register( - 'AUTH_LDAP{}_BIND_DN'.format(append_str), - field_class=fields.CharField, - allow_blank=True, - default='', - validators=[validate_ldap_bind_dn], - label=_('LDAP Bind DN'), - help_text=_( - 'DN (Distinguished Name) of user to bind for all search queries. This' - ' is the system user account we will use to login to query LDAP for other' - ' user information. Refer to the documentation for example syntax.' - ), - category=_('LDAP'), - category_slug='ldap', - ) - - register( - 'AUTH_LDAP{}_BIND_PASSWORD'.format(append_str), - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('LDAP Bind Password'), - help_text=_('Password used to bind LDAP user account.'), - category=_('LDAP'), - category_slug='ldap', - encrypted=True, - ) - - register( - 'AUTH_LDAP{}_START_TLS'.format(append_str), - field_class=fields.BooleanField, - default=False, - label=_('LDAP Start TLS'), - help_text=_('Whether to enable TLS when the LDAP connection is not using SSL.'), - category=_('LDAP'), - category_slug='ldap', - ) - - register( - 'AUTH_LDAP{}_CONNECTION_OPTIONS'.format(append_str), - field_class=LDAPConnectionOptionsField, - default={'OPT_REFERRALS': 0, 'OPT_NETWORK_TIMEOUT': 30}, - label=_('LDAP Connection Options'), - help_text=_( - 'Additional options to set for the LDAP connection. LDAP ' - 'referrals are disabled by default (to prevent certain LDAP ' - 'queries from hanging with AD). Option names should be strings ' - '(e.g. "OPT_REFERRALS"). Refer to ' - 'https://www.python-ldap.org/doc/html/ldap.html#options for ' - 'possible options and values that can be set.' - ), - category=_('LDAP'), - category_slug='ldap', - placeholder=collections.OrderedDict([('OPT_REFERRALS', 0), ('OPT_NETWORK_TIMEOUT', 30)]), - ) - - register( - 'AUTH_LDAP{}_USER_SEARCH'.format(append_str), - field_class=LDAPSearchUnionField, - default=[], - label=_('LDAP User Search'), - help_text=_( - 'LDAP search query to find users. Any user that matches the given ' - 'pattern will be able to login to the service. The user should also be ' - 'mapped into an organization (as defined in the ' - 'AUTH_LDAP_ORGANIZATION_MAP setting). If multiple search queries ' - 'need to be supported use of "LDAPUnion" is possible. See ' - 'the documentation for details.' - ), - category=_('LDAP'), - category_slug='ldap', - placeholder=('OU=Users,DC=example,DC=com', 'SCOPE_SUBTREE', '(sAMAccountName=%(user)s)'), - ) - - register( - 'AUTH_LDAP{}_USER_DN_TEMPLATE'.format(append_str), - field_class=LDAPDNWithUserField, - allow_blank=True, - allow_null=True, - default=None, - label=_('LDAP User DN Template'), - help_text=_( - 'Alternative to user search, if user DNs are all of the same ' - 'format. This approach is more efficient for user lookups than ' - 'searching if it is usable in your organizational environment. If ' - 'this setting has a value it will be used instead of ' - 'AUTH_LDAP_USER_SEARCH.' - ), - category=_('LDAP'), - category_slug='ldap', - placeholder='uid=%(user)s,OU=Users,DC=example,DC=com', - ) - - register( - 'AUTH_LDAP{}_USER_ATTR_MAP'.format(append_str), - field_class=LDAPUserAttrMapField, - default={}, - label=_('LDAP User Attribute Map'), - help_text=_( - 'Mapping of LDAP user schema to API user attributes. The default' - ' setting is valid for ActiveDirectory but users with other LDAP' - ' configurations may need to change the values. Refer to the' - ' documentation for additional details.' - ), - category=_('LDAP'), - category_slug='ldap', - placeholder=collections.OrderedDict([('first_name', 'givenName'), ('last_name', 'sn'), ('email', 'mail')]), - ) - - register( - 'AUTH_LDAP{}_GROUP_SEARCH'.format(append_str), - field_class=LDAPSearchField, - default=[], - label=_('LDAP Group Search'), - help_text=_( - 'Users are mapped to organizations based on their membership in LDAP' - ' groups. This setting defines the LDAP search query to find groups. ' - 'Unlike the user search, group search does not support LDAPSearchUnion.' - ), - category=_('LDAP'), - category_slug='ldap', - placeholder=('DC=example,DC=com', 'SCOPE_SUBTREE', '(objectClass=group)'), - ) - - register( - 'AUTH_LDAP{}_GROUP_TYPE'.format(append_str), - field_class=LDAPGroupTypeField, - label=_('LDAP Group Type'), - help_text=_( - 'The group type may need to be changed based on the type of the ' - 'LDAP server. Values are listed at: ' - 'https://django-auth-ldap.readthedocs.io/en/stable/groups.html#types-of-groups' - ), - category=_('LDAP'), - category_slug='ldap', - default='MemberDNGroupType', - depends_on=['AUTH_LDAP{}_GROUP_TYPE_PARAMS'.format(append_str)], - ) - - register( - 'AUTH_LDAP{}_GROUP_TYPE_PARAMS'.format(append_str), - field_class=LDAPGroupTypeParamsField, - label=_('LDAP Group Type Parameters'), - help_text=_('Key value parameters to send the chosen group type init method.'), - category=_('LDAP'), - category_slug='ldap', - default=collections.OrderedDict([('member_attr', 'member'), ('name_attr', 'cn')]), - placeholder=collections.OrderedDict([('ldap_group_user_attr', 'legacyuid'), ('member_attr', 'member'), ('name_attr', 'cn')]), - depends_on=['AUTH_LDAP{}_GROUP_TYPE'.format(append_str)], - ) - - register( - 'AUTH_LDAP{}_REQUIRE_GROUP'.format(append_str), - field_class=LDAPDNField, - allow_blank=True, - allow_null=True, - default=None, - label=_('LDAP Require Group'), - help_text=_( - 'Group DN required to login. If specified, user must be a member ' - 'of this group to login via LDAP. If not set, everyone in LDAP ' - 'that matches the user search will be able to login to the service. ' - 'Only one require group is supported.' - ), - category=_('LDAP'), - category_slug='ldap', - placeholder='CN=Service Users,OU=Users,DC=example,DC=com', - ) - - register( - 'AUTH_LDAP{}_DENY_GROUP'.format(append_str), - field_class=LDAPDNField, - allow_blank=True, - allow_null=True, - default=None, - label=_('LDAP Deny Group'), - help_text=_( - 'Group DN denied from login. If specified, user will not be ' 'allowed to login if a member of this group. Only one deny group ' 'is supported.' - ), - category=_('LDAP'), - category_slug='ldap', - placeholder='CN=Disabled Users,OU=Users,DC=example,DC=com', - ) - - register( - 'AUTH_LDAP{}_USER_FLAGS_BY_GROUP'.format(append_str), - field_class=LDAPUserFlagsField, - default={}, - label=_('LDAP User Flags By Group'), - help_text=_( - 'Retrieve users from a given group. At this time, superuser and system' - ' auditors are the only groups supported. Refer to the' - ' documentation for more detail.' - ), - category=_('LDAP'), - category_slug='ldap', - placeholder=collections.OrderedDict( - [('is_superuser', 'CN=Domain Admins,CN=Users,DC=example,DC=com'), ('is_system_auditor', 'CN=Domain Auditors,CN=Users,DC=example,DC=com')] - ), - ) - - register( - 'AUTH_LDAP{}_ORGANIZATION_MAP'.format(append_str), - field_class=LDAPOrganizationMapField, - default={}, - label=_('LDAP Organization Map'), - help_text=_( - 'Mapping between organization admins/users and LDAP groups. This ' - 'controls which users are placed into which organizations ' - 'relative to their LDAP group memberships. Configuration details ' - 'are available in the documentation.' - ), - category=_('LDAP'), - category_slug='ldap', - placeholder=collections.OrderedDict( - [ - ( - 'Test Org', - collections.OrderedDict( - [ - ('admins', 'CN=Domain Admins,CN=Users,DC=example,DC=com'), - ('auditors', 'CN=Domain Auditors,CN=Users,DC=example,DC=com'), - ('users', ['CN=Domain Users,CN=Users,DC=example,DC=com']), - ('remove_users', True), - ('remove_admins', True), - ] - ), - ), - ( - 'Test Org 2', - collections.OrderedDict( - [('admins', 'CN=Administrators,CN=Builtin,DC=example,DC=com'), ('users', True), ('remove_users', True), ('remove_admins', True)] - ), - ), - ] - ), - ) - - register( - 'AUTH_LDAP{}_TEAM_MAP'.format(append_str), - field_class=LDAPTeamMapField, - default={}, - label=_('LDAP Team Map'), - help_text=_('Mapping between team members (users) and LDAP groups. Configuration' ' details are available in the documentation.'), - category=_('LDAP'), - category_slug='ldap', - placeholder=collections.OrderedDict( - [ - ( - 'My Team', - collections.OrderedDict([('organization', 'Test Org'), ('users', ['CN=Domain Users,CN=Users,DC=example,DC=com']), ('remove', True)]), - ), - ( - 'Other Team', - collections.OrderedDict([('organization', 'Test Org 2'), ('users', 'CN=Other Users,CN=Users,DC=example,DC=com'), ('remove', False)]), - ), - ] - ), - ) - - -_register_ldap() -_register_ldap('1') -_register_ldap('2') -_register_ldap('3') -_register_ldap('4') -_register_ldap('5') - -############################################################################### -# RADIUS AUTHENTICATION SETTINGS -############################################################################### - -register( - 'RADIUS_SERVER', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('RADIUS Server'), - help_text=_('Hostname/IP of RADIUS server. RADIUS authentication is ' 'disabled if this setting is empty.'), - category=_('RADIUS'), - category_slug='radius', - placeholder='radius.example.com', -) - -register( - 'RADIUS_PORT', - field_class=fields.IntegerField, - min_value=1, - max_value=65535, - default=1812, - label=_('RADIUS Port'), - help_text=_('Port of RADIUS server.'), - category=_('RADIUS'), - category_slug='radius', -) - -register( - 'RADIUS_SECRET', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('RADIUS Secret'), - help_text=_('Shared secret for authenticating to RADIUS server.'), - category=_('RADIUS'), - category_slug='radius', - encrypted=True, -) - -############################################################################### -# TACACSPLUS AUTHENTICATION SETTINGS -############################################################################### - -register( - 'TACACSPLUS_HOST', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('TACACS+ Server'), - help_text=_('Hostname of TACACS+ server.'), - category=_('TACACS+'), - category_slug='tacacsplus', -) - -register( - 'TACACSPLUS_PORT', - field_class=fields.IntegerField, - min_value=1, - max_value=65535, - default=49, - label=_('TACACS+ Port'), - help_text=_('Port number of TACACS+ server.'), - category=_('TACACS+'), - category_slug='tacacsplus', -) - -register( - 'TACACSPLUS_SECRET', - field_class=fields.CharField, - allow_blank=True, - default='', - validators=[validate_tacacsplus_disallow_nonascii], - label=_('TACACS+ Secret'), - help_text=_('Shared secret for authenticating to TACACS+ server.'), - category=_('TACACS+'), - category_slug='tacacsplus', - encrypted=True, -) - -register( - 'TACACSPLUS_SESSION_TIMEOUT', - field_class=fields.IntegerField, - min_value=0, - default=5, - label=_('TACACS+ Auth Session Timeout'), - help_text=_('TACACS+ session timeout value in seconds, 0 disables timeout.'), - category=_('TACACS+'), - category_slug='tacacsplus', - unit=_('seconds'), -) - -register( - 'TACACSPLUS_AUTH_PROTOCOL', - field_class=fields.ChoiceField, - choices=['ascii', 'pap'], - default='ascii', - label=_('TACACS+ Authentication Protocol'), - help_text=_('Choose the authentication protocol used by TACACS+ client.'), - category=_('TACACS+'), - category_slug='tacacsplus', -) - -############################################################################### -# GOOGLE OAUTH2 AUTHENTICATION SETTINGS -############################################################################### - -register( - 'SOCIAL_AUTH_GOOGLE_OAUTH2_CALLBACK_URL', - field_class=fields.CharField, - read_only=True, - default=SocialAuthCallbackURL('google-oauth2'), - label=_('Google OAuth2 Callback URL'), - help_text=_( - 'Provide this URL as the callback URL for your application as part ' 'of your registration process. Refer to the ' 'documentation for more detail.' - ), - category=_('Google OAuth2'), - category_slug='google-oauth2', - depends_on=['TOWER_URL_BASE'], -) - -register( - 'SOCIAL_AUTH_GOOGLE_OAUTH2_KEY', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('Google OAuth2 Key'), - help_text=_('The OAuth2 key from your web application.'), - category=_('Google OAuth2'), - category_slug='google-oauth2', - placeholder='528620852399-gm2dt4hrl2tsj67fqamk09k1e0ad6gd8.apps.googleusercontent.com', -) - -register( - 'SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('Google OAuth2 Secret'), - help_text=_('The OAuth2 secret from your web application.'), - category=_('Google OAuth2'), - category_slug='google-oauth2', - placeholder='q2fMVCmEregbg-drvebPp8OW', - encrypted=True, -) - -register( - 'SOCIAL_AUTH_GOOGLE_OAUTH2_WHITELISTED_DOMAINS', - field_class=fields.StringListField, - default=[], - label=_('Google OAuth2 Allowed Domains'), - help_text=_('Update this setting to restrict the domains who are allowed to ' 'login using Google OAuth2.'), - category=_('Google OAuth2'), - category_slug='google-oauth2', - placeholder=['example.com'], -) - -register( - 'SOCIAL_AUTH_GOOGLE_OAUTH2_AUTH_EXTRA_ARGUMENTS', - field_class=fields.DictField, - default={}, - label=_('Google OAuth2 Extra Arguments'), - help_text=_( - 'Extra arguments for Google OAuth2 login. You can restrict it to' - ' only allow a single domain to authenticate, even if the user is' - ' logged in with multple Google accounts. Refer to the' - ' documentation for more detail.' - ), - category=_('Google OAuth2'), - category_slug='google-oauth2', - placeholder={'hd': 'example.com'}, -) - -register( - 'SOCIAL_AUTH_GOOGLE_OAUTH2_ORGANIZATION_MAP', - field_class=SocialOrganizationMapField, - allow_null=True, - default=None, - label=_('Google OAuth2 Organization Map'), - help_text=SOCIAL_AUTH_ORGANIZATION_MAP_HELP_TEXT, - category=_('Google OAuth2'), - category_slug='google-oauth2', - placeholder=SOCIAL_AUTH_ORGANIZATION_MAP_PLACEHOLDER, -) - -register( - 'SOCIAL_AUTH_GOOGLE_OAUTH2_TEAM_MAP', - field_class=SocialTeamMapField, - allow_null=True, - default=None, - label=_('Google OAuth2 Team Map'), - help_text=SOCIAL_AUTH_TEAM_MAP_HELP_TEXT, - category=_('Google OAuth2'), - category_slug='google-oauth2', - placeholder=SOCIAL_AUTH_TEAM_MAP_PLACEHOLDER, -) - -############################################################################### -# GITHUB OAUTH2 AUTHENTICATION SETTINGS -############################################################################### - -register( - 'SOCIAL_AUTH_GITHUB_CALLBACK_URL', - field_class=fields.CharField, - read_only=True, - default=SocialAuthCallbackURL('github'), - label=_('GitHub OAuth2 Callback URL'), - help_text=_( - 'Provide this URL as the callback URL for your application as part ' 'of your registration process. Refer to the ' 'documentation for more detail.' - ), - category=_('GitHub OAuth2'), - category_slug='github', - depends_on=['TOWER_URL_BASE'], -) - -register( - 'SOCIAL_AUTH_GITHUB_KEY', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('GitHub OAuth2 Key'), - help_text=_('The OAuth2 key (Client ID) from your GitHub developer application.'), - category=_('GitHub OAuth2'), - category_slug='github', -) - -register( - 'SOCIAL_AUTH_GITHUB_SECRET', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('GitHub OAuth2 Secret'), - help_text=_('The OAuth2 secret (Client Secret) from your GitHub developer application.'), - category=_('GitHub OAuth2'), - category_slug='github', - encrypted=True, -) - -register( - 'SOCIAL_AUTH_GITHUB_ORGANIZATION_MAP', - field_class=SocialOrganizationMapField, - allow_null=True, - default=None, - label=_('GitHub OAuth2 Organization Map'), - help_text=SOCIAL_AUTH_ORGANIZATION_MAP_HELP_TEXT, - category=_('GitHub OAuth2'), - category_slug='github', - placeholder=SOCIAL_AUTH_ORGANIZATION_MAP_PLACEHOLDER, -) - -register( - 'SOCIAL_AUTH_GITHUB_TEAM_MAP', - field_class=SocialTeamMapField, - allow_null=True, - default=None, - label=_('GitHub OAuth2 Team Map'), - help_text=SOCIAL_AUTH_TEAM_MAP_HELP_TEXT, - category=_('GitHub OAuth2'), - category_slug='github', - placeholder=SOCIAL_AUTH_TEAM_MAP_PLACEHOLDER, -) - -############################################################################### -# GITHUB ORG OAUTH2 AUTHENTICATION SETTINGS -############################################################################### - -register( - 'SOCIAL_AUTH_GITHUB_ORG_CALLBACK_URL', - field_class=fields.CharField, - read_only=True, - default=SocialAuthCallbackURL('github-org'), - label=_('GitHub Organization OAuth2 Callback URL'), - help_text=_( - 'Provide this URL as the callback URL for your application as part ' 'of your registration process. Refer to the ' 'documentation for more detail.' - ), - category=_('GitHub Organization OAuth2'), - category_slug='github-org', - depends_on=['TOWER_URL_BASE'], -) - -register( - 'SOCIAL_AUTH_GITHUB_ORG_KEY', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('GitHub Organization OAuth2 Key'), - help_text=_('The OAuth2 key (Client ID) from your GitHub organization application.'), - category=_('GitHub Organization OAuth2'), - category_slug='github-org', -) - -register( - 'SOCIAL_AUTH_GITHUB_ORG_SECRET', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('GitHub Organization OAuth2 Secret'), - help_text=_('The OAuth2 secret (Client Secret) from your GitHub organization application.'), - category=_('GitHub Organization OAuth2'), - category_slug='github-org', - encrypted=True, -) - -register( - 'SOCIAL_AUTH_GITHUB_ORG_NAME', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('GitHub Organization Name'), - help_text=_('The name of your GitHub organization, as used in your ' 'organization\'s URL: https://github.com//.'), - category=_('GitHub Organization OAuth2'), - category_slug='github-org', -) - -register( - 'SOCIAL_AUTH_GITHUB_ORG_ORGANIZATION_MAP', - field_class=SocialOrganizationMapField, - allow_null=True, - default=None, - label=_('GitHub Organization OAuth2 Organization Map'), - help_text=SOCIAL_AUTH_ORGANIZATION_MAP_HELP_TEXT, - category=_('GitHub Organization OAuth2'), - category_slug='github-org', - placeholder=SOCIAL_AUTH_ORGANIZATION_MAP_PLACEHOLDER, -) - -register( - 'SOCIAL_AUTH_GITHUB_ORG_TEAM_MAP', - field_class=SocialTeamMapField, - allow_null=True, - default=None, - label=_('GitHub Organization OAuth2 Team Map'), - help_text=SOCIAL_AUTH_TEAM_MAP_HELP_TEXT, - category=_('GitHub Organization OAuth2'), - category_slug='github-org', - placeholder=SOCIAL_AUTH_TEAM_MAP_PLACEHOLDER, -) - -############################################################################### -# GITHUB TEAM OAUTH2 AUTHENTICATION SETTINGS -############################################################################### - -register( - 'SOCIAL_AUTH_GITHUB_TEAM_CALLBACK_URL', - field_class=fields.CharField, - read_only=True, - default=SocialAuthCallbackURL('github-team'), - label=_('GitHub Team OAuth2 Callback URL'), - help_text=_( - 'Create an organization-owned application at ' - 'https://github.com/organizations//settings/applications ' - 'and obtain an OAuth2 key (Client ID) and secret (Client Secret). ' - 'Provide this URL as the callback URL for your application.' - ), - category=_('GitHub Team OAuth2'), - category_slug='github-team', - depends_on=['TOWER_URL_BASE'], -) - -register( - 'SOCIAL_AUTH_GITHUB_TEAM_KEY', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('GitHub Team OAuth2 Key'), - help_text=_('The OAuth2 key (Client ID) from your GitHub organization application.'), - category=_('GitHub Team OAuth2'), - category_slug='github-team', -) - -register( - 'SOCIAL_AUTH_GITHUB_TEAM_SECRET', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('GitHub Team OAuth2 Secret'), - help_text=_('The OAuth2 secret (Client Secret) from your GitHub organization application.'), - category=_('GitHub Team OAuth2'), - category_slug='github-team', - encrypted=True, -) - -register( - 'SOCIAL_AUTH_GITHUB_TEAM_ID', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('GitHub Team ID'), - help_text=_('Find the numeric team ID using the Github API: ' 'http://fabian-kostadinov.github.io/2015/01/16/how-to-find-a-github-team-id/.'), - category=_('GitHub Team OAuth2'), - category_slug='github-team', -) - -register( - 'SOCIAL_AUTH_GITHUB_TEAM_ORGANIZATION_MAP', - field_class=SocialOrganizationMapField, - allow_null=True, - default=None, - label=_('GitHub Team OAuth2 Organization Map'), - help_text=SOCIAL_AUTH_ORGANIZATION_MAP_HELP_TEXT, - category=_('GitHub Team OAuth2'), - category_slug='github-team', - placeholder=SOCIAL_AUTH_ORGANIZATION_MAP_PLACEHOLDER, -) - -register( - 'SOCIAL_AUTH_GITHUB_TEAM_TEAM_MAP', - field_class=SocialTeamMapField, - allow_null=True, - default=None, - label=_('GitHub Team OAuth2 Team Map'), - help_text=SOCIAL_AUTH_TEAM_MAP_HELP_TEXT, - category=_('GitHub Team OAuth2'), - category_slug='github-team', - placeholder=SOCIAL_AUTH_TEAM_MAP_PLACEHOLDER, -) - -############################################################################### -# GITHUB ENTERPRISE OAUTH2 AUTHENTICATION SETTINGS -############################################################################### - -register( - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_CALLBACK_URL', - field_class=fields.CharField, - read_only=True, - default=SocialAuthCallbackURL('github-enterprise'), - label=_('GitHub Enterprise OAuth2 Callback URL'), - help_text=_( - 'Provide this URL as the callback URL for your application as part ' 'of your registration process. Refer to the ' 'documentation for more detail.' - ), - category=_('GitHub Enterprise OAuth2'), - category_slug='github-enterprise', - depends_on=['TOWER_URL_BASE'], -) - -register( - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_URL', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('GitHub Enterprise URL'), - help_text=_('The URL for your Github Enterprise instance, e.g.: http(s)://hostname/. Refer to Github Enterprise ' 'documentation for more details.'), - category=_('GitHub Enterprise OAuth2'), - category_slug='github-enterprise', -) - -register( - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('GitHub Enterprise API URL'), - help_text=_( - 'The API URL for your GitHub Enterprise instance, e.g.: http(s)://hostname/api/v3/. Refer to Github ' 'Enterprise documentation for more details.' - ), - category=_('GitHub Enterprise OAuth2'), - category_slug='github-enterprise', -) - -register( - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_KEY', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('GitHub Enterprise OAuth2 Key'), - help_text=_('The OAuth2 key (Client ID) from your GitHub Enterprise developer application.'), - category=_('GitHub Enterprise OAuth2'), - category_slug='github-enterprise', -) - -register( - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_SECRET', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('GitHub Enterprise OAuth2 Secret'), - help_text=_('The OAuth2 secret (Client Secret) from your GitHub Enterprise developer application.'), - category=_('GitHub OAuth2'), - category_slug='github-enterprise', - encrypted=True, -) - -register( - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_ORGANIZATION_MAP', - field_class=SocialOrganizationMapField, - allow_null=True, - default=None, - label=_('GitHub Enterprise OAuth2 Organization Map'), - help_text=SOCIAL_AUTH_ORGANIZATION_MAP_HELP_TEXT, - category=_('GitHub Enterprise OAuth2'), - category_slug='github-enterprise', - placeholder=SOCIAL_AUTH_ORGANIZATION_MAP_PLACEHOLDER, -) - -register( - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_MAP', - field_class=SocialTeamMapField, - allow_null=True, - default=None, - label=_('GitHub Enterprise OAuth2 Team Map'), - help_text=SOCIAL_AUTH_TEAM_MAP_HELP_TEXT, - category=_('GitHub Enterprise OAuth2'), - category_slug='github-enterprise', - placeholder=SOCIAL_AUTH_TEAM_MAP_PLACEHOLDER, -) - -############################################################################### -# GITHUB ENTERPRISE ORG OAUTH2 AUTHENTICATION SETTINGS -############################################################################### - -register( - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_CALLBACK_URL', - field_class=fields.CharField, - read_only=True, - default=SocialAuthCallbackURL('github-enterprise-org'), - label=_('GitHub Enterprise Organization OAuth2 Callback URL'), - help_text=_( - 'Provide this URL as the callback URL for your application as part ' 'of your registration process. Refer to the ' 'documentation for more detail.' - ), - category=_('GitHub Enterprise Organization OAuth2'), - category_slug='github-enterprise-org', - depends_on=['TOWER_URL_BASE'], -) - -register( - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_URL', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('GitHub Enterprise Organization URL'), - help_text=_('The URL for your Github Enterprise instance, e.g.: http(s)://hostname/. Refer to Github Enterprise ' 'documentation for more details.'), - category=_('GitHub Enterprise OAuth2'), - category_slug='github-enterprise-org', -) - -register( - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_API_URL', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('GitHub Enterprise Organization API URL'), - help_text=_( - 'The API URL for your GitHub Enterprise instance, e.g.: http(s)://hostname/api/v3/. Refer to Github ' 'Enterprise documentation for more details.' - ), - category=_('GitHub Enterprise OAuth2'), - category_slug='github-enterprise-org', -) - -register( - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_KEY', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('GitHub Enterprise Organization OAuth2 Key'), - help_text=_('The OAuth2 key (Client ID) from your GitHub Enterprise organization application.'), - category=_('GitHub Enterprise Organization OAuth2'), - category_slug='github-enterprise-org', -) - -register( - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_SECRET', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('GitHub Enterprise Organization OAuth2 Secret'), - help_text=_('The OAuth2 secret (Client Secret) from your GitHub Enterprise organization application.'), - category=_('GitHub Enterprise Organization OAuth2'), - category_slug='github-enterprise-org', - encrypted=True, -) - -register( - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_NAME', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('GitHub Enterprise Organization Name'), - help_text=_('The name of your GitHub Enterprise organization, as used in your ' 'organization\'s URL: https://github.com//.'), - category=_('GitHub Enterprise Organization OAuth2'), - category_slug='github-enterprise-org', -) - -register( - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_ORGANIZATION_MAP', - field_class=SocialOrganizationMapField, - allow_null=True, - default=None, - label=_('GitHub Enterprise Organization OAuth2 Organization Map'), - help_text=SOCIAL_AUTH_ORGANIZATION_MAP_HELP_TEXT, - category=_('GitHub Enterprise Organization OAuth2'), - category_slug='github-enterprise-org', - placeholder=SOCIAL_AUTH_ORGANIZATION_MAP_PLACEHOLDER, -) - -register( - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_TEAM_MAP', - field_class=SocialTeamMapField, - allow_null=True, - default=None, - label=_('GitHub Enterprise Organization OAuth2 Team Map'), - help_text=SOCIAL_AUTH_TEAM_MAP_HELP_TEXT, - category=_('GitHub Enterprise Organization OAuth2'), - category_slug='github-enterprise-org', - placeholder=SOCIAL_AUTH_TEAM_MAP_PLACEHOLDER, -) - -############################################################################### -# GITHUB ENTERPRISE TEAM OAUTH2 AUTHENTICATION SETTINGS -############################################################################### - -register( - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_CALLBACK_URL', - field_class=fields.CharField, - read_only=True, - default=SocialAuthCallbackURL('github-enterprise-team'), - label=_('GitHub Enterprise Team OAuth2 Callback URL'), - help_text=_( - 'Create an organization-owned application at ' - 'https://github.com/organizations//settings/applications ' - 'and obtain an OAuth2 key (Client ID) and secret (Client Secret). ' - 'Provide this URL as the callback URL for your application.' - ), - category=_('GitHub Enterprise Team OAuth2'), - category_slug='github-enterprise-team', - depends_on=['TOWER_URL_BASE'], -) - -register( - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_URL', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('GitHub Enterprise Team URL'), - help_text=_('The URL for your Github Enterprise instance, e.g.: http(s)://hostname/. Refer to Github Enterprise ' 'documentation for more details.'), - category=_('GitHub Enterprise OAuth2'), - category_slug='github-enterprise-team', -) - -register( - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_API_URL', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('GitHub Enterprise Team API URL'), - help_text=_( - 'The API URL for your GitHub Enterprise instance, e.g.: http(s)://hostname/api/v3/. Refer to Github ' 'Enterprise documentation for more details.' - ), - category=_('GitHub Enterprise OAuth2'), - category_slug='github-enterprise-team', -) - -register( - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_KEY', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('GitHub Enterprise Team OAuth2 Key'), - help_text=_('The OAuth2 key (Client ID) from your GitHub Enterprise organization application.'), - category=_('GitHub Enterprise Team OAuth2'), - category_slug='github-enterprise-team', -) - -register( - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_SECRET', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('GitHub Enterprise Team OAuth2 Secret'), - help_text=_('The OAuth2 secret (Client Secret) from your GitHub Enterprise organization application.'), - category=_('GitHub Enterprise Team OAuth2'), - category_slug='github-enterprise-team', - encrypted=True, -) - -register( - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ID', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('GitHub Enterprise Team ID'), - help_text=_('Find the numeric team ID using the Github Enterprise API: ' 'http://fabian-kostadinov.github.io/2015/01/16/how-to-find-a-github-team-id/.'), - category=_('GitHub Enterprise Team OAuth2'), - category_slug='github-enterprise-team', -) - -register( - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ORGANIZATION_MAP', - field_class=SocialOrganizationMapField, - allow_null=True, - default=None, - label=_('GitHub Enterprise Team OAuth2 Organization Map'), - help_text=SOCIAL_AUTH_ORGANIZATION_MAP_HELP_TEXT, - category=_('GitHub Enterprise Team OAuth2'), - category_slug='github-enterprise-team', - placeholder=SOCIAL_AUTH_ORGANIZATION_MAP_PLACEHOLDER, -) - -register( - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_TEAM_MAP', - field_class=SocialTeamMapField, - allow_null=True, - default=None, - label=_('GitHub Enterprise Team OAuth2 Team Map'), - help_text=SOCIAL_AUTH_TEAM_MAP_HELP_TEXT, - category=_('GitHub Enterprise Team OAuth2'), - category_slug='github-enterprise-team', - placeholder=SOCIAL_AUTH_TEAM_MAP_PLACEHOLDER, -) - -############################################################################### -# MICROSOFT AZURE ACTIVE DIRECTORY SETTINGS -############################################################################### - -register( - 'SOCIAL_AUTH_AZUREAD_OAUTH2_CALLBACK_URL', - field_class=fields.CharField, - read_only=True, - default=SocialAuthCallbackURL('azuread-oauth2'), - label=_('Azure AD OAuth2 Callback URL'), - help_text=_( - 'Provide this URL as the callback URL for your application as part' ' of your registration process. Refer to the' ' documentation for more detail. ' - ), - category=_('Azure AD OAuth2'), - category_slug='azuread-oauth2', - depends_on=['TOWER_URL_BASE'], -) - -register( - 'SOCIAL_AUTH_AZUREAD_OAUTH2_KEY', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('Azure AD OAuth2 Key'), - help_text=_('The OAuth2 key (Client ID) from your Azure AD application.'), - category=_('Azure AD OAuth2'), - category_slug='azuread-oauth2', -) - -register( - 'SOCIAL_AUTH_AZUREAD_OAUTH2_SECRET', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('Azure AD OAuth2 Secret'), - help_text=_('The OAuth2 secret (Client Secret) from your Azure AD application.'), - category=_('Azure AD OAuth2'), - category_slug='azuread-oauth2', - encrypted=True, -) - -register( - 'SOCIAL_AUTH_AZUREAD_OAUTH2_ORGANIZATION_MAP', - field_class=SocialOrganizationMapField, - allow_null=True, - default=None, - label=_('Azure AD OAuth2 Organization Map'), - help_text=SOCIAL_AUTH_ORGANIZATION_MAP_HELP_TEXT, - category=_('Azure AD OAuth2'), - category_slug='azuread-oauth2', - placeholder=SOCIAL_AUTH_ORGANIZATION_MAP_PLACEHOLDER, -) - -register( - 'SOCIAL_AUTH_AZUREAD_OAUTH2_TEAM_MAP', - field_class=SocialTeamMapField, - allow_null=True, - default=None, - label=_('Azure AD OAuth2 Team Map'), - help_text=SOCIAL_AUTH_TEAM_MAP_HELP_TEXT, - category=_('Azure AD OAuth2'), - category_slug='azuread-oauth2', - placeholder=SOCIAL_AUTH_TEAM_MAP_PLACEHOLDER, -) - -############################################################################### -# Generic OIDC AUTHENTICATION SETTINGS -############################################################################### - -register( - 'SOCIAL_AUTH_OIDC_KEY', - field_class=fields.CharField, - allow_null=False, - default=None, - label=_('OIDC Key'), - help_text='The OIDC key (Client ID) from your IDP.', - category=_('Generic OIDC'), - category_slug='oidc', -) - -register( - 'SOCIAL_AUTH_OIDC_SECRET', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('OIDC Secret'), - help_text=_('The OIDC secret (Client Secret) from your IDP.'), - category=_('Generic OIDC'), - category_slug='oidc', - encrypted=True, -) - -register( - 'SOCIAL_AUTH_OIDC_OIDC_ENDPOINT', - field_class=fields.CharField, - allow_blank=True, - default='', - label=_('OIDC Provider URL'), - help_text=_('The URL for your OIDC provider including the path up to /.well-known/openid-configuration'), - category=_('Generic OIDC'), - category_slug='oidc', -) - -register( - 'SOCIAL_AUTH_OIDC_VERIFY_SSL', - field_class=fields.BooleanField, - default=True, - label=_('Verify OIDC Provider Certificate'), - help_text=_('Verify the OIDV provider ssl certificate.'), - category=_('Generic OIDC'), - category_slug='oidc', -) - -############################################################################### -# SAML AUTHENTICATION SETTINGS -############################################################################### - - -def get_saml_metadata_url(): - return urlparse.urljoin(settings.TOWER_URL_BASE, reverse('sso:saml_metadata')) - - -def get_saml_entity_id(): - return settings.TOWER_URL_BASE - - -register( - 'SAML_AUTO_CREATE_OBJECTS', - field_class=fields.BooleanField, - default=True, - label=_('Automatically Create Organizations and Teams on SAML Login'), - help_text=_('When enabled (the default), mapped Organizations and Teams ' 'will be created automatically on successful SAML login.'), - category=_('SAML'), - category_slug='saml', -) - -register( - 'SOCIAL_AUTH_SAML_CALLBACK_URL', - field_class=fields.CharField, - read_only=True, - default=SocialAuthCallbackURL('saml'), - label=_('SAML Assertion Consumer Service (ACS) URL'), - help_text=_( - 'Register the service as a service provider (SP) with each identity ' - 'provider (IdP) you have configured. Provide your SP Entity ID ' - 'and this ACS URL for your application.' - ), - category=_('SAML'), - category_slug='saml', - depends_on=['TOWER_URL_BASE'], -) - -register( - 'SOCIAL_AUTH_SAML_METADATA_URL', - field_class=fields.CharField, - read_only=True, - default=get_saml_metadata_url, - label=_('SAML Service Provider Metadata URL'), - help_text=_('If your identity provider (IdP) allows uploading an XML ' 'metadata file, you can download one from this URL.'), - category=_('SAML'), - category_slug='saml', -) - -register( - 'SOCIAL_AUTH_SAML_SP_ENTITY_ID', - field_class=fields.CharField, - allow_blank=True, - default=get_saml_entity_id, - label=_('SAML Service Provider Entity ID'), - help_text=_( - 'The application-defined unique identifier used as the ' - 'audience of the SAML service provider (SP) configuration. ' - 'This is usually the URL for the service.' - ), - category=_('SAML'), - category_slug='saml', - depends_on=['TOWER_URL_BASE'], -) - -register( - 'SOCIAL_AUTH_SAML_SP_PUBLIC_CERT', - field_class=fields.CharField, - allow_blank=True, - required=True, - validators=[validate_certificate], - label=_('SAML Service Provider Public Certificate'), - help_text=_('Create a keypair to use as a service provider (SP) ' 'and include the certificate content here.'), - category=_('SAML'), - category_slug='saml', -) - -register( - 'SOCIAL_AUTH_SAML_SP_PRIVATE_KEY', - field_class=fields.CharField, - allow_blank=True, - required=True, - validators=[validate_private_key], - label=_('SAML Service Provider Private Key'), - help_text=_('Create a keypair to use as a service provider (SP) ' 'and include the private key content here.'), - category=_('SAML'), - category_slug='saml', - encrypted=True, -) - -register( - 'SOCIAL_AUTH_SAML_ORG_INFO', - field_class=SAMLOrgInfoField, - required=True, - label=_('SAML Service Provider Organization Info'), - help_text=_('Provide the URL, display name, and the name of your app. Refer to' ' the documentation for example syntax.'), - category=_('SAML'), - category_slug='saml', - placeholder=collections.OrderedDict( - [('en-US', collections.OrderedDict([('name', 'example'), ('displayname', 'Example'), ('url', 'http://www.example.com')]))] - ), -) - -register( - 'SOCIAL_AUTH_SAML_TECHNICAL_CONTACT', - field_class=SAMLContactField, - allow_blank=True, - required=True, - label=_('SAML Service Provider Technical Contact'), - help_text=_('Provide the name and email address of the technical contact for' ' your service provider. Refer to the documentation' ' for example syntax.'), - category=_('SAML'), - category_slug='saml', - placeholder=collections.OrderedDict([('givenName', 'Technical Contact'), ('emailAddress', 'techsup@example.com')]), -) - -register( - 'SOCIAL_AUTH_SAML_SUPPORT_CONTACT', - field_class=SAMLContactField, - allow_blank=True, - required=True, - label=_('SAML Service Provider Support Contact'), - help_text=_('Provide the name and email address of the support contact for your' ' service provider. Refer to the documentation for' ' example syntax.'), - category=_('SAML'), - category_slug='saml', - placeholder=collections.OrderedDict([('givenName', 'Support Contact'), ('emailAddress', 'support@example.com')]), -) - -register( - 'SOCIAL_AUTH_SAML_ENABLED_IDPS', - field_class=SAMLEnabledIdPsField, - default={}, - label=_('SAML Enabled Identity Providers'), - help_text=_( - 'Configure the Entity ID, SSO URL and certificate for each identity' - ' provider (IdP) in use. Multiple SAML IdPs are supported. Some IdPs' - ' may provide user data using attribute names that differ from the' - ' default OIDs. Attribute names may be overridden for each IdP. Refer' - ' to the Ansible documentation for additional details and syntax.' - ), - category=_('SAML'), - category_slug='saml', - placeholder=collections.OrderedDict( - [ - ( - 'Okta', - collections.OrderedDict( - [ - ('entity_id', 'http://www.okta.com/HHniyLkaxk9e76wD0Thh'), - ('url', 'https://dev-123456.oktapreview.com/app/ansibletower/HHniyLkaxk9e76wD0Thh/sso/saml'), - ('x509cert', 'MIIDpDCCAoygAwIBAgIGAVVZ4rPzMA0GCSqGSIb3...'), - ('attr_user_permanent_id', 'username'), - ('attr_first_name', 'first_name'), - ('attr_last_name', 'last_name'), - ('attr_username', 'username'), - ('attr_email', 'email'), - ] - ), - ), - ( - 'OneLogin', - collections.OrderedDict( - [ - ('entity_id', 'https://app.onelogin.com/saml/metadata/123456'), - ('url', 'https://example.onelogin.com/trust/saml2/http-post/sso/123456'), - ('x509cert', 'MIIEJjCCAw6gAwIBAgIUfuSD54OPSBhndDHh3gZo...'), - ('attr_user_permanent_id', 'name_id'), - ('attr_first_name', 'User.FirstName'), - ('attr_last_name', 'User.LastName'), - ('attr_username', 'User.email'), - ('attr_email', 'User.email'), - ] - ), - ), - ] - ), -) - -register( - 'SOCIAL_AUTH_SAML_SECURITY_CONFIG', - field_class=SAMLSecurityField, - allow_null=True, - default={'requestedAuthnContext': False}, - label=_('SAML Security Config'), - help_text=_( - 'A dict of key value pairs that are passed to the underlying' ' python-saml security setting' ' https://github.com/onelogin/python-saml#settings' - ), - category=_('SAML'), - category_slug='saml', - placeholder=collections.OrderedDict( - [ - ("nameIdEncrypted", False), - ("authnRequestsSigned", False), - ("logoutRequestSigned", False), - ("logoutResponseSigned", False), - ("signMetadata", False), - ("wantMessagesSigned", False), - ("wantAssertionsSigned", False), - ("wantAssertionsEncrypted", False), - ("wantNameId", True), - ("wantNameIdEncrypted", False), - ("wantAttributeStatement", True), - ("requestedAuthnContext", True), - ("requestedAuthnContextComparison", "exact"), - ("metadataValidUntil", "2015-06-26T20:00:00Z"), - ("metadataCacheDuration", "PT518400S"), - ("signatureAlgorithm", "http://www.w3.org/2000/09/xmldsig#rsa-sha1"), - ("digestAlgorithm", "http://www.w3.org/2000/09/xmldsig#sha1"), - ] - ), -) - -register( - 'SOCIAL_AUTH_SAML_SP_EXTRA', - field_class=fields.DictField, - allow_null=True, - default=None, - label=_('SAML Service Provider extra configuration data'), - help_text=_('A dict of key value pairs to be passed to the underlying' ' python-saml Service Provider configuration setting.'), - category=_('SAML'), - category_slug='saml', - placeholder=collections.OrderedDict(), -) - -register( - 'SOCIAL_AUTH_SAML_EXTRA_DATA', - field_class=fields.ListTuplesField, - allow_null=True, - default=None, - label=_('SAML IDP to extra_data attribute mapping'), - help_text=_('A list of tuples that maps IDP attributes to extra_attributes.' ' Each attribute will be a list of values, even if only 1 value.'), - category=_('SAML'), - category_slug='saml', - placeholder=[('attribute_name', 'extra_data_name_for_attribute'), ('department', 'department'), ('manager_full_name', 'manager_full_name')], -) - -register( - 'SOCIAL_AUTH_SAML_ORGANIZATION_MAP', - field_class=SocialOrganizationMapField, - allow_null=True, - default=None, - label=_('SAML Organization Map'), - help_text=SOCIAL_AUTH_ORGANIZATION_MAP_HELP_TEXT, - category=_('SAML'), - category_slug='saml', - placeholder=SOCIAL_AUTH_ORGANIZATION_MAP_PLACEHOLDER, -) - -register( - 'SOCIAL_AUTH_SAML_TEAM_MAP', - field_class=SocialTeamMapField, - allow_null=True, - default=None, - label=_('SAML Team Map'), - help_text=SOCIAL_AUTH_TEAM_MAP_HELP_TEXT, - category=_('SAML'), - category_slug='saml', - placeholder=SOCIAL_AUTH_TEAM_MAP_PLACEHOLDER, -) - -register( - 'SOCIAL_AUTH_SAML_ORGANIZATION_ATTR', - field_class=SAMLOrgAttrField, - allow_null=True, - default=None, - label=_('SAML Organization Attribute Mapping'), - help_text=_('Used to translate user organization membership.'), - category=_('SAML'), - category_slug='saml', - placeholder=collections.OrderedDict( - [ - ('saml_attr', 'organization'), - ('saml_admin_attr', 'organization_admin'), - ('saml_auditor_attr', 'organization_auditor'), - ('remove', True), - ('remove_admins', True), - ('remove_auditors', True), - ] - ), -) - -register( - 'SOCIAL_AUTH_SAML_TEAM_ATTR', - field_class=SAMLTeamAttrField, - allow_null=True, - default=None, - label=_('SAML Team Attribute Mapping'), - help_text=_('Used to translate user team membership.'), - category=_('SAML'), - category_slug='saml', - placeholder=collections.OrderedDict( - [ - ('saml_attr', 'team'), - ('remove', True), - ( - 'team_org_map', - [ - collections.OrderedDict([('team', 'Marketing'), ('organization', 'Red Hat')]), - collections.OrderedDict([('team', 'Human Resources'), ('organization', 'Red Hat')]), - collections.OrderedDict([('team', 'Engineering'), ('organization', 'Red Hat')]), - collections.OrderedDict([('team', 'Engineering'), ('organization', 'Ansible')]), - collections.OrderedDict([('team', 'Quality Engineering'), ('organization', 'Ansible')]), - collections.OrderedDict([('team', 'Sales'), ('organization', 'Ansible')]), - ], - ), - ] - ), -) - -register( - 'SOCIAL_AUTH_SAML_USER_FLAGS_BY_ATTR', - field_class=SAMLUserFlagsAttrField, - allow_null=True, - default=None, - label=_('SAML User Flags Attribute Mapping'), - help_text=_('Used to map super users and system auditors from SAML.'), - category=_('SAML'), - category_slug='saml', - placeholder=[ - ('is_superuser_attr', 'saml_attr'), - ('is_superuser_value', ['value']), - ('is_superuser_role', ['saml_role']), - ('remove_superusers', True), - ('is_system_auditor_attr', 'saml_attr'), - ('is_system_auditor_value', ['value']), - ('is_system_auditor_role', ['saml_role']), - ('remove_system_auditors', True), - ], -) - - -def tacacs_validate(serializer, attrs): - if not serializer.instance or not hasattr(serializer.instance, 'TACACSPLUS_HOST') or not hasattr(serializer.instance, 'TACACSPLUS_SECRET'): - return attrs - errors = [] - host = serializer.instance.TACACSPLUS_HOST - if 'TACACSPLUS_HOST' in attrs: - host = attrs['TACACSPLUS_HOST'] - secret = serializer.instance.TACACSPLUS_SECRET - if 'TACACSPLUS_SECRET' in attrs: - secret = attrs['TACACSPLUS_SECRET'] - if host and not secret: - errors.append('TACACSPLUS_SECRET is required when TACACSPLUS_HOST is provided.') - if errors: - raise serializers.ValidationError(_('\n'.join(errors))) - return attrs - - -register_validate('tacacsplus', tacacs_validate) diff --git a/awx/sso/fields.py b/awx/sso/fields.py deleted file mode 100644 index 25b7f2c304a6..000000000000 --- a/awx/sso/fields.py +++ /dev/null @@ -1,725 +0,0 @@ -import collections -import copy -import inspect -import json -import re - -import six - -# Python LDAP -import ldap -import awx - -# Django -from django.utils.translation import gettext_lazy as _ - -# Django Auth LDAP -import django_auth_ldap.config -from django_auth_ldap.config import LDAPSearch, LDAPSearchUnion - -from rest_framework.exceptions import ValidationError -from rest_framework.fields import empty, Field, SkipField - -# This must be imported so get_subclasses picks it up -from awx.sso.ldap_group_types import PosixUIDGroupType # noqa - -# AWX -from awx.conf import fields -from awx.main.validators import validate_certificate -from awx.sso.validators import ( # noqa - validate_ldap_dn, - validate_ldap_bind_dn, - validate_ldap_dn_with_user, - validate_ldap_filter, - validate_ldap_filter_with_user, - validate_tacacsplus_disallow_nonascii, -) - - -def get_subclasses(cls): - for subclass in cls.__subclasses__(): - for subsubclass in get_subclasses(subclass): - yield subsubclass - yield subclass - - -def find_class_in_modules(class_name): - """ - Used to find ldap subclasses by string - """ - module_search_space = [django_auth_ldap.config, awx.sso.ldap_group_types] - for m in module_search_space: - cls = getattr(m, class_name, None) - if cls: - return cls - return None - - -class DependsOnMixin: - def get_depends_on(self): - """ - Get the value of the dependent field. - First try to find the value in the request. - Then fall back to the raw value from the setting in the DB. - """ - from django.conf import settings - - dependent_key = next(iter(self.depends_on)) - - if self.context: - request = self.context.get('request', None) - if request and request.data and request.data.get(dependent_key, None): - return request.data.get(dependent_key) - res = settings._get_local(dependent_key, validate=False) - return res - - -class _Forbidden(Field): - default_error_messages = {'invalid': _('Invalid field.')} - - def run_validation(self, value): - self.fail('invalid') - - -class HybridDictField(fields.DictField): - """A DictField, but with defined fixed Fields for certain keys.""" - - def __init__(self, *args, **kwargs): - self.allow_blank = kwargs.pop('allow_blank', False) - - fields = [ - sorted( - ((field_name, obj) for field_name, obj in cls.__dict__.items() if isinstance(obj, Field) and field_name != 'child'), - key=lambda x: x[1]._creation_counter, - ) - for cls in reversed(self.__class__.__mro__) - ] - self._declared_fields = collections.OrderedDict(f for group in fields for f in group) - - super().__init__(*args, **kwargs) - - def to_representation(self, value): - fields = copy.deepcopy(self._declared_fields) - return { - key: field.to_representation(val) if val is not None else None - for key, val, field in ((six.text_type(key), val, fields.get(key, self.child)) for key, val in value.items()) - if not field.write_only - } - - def run_child_validation(self, data): - result = {} - - if not data and self.allow_blank: - return result - - errors = collections.OrderedDict() - fields = copy.deepcopy(self._declared_fields) - keys = set(fields.keys()) | set(data.keys()) - - for key in keys: - value = data.get(key, empty) - key = six.text_type(key) - field = fields.get(key, self.child) - try: - if field.read_only: - continue # Ignore read_only fields, as Serializer seems to do. - result[key] = field.run_validation(value) - except ValidationError as e: - errors[key] = e.detail - except SkipField: - pass - - if not errors: - return result - raise ValidationError(errors) - - -class AuthenticationBackendsField(fields.StringListField): - # Mapping of settings that must be set in order to enable each - # authentication backend. - REQUIRED_BACKEND_SETTINGS = collections.OrderedDict( - [ - ('awx.sso.backends.LDAPBackend', ['AUTH_LDAP_SERVER_URI']), - ('awx.sso.backends.LDAPBackend1', ['AUTH_LDAP_1_SERVER_URI']), - ('awx.sso.backends.LDAPBackend2', ['AUTH_LDAP_2_SERVER_URI']), - ('awx.sso.backends.LDAPBackend3', ['AUTH_LDAP_3_SERVER_URI']), - ('awx.sso.backends.LDAPBackend4', ['AUTH_LDAP_4_SERVER_URI']), - ('awx.sso.backends.LDAPBackend5', ['AUTH_LDAP_5_SERVER_URI']), - ('awx.sso.backends.RADIUSBackend', ['RADIUS_SERVER']), - ('social_core.backends.google.GoogleOAuth2', ['SOCIAL_AUTH_GOOGLE_OAUTH2_KEY', 'SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET']), - ('social_core.backends.github.GithubOAuth2', ['SOCIAL_AUTH_GITHUB_KEY', 'SOCIAL_AUTH_GITHUB_SECRET']), - ('social_core.backends.open_id_connect.OpenIdConnectAuth', ['SOCIAL_AUTH_OIDC_KEY', 'SOCIAL_AUTH_OIDC_SECRET', 'SOCIAL_AUTH_OIDC_OIDC_ENDPOINT']), - ( - 'social_core.backends.github.GithubOrganizationOAuth2', - ['SOCIAL_AUTH_GITHUB_ORG_KEY', 'SOCIAL_AUTH_GITHUB_ORG_SECRET', 'SOCIAL_AUTH_GITHUB_ORG_NAME'], - ), - ('social_core.backends.github.GithubTeamOAuth2', ['SOCIAL_AUTH_GITHUB_TEAM_KEY', 'SOCIAL_AUTH_GITHUB_TEAM_SECRET', 'SOCIAL_AUTH_GITHUB_TEAM_ID']), - ( - 'social_core.backends.github_enterprise.GithubEnterpriseOAuth2', - [ - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_URL', - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL', - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_KEY', - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_SECRET', - ], - ), - ( - 'social_core.backends.github_enterprise.GithubEnterpriseOrganizationOAuth2', - [ - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_URL', - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_API_URL', - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_KEY', - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_SECRET', - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_NAME', - ], - ), - ( - 'social_core.backends.github_enterprise.GithubEnterpriseTeamOAuth2', - [ - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_URL', - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_API_URL', - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_KEY', - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_SECRET', - 'SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ID', - ], - ), - ('social_core.backends.azuread.AzureADOAuth2', ['SOCIAL_AUTH_AZUREAD_OAUTH2_KEY', 'SOCIAL_AUTH_AZUREAD_OAUTH2_SECRET']), - ( - 'awx.sso.backends.SAMLAuth', - [ - 'SOCIAL_AUTH_SAML_SP_ENTITY_ID', - 'SOCIAL_AUTH_SAML_SP_PUBLIC_CERT', - 'SOCIAL_AUTH_SAML_SP_PRIVATE_KEY', - 'SOCIAL_AUTH_SAML_ORG_INFO', - 'SOCIAL_AUTH_SAML_TECHNICAL_CONTACT', - 'SOCIAL_AUTH_SAML_SUPPORT_CONTACT', - 'SOCIAL_AUTH_SAML_ENABLED_IDPS', - ], - ), - ('django.contrib.auth.backends.ModelBackend', []), - ('awx.main.backends.AWXModelBackend', []), - ] - ) - - @classmethod - def get_all_required_settings(cls): - all_required_settings = set(['LICENSE']) - for required_settings in cls.REQUIRED_BACKEND_SETTINGS.values(): - all_required_settings.update(required_settings) - return all_required_settings - - def __init__(self, *args, **kwargs): - kwargs.setdefault('default', self._default_from_required_settings) - super(AuthenticationBackendsField, self).__init__(*args, **kwargs) - - def _default_from_required_settings(self): - from django.conf import settings - - try: - backends = settings._awx_conf_settings._get_default('AUTHENTICATION_BACKENDS') - except AttributeError: - backends = self.REQUIRED_BACKEND_SETTINGS.keys() - # Filter which authentication backends are enabled based on their - # required settings being defined and non-empty. - for backend, required_settings in self.REQUIRED_BACKEND_SETTINGS.items(): - if backend not in backends: - continue - if all([getattr(settings, rs, None) for rs in required_settings]): - continue - backends = [x for x in backends if x != backend] - return backends - - -class LDAPServerURIField(fields.URLField): - def __init__(self, **kwargs): - kwargs.setdefault('schemes', ('ldap', 'ldaps')) - kwargs.setdefault('allow_plain_hostname', True) - super(LDAPServerURIField, self).__init__(**kwargs) - - def run_validators(self, value): - for url in filter(None, re.split(r'[, ]', (value or ''))): - super(LDAPServerURIField, self).run_validators(url) - return value - - -class LDAPConnectionOptionsField(fields.DictField): - default_error_messages = {'invalid_options': _('Invalid connection option(s): {invalid_options}.')} - - def to_representation(self, value): - value = value or {} - opt_names = ldap.OPT_NAMES_DICT - # Convert integer options to their named constants. - repr_value = {} - for opt, opt_value in value.items(): - if opt in opt_names: - repr_value[opt_names[opt]] = opt_value - return repr_value - - def to_internal_value(self, data): - data = super(LDAPConnectionOptionsField, self).to_internal_value(data) - valid_options = dict([(v, k) for k, v in ldap.OPT_NAMES_DICT.items()]) - invalid_options = set(data.keys()) - set(valid_options.keys()) - if invalid_options: - invalid_options = sorted(list(invalid_options)) - options_display = json.dumps(invalid_options).lstrip('[').rstrip(']') - self.fail('invalid_options', invalid_options=options_display) - # Convert named options to their integer constants. - internal_data = {} - for opt_name, opt_value in data.items(): - internal_data[valid_options[opt_name]] = opt_value - return internal_data - - -class LDAPDNField(fields.CharField): - def __init__(self, **kwargs): - super(LDAPDNField, self).__init__(**kwargs) - self.validators.append(validate_ldap_dn) - - def run_validation(self, data=empty): - value = super(LDAPDNField, self).run_validation(data) - # django-auth-ldap expects DN fields (like AUTH_LDAP_REQUIRE_GROUP) - # to be either a valid string or ``None`` (not an empty string) - return None if value == '' else value - - -class LDAPDNListField(fields.StringListField): - def __init__(self, **kwargs): - super(LDAPDNListField, self).__init__(**kwargs) - self.validators.append(lambda dn: list(map(validate_ldap_dn, dn))) - - def run_validation(self, data=empty): - if not isinstance(data, (list, tuple)): - data = [data] - return super(LDAPDNListField, self).run_validation(data) - - -class LDAPDNWithUserField(fields.CharField): - def __init__(self, **kwargs): - super(LDAPDNWithUserField, self).__init__(**kwargs) - self.validators.append(validate_ldap_dn_with_user) - - def run_validation(self, data=empty): - value = super(LDAPDNWithUserField, self).run_validation(data) - # django-auth-ldap expects DN fields (like AUTH_LDAP_USER_DN_TEMPLATE) - # to be either a valid string or ``None`` (not an empty string) - return None if value == '' else value - - -class LDAPFilterField(fields.CharField): - def __init__(self, **kwargs): - super(LDAPFilterField, self).__init__(**kwargs) - self.validators.append(validate_ldap_filter) - - -class LDAPFilterWithUserField(fields.CharField): - def __init__(self, **kwargs): - super(LDAPFilterWithUserField, self).__init__(**kwargs) - self.validators.append(validate_ldap_filter_with_user) - - -class LDAPScopeField(fields.ChoiceField): - def __init__(self, choices=None, **kwargs): - choices = choices or [('SCOPE_BASE', _('Base')), ('SCOPE_ONELEVEL', _('One Level')), ('SCOPE_SUBTREE', _('Subtree'))] - super(LDAPScopeField, self).__init__(choices, **kwargs) - - def to_representation(self, value): - for choice in self.choices.keys(): - if value == getattr(ldap, choice): - return choice - return super(LDAPScopeField, self).to_representation(value) - - def to_internal_value(self, data): - value = super(LDAPScopeField, self).to_internal_value(data) - return getattr(ldap, value) - - -class LDAPSearchField(fields.ListField): - default_error_messages = { - 'invalid_length': _('Expected a list of three items but got {length} instead.'), - 'type_error': _('Expected an instance of LDAPSearch but got {input_type} instead.'), - } - ldap_filter_field_class = LDAPFilterField - - def to_representation(self, value): - if not value: - return [] - if not isinstance(value, LDAPSearch): - self.fail('type_error', input_type=type(value)) - return [ - LDAPDNField().to_representation(value.base_dn), - LDAPScopeField().to_representation(value.scope), - self.ldap_filter_field_class().to_representation(value.filterstr), - ] - - def to_internal_value(self, data): - data = super(LDAPSearchField, self).to_internal_value(data) - if len(data) == 0: - return None - if len(data) != 3: - self.fail('invalid_length', length=len(data)) - return LDAPSearch( - LDAPDNField().run_validation(data[0]), LDAPScopeField().run_validation(data[1]), self.ldap_filter_field_class().run_validation(data[2]) - ) - - -class LDAPSearchWithUserField(LDAPSearchField): - ldap_filter_field_class = LDAPFilterWithUserField - - -class LDAPSearchUnionField(fields.ListField): - default_error_messages = {'type_error': _('Expected an instance of LDAPSearch or LDAPSearchUnion but got {input_type} instead.')} - ldap_search_field_class = LDAPSearchWithUserField - - def to_representation(self, value): - if not value: - return [] - elif isinstance(value, LDAPSearchUnion): - return [self.ldap_search_field_class().to_representation(s) for s in value.searches] - elif isinstance(value, LDAPSearch): - return self.ldap_search_field_class().to_representation(value) - else: - self.fail('type_error', input_type=type(value)) - - def to_internal_value(self, data): - data = super(LDAPSearchUnionField, self).to_internal_value(data) - if len(data) == 0: - return None - if len(data) == 3 and isinstance(data[0], str): - return self.ldap_search_field_class().run_validation(data) - else: - search_args = [] - for i in range(len(data)): - if not isinstance(data[i], list): - raise ValidationError('In order to ultilize LDAP Union, input element No. %d' ' should be a search query array.' % (i + 1)) - try: - search_args.append(self.ldap_search_field_class().run_validation(data[i])) - except Exception as e: - if hasattr(e, 'detail') and isinstance(e.detail, list): - e.detail.insert(0, "Error parsing LDAP Union element No. %d:" % (i + 1)) - raise e - return LDAPSearchUnion(*search_args) - - -class LDAPUserAttrMapField(fields.DictField): - default_error_messages = {'invalid_attrs': _('Invalid user attribute(s): {invalid_attrs}.')} - valid_user_attrs = {'first_name', 'last_name', 'email'} - child = fields.CharField() - - def to_internal_value(self, data): - data = super(LDAPUserAttrMapField, self).to_internal_value(data) - invalid_attrs = set(data.keys()) - self.valid_user_attrs - if invalid_attrs: - invalid_attrs = sorted(list(invalid_attrs)) - attrs_display = json.dumps(invalid_attrs).lstrip('[').rstrip(']') - self.fail('invalid_attrs', invalid_attrs=attrs_display) - return data - - -class LDAPGroupTypeField(fields.ChoiceField, DependsOnMixin): - default_error_messages = { - 'type_error': _('Expected an instance of LDAPGroupType but got {input_type} instead.'), - 'missing_parameters': _('Missing required parameters in {dependency}.'), - 'invalid_parameters': _('Invalid group_type parameters. Expected instance of dict but got {parameters_type} instead.'), - } - - def __init__(self, choices=None, **kwargs): - group_types = get_subclasses(django_auth_ldap.config.LDAPGroupType) - choices = choices or [(x.__name__, x.__name__) for x in group_types] - super(LDAPGroupTypeField, self).__init__(choices, **kwargs) - - def to_representation(self, value): - if not value: - return 'MemberDNGroupType' - if not isinstance(value, django_auth_ldap.config.LDAPGroupType): - self.fail('type_error', input_type=type(value)) - return value.__class__.__name__ - - def to_internal_value(self, data): - data = super(LDAPGroupTypeField, self).to_internal_value(data) - if not data: - return None - - cls = find_class_in_modules(data) - if not cls: - return None - - # Per-group type parameter validation and handling here - - # Backwords compatability. Before AUTH_LDAP_GROUP_TYPE_PARAMS existed - # MemberDNGroupType was the only group type, of the underlying lib, that - # took a parameter. - params = self.get_depends_on() or {} - params_sanitized = dict() - - cls_args = inspect.getfullargspec(cls.__init__).args[1:] - - if cls_args: - if not isinstance(params, dict): - self.fail('invalid_parameters', parameters_type=type(params)) - - for attr in cls_args: - if attr in params: - params_sanitized[attr] = params[attr] - - try: - return cls(**params_sanitized) - except TypeError: - self.fail('missing_parameters', dependency=list(self.depends_on)[0]) - - -class LDAPGroupTypeParamsField(fields.DictField, DependsOnMixin): - default_error_messages = {'invalid_keys': _('Invalid key(s): {invalid_keys}.')} - - def to_internal_value(self, value): - value = super(LDAPGroupTypeParamsField, self).to_internal_value(value) - if not value: - return value - group_type_str = self.get_depends_on() - group_type_str = group_type_str or '' - - group_type_cls = find_class_in_modules(group_type_str) - if not group_type_cls: - # Fail safe - return {} - - invalid_keys = set(value.keys()) - set(inspect.getfullargspec(group_type_cls.__init__).args[1:]) - if invalid_keys: - invalid_keys = sorted(list(invalid_keys)) - keys_display = json.dumps(invalid_keys).lstrip('[').rstrip(']') - self.fail('invalid_keys', invalid_keys=keys_display) - return value - - -class LDAPUserFlagsField(fields.DictField): - default_error_messages = {'invalid_flag': _('Invalid user flag: "{invalid_flag}".')} - valid_user_flags = {'is_superuser', 'is_system_auditor'} - child = LDAPDNListField() - - def to_internal_value(self, data): - data = super(LDAPUserFlagsField, self).to_internal_value(data) - invalid_flags = set(data.keys()) - self.valid_user_flags - if invalid_flags: - self.fail('invalid_flag', invalid_flag=list(invalid_flags)[0]) - return data - - -class LDAPDNMapField(fields.StringListBooleanField): - child = LDAPDNField() - - -class LDAPSingleOrganizationMapField(HybridDictField): - admins = LDAPDNMapField(allow_null=True, required=False) - users = LDAPDNMapField(allow_null=True, required=False) - auditors = LDAPDNMapField(allow_null=True, required=False) - remove_admins = fields.BooleanField(required=False) - remove_users = fields.BooleanField(required=False) - remove_auditors = fields.BooleanField(required=False) - - child = _Forbidden() - - -class LDAPOrganizationMapField(fields.DictField): - child = LDAPSingleOrganizationMapField() - - -class LDAPSingleTeamMapField(HybridDictField): - organization = fields.CharField() - users = LDAPDNMapField(allow_null=True, required=False) - remove = fields.BooleanField(required=False) - - child = _Forbidden() - - -class LDAPTeamMapField(fields.DictField): - child = LDAPSingleTeamMapField() - - -class SocialMapStringRegexField(fields.CharField): - def to_representation(self, value): - if isinstance(value, type(re.compile(''))): - flags = [] - if value.flags & re.I: - flags.append('i') - if value.flags & re.M: - flags.append('m') - return '/{}/{}'.format(value.pattern, ''.join(flags)) - else: - return super(SocialMapStringRegexField, self).to_representation(value) - - def to_internal_value(self, data): - data = super(SocialMapStringRegexField, self).to_internal_value(data) - match = re.match(r'^/(?P.*)/(?P[im]+)?$', data) - if match: - flags = 0 - if match.group('flags'): - if 'i' in match.group('flags'): - flags |= re.I - if 'm' in match.group('flags'): - flags |= re.M - try: - return re.compile(match.group('pattern'), flags) - except re.error as e: - raise ValidationError('{}: {}'.format(e, data)) - return data - - -class SocialMapField(fields.ListField): - default_error_messages = {'type_error': _('Expected None, True, False, a string or list of strings but got {input_type} instead.')} - child = SocialMapStringRegexField() - - def to_representation(self, value): - if isinstance(value, (list, tuple)): - return super(SocialMapField, self).to_representation(value) - elif value in fields.BooleanField.TRUE_VALUES: - return True - elif value in fields.BooleanField.FALSE_VALUES: - return False - elif value in fields.BooleanField.NULL_VALUES: - return None - elif isinstance(value, (str, type(re.compile('')))): - return self.child.to_representation(value) - else: - self.fail('type_error', input_type=type(value)) - - def to_internal_value(self, data): - if isinstance(data, (list, tuple)): - return super(SocialMapField, self).to_internal_value(data) - elif data in fields.BooleanField.TRUE_VALUES: - return True - elif data in fields.BooleanField.FALSE_VALUES: - return False - elif data in fields.BooleanField.NULL_VALUES: - return None - elif isinstance(data, str): - return self.child.run_validation(data) - else: - self.fail('type_error', input_type=type(data)) - - -class SocialSingleOrganizationMapField(HybridDictField): - admins = SocialMapField(allow_null=True, required=False) - users = SocialMapField(allow_null=True, required=False) - remove_admins = fields.BooleanField(required=False) - remove_users = fields.BooleanField(required=False) - organization_alias = SocialMapField(allow_null=True, required=False) - - child = _Forbidden() - - -class SocialOrganizationMapField(fields.DictField): - child = SocialSingleOrganizationMapField() - - -class SocialSingleTeamMapField(HybridDictField): - organization = fields.CharField() - users = SocialMapField(allow_null=True, required=False) - remove = fields.BooleanField(required=False) - - child = _Forbidden() - - -class SocialTeamMapField(fields.DictField): - child = SocialSingleTeamMapField() - - -class SAMLOrgInfoValueField(HybridDictField): - name = fields.CharField() - displayname = fields.CharField() - url = fields.URLField() - - -class SAMLOrgInfoField(fields.DictField): - default_error_messages = {'invalid_lang_code': _('Invalid language code(s) for org info: {invalid_lang_codes}.')} - child = SAMLOrgInfoValueField() - - def to_internal_value(self, data): - data = super(SAMLOrgInfoField, self).to_internal_value(data) - invalid_keys = set() - for key in data.keys(): - if not re.match(r'^[a-z]{2}(?:-[a-z]{2})??$', key, re.I): - invalid_keys.add(key) - if invalid_keys: - invalid_keys = sorted(list(invalid_keys)) - keys_display = json.dumps(invalid_keys).lstrip('[').rstrip(']') - self.fail('invalid_lang_code', invalid_lang_codes=keys_display) - return data - - -class SAMLContactField(HybridDictField): - givenName = fields.CharField() - emailAddress = fields.EmailField() - - -class SAMLIdPField(HybridDictField): - entity_id = fields.CharField() - url = fields.URLField() - x509cert = fields.CharField(validators=[validate_certificate]) - attr_user_permanent_id = fields.CharField(required=False) - attr_first_name = fields.CharField(required=False) - attr_last_name = fields.CharField(required=False) - attr_username = fields.CharField(required=False) - attr_email = fields.CharField(required=False) - - -class SAMLEnabledIdPsField(fields.DictField): - child = SAMLIdPField() - - -class SAMLSecurityField(HybridDictField): - nameIdEncrypted = fields.BooleanField(required=False) - authnRequestsSigned = fields.BooleanField(required=False) - logoutRequestSigned = fields.BooleanField(required=False) - logoutResponseSigned = fields.BooleanField(required=False) - signMetadata = fields.BooleanField(required=False) - wantMessagesSigned = fields.BooleanField(required=False) - wantAssertionsSigned = fields.BooleanField(required=False) - wantAssertionsEncrypted = fields.BooleanField(required=False) - wantNameId = fields.BooleanField(required=False) - wantNameIdEncrypted = fields.BooleanField(required=False) - wantAttributeStatement = fields.BooleanField(required=False) - requestedAuthnContext = fields.StringListBooleanField(required=False) - requestedAuthnContextComparison = fields.CharField(required=False) - metadataValidUntil = fields.CharField(allow_null=True, required=False) - metadataCacheDuration = fields.CharField(allow_null=True, required=False) - signatureAlgorithm = fields.CharField(allow_null=True, required=False) - digestAlgorithm = fields.CharField(allow_null=True, required=False) - - -class SAMLOrgAttrField(HybridDictField): - remove = fields.BooleanField(required=False) - saml_attr = fields.CharField(required=False, allow_null=True) - remove_admins = fields.BooleanField(required=False) - saml_admin_attr = fields.CharField(required=False, allow_null=True) - remove_auditors = fields.BooleanField(required=False) - saml_auditor_attr = fields.CharField(required=False, allow_null=True) - - child = _Forbidden() - - -class SAMLTeamAttrTeamOrgMapField(HybridDictField): - team = fields.CharField(required=True, allow_null=False) - team_alias = fields.CharField(required=False, allow_null=True) - organization = fields.CharField(required=True, allow_null=False) - - child = _Forbidden() - - -class SAMLTeamAttrField(HybridDictField): - team_org_map = fields.ListField(required=False, child=SAMLTeamAttrTeamOrgMapField(), allow_null=True) - remove = fields.BooleanField(required=False) - saml_attr = fields.CharField(required=False, allow_null=True) - - child = _Forbidden() - - -class SAMLUserFlagsAttrField(HybridDictField): - is_superuser_attr = fields.CharField(required=False, allow_null=True) - is_superuser_value = fields.StringListField(required=False, allow_null=True) - is_superuser_role = fields.StringListField(required=False, allow_null=True) - remove_superusers = fields.BooleanField(required=False, allow_null=True) - is_system_auditor_attr = fields.CharField(required=False, allow_null=True) - is_system_auditor_value = fields.StringListField(required=False, allow_null=True) - is_system_auditor_role = fields.StringListField(required=False, allow_null=True) - remove_system_auditors = fields.BooleanField(required=False, allow_null=True) - - child = _Forbidden() diff --git a/awx/sso/ldap_group_types.py b/awx/sso/ldap_group_types.py deleted file mode 100644 index 2a5434c15440..000000000000 --- a/awx/sso/ldap_group_types.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright (c) 2018 Ansible by Red Hat -# All Rights Reserved. - -# Python -import ldap - -# Django -from django.utils.encoding import force_str - -# 3rd party -from django_auth_ldap.config import LDAPGroupType - - -class PosixUIDGroupType(LDAPGroupType): - def __init__(self, name_attr='cn', ldap_group_user_attr='uid'): - self.ldap_group_user_attr = ldap_group_user_attr - super(PosixUIDGroupType, self).__init__(name_attr) - - """ - An LDAPGroupType subclass that handles non-standard DS. - """ - - def user_groups(self, ldap_user, group_search): - """ - Searches for any group that is either the user's primary or contains the - user as a member. - """ - groups = [] - - try: - user_uid = ldap_user.attrs[self.ldap_group_user_attr][0] - - if 'gidNumber' in ldap_user.attrs: - user_gid = ldap_user.attrs['gidNumber'][0] - filterstr = u'(|(gidNumber=%s)(memberUid=%s))' % ( - self.ldap.filter.escape_filter_chars(user_gid), - self.ldap.filter.escape_filter_chars(user_uid), - ) - else: - filterstr = u'(memberUid=%s)' % (self.ldap.filter.escape_filter_chars(user_uid),) - - search = group_search.search_with_additional_term_string(filterstr) - search.attrlist = [str(self.name_attr)] - groups = search.execute(ldap_user.connection) - except (KeyError, IndexError): - pass - - return groups - - def is_member(self, ldap_user, group_dn): - """ - Returns True if the group is the user's primary group or if the user is - listed in the group's memberUid attribute. - """ - is_member = False - try: - user_uid = ldap_user.attrs[self.ldap_group_user_attr][0] - - try: - is_member = ldap_user.connection.compare_s(force_str(group_dn), 'memberUid', force_str(user_uid)) - except (ldap.UNDEFINED_TYPE, ldap.NO_SUCH_ATTRIBUTE): - is_member = False - - if not is_member: - try: - user_gid = ldap_user.attrs['gidNumber'][0] - is_member = ldap_user.connection.compare_s(force_str(group_dn), 'gidNumber', force_str(user_gid)) - except (ldap.UNDEFINED_TYPE, ldap.NO_SUCH_ATTRIBUTE): - is_member = False - except (KeyError, IndexError): - is_member = False - - return is_member diff --git a/awx/sso/middleware.py b/awx/sso/middleware.py deleted file mode 100644 index f8b2b7974167..000000000000 --- a/awx/sso/middleware.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright (c) 2015 Ansible, Inc. -# All Rights Reserved. - -# Python -import urllib.parse - -# Django -from django.conf import settings -from django.utils.functional import LazyObject -from django.shortcuts import redirect - -# Python Social Auth -from social_core.exceptions import SocialAuthBaseException -from social_core.utils import social_logger -from social_django import utils -from social_django.middleware import SocialAuthExceptionMiddleware - - -class SocialAuthMiddleware(SocialAuthExceptionMiddleware): - def process_request(self, request): - if request.path.startswith('/sso'): - # See upgrade blocker note in requirements/README.md - utils.BACKENDS = settings.AUTHENTICATION_BACKENDS - token_key = request.COOKIES.get('token', '') - token_key = urllib.parse.quote(urllib.parse.unquote(token_key).strip('"')) - - if not hasattr(request, 'successful_authenticator'): - request.successful_authenticator = None - - if not request.path.startswith('/sso/') and 'migrations_notran' not in request.path: - if request.user and request.user.is_authenticated: - # The rest of the code base rely hevily on type/inheritance checks, - # LazyObject sent from Django auth middleware can be buggy if not - # converted back to its original object. - if isinstance(request.user, LazyObject) and request.user._wrapped: - request.user = request.user._wrapped - request.session.pop('social_auth_error', None) - request.session.pop('social_auth_last_backend', None) - return self.get_response(request) - - def process_view(self, request, callback, callback_args, callback_kwargs): - if request.path.startswith('/sso/login/'): - request.session['social_auth_last_backend'] = callback_kwargs['backend'] - - def process_exception(self, request, exception): - strategy = getattr(request, 'social_strategy', None) - if strategy is None or self.raise_exception(request, exception): - return - - if isinstance(exception, SocialAuthBaseException) or request.path.startswith('/sso/'): - backend = getattr(request, 'backend', None) - backend_name = getattr(backend, 'name', 'unknown-backend') - - message = self.get_message(request, exception) - if request.session.get('social_auth_last_backend') != backend_name: - backend_name = request.session.get('social_auth_last_backend') - message = request.GET.get('error_description', message) - - full_backend_name = backend_name - try: - idp_name = strategy.request_data()['RelayState'] - full_backend_name = '%s:%s' % (backend_name, idp_name) - except KeyError: - pass - - social_logger.error(message) - - url = self.get_redirect_uri(request, exception) - request.session['social_auth_error'] = (full_backend_name, message) - return redirect(url) - - def get_message(self, request, exception): - msg = str(exception) - if msg and msg[-1] not in '.?!': - msg = msg + '.' - return msg - - def get_redirect_uri(self, request, exception): - strategy = getattr(request, 'social_strategy', None) - return strategy.session_get('next', '') or strategy.setting('LOGIN_ERROR_URL') diff --git a/awx/sso/migrations/0001_initial.py b/awx/sso/migrations/0001_initial.py deleted file mode 100644 index d759e22437b5..000000000000 --- a/awx/sso/migrations/0001_initial.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import migrations, models -from django.conf import settings - - -class Migration(migrations.Migration): - dependencies = [migrations.swappable_dependency(settings.AUTH_USER_MODEL)] - - operations = [ - migrations.CreateModel( - name='UserEnterpriseAuth', - fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('provider', models.CharField(max_length=32, choices=[(b'radius', 'RADIUS'), (b'tacacs+', 'TACACS+')])), - ('user', models.ForeignKey(related_name='enterprise_auth', on_delete=models.CASCADE, to=settings.AUTH_USER_MODEL)), - ], - ), - migrations.AlterUniqueTogether(name='userenterpriseauth', unique_together=set([('user', 'provider')])), - ] diff --git a/awx/sso/migrations/0002_expand_provider_options.py b/awx/sso/migrations/0002_expand_provider_options.py deleted file mode 100644 index 68f877717f2f..000000000000 --- a/awx/sso/migrations/0002_expand_provider_options.py +++ /dev/null @@ -1,16 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [('sso', '0001_initial')] - - operations = [ - migrations.AlterField( - model_name='userenterpriseauth', - name='provider', - field=models.CharField(max_length=32, choices=[('radius', 'RADIUS'), ('tacacs+', 'TACACS+'), ('saml', 'SAML')]), - ) - ] diff --git a/awx/sso/migrations/0003_convert_saml_string_to_list.py b/awx/sso/migrations/0003_convert_saml_string_to_list.py deleted file mode 100644 index bacc25e3c00f..000000000000 --- a/awx/sso/migrations/0003_convert_saml_string_to_list.py +++ /dev/null @@ -1,58 +0,0 @@ -from django.db import migrations, connection -import json - -_values_to_change = ['is_superuser_value', 'is_superuser_role', 'is_system_auditor_value', 'is_system_auditor_role'] - - -def _get_setting(): - with connection.cursor() as cursor: - cursor.execute('SELECT value FROM conf_setting WHERE key= %s', ['SOCIAL_AUTH_SAML_USER_FLAGS_BY_ATTR']) - row = cursor.fetchone() - if row == None: - return {} - existing_setting = row[0] - - try: - existing_json = json.loads(existing_setting) - except json.decoder.JSONDecodeError as e: - print("Failed to decode existing json setting:") - print(existing_setting) - raise e - - return existing_json - - -def _set_setting(value): - with connection.cursor() as cursor: - cursor.execute('UPDATE conf_setting SET value = %s WHERE key = %s', [json.dumps(value), 'SOCIAL_AUTH_SAML_USER_FLAGS_BY_ATTR']) - - -def forwards(app, schema_editor): - # The Operation should use schema_editor to apply any changes it - # wants to make to the database. - existing_json = _get_setting() - for key in _values_to_change: - if existing_json.get(key, None) and isinstance(existing_json.get(key), str): - existing_json[key] = [existing_json.get(key)] - _set_setting(existing_json) - - -def backwards(app, schema_editor): - existing_json = _get_setting() - for key in _values_to_change: - if existing_json.get(key, None) and not isinstance(existing_json.get(key), str): - try: - existing_json[key] = existing_json.get(key).pop() - except IndexError: - existing_json[key] = "" - _set_setting(existing_json) - - -class Migration(migrations.Migration): - dependencies = [ - ('sso', '0002_expand_provider_options'), - ] - - operations = [ - migrations.RunPython(forwards, backwards), - ] diff --git a/awx/sso/models.py b/awx/sso/models.py deleted file mode 100644 index 28eb23857f4b..000000000000 --- a/awx/sso/models.py +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright (c) 2015 Ansible, Inc. -# All Rights Reserved. - -# Django -from django.db import models -from django.contrib.auth.models import User -from django.utils.translation import gettext_lazy as _ - - -class UserEnterpriseAuth(models.Model): - """Enterprise Auth association model""" - - PROVIDER_CHOICES = (('radius', _('RADIUS')), ('tacacs+', _('TACACS+')), ('saml', _('SAML'))) - - class Meta: - unique_together = ('user', 'provider') - - user = models.ForeignKey(User, related_name='enterprise_auth', on_delete=models.CASCADE) - provider = models.CharField(max_length=32, choices=PROVIDER_CHOICES) diff --git a/awx/sso/saml_pipeline.py b/awx/sso/saml_pipeline.py deleted file mode 100644 index e8c4f9ff6d8c..000000000000 --- a/awx/sso/saml_pipeline.py +++ /dev/null @@ -1,291 +0,0 @@ -# Copyright (c) 2015 Ansible, Inc. -# All Rights Reserved. - -# Python -import re -import logging - -# Django -from django.conf import settings - -from awx.main.models import Team -from awx.sso.common import create_org_and_teams, reconcile_users_org_team_mappings, get_orgs_by_ids - -logger = logging.getLogger('awx.sso.saml_pipeline') - - -def populate_user(backend, details, user=None, *args, **kwargs): - if not user: - return - - # Build the in-memory settings for how this user should be modeled - desired_org_state = {} - desired_team_state = {} - orgs_to_create = [] - teams_to_create = {} - _update_user_orgs_by_saml_attr(backend, desired_org_state, orgs_to_create, **kwargs) - _update_user_teams_by_saml_attr(desired_team_state, teams_to_create, **kwargs) - _update_user_orgs(backend, desired_org_state, orgs_to_create, user) - _update_user_teams(backend, desired_team_state, teams_to_create, user) - - # If the SAML adapter is allowed to create objects, lets do that first - create_org_and_teams(orgs_to_create, teams_to_create, 'SAML', settings.SAML_AUTO_CREATE_OBJECTS) - - # Finally reconcile the user - reconcile_users_org_team_mappings(user, desired_org_state, desired_team_state, 'SAML') - - -def _update_m2m_from_expression(user, expr, remove=True): - """ - Helper function to update m2m relationship based on user matching one or - more expressions. - """ - should_add = False - if expr is None or not expr: - pass - elif expr is True: - should_add = True - else: - if isinstance(expr, (str, type(re.compile('')))): - expr = [expr] - for ex in expr: - if isinstance(ex, str): - if user.username == ex or user.email == ex: - should_add = True - elif isinstance(ex, type(re.compile(''))): - if ex.match(user.username) or ex.match(user.email): - should_add = True - if should_add: - return True - elif remove: - return False - else: - return None - - -def _update_user_orgs(backend, desired_org_state, orgs_to_create, user=None): - """ - Update organization memberships for the given user based on mapping rules - defined in settings. - """ - org_map = backend.setting('ORGANIZATION_MAP') or {} - for org_name, org_opts in org_map.items(): - organization_alias = org_opts.get('organization_alias') - if organization_alias: - organization_name = organization_alias - else: - organization_name = org_name - if organization_name not in orgs_to_create: - orgs_to_create.append(organization_name) - - remove = bool(org_opts.get('remove', True)) - - if organization_name not in desired_org_state: - desired_org_state[organization_name] = {} - - for role_name, user_type in (('admin_role', 'admins'), ('member_role', 'users'), ('auditor_role', 'auditors')): - is_member_expression = org_opts.get(user_type, None) - remove_members = bool(org_opts.get('remove_{}'.format(user_type), remove)) - has_role = _update_m2m_from_expression(user, is_member_expression, remove_members) - desired_org_state[organization_name][role_name] = has_role - - -def _update_user_teams(backend, desired_team_state, teams_to_create, user=None): - """ - Update team memberships for the given user based on mapping rules defined - in settings. - """ - - team_map = backend.setting('TEAM_MAP') or {} - for team_name, team_opts in team_map.items(): - # Get or create the org to update. - if 'organization' not in team_opts: - continue - teams_to_create[team_name] = team_opts['organization'] - users_expr = team_opts.get('users', None) - remove = bool(team_opts.get('remove', True)) - add_or_remove = _update_m2m_from_expression(user, users_expr, remove) - if add_or_remove is not None: - org_name = team_opts['organization'] - if org_name not in desired_team_state: - desired_team_state[org_name] = {} - desired_team_state[org_name][team_name] = {'member_role': add_or_remove} - - -def _update_user_orgs_by_saml_attr(backend, desired_org_state, orgs_to_create, **kwargs): - org_map = settings.SOCIAL_AUTH_SAML_ORGANIZATION_ATTR - roles_and_flags = ( - ('member_role', 'remove', 'saml_attr'), - ('admin_role', 'remove_admins', 'saml_admin_attr'), - ('auditor_role', 'remove_auditors', 'saml_auditor_attr'), - ) - - # If the remove_flag was present we need to load all of the orgs and remove the user from the role - all_orgs = None - for role, remove_flag, _ in roles_and_flags: - remove = bool(org_map.get(remove_flag, True)) - if remove: - # Only get the all orgs once, and only if needed - if all_orgs is None: - all_orgs = get_orgs_by_ids() - for org_name in all_orgs.keys(): - if org_name not in desired_org_state: - desired_org_state[org_name] = {} - desired_org_state[org_name][role] = False - - # Now we can add the user as a member/admin/auditor for any orgs they have specified - for role, _, attr_flag in roles_and_flags: - if org_map.get(attr_flag) is None: - continue - saml_attr_values = kwargs.get('response', {}).get('attributes', {}).get(org_map.get(attr_flag), []) - for org_name in saml_attr_values: - try: - organization_alias = backend.setting('ORGANIZATION_MAP').get(org_name).get('organization_alias') - if organization_alias is not None: - organization_name = organization_alias - else: - organization_name = org_name - except Exception: - organization_name = org_name - if organization_name not in orgs_to_create: - orgs_to_create.append(organization_name) - if organization_name not in desired_org_state: - desired_org_state[organization_name] = {} - desired_org_state[organization_name][role] = True - - -def _update_user_teams_by_saml_attr(desired_team_state, teams_to_create, **kwargs): - # - # Map users into organizations based on SOCIAL_AUTH_SAML_TEAM_ATTR setting - # - team_map = settings.SOCIAL_AUTH_SAML_TEAM_ATTR - if team_map.get('saml_attr') is None: - return - - all_teams = None - # The role and flag is hard coded here but intended to be flexible in case we ever wanted to add another team type - for role, remove_flag in [('member_role', 'remove')]: - remove = bool(team_map.get(remove_flag, True)) - if remove: - # Only get the all orgs once, and only if needed - if all_teams is None: - all_teams = Team.objects.all().values_list('name', 'organization__name') - for team_name, organization_name in all_teams: - if organization_name not in desired_team_state: - desired_team_state[organization_name] = {} - desired_team_state[organization_name][team_name] = {role: False} - - saml_team_names = set(kwargs.get('response', {}).get('attributes', {}).get(team_map['saml_attr'], [])) - - for team_name_map in team_map.get('team_org_map', []): - team_name = team_name_map.get('team', None) - team_alias = team_name_map.get('team_alias', None) - organization_name = team_name_map.get('organization', None) - if team_name in saml_team_names: - if not organization_name: - # Settings field validation should prevent this. - logger.error("organization name invalid for team {}".format(team_name)) - continue - - if team_alias: - team_name = team_alias - - teams_to_create[team_name] = organization_name - user_is_member_of_team = True - else: - user_is_member_of_team = False - - if organization_name not in desired_team_state: - desired_team_state[organization_name] = {} - desired_team_state[organization_name][team_name] = {'member_role': user_is_member_of_team} - - -def _get_matches(list1, list2): - # Because we are just doing an intersection here we don't really care which list is in which parameter - - # A SAML provider could return either a string or a list of items so we need to coerce the SAML value into a list (if needed) - if not isinstance(list1, (list, tuple)): - list1 = [list1] - - # In addition, we used to allow strings in the SAML config instead of Lists. The migration should take case of that but just in case, we will convert our list too - if not isinstance(list2, (list, tuple)): - list2 = [list2] - - return set(list1).intersection(set(list2)) - - -def _check_flag(user, flag, attributes, user_flags_settings): - ''' - Helper function to set the is_superuser is_system_auditor flags for the SAML adapter - Returns the new flag and whether or not it changed the flag - ''' - new_flag = False - is_role_key = "is_%s_role" % (flag) - is_attr_key = "is_%s_attr" % (flag) - is_value_key = "is_%s_value" % (flag) - remove_setting = "remove_%ss" % (flag) - - # Check to see if we are respecting a role and, if so, does our user have that role? - required_roles = user_flags_settings.get(is_role_key, None) - if required_roles: - matching_roles = _get_matches(required_roles, attributes.get('Role', [])) - - # We do a 2 layer check here so that we don't spit out the else message if there is no role defined - if matching_roles: - logger.debug("User %s has %s role(s) %s" % (user.username, flag, ', '.join(matching_roles))) - new_flag = True - else: - logger.debug("User %s is missing the %s role(s) %s" % (user.username, flag, ', '.join(required_roles))) - - # Next, check to see if we are respecting an attribute; this will take priority over the role if its defined - attr_setting = user_flags_settings.get(is_attr_key, None) - if attr_setting and attributes.get(attr_setting, None): - # Do we have a required value for the attribute - required_value = user_flags_settings.get(is_value_key, None) - if required_value: - # If so, check and see if the value of the attr matches the required value - saml_user_attribute_value = attributes.get(attr_setting, None) - matching_values = _get_matches(required_value, saml_user_attribute_value) - - if matching_values: - logger.debug("Giving %s %s from attribute %s with matching values %s" % (user.username, flag, attr_setting, ', '.join(matching_values))) - new_flag = True - # if they don't match make sure that new_flag is false - else: - logger.debug( - "Refusing %s for %s because attr %s (%s) did not match value(s) %s" - % (flag, user.username, attr_setting, ", ".join(saml_user_attribute_value), ', '.join(required_value)) - ) - new_flag = False - # If there was no required value then we can just allow them in because of the attribute - else: - logger.debug("Giving %s %s from attribute %s" % (user.username, flag, attr_setting)) - new_flag = True - - # Get the users old flag - old_value = getattr(user, "is_%s" % (flag)) - - # If we are not removing the flag and they were a system admin and now we don't want them to be just return - remove_flag = user_flags_settings.get(remove_setting, True) - if not remove_flag and (old_value and not new_flag): - logger.debug("Remove flag %s preventing removal of %s for %s" % (remove_flag, flag, user.username)) - return old_value, False - - # If the user was flagged and we are going to make them not flagged make sure there is a message - if old_value and not new_flag: - logger.debug("Revoking %s from %s" % (flag, user.username)) - - return new_flag, old_value != new_flag - - -def update_user_flags(backend, details, user=None, *args, **kwargs): - user_flags_settings = settings.SOCIAL_AUTH_SAML_USER_FLAGS_BY_ATTR - - attributes = kwargs.get('response', {}).get('attributes', {}) - logger.debug("User attributes for %s: %s" % (user.username, attributes)) - - user.is_superuser, superuser_changed = _check_flag(user, 'superuser', attributes, user_flags_settings) - user.is_system_auditor, auditor_changed = _check_flag(user, 'system_auditor', attributes, user_flags_settings) - - if superuser_changed or auditor_changed: - user.save() diff --git a/awx/sso/social_base_pipeline.py b/awx/sso/social_base_pipeline.py deleted file mode 100644 index ccdaf1d20079..000000000000 --- a/awx/sso/social_base_pipeline.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright (c) 2015 Ansible, Inc. -# All Rights Reserved. - -# Python Social Auth -from social_core.exceptions import AuthException - -# Django -from django.utils.translation import gettext_lazy as _ - - -class AuthNotFound(AuthException): - def __init__(self, backend, email_or_uid, *args, **kwargs): - self.email_or_uid = email_or_uid - super(AuthNotFound, self).__init__(backend, *args, **kwargs) - - def __str__(self): - return _('An account cannot be found for {0}').format(self.email_or_uid) - - -class AuthInactive(AuthException): - def __str__(self): - return _('Your account is inactive') - - -def check_user_found_or_created(backend, details, user=None, *args, **kwargs): - if not user: - email_or_uid = details.get('email') or kwargs.get('email') or kwargs.get('uid') or '???' - raise AuthNotFound(backend, email_or_uid) - - -def set_is_active_for_new_user(strategy, details, user=None, *args, **kwargs): - if kwargs.get('is_new', False): - details['is_active'] = True - return {'details': details} - - -def prevent_inactive_login(backend, details, user=None, *args, **kwargs): - if user and not user.is_active: - raise AuthInactive(backend) diff --git a/awx/sso/social_pipeline.py b/awx/sso/social_pipeline.py deleted file mode 100644 index b4fb4c1fe323..000000000000 --- a/awx/sso/social_pipeline.py +++ /dev/null @@ -1,90 +0,0 @@ -# Copyright (c) 2015 Ansible, Inc. -# All Rights Reserved. - -# Python -import re -import logging - -from awx.sso.common import get_or_create_org_with_default_galaxy_cred - -logger = logging.getLogger('awx.sso.social_pipeline') - - -def _update_m2m_from_expression(user, related, expr, remove=True): - """ - Helper function to update m2m relationship based on user matching one or - more expressions. - """ - should_add = False - if expr is None: - return - elif not expr: - pass - elif expr is True: - should_add = True - else: - if isinstance(expr, (str, type(re.compile('')))): - expr = [expr] - for ex in expr: - if isinstance(ex, str): - if user.username == ex or user.email == ex: - should_add = True - elif isinstance(ex, type(re.compile(''))): - if ex.match(user.username) or ex.match(user.email): - should_add = True - if should_add: - related.add(user) - elif remove: - related.remove(user) - - -def update_user_orgs(backend, details, user=None, *args, **kwargs): - """ - Update organization memberships for the given user based on mapping rules - defined in settings. - """ - if not user: - return - - org_map = backend.setting('ORGANIZATION_MAP') or {} - for org_name, org_opts in org_map.items(): - organization_alias = org_opts.get('organization_alias') - if organization_alias: - organization_name = organization_alias - else: - organization_name = org_name - org = get_or_create_org_with_default_galaxy_cred(name=organization_name) - - # Update org admins from expression(s). - remove = bool(org_opts.get('remove', True)) - admins_expr = org_opts.get('admins', None) - remove_admins = bool(org_opts.get('remove_admins', remove)) - _update_m2m_from_expression(user, org.admin_role.members, admins_expr, remove_admins) - - # Update org users from expression(s). - users_expr = org_opts.get('users', None) - remove_users = bool(org_opts.get('remove_users', remove)) - _update_m2m_from_expression(user, org.member_role.members, users_expr, remove_users) - - -def update_user_teams(backend, details, user=None, *args, **kwargs): - """ - Update team memberships for the given user based on mapping rules defined - in settings. - """ - if not user: - return - from awx.main.models import Team - - team_map = backend.setting('TEAM_MAP') or {} - for team_name, team_opts in team_map.items(): - # Get or create the org to update. - if 'organization' not in team_opts: - continue - org = get_or_create_org_with_default_galaxy_cred(name=team_opts['organization']) - - # Update team members from expression(s). - team = Team.objects.get_or_create(name=team_name, organization=org)[0] - users_expr = team_opts.get('users', None) - remove = bool(team_opts.get('remove', True)) - _update_m2m_from_expression(user, team.member_role.members, users_expr, remove) diff --git a/awx/sso/tests/__init__.py b/awx/sso/tests/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/awx/sso/tests/conftest.py b/awx/sso/tests/conftest.py deleted file mode 100644 index f94b1c528f6d..000000000000 --- a/awx/sso/tests/conftest.py +++ /dev/null @@ -1,34 +0,0 @@ -import pytest - -from django.contrib.auth.models import User - -from awx.sso.backends import TACACSPlusBackend -from awx.sso.models import UserEnterpriseAuth - - -@pytest.fixture -def tacacsplus_backend(): - return TACACSPlusBackend() - - -@pytest.fixture -def existing_normal_user(): - try: - user = User.objects.get(username="alice") - except User.DoesNotExist: - user = User(username="alice", password="password") - user.save() - return user - - -@pytest.fixture -def existing_tacacsplus_user(): - try: - user = User.objects.get(username="foo") - except User.DoesNotExist: - user = User(username="foo") - user.set_unusable_password() - user.save() - enterprise_auth = UserEnterpriseAuth(user=user, provider='tacacs+') - enterprise_auth.save() - return user diff --git a/awx/sso/tests/functional/__init__.py b/awx/sso/tests/functional/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/awx/sso/tests/functional/test_backends.py b/awx/sso/tests/functional/test_backends.py deleted file mode 100644 index a0d2c31da3e2..000000000000 --- a/awx/sso/tests/functional/test_backends.py +++ /dev/null @@ -1,115 +0,0 @@ -import pytest -from awx.sso.backends import _update_m2m_from_groups - - -class MockLDAPGroups(object): - def is_member_of(self, group_dn): - return bool(group_dn) - - -class MockLDAPUser(object): - def _get_groups(self): - return MockLDAPGroups() - - -@pytest.mark.parametrize( - "setting, expected_result", - [ - (True, True), - ('something', True), - (False, False), - ('', False), - ], -) -def test_mock_objects(setting, expected_result): - ldap_user = MockLDAPUser() - assert ldap_user._get_groups().is_member_of(setting) == expected_result - - -@pytest.mark.parametrize( - "opts, remove, expected_result", - [ - # In these case we will pass no opts so we should get None as a return in all cases - ( - None, - False, - None, - ), - ( - None, - True, - None, - ), - # Next lets test with empty opts ([]) This should return False if remove is True and None otherwise - ( - [], - True, - False, - ), - ( - [], - False, - None, - ), - # Next opts is True, this will always return True - ( - True, - True, - True, - ), - ( - True, - False, - True, - ), - # If we get only a non-string as an option we hit a continue and will either return None or False depending on the remove flag - ( - [32], - False, - None, - ), - ( - [32], - True, - False, - ), - # Finally we need to test whether or not a user should be allowed in or not. - # We use a mock class for ldap_user that simply returns true/false based on the otps - ( - ['true'], - False, - True, - ), - # In this test we are going to pass a string to test the part of the code that coverts strings into array, this should give us True - ( - 'something', - True, - True, - ), - ( - [''], - False, - None, - ), - ( - False, - True, - False, - ), - # Empty strings are considered opts == None and will result in None or False based on the remove flag - ( - '', - True, - False, - ), - ( - '', - False, - None, - ), - ], -) -@pytest.mark.django_db -def test__update_m2m_from_groups(opts, remove, expected_result): - ldap_user = MockLDAPUser() - assert expected_result == _update_m2m_from_groups(ldap_user, opts, remove) diff --git a/awx/sso/tests/functional/test_common.py b/awx/sso/tests/functional/test_common.py deleted file mode 100644 index 4fc3edd841bb..000000000000 --- a/awx/sso/tests/functional/test_common.py +++ /dev/null @@ -1,280 +0,0 @@ -import pytest -from collections import Counter -from django.core.exceptions import FieldError -from django.utils.timezone import now - -from awx.main.models import Credential, CredentialType, Organization, Team, User -from awx.sso.common import get_orgs_by_ids, reconcile_users_org_team_mappings, create_org_and_teams, get_or_create_org_with_default_galaxy_cred - - -@pytest.mark.django_db -class TestCommonFunctions: - @pytest.fixture - def orgs(self): - o1 = Organization.objects.create(name='Default1') - o2 = Organization.objects.create(name='Default2') - o3 = Organization.objects.create(name='Default3') - return (o1, o2, o3) - - @pytest.fixture - def galaxy_credential(self): - galaxy_type = CredentialType.objects.create(kind='galaxy') - cred = Credential( - created=now(), modified=now(), name='Ansible Galaxy', managed=True, credential_type=galaxy_type, inputs={'url': 'https://galaxy.ansible.com/'} - ) - cred.save() - - def test_get_orgs_by_ids(self, orgs): - orgs_and_ids = get_orgs_by_ids() - o1, o2, o3 = orgs - assert Counter(orgs_and_ids.keys()) == Counter([o1.name, o2.name, o3.name]) - assert Counter(orgs_and_ids.values()) == Counter([o1.id, o2.id, o3.id]) - - def test_reconcile_users_org_team_mappings(self): - # Create objects for us to play with - user = User.objects.create(username='user1@foo.com', last_name='foo', first_name='bar', email='user1@foo.com', is_active=True) - org1 = Organization.objects.create(name='Default1') - org2 = Organization.objects.create(name='Default2') - team1 = Team.objects.create(name='Team1', organization=org1) - team2 = Team.objects.create(name='Team1', organization=org2) - - # Try adding nothing - reconcile_users_org_team_mappings(user, {}, {}, 'Nada') - assert list(user.roles.all()) == [] - - # Add a user to an org that does not exist (should have no affect) - reconcile_users_org_team_mappings( - user, - { - 'junk': {'member_role': True}, - }, - {}, - 'Nada', - ) - assert list(user.roles.all()) == [] - - # Remove a user to an org that does not exist (should have no affect) - reconcile_users_org_team_mappings( - user, - { - 'junk': {'member_role': False}, - }, - {}, - 'Nada', - ) - assert list(user.roles.all()) == [] - - # Add the user to the orgs - reconcile_users_org_team_mappings(user, {org1.name: {'member_role': True}, org2.name: {'member_role': True}}, {}, 'Nada') - assert len(user.roles.all()) == 2 - assert user in org1.member_role - assert user in org2.member_role - - # Remove the user from the orgs - reconcile_users_org_team_mappings(user, {org1.name: {'member_role': False}, org2.name: {'member_role': False}}, {}, 'Nada') - assert list(user.roles.all()) == [] - assert user not in org1.member_role - assert user not in org2.member_role - - # Remove the user from the orgs (again, should have no affect) - reconcile_users_org_team_mappings(user, {org1.name: {'member_role': False}, org2.name: {'member_role': False}}, {}, 'Nada') - assert list(user.roles.all()) == [] - assert user not in org1.member_role - assert user not in org2.member_role - - # Add a user back to the member role - reconcile_users_org_team_mappings( - user, - { - org1.name: { - 'member_role': True, - }, - }, - {}, - 'Nada', - ) - users_roles = set(user.roles.values_list('pk', flat=True)) - assert len(users_roles) == 1 - assert user in org1.member_role - - # Add the user to additional roles - reconcile_users_org_team_mappings( - user, - { - org1.name: {'admin_role': True, 'auditor_role': True}, - }, - {}, - 'Nada', - ) - assert len(user.roles.all()) == 3 - assert user in org1.member_role - assert user in org1.admin_role - assert user in org1.auditor_role - - # Add a user to a non-existent role (results in FieldError exception) - with pytest.raises(FieldError): - reconcile_users_org_team_mappings( - user, - { - org1.name: { - 'dne_role': True, - }, - }, - {}, - 'Nada', - ) - - # Try adding a user to a role that should not exist on an org (technically this works at this time) - reconcile_users_org_team_mappings( - user, - { - org1.name: { - 'read_role_id': True, - }, - }, - {}, - 'Nada', - ) - assert len(user.roles.all()) == 4 - assert user in org1.member_role - assert user in org1.admin_role - assert user in org1.auditor_role - - # Remove all of the org perms to test team perms - reconcile_users_org_team_mappings( - user, - { - org1.name: { - 'read_role_id': False, - 'member_role': False, - 'admin_role': False, - 'auditor_role': False, - }, - }, - {}, - 'Nada', - ) - assert list(user.roles.all()) == [] - - # Add the user as a member to one of the teams - reconcile_users_org_team_mappings(user, {}, {org1.name: {team1.name: {'member_role': True}}}, 'Nada') - assert len(user.roles.all()) == 1 - assert user in team1.member_role - # Validate that the user did not become a member of a team with the same name in a different org - assert user not in team2.member_role - - # Remove the user from the team - reconcile_users_org_team_mappings(user, {}, {org1.name: {team1.name: {'member_role': False}}}, 'Nada') - assert list(user.roles.all()) == [] - assert user not in team1.member_role - - # Remove the user from the team again - reconcile_users_org_team_mappings(user, {}, {org1.name: {team1.name: {'member_role': False}}}, 'Nada') - assert list(user.roles.all()) == [] - - # Add the user to a team that does not exist (should have no affect) - reconcile_users_org_team_mappings(user, {}, {org1.name: {'junk': {'member_role': True}}}, 'Nada') - assert list(user.roles.all()) == [] - - # Remove the user from a team that does not exist (should have no affect) - reconcile_users_org_team_mappings(user, {}, {org1.name: {'junk': {'member_role': False}}}, 'Nada') - assert list(user.roles.all()) == [] - - # Test a None setting - reconcile_users_org_team_mappings(user, {}, {org1.name: {'junk': {'member_role': None}}}, 'Nada') - assert list(user.roles.all()) == [] - - # Add the user multiple teams in different orgs - reconcile_users_org_team_mappings(user, {}, {org1.name: {team1.name: {'member_role': True}}, org2.name: {team2.name: {'member_role': True}}}, 'Nada') - assert len(user.roles.all()) == 2 - assert user in team1.member_role - assert user in team2.member_role - - # Remove the user from just one of the teams - reconcile_users_org_team_mappings(user, {}, {org2.name: {team2.name: {'member_role': False}}}, 'Nada') - assert len(user.roles.all()) == 1 - assert user in team1.member_role - assert user not in team2.member_role - - @pytest.mark.parametrize( - "org_list, team_map, can_create, org_count, team_count", - [ - # In this case we will only pass in organizations - ( - ["org1", "org2"], - {}, - True, - 2, - 0, - ), - # In this case we will only pass in teams but the orgs will be created from the teams - ( - [], - {"team1": "org1", "team2": "org2"}, - True, - 2, - 2, - ), - # In this case we will reuse an org - ( - ["org1"], - {"team1": "org1", "team2": "org1"}, - True, - 1, - 2, - ), - # In this case we have a combination of orgs, orgs reused and an org created by a team - ( - ["org1", "org2", "org3"], - {"team1": "org1", "team2": "org4"}, - True, - 4, - 2, - ), - # In this case we will test a case that the UI should prevent and have a team with no Org - # This should create org1/2 but only team1 - ( - ["org1"], - {"team1": "org2", "team2": None}, - True, - 2, - 1, - ), - # Block any creation with the can_create flag - ( - ["org1"], - {"team1": "org2", "team2": None}, - False, - 0, - 0, - ), - ], - ) - def test_create_org_and_teams(self, galaxy_credential, org_list, team_map, can_create, org_count, team_count): - create_org_and_teams(org_list, team_map, 'py.test', can_create=can_create) - assert Organization.objects.count() == org_count - assert Team.objects.count() == team_count - - def test_get_or_create_org_with_default_galaxy_cred_add_galaxy_cred(self, galaxy_credential): - # If this method creates the org it should get the default galaxy credential - num_orgs = 4 - for number in range(1, (num_orgs + 1)): - get_or_create_org_with_default_galaxy_cred(name=f"Default {number}") - - assert Organization.objects.count() == 4 - - for o in Organization.objects.all(): - assert o.galaxy_credentials.count() == 1 - assert o.galaxy_credentials.first().name == 'Ansible Galaxy' - - def test_get_or_create_org_with_default_galaxy_cred_no_galaxy_cred(self, galaxy_credential): - # If the org is pre-created, we should not add the galaxy_credential - num_orgs = 4 - for number in range(1, (num_orgs + 1)): - Organization.objects.create(name=f"Default {number}") - get_or_create_org_with_default_galaxy_cred(name=f"Default {number}") - - assert Organization.objects.count() == 4 - - for o in Organization.objects.all(): - assert o.galaxy_credentials.count() == 0 diff --git a/awx/sso/tests/functional/test_get_or_set_enterprise_user.py b/awx/sso/tests/functional/test_get_or_set_enterprise_user.py deleted file mode 100644 index 3f37b41df319..000000000000 --- a/awx/sso/tests/functional/test_get_or_set_enterprise_user.py +++ /dev/null @@ -1,37 +0,0 @@ -# Python -import pytest -from unittest import mock - -# AWX -from awx.sso.backends import _get_or_set_enterprise_user - - -@pytest.mark.django_db -def test_fetch_user_if_exist(existing_tacacsplus_user): - with mock.patch('awx.sso.backends.logger') as mocked_logger: - new_user = _get_or_set_enterprise_user("foo", "password", "tacacs+") - mocked_logger.debug.assert_not_called() - mocked_logger.warning.assert_not_called() - assert new_user == existing_tacacsplus_user - - -@pytest.mark.django_db -def test_create_user_if_not_exist(existing_tacacsplus_user): - with mock.patch('awx.sso.backends.logger') as mocked_logger: - new_user = _get_or_set_enterprise_user("bar", "password", "tacacs+") - mocked_logger.debug.assert_called_once_with(u'Created enterprise user bar via TACACS+ backend.') - assert new_user != existing_tacacsplus_user - - -@pytest.mark.django_db -def test_created_user_has_no_usable_password(): - new_user = _get_or_set_enterprise_user("bar", "password", "tacacs+") - assert not new_user.has_usable_password() - - -@pytest.mark.django_db -def test_non_enterprise_user_does_not_get_pass(existing_normal_user): - with mock.patch('awx.sso.backends.logger') as mocked_logger: - new_user = _get_or_set_enterprise_user("alice", "password", "tacacs+") - mocked_logger.warning.assert_called_once_with(u'Enterprise user alice already defined in Tower.') - assert new_user is None diff --git a/awx/sso/tests/functional/test_ldap.py b/awx/sso/tests/functional/test_ldap.py deleted file mode 100644 index 881ab29e2b4f..000000000000 --- a/awx/sso/tests/functional/test_ldap.py +++ /dev/null @@ -1,19 +0,0 @@ -from django.test.utils import override_settings -import ldap -import pytest - -from awx.sso.backends import LDAPSettings - - -@override_settings(AUTH_LDAP_CONNECTION_OPTIONS={ldap.OPT_NETWORK_TIMEOUT: 60}) -@pytest.mark.django_db -def test_ldap_with_custom_timeout(): - settings = LDAPSettings() - assert settings.CONNECTION_OPTIONS == {ldap.OPT_NETWORK_TIMEOUT: 60} - - -@override_settings(AUTH_LDAP_CONNECTION_OPTIONS={ldap.OPT_REFERRALS: 0}) -@pytest.mark.django_db -def test_ldap_with_missing_timeout(): - settings = LDAPSettings() - assert settings.CONNECTION_OPTIONS == {ldap.OPT_REFERRALS: 0, ldap.OPT_NETWORK_TIMEOUT: 30} diff --git a/awx/sso/tests/functional/test_saml_pipeline.py b/awx/sso/tests/functional/test_saml_pipeline.py deleted file mode 100644 index 628d793d4eec..000000000000 --- a/awx/sso/tests/functional/test_saml_pipeline.py +++ /dev/null @@ -1,639 +0,0 @@ -import pytest -import re - -from django.test.utils import override_settings -from awx.main.models import User, Organization, Team -from awx.sso.saml_pipeline import ( - _update_m2m_from_expression, - _update_user_orgs, - _update_user_teams, - _update_user_orgs_by_saml_attr, - _update_user_teams_by_saml_attr, - _check_flag, -) - -# from unittest import mock -# from django.utils.timezone import now -# , Credential, CredentialType - - -@pytest.fixture -def users(): - u1 = User.objects.create(username='user1@foo.com', last_name='foo', first_name='bar', email='user1@foo.com') - u2 = User.objects.create(username='user2@foo.com', last_name='foo', first_name='bar', email='user2@foo.com') - u3 = User.objects.create(username='user3@foo.com', last_name='foo', first_name='bar', email='user3@foo.com') - return (u1, u2, u3) - - -@pytest.mark.django_db -class TestSAMLPopulateUser: - # The main populate_user does not need to be tested since its just a conglomeration of other functions that we test - # This test is here in case someone alters the code in the future in a way that does require testing - def test_populate_user(self): - assert True - - -@pytest.mark.django_db -class TestSAMLSimpleMaps: - # This tests __update_user_orgs and __update_user_teams - @pytest.fixture - def backend(self): - class Backend: - s = { - 'ORGANIZATION_MAP': { - 'Default': { - 'remove': True, - 'admins': 'foobar', - 'remove_admins': True, - 'users': 'foo', - 'remove_users': True, - 'organization_alias': '', - } - }, - 'TEAM_MAP': {'Blue': {'organization': 'Default', 'remove': True, 'users': ''}, 'Red': {'organization': 'Default', 'remove': True, 'users': ''}}, - } - - def setting(self, key): - return self.s[key] - - return Backend() - - def test__update_user_orgs(self, backend, users): - u1, u2, u3 = users - - # Test user membership logic with regular expressions - backend.setting('ORGANIZATION_MAP')['Default']['admins'] = re.compile('.*') - backend.setting('ORGANIZATION_MAP')['Default']['users'] = re.compile('.*') - - desired_org_state = {} - orgs_to_create = [] - _update_user_orgs(backend, desired_org_state, orgs_to_create, u1) - _update_user_orgs(backend, desired_org_state, orgs_to_create, u2) - _update_user_orgs(backend, desired_org_state, orgs_to_create, u3) - - assert desired_org_state == {'Default': {'member_role': True, 'admin_role': True, 'auditor_role': False}} - assert orgs_to_create == ['Default'] - - # Test remove feature enabled - backend.setting('ORGANIZATION_MAP')['Default']['admins'] = '' - backend.setting('ORGANIZATION_MAP')['Default']['users'] = '' - backend.setting('ORGANIZATION_MAP')['Default']['remove_admins'] = True - backend.setting('ORGANIZATION_MAP')['Default']['remove_users'] = True - desired_org_state = {} - orgs_to_create = [] - _update_user_orgs(backend, desired_org_state, orgs_to_create, u1) - assert desired_org_state == {'Default': {'member_role': False, 'admin_role': False, 'auditor_role': False}} - assert orgs_to_create == ['Default'] - - # Test remove feature disabled - backend.setting('ORGANIZATION_MAP')['Default']['remove_admins'] = False - backend.setting('ORGANIZATION_MAP')['Default']['remove_users'] = False - desired_org_state = {} - orgs_to_create = [] - _update_user_orgs(backend, desired_org_state, orgs_to_create, u2) - - assert desired_org_state == {'Default': {'member_role': None, 'admin_role': None, 'auditor_role': False}} - assert orgs_to_create == ['Default'] - - # Test organization alias feature - backend.setting('ORGANIZATION_MAP')['Default']['organization_alias'] = 'Default_Alias' - orgs_to_create = [] - _update_user_orgs(backend, {}, orgs_to_create, u1) - assert orgs_to_create == ['Default_Alias'] - - def test__update_user_teams(self, backend, users): - u1, u2, u3 = users - - # Test user membership logic with regular expressions - backend.setting('TEAM_MAP')['Blue']['users'] = re.compile('.*') - backend.setting('TEAM_MAP')['Red']['users'] = re.compile('.*') - - desired_team_state = {} - teams_to_create = {} - _update_user_teams(backend, desired_team_state, teams_to_create, u1) - assert teams_to_create == {'Red': 'Default', 'Blue': 'Default'} - assert desired_team_state == {'Default': {'Blue': {'member_role': True}, 'Red': {'member_role': True}}} - - # Test remove feature enabled - backend.setting('TEAM_MAP')['Blue']['remove'] = True - backend.setting('TEAM_MAP')['Red']['remove'] = True - backend.setting('TEAM_MAP')['Blue']['users'] = '' - backend.setting('TEAM_MAP')['Red']['users'] = '' - - desired_team_state = {} - teams_to_create = {} - _update_user_teams(backend, desired_team_state, teams_to_create, u1) - assert teams_to_create == {'Red': 'Default', 'Blue': 'Default'} - assert desired_team_state == {'Default': {'Blue': {'member_role': False}, 'Red': {'member_role': False}}} - - # Test remove feature disabled - backend.setting('TEAM_MAP')['Blue']['remove'] = False - backend.setting('TEAM_MAP')['Red']['remove'] = False - - desired_team_state = {} - teams_to_create = {} - _update_user_teams(backend, desired_team_state, teams_to_create, u2) - assert teams_to_create == {'Red': 'Default', 'Blue': 'Default'} - # If we don't care about team memberships we just don't add them to the hash so this would be an empty hash - assert desired_team_state == {} - - -@pytest.mark.django_db -class TestSAMLM2M: - @pytest.mark.parametrize( - "expression, remove, expected_return", - [ - # No expression with no remove - (None, False, None), - ("", False, None), - # No expression with remove - (None, True, False), - # True expression with and without remove - (True, False, True), - (True, True, True), - # Single string matching the user name - ("user1", False, True), - # Single string matching the user email - ("user1@foo.com", False, True), - # Single string not matching username or email, no remove - ("user27", False, None), - # Single string not matching username or email, with remove - ("user27", True, False), - # Same tests with arrays instead of strings - (["user1"], False, True), - (["user1@foo.com"], False, True), - (["user27"], False, None), - (["user27"], True, False), - # Arrays with nothing matching - (["user27", "user28"], False, None), - (["user27", "user28"], True, False), - # Arrays with all matches - (["user1", "user1@foo.com"], False, True), - # Arrays with some match, some not - (["user1", "user28", "user27"], False, True), - # - # Note: For RE's, usually settings takes care of the compilation for us, so we have to do it manually for testing. - # we also need to remove any / or flags for the compile to happen - # - # Matching username regex non-array - (re.compile("^user.*"), False, True), - (re.compile("^user.*"), True, True), - # Matching email regex non-array - (re.compile(".*@foo.com$"), False, True), - (re.compile(".*@foo.com$"), True, True), - # Non-array not matching username or email - (re.compile("^$"), False, None), - (re.compile("^$"), True, False), - # All re tests just in array form - ([re.compile("^user.*")], False, True), - ([re.compile("^user.*")], True, True), - ([re.compile(".*@foo.com$")], False, True), - ([re.compile(".*@foo.com$")], True, True), - ([re.compile("^$")], False, None), - ([re.compile("^$")], True, False), - # An re with username matching but not email - ([re.compile("^user.*"), re.compile(".*@bar.com$")], False, True), - # An re with email matching but not username - ([re.compile("^user27$"), re.compile(".*@foo.com$")], False, True), - # An re array with no matching - ([re.compile("^user27$"), re.compile(".*@bar.com$")], False, None), - ([re.compile("^user27$"), re.compile(".*@bar.com$")], True, False), - # - # A mix of re and strings - # - # String matches, re does not - (["user1", re.compile(".*@bar.com$")], False, True), - # String does not match, re does - (["user27", re.compile(".*@foo.com$")], False, True), - # Nothing matches - (["user27", re.compile(".*@bar.com$")], False, None), - (["user27", re.compile(".*@bar.com$")], True, False), - ], - ) - def test__update_m2m_from_expression(self, expression, remove, expected_return): - user = User.objects.create(username='user1', last_name='foo', first_name='bar', email='user1@foo.com') - return_val = _update_m2m_from_expression(user, expression, remove) - assert return_val == expected_return - - -@pytest.mark.django_db -class TestSAMLAttrMaps: - @pytest.fixture - def backend(self): - class Backend: - s = { - 'ORGANIZATION_MAP': { - 'Default1': { - 'remove': True, - 'admins': 'foobar', - 'remove_admins': True, - 'users': 'foo', - 'remove_users': True, - 'organization_alias': 'o1_alias', - } - } - } - - def setting(self, key): - return self.s[key] - - return Backend() - - @pytest.mark.parametrize( - "setting, expected_state, expected_orgs_to_create, kwargs_member_of_mods", - [ - ( - # Default test, make sure that our roles get applied and removed as specified (with an alias) - { - 'saml_attr': 'memberOf', - 'saml_admin_attr': 'admins', - 'saml_auditor_attr': 'auditors', - 'remove': True, - 'remove_admins': True, - }, - { - 'Default2': {'member_role': True}, - 'Default3': {'admin_role': True}, - 'Default4': {'auditor_role': True}, - 'o1_alias': {'member_role': True}, - 'Rando1': {'admin_role': False, 'auditor_role': False, 'member_role': False}, - }, - [ - 'o1_alias', - 'Default2', - 'Default3', - 'Default4', - ], - None, - ), - ( - # Similar test, we are just going to override the values "coming from the IdP" to limit the teams - { - 'saml_attr': 'memberOf', - 'saml_admin_attr': 'admins', - 'saml_auditor_attr': 'auditors', - 'remove': True, - 'remove_admins': True, - }, - { - 'Default3': {'admin_role': True, 'member_role': True}, - 'Default4': {'auditor_role': True}, - 'Rando1': {'admin_role': False, 'auditor_role': False, 'member_role': False}, - }, - [ - 'Default3', - 'Default4', - ], - ['Default3'], - ), - ( - # Test to make sure the remove logic is working - { - 'saml_attr': 'memberOf', - 'saml_admin_attr': 'admins', - 'saml_auditor_attr': 'auditors', - 'remove': False, - 'remove_admins': False, - 'remove_auditors': False, - }, - { - 'Default2': {'member_role': True}, - 'Default3': {'admin_role': True}, - 'Default4': {'auditor_role': True}, - 'o1_alias': {'member_role': True}, - }, - [ - 'o1_alias', - 'Default2', - 'Default3', - 'Default4', - ], - ['Default1', 'Default2'], - ), - ], - ) - def test__update_user_orgs_by_saml_attr(self, backend, setting, expected_state, expected_orgs_to_create, kwargs_member_of_mods): - kwargs = { - 'username': u'cmeyers@redhat.com', - 'uid': 'idp:cmeyers@redhat.com', - 'request': {u'SAMLResponse': [], u'RelayState': [u'idp']}, - 'is_new': False, - 'response': { - 'session_index': '_0728f0e0-b766-0135-75fa-02842b07c044', - 'idp_name': u'idp', - 'attributes': { - 'memberOf': ['Default1', 'Default2'], - 'admins': ['Default3'], - 'auditors': ['Default4'], - 'groups': ['Blue', 'Red'], - 'User.email': ['cmeyers@redhat.com'], - 'User.LastName': ['Meyers'], - 'name_id': 'cmeyers@redhat.com', - 'User.FirstName': ['Chris'], - 'PersonImmutableID': [], - }, - }, - 'social': None, - 'strategy': None, - 'new_association': False, - } - if kwargs_member_of_mods: - kwargs['response']['attributes']['memberOf'] = kwargs_member_of_mods - - # Create a random organization in the database for testing - Organization.objects.create(name='Rando1') - - with override_settings(SOCIAL_AUTH_SAML_ORGANIZATION_ATTR=setting): - desired_org_state = {} - orgs_to_create = [] - _update_user_orgs_by_saml_attr(backend, desired_org_state, orgs_to_create, **kwargs) - assert desired_org_state == expected_state - assert orgs_to_create == expected_orgs_to_create - - @pytest.mark.parametrize( - "setting, expected_team_state, expected_teams_to_create, kwargs_group_override", - [ - ( - { - 'saml_attr': 'groups', - 'remove': False, - 'team_org_map': [ - {'team': 'Blue', 'organization': 'Default1'}, - {'team': 'Blue', 'organization': 'Default2'}, - {'team': 'Blue', 'organization': 'Default3'}, - {'team': 'Red', 'organization': 'Default1'}, - {'team': 'Green', 'organization': 'Default1'}, - {'team': 'Green', 'organization': 'Default3'}, - {'team': 'Yellow', 'team_alias': 'Yellow_Alias', 'organization': 'Default4', 'organization_alias': 'Default4_Alias'}, - ], - }, - { - 'Default1': { - 'Blue': {'member_role': True}, - 'Green': {'member_role': False}, - 'Red': {'member_role': True}, - }, - 'Default2': { - 'Blue': {'member_role': True}, - }, - 'Default3': { - 'Blue': {'member_role': True}, - 'Green': {'member_role': False}, - }, - 'Default4': { - 'Yellow': {'member_role': False}, - }, - }, - { - 'Blue': 'Default3', - 'Red': 'Default1', - }, - None, - ), - ( - { - 'saml_attr': 'groups', - 'remove': False, - 'team_org_map': [ - {'team': 'Blue', 'organization': 'Default1'}, - {'team': 'Blue', 'organization': 'Default2'}, - {'team': 'Blue', 'organization': 'Default3'}, - {'team': 'Red', 'organization': 'Default1'}, - {'team': 'Green', 'organization': 'Default1'}, - {'team': 'Green', 'organization': 'Default3'}, - {'team': 'Yellow', 'team_alias': 'Yellow_Alias', 'organization': 'Default4', 'organization_alias': 'Default4_Alias'}, - ], - }, - { - 'Default1': { - 'Blue': {'member_role': True}, - 'Green': {'member_role': True}, - 'Red': {'member_role': True}, - }, - 'Default2': { - 'Blue': {'member_role': True}, - }, - 'Default3': { - 'Blue': {'member_role': True}, - 'Green': {'member_role': True}, - }, - 'Default4': { - 'Yellow': {'member_role': False}, - }, - }, - { - 'Blue': 'Default3', - 'Red': 'Default1', - 'Green': 'Default3', - }, - ['Blue', 'Red', 'Green'], - ), - ( - { - 'saml_attr': 'groups', - 'remove': True, - 'team_org_map': [ - {'team': 'Blue', 'organization': 'Default1'}, - {'team': 'Blue', 'organization': 'Default2'}, - {'team': 'Blue', 'organization': 'Default3'}, - {'team': 'Red', 'organization': 'Default1'}, - {'team': 'Green', 'organization': 'Default1'}, - {'team': 'Green', 'organization': 'Default3'}, - {'team': 'Yellow', 'team_alias': 'Yellow_Alias', 'organization': 'Default4', 'organization_alias': 'Default4_Alias'}, - ], - }, - { - 'Default1': { - 'Blue': {'member_role': False}, - 'Green': {'member_role': True}, - 'Red': {'member_role': False}, - }, - 'Default2': { - 'Blue': {'member_role': False}, - }, - 'Default3': { - 'Blue': {'member_role': False}, - 'Green': {'member_role': True}, - }, - 'Default4': { - 'Yellow': {'member_role': False}, - }, - 'Rando1': { - 'Rando1': {'member_role': False}, - }, - }, - { - 'Green': 'Default3', - }, - ['Green'], - ), - ], - ) - def test__update_user_teams_by_saml_attr(self, setting, expected_team_state, expected_teams_to_create, kwargs_group_override): - kwargs = { - 'username': u'cmeyers@redhat.com', - 'uid': 'idp:cmeyers@redhat.com', - 'request': {u'SAMLResponse': [], u'RelayState': [u'idp']}, - 'is_new': False, - 'response': { - 'session_index': '_0728f0e0-b766-0135-75fa-02842b07c044', - 'idp_name': u'idp', - 'attributes': { - 'memberOf': ['Default1', 'Default2'], - 'admins': ['Default3'], - 'auditors': ['Default4'], - 'groups': ['Blue', 'Red'], - 'User.email': ['cmeyers@redhat.com'], - 'User.LastName': ['Meyers'], - 'name_id': 'cmeyers@redhat.com', - 'User.FirstName': ['Chris'], - 'PersonImmutableID': [], - }, - }, - 'social': None, - 'strategy': None, - 'new_association': False, - } - if kwargs_group_override: - kwargs['response']['attributes']['groups'] = kwargs_group_override - - o = Organization.objects.create(name='Rando1') - Team.objects.create(name='Rando1', organization_id=o.id) - - with override_settings(SOCIAL_AUTH_SAML_TEAM_ATTR=setting): - desired_team_state = {} - teams_to_create = {} - _update_user_teams_by_saml_attr(desired_team_state, teams_to_create, **kwargs) - assert desired_team_state == expected_team_state - assert teams_to_create == expected_teams_to_create - - -@pytest.mark.django_db -class TestSAMLUserFlags: - @pytest.mark.parametrize( - "user_flags_settings, expected, is_superuser", - [ - # In this case we will pass no user flags so new_flag should be false and changed will def be false - ( - {}, - (False, False), - False, - ), - # NOTE: The first handful of tests test role/value as string instead of lists. - # This was from the initial implementation of these fields but the code should be able to handle this - # There are a couple tests at the end of this which will validate arrays in these values. - # - # In this case we will give the user a group to make them an admin - ( - {'is_superuser_role': 'test-role-1'}, - (True, True), - False, - ), - # In this case we will give the user a flag that will make then an admin - ( - {'is_superuser_attr': 'is_superuser'}, - (True, True), - False, - ), - # In this case we will give the user a flag but the wrong value - ( - {'is_superuser_attr': 'is_superuser', 'is_superuser_value': 'junk'}, - (False, False), - False, - ), - # In this case we will give the user a flag and the right value - ( - {'is_superuser_attr': 'is_superuser', 'is_superuser_value': 'true'}, - (True, True), - False, - ), - # In this case we will give the user a proper role and an is_superuser_attr role that they don't have, this should make them an admin - ( - {'is_superuser_role': 'test-role-1', 'is_superuser_attr': 'gibberish', 'is_superuser_value': 'true'}, - (True, True), - False, - ), - # In this case we will give the user a proper role and an is_superuser_attr role that they have, this should make them an admin - ( - {'is_superuser_role': 'test-role-1', 'is_superuser_attr': 'test-role-1'}, - (True, True), - False, - ), - # In this case we will give the user a proper role and an is_superuser_attr role that they have but a bad value, this should make them an admin - ( - {'is_superuser_role': 'test-role-1', 'is_superuser_attr': 'is_superuser', 'is_superuser_value': 'junk'}, - (False, False), - False, - ), - # In this case we will give the user everything - ( - {'is_superuser_role': 'test-role-1', 'is_superuser_attr': 'is_superuser', 'is_superuser_value': 'true'}, - (True, True), - False, - ), - # In this test case we will validate that a single attribute (instead of a list) still works - ( - {'is_superuser_attr': 'name_id', 'is_superuser_value': 'test_id'}, - (True, True), - False, - ), - # This will be a negative test for a single attribute - ( - {'is_superuser_attr': 'name_id', 'is_superuser_value': 'junk'}, - (False, False), - False, - ), - # The user is already a superuser so we should remove them - ( - {'is_superuser_attr': 'name_id', 'is_superuser_value': 'junk', 'remove_superusers': True}, - (False, True), - True, - ), - # The user is already a superuser but we don't have a remove field - ( - {'is_superuser_attr': 'name_id', 'is_superuser_value': 'junk', 'remove_superusers': False}, - (True, False), - True, - ), - # Positive test for multiple values for is_superuser_value - ( - {'is_superuser_attr': 'is_superuser', 'is_superuser_value': ['junk', 'junk2', 'else', 'junk']}, - (True, True), - False, - ), - # Negative test for multiple values for is_superuser_value - ( - {'is_superuser_attr': 'is_superuser', 'is_superuser_value': ['junk', 'junk2', 'junk']}, - (False, True), - True, - ), - # Positive test for multiple values of is_superuser_role - ( - {'is_superuser_role': ['junk', 'junk2', 'something', 'junk']}, - (True, True), - False, - ), - # Negative test for multiple values of is_superuser_role - ( - {'is_superuser_role': ['junk', 'junk2', 'junk']}, - (False, True), - True, - ), - ], - ) - def test__check_flag(self, user_flags_settings, expected, is_superuser): - user = User() - user.username = 'John' - user.is_superuser = is_superuser - - attributes = { - 'email': ['noone@nowhere.com'], - 'last_name': ['Westcott'], - 'is_superuser': ['something', 'else', 'true'], - 'username': ['test_id'], - 'first_name': ['John'], - 'Role': ['test-role-1', 'something', 'different'], - 'name_id': 'test_id', - } - - assert expected == _check_flag(user, 'superuser', attributes, user_flags_settings) diff --git a/awx/sso/tests/functional/test_social_base_pipeline.py b/awx/sso/tests/functional/test_social_base_pipeline.py deleted file mode 100644 index 38a49e15f331..000000000000 --- a/awx/sso/tests/functional/test_social_base_pipeline.py +++ /dev/null @@ -1,76 +0,0 @@ -import pytest - -from awx.main.models import User -from awx.sso.social_base_pipeline import AuthNotFound, check_user_found_or_created, set_is_active_for_new_user, prevent_inactive_login, AuthInactive - - -@pytest.mark.django_db -class TestSocialBasePipeline: - def test_check_user_found_or_created_no_exception(self): - # If we have a user (the True param, we should not get an exception) - try: - check_user_found_or_created(None, {}, True) - except AuthNotFound: - assert False, 'check_user_found_or_created should not have raised an exception with a user' - - @pytest.mark.parametrize( - "details, kwargs, expected_id", - [ - ( - {}, - {}, - '???', - ), - ( - {}, - {'uid': 'kwargs_uid'}, - 'kwargs_uid', - ), - ( - {}, - {'uid': 'kwargs_uid', 'email': 'kwargs_email'}, - 'kwargs_email', - ), - ( - {'email': 'details_email'}, - {'uid': 'kwargs_uid', 'email': 'kwargs_email'}, - 'details_email', - ), - ], - ) - def test_check_user_found_or_created_exceptions(self, details, expected_id, kwargs): - with pytest.raises(AuthNotFound) as e: - check_user_found_or_created(None, details, False, None, **kwargs) - assert f'An account cannot be found for {expected_id}' == str(e.value) - - @pytest.mark.parametrize( - "kwargs, expected_details, expected_response", - [ - ({}, {}, None), - ({'is_new': False}, {}, None), - ({'is_new': True}, {'is_active': True}, {'details': {'is_active': True}}), - ], - ) - def test_set_is_active_for_new_user(self, kwargs, expected_details, expected_response): - details = {} - response = set_is_active_for_new_user(None, details, None, None, **kwargs) - assert details == expected_details - assert response == expected_response - - def test_prevent_inactive_login_no_exception_no_user(self): - try: - prevent_inactive_login(None, None, None, None, None) - except AuthInactive: - assert False, 'prevent_inactive_login should not have raised an exception with no user' - - def test_prevent_inactive_login_no_exception_active_user(self): - user = User.objects.create(username='user1@foo.com', last_name='foo', first_name='bar', email='user1@foo.com', is_active=True) - try: - prevent_inactive_login(None, None, user, None, None) - except AuthInactive: - assert False, 'prevent_inactive_login should not have raised an exception with an active user' - - def test_prevent_inactive_login_no_exception_inactive_user(self): - user = User.objects.create(username='user1@foo.com', last_name='foo', first_name='bar', email='user1@foo.com', is_active=False) - with pytest.raises(AuthInactive): - prevent_inactive_login(None, None, user, None, None) diff --git a/awx/sso/tests/functional/test_social_pipeline.py b/awx/sso/tests/functional/test_social_pipeline.py deleted file mode 100644 index f26886e71944..000000000000 --- a/awx/sso/tests/functional/test_social_pipeline.py +++ /dev/null @@ -1,113 +0,0 @@ -import pytest -import re - -from awx.sso.social_pipeline import update_user_orgs, update_user_teams -from awx.main.models import User, Team, Organization - - -@pytest.fixture -def users(): - u1 = User.objects.create(username='user1@foo.com', last_name='foo', first_name='bar', email='user1@foo.com') - u2 = User.objects.create(username='user2@foo.com', last_name='foo', first_name='bar', email='user2@foo.com') - u3 = User.objects.create(username='user3@foo.com', last_name='foo', first_name='bar', email='user3@foo.com') - return (u1, u2, u3) - - -@pytest.mark.django_db -class TestSocialPipeline: - @pytest.fixture - def backend(self): - class Backend: - s = { - 'ORGANIZATION_MAP': { - 'Default': { - 'remove': True, - 'admins': 'foobar', - 'remove_admins': True, - 'users': 'foo', - 'remove_users': True, - 'organization_alias': '', - } - }, - 'TEAM_MAP': {'Blue': {'organization': 'Default', 'remove': True, 'users': ''}, 'Red': {'organization': 'Default', 'remove': True, 'users': ''}}, - } - - def setting(self, key): - return self.s[key] - - return Backend() - - @pytest.fixture - def org(self): - return Organization.objects.create(name="Default") - - def test_update_user_orgs(self, org, backend, users): - u1, u2, u3 = users - - # Test user membership logic with regular expressions - backend.setting('ORGANIZATION_MAP')['Default']['admins'] = re.compile('.*') - backend.setting('ORGANIZATION_MAP')['Default']['users'] = re.compile('.*') - - update_user_orgs(backend, None, u1) - update_user_orgs(backend, None, u2) - update_user_orgs(backend, None, u3) - - assert org.admin_role.members.count() == 3 - assert org.member_role.members.count() == 3 - - # Test remove feature enabled - backend.setting('ORGANIZATION_MAP')['Default']['admins'] = '' - backend.setting('ORGANIZATION_MAP')['Default']['users'] = '' - backend.setting('ORGANIZATION_MAP')['Default']['remove_admins'] = True - backend.setting('ORGANIZATION_MAP')['Default']['remove_users'] = True - update_user_orgs(backend, None, u1) - - assert org.admin_role.members.count() == 2 - assert org.member_role.members.count() == 2 - - # Test remove feature disabled - backend.setting('ORGANIZATION_MAP')['Default']['remove_admins'] = False - backend.setting('ORGANIZATION_MAP')['Default']['remove_users'] = False - update_user_orgs(backend, None, u2) - - assert org.admin_role.members.count() == 2 - assert org.member_role.members.count() == 2 - - # Test organization alias feature - backend.setting('ORGANIZATION_MAP')['Default']['organization_alias'] = 'Default_Alias' - update_user_orgs(backend, None, u1) - assert Organization.objects.get(name="Default_Alias") is not None - - def test_update_user_teams(self, backend, users): - u1, u2, u3 = users - - # Test user membership logic with regular expressions - backend.setting('TEAM_MAP')['Blue']['users'] = re.compile('.*') - backend.setting('TEAM_MAP')['Red']['users'] = re.compile('.*') - - update_user_teams(backend, None, u1) - update_user_teams(backend, None, u2) - update_user_teams(backend, None, u3) - - assert Team.objects.get(name="Red").member_role.members.count() == 3 - assert Team.objects.get(name="Blue").member_role.members.count() == 3 - - # Test remove feature enabled - backend.setting('TEAM_MAP')['Blue']['remove'] = True - backend.setting('TEAM_MAP')['Red']['remove'] = True - backend.setting('TEAM_MAP')['Blue']['users'] = '' - backend.setting('TEAM_MAP')['Red']['users'] = '' - - update_user_teams(backend, None, u1) - - assert Team.objects.get(name="Red").member_role.members.count() == 2 - assert Team.objects.get(name="Blue").member_role.members.count() == 2 - - # Test remove feature disabled - backend.setting('TEAM_MAP')['Blue']['remove'] = False - backend.setting('TEAM_MAP')['Red']['remove'] = False - - update_user_teams(backend, None, u2) - - assert Team.objects.get(name="Red").member_role.members.count() == 2 - assert Team.objects.get(name="Blue").member_role.members.count() == 2 diff --git a/awx/sso/tests/test_env.py b/awx/sso/tests/test_env.py deleted file mode 100644 index b63da8ed8a16..000000000000 --- a/awx/sso/tests/test_env.py +++ /dev/null @@ -1,4 +0,0 @@ -# Ensure that our autouse overwrites are working -def test_cache(settings): - assert settings.CACHES['default']['BACKEND'] == 'django.core.cache.backends.locmem.LocMemCache' - assert settings.CACHES['default']['LOCATION'].startswith('unique-') diff --git a/awx/sso/tests/unit/test_fields.py b/awx/sso/tests/unit/test_fields.py deleted file mode 100644 index 35ab58d07fab..000000000000 --- a/awx/sso/tests/unit/test_fields.py +++ /dev/null @@ -1,235 +0,0 @@ -import pytest -from unittest import mock - -from rest_framework.exceptions import ValidationError - -from awx.sso.fields import SAMLOrgAttrField, SAMLTeamAttrField, SAMLUserFlagsAttrField, LDAPGroupTypeParamsField, LDAPServerURIField - - -class TestSAMLOrgAttrField: - @pytest.mark.parametrize( - "data, expected", - [ - ({}, {}), - ({'remove': True, 'saml_attr': 'foobar'}, {'remove': True, 'saml_attr': 'foobar'}), - ({'remove': True, 'saml_attr': 1234}, {'remove': True, 'saml_attr': '1234'}), - ({'remove': True, 'saml_attr': 3.14}, {'remove': True, 'saml_attr': '3.14'}), - ({'saml_attr': 'foobar'}, {'saml_attr': 'foobar'}), - ({'remove': True}, {'remove': True}), - ({'remove': True, 'saml_admin_attr': 'foobar'}, {'remove': True, 'saml_admin_attr': 'foobar'}), - ({'saml_admin_attr': 'foobar'}, {'saml_admin_attr': 'foobar'}), - ({'remove_admins': True, 'saml_admin_attr': 'foobar'}, {'remove_admins': True, 'saml_admin_attr': 'foobar'}), - ( - {'remove': True, 'saml_attr': 'foo', 'remove_admins': True, 'saml_admin_attr': 'bar'}, - {'remove': True, 'saml_attr': 'foo', 'remove_admins': True, 'saml_admin_attr': 'bar'}, - ), - ], - ) - def test_internal_value_valid(self, data, expected): - field = SAMLOrgAttrField() - res = field.to_internal_value(data) - assert res == expected - - @pytest.mark.parametrize( - "data, expected", - [ - ({'remove': 'blah', 'saml_attr': 'foobar'}, {'remove': ['Must be a valid boolean.']}), - ({'remove': True, 'saml_attr': False}, {'saml_attr': ['Not a valid string.']}), - ( - {'remove': True, 'saml_attr': False, 'foo': 'bar', 'gig': 'ity'}, - {'saml_attr': ['Not a valid string.'], 'foo': ['Invalid field.'], 'gig': ['Invalid field.']}, - ), - ({'remove_admins': True, 'saml_admin_attr': False}, {'saml_admin_attr': ['Not a valid string.']}), - ({'remove_admins': 'blah', 'saml_admin_attr': 'foobar'}, {'remove_admins': ['Must be a valid boolean.']}), - ], - ) - def test_internal_value_invalid(self, data, expected): - field = SAMLOrgAttrField() - with pytest.raises(ValidationError) as e: - field.to_internal_value(data) - assert e.value.detail == expected - - -class TestSAMLTeamAttrField: - @pytest.mark.parametrize( - "data", - [ - {}, - {'remove': True, 'saml_attr': 'foobar', 'team_org_map': []}, - {'remove': True, 'saml_attr': 'foobar', 'team_org_map': [{'team': 'Engineering', 'organization': 'Ansible'}]}, - { - 'remove': True, - 'saml_attr': 'foobar', - 'team_org_map': [ - {'team': 'Engineering', 'organization': 'Ansible'}, - {'team': 'Engineering', 'organization': 'Ansible2'}, - {'team': 'Engineering2', 'organization': 'Ansible'}, - ], - }, - { - 'remove': True, - 'saml_attr': 'foobar', - 'team_org_map': [ - {'team': 'Engineering', 'organization': 'Ansible'}, - {'team': 'Engineering', 'organization': 'Ansible2'}, - {'team': 'Engineering2', 'organization': 'Ansible'}, - ], - }, - { - 'remove': True, - 'saml_attr': 'foobar', - 'team_org_map': [ - {'team': 'Engineering', 'team_alias': 'Engineering Team', 'organization': 'Ansible'}, - {'team': 'Engineering', 'organization': 'Ansible2'}, - {'team': 'Engineering2', 'organization': 'Ansible'}, - ], - }, - ], - ) - def test_internal_value_valid(self, data): - field = SAMLTeamAttrField() - res = field.to_internal_value(data) - assert res == data - - @pytest.mark.parametrize( - "data, expected", - [ - ( - {'remove': True, 'saml_attr': 'foobar', 'team_org_map': [{'team': 'foobar', 'not_a_valid_key': 'blah', 'organization': 'Ansible'}]}, - {'team_org_map': {0: {'not_a_valid_key': ['Invalid field.']}}}, - ), - ( - {'remove': False, 'saml_attr': 'foobar', 'team_org_map': [{'organization': 'Ansible'}]}, - {'team_org_map': {0: {'team': ['This field is required.']}}}, - ), - ( - {'remove': False, 'saml_attr': 'foobar', 'team_org_map': [{}]}, - {'team_org_map': {0: {'organization': ['This field is required.'], 'team': ['This field is required.']}}}, - ), - ], - ) - def test_internal_value_invalid(self, data, expected): - field = SAMLTeamAttrField() - with pytest.raises(ValidationError) as e: - field.to_internal_value(data) - assert e.value.detail == expected - - -class TestSAMLUserFlagsAttrField: - @pytest.mark.parametrize( - "data", - [ - {}, - {'is_superuser_attr': 'something'}, - {'is_superuser_value': ['value']}, - {'is_superuser_role': ['my_peeps']}, - {'remove_superusers': False}, - {'is_system_auditor_attr': 'something_else'}, - {'is_system_auditor_value': ['value2']}, - {'is_system_auditor_role': ['other_peeps']}, - {'remove_system_auditors': False}, - ], - ) - def test_internal_value_valid(self, data): - field = SAMLUserFlagsAttrField() - res = field.to_internal_value(data) - assert res == data - - @pytest.mark.parametrize( - "data, expected", - [ - ( - { - 'junk': 'something', - 'is_superuser_value': 'value', - 'is_superuser_role': 'my_peeps', - 'is_system_auditor_attr': 'else', - 'is_system_auditor_value': 'value2', - 'is_system_auditor_role': 'other_peeps', - }, - { - 'junk': ['Invalid field.'], - 'is_superuser_role': ['Expected a list of items but got type "str".'], - 'is_superuser_value': ['Expected a list of items but got type "str".'], - 'is_system_auditor_role': ['Expected a list of items but got type "str".'], - 'is_system_auditor_value': ['Expected a list of items but got type "str".'], - }, - ), - ( - { - 'junk': 'something', - }, - { - 'junk': ['Invalid field.'], - }, - ), - ( - { - 'junk': 'something', - 'junk2': 'else', - }, - { - 'junk': ['Invalid field.'], - 'junk2': ['Invalid field.'], - }, - ), - # make sure we can't pass a string to the boolean fields - ( - { - 'remove_superusers': 'test', - 'remove_system_auditors': 'test', - }, - { - "remove_superusers": ["Must be a valid boolean."], - "remove_system_auditors": ["Must be a valid boolean."], - }, - ), - ], - ) - def test_internal_value_invalid(self, data, expected): - field = SAMLUserFlagsAttrField() - with pytest.raises(ValidationError) as e: - field.to_internal_value(data) - print(e.value.detail) - assert e.value.detail == expected - - -class TestLDAPGroupTypeParamsField: - @pytest.mark.parametrize( - "group_type, data, expected", - [ - ('LDAPGroupType', {'name_attr': 'user', 'bob': ['a', 'b'], 'scooter': 'hello'}, ['Invalid key(s): "bob", "scooter".']), - ('MemberDNGroupType', {'name_attr': 'user', 'member_attr': 'west', 'bob': ['a', 'b'], 'scooter': 'hello'}, ['Invalid key(s): "bob", "scooter".']), - ( - 'PosixUIDGroupType', - {'name_attr': 'user', 'member_attr': 'west', 'ldap_group_user_attr': 'legacyThing', 'bob': ['a', 'b'], 'scooter': 'hello'}, - ['Invalid key(s): "bob", "member_attr", "scooter".'], - ), - ], - ) - def test_internal_value_invalid(self, group_type, data, expected): - field = LDAPGroupTypeParamsField() - field.get_depends_on = mock.MagicMock(return_value=group_type) - - with pytest.raises(ValidationError) as e: - field.to_internal_value(data) - assert e.value.detail == expected - - -class TestLDAPServerURIField: - @pytest.mark.parametrize( - "ldap_uri, exception, expected", - [ - (r'ldap://servername.com:444', None, r'ldap://servername.com:444'), - (r'ldap://servername.so3:444', None, r'ldap://servername.so3:444'), - (r'ldaps://servername3.s300:344', None, r'ldaps://servername3.s300:344'), - (r'ldap://servername.-so3:444', ValidationError, None), - ], - ) - def test_run_validators_valid(self, ldap_uri, exception, expected): - field = LDAPServerURIField() - if exception is None: - assert field.run_validators(ldap_uri) == expected - else: - with pytest.raises(exception): - field.run_validators(ldap_uri) diff --git a/awx/sso/tests/unit/test_ldap.py b/awx/sso/tests/unit/test_ldap.py deleted file mode 100644 index 300102934f79..000000000000 --- a/awx/sso/tests/unit/test_ldap.py +++ /dev/null @@ -1,25 +0,0 @@ -import ldap - -from awx.sso.backends import LDAPSettings -from awx.sso.validators import validate_ldap_filter -from django.core.cache import cache - - -def test_ldap_default_settings(mocker): - from_db = mocker.Mock(**{'order_by.return_value': []}) - with mocker.patch('awx.conf.models.Setting.objects.filter', return_value=from_db): - settings = LDAPSettings() - assert settings.ORGANIZATION_MAP == {} - assert settings.TEAM_MAP == {} - - -def test_ldap_default_network_timeout(mocker): - cache.clear() # clearing cache avoids picking up stray default for OPT_REFERRALS - from_db = mocker.Mock(**{'order_by.return_value': []}) - with mocker.patch('awx.conf.models.Setting.objects.filter', return_value=from_db): - settings = LDAPSettings() - assert settings.CONNECTION_OPTIONS[ldap.OPT_NETWORK_TIMEOUT] == 30 - - -def test_ldap_filter_validator(): - validate_ldap_filter('(test-uid=%(user)s)', with_user=True) diff --git a/awx/sso/tests/unit/test_pipelines.py b/awx/sso/tests/unit/test_pipelines.py deleted file mode 100644 index 94a1111187b8..000000000000 --- a/awx/sso/tests/unit/test_pipelines.py +++ /dev/null @@ -1,12 +0,0 @@ -import pytest - - -@pytest.mark.parametrize( - "lib", - [ - ("saml_pipeline"), - ("social_pipeline"), - ], -) -def test_module_loads(lib): - module = __import__("awx.sso." + lib) # noqa diff --git a/awx/sso/tests/unit/test_tacacsplus.py b/awx/sso/tests/unit/test_tacacsplus.py deleted file mode 100644 index 60ed0c47995d..000000000000 --- a/awx/sso/tests/unit/test_tacacsplus.py +++ /dev/null @@ -1,49 +0,0 @@ -from unittest import mock - - -def test_empty_host_fails_auth(tacacsplus_backend): - with mock.patch('awx.sso.backends.django_settings') as settings: - settings.TACACSPLUS_HOST = '' - ret_user = tacacsplus_backend.authenticate(None, u"user", u"pass") - assert ret_user is None - - -def test_client_raises_exception(tacacsplus_backend): - client = mock.MagicMock() - client.authenticate.side_effect = Exception("foo") - with mock.patch('awx.sso.backends.django_settings') as settings, mock.patch('awx.sso.backends.logger') as logger, mock.patch( - 'tacacs_plus.TACACSClient', return_value=client - ): - settings.TACACSPLUS_HOST = 'localhost' - settings.TACACSPLUS_AUTH_PROTOCOL = 'ascii' - ret_user = tacacsplus_backend.authenticate(None, u"user", u"pass") - assert ret_user is None - logger.exception.assert_called_once_with("TACACS+ Authentication Error: foo") - - -def test_client_return_invalid_fails_auth(tacacsplus_backend): - auth = mock.MagicMock() - auth.valid = False - client = mock.MagicMock() - client.authenticate.return_value = auth - with mock.patch('awx.sso.backends.django_settings') as settings, mock.patch('tacacs_plus.TACACSClient', return_value=client): - settings.TACACSPLUS_HOST = 'localhost' - settings.TACACSPLUS_AUTH_PROTOCOL = 'ascii' - ret_user = tacacsplus_backend.authenticate(None, u"user", u"pass") - assert ret_user is None - - -def test_client_return_valid_passes_auth(tacacsplus_backend): - auth = mock.MagicMock() - auth.valid = True - client = mock.MagicMock() - client.authenticate.return_value = auth - user = mock.MagicMock() - user.has_usable_password = mock.MagicMock(return_value=False) - with mock.patch('awx.sso.backends.django_settings') as settings, mock.patch('tacacs_plus.TACACSClient', return_value=client), mock.patch( - 'awx.sso.backends._get_or_set_enterprise_user', return_value=user - ): - settings.TACACSPLUS_HOST = 'localhost' - settings.TACACSPLUS_AUTH_PROTOCOL = 'ascii' - ret_user = tacacsplus_backend.authenticate(None, u"user", u"pass") - assert ret_user == user diff --git a/awx/sso/urls.py b/awx/sso/urls.py deleted file mode 100644 index 93da0996c970..000000000000 --- a/awx/sso/urls.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) 2015 Ansible, Inc. -# All Rights Reserved. - -from django.urls import re_path - -from awx.sso.views import sso_complete, sso_error, sso_inactive, saml_metadata - - -app_name = 'sso' -urlpatterns = [ - re_path(r'^complete/$', sso_complete, name='sso_complete'), - re_path(r'^error/$', sso_error, name='sso_error'), - re_path(r'^inactive/$', sso_inactive, name='sso_inactive'), - re_path(r'^metadata/saml/$', saml_metadata, name='saml_metadata'), -] diff --git a/awx/sso/validators.py b/awx/sso/validators.py deleted file mode 100644 index 478b86b36fc9..000000000000 --- a/awx/sso/validators.py +++ /dev/null @@ -1,74 +0,0 @@ -# Python -import re - -# Python-LDAP -import ldap - -# Django -from django.core.exceptions import ValidationError -from django.utils.translation import gettext_lazy as _ - -__all__ = [ - 'validate_ldap_dn', - 'validate_ldap_dn_with_user', - 'validate_ldap_bind_dn', - 'validate_ldap_filter', - 'validate_ldap_filter_with_user', - 'validate_tacacsplus_disallow_nonascii', -] - - -def validate_ldap_dn(value, with_user=False): - if with_user: - if '%(user)s' not in value: - raise ValidationError(_('DN must include "%%(user)s" placeholder for username: %s') % value) - dn_value = value.replace('%(user)s', 'USER') - else: - dn_value = value - try: - ldap.dn.str2dn(dn_value.encode('utf-8')) - except ldap.DECODING_ERROR: - raise ValidationError(_('Invalid DN: %s') % value) - - -def validate_ldap_dn_with_user(value): - validate_ldap_dn(value, with_user=True) - - -def validate_ldap_bind_dn(value): - if not re.match(r'^[A-Za-z][A-Za-z0-9._-]*?\\[A-Za-z0-9 ._-]+?$', value.strip()) and not re.match( - r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$', value.strip() - ): - validate_ldap_dn(value) - - -def validate_ldap_filter(value, with_user=False): - value = value.strip() - if not value: - return - if with_user: - if '%(user)s' not in value: - raise ValidationError(_('DN must include "%%(user)s" placeholder for username: %s') % value) - dn_value = value.replace('%(user)s', 'USER') - else: - dn_value = value - if re.match(r'^\([A-Za-z0-9-]+?=[^()]+?\)$', dn_value): - return - elif re.match(r'^\([&|!]\(.*?\)\)$', dn_value): - try: - map(validate_ldap_filter, ['(%s)' % x for x in dn_value[3:-2].split(')(')]) - return - except ValidationError: - pass - raise ValidationError(_('Invalid filter: %s') % value) - - -def validate_ldap_filter_with_user(value): - validate_ldap_filter(value, with_user=True) - - -def validate_tacacsplus_disallow_nonascii(value): - try: - value.encode('ascii') - except (UnicodeEncodeError, UnicodeDecodeError): - raise ValidationError(_('TACACS+ secret does not allow non-ascii characters')) diff --git a/awx/sso/views.py b/awx/sso/views.py deleted file mode 100644 index c4ecdc763239..000000000000 --- a/awx/sso/views.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright (c) 2015 Ansible, Inc. -# All Rights Reserved. - -# Python -import urllib.parse -import logging - -# Django -from django.urls import reverse -from django.http import HttpResponse -from django.views.generic import View -from django.views.generic.base import RedirectView -from django.utils.encoding import smart_str -from django.conf import settings - -logger = logging.getLogger('awx.sso.views') - - -class BaseRedirectView(RedirectView): - permanent = True - - def get_redirect_url(self, *args, **kwargs): - last_path = self.request.COOKIES.get('lastPath', '') - last_path = urllib.parse.quote(urllib.parse.unquote(last_path).strip('"')) - url = reverse('ui:index') - if last_path: - return '%s#%s' % (url, last_path) - else: - return url - - -sso_error = BaseRedirectView.as_view() -sso_inactive = BaseRedirectView.as_view() - - -class CompleteView(BaseRedirectView): - def dispatch(self, request, *args, **kwargs): - response = super(CompleteView, self).dispatch(request, *args, **kwargs) - if self.request.user and self.request.user.is_authenticated: - logger.info(smart_str(u"User {} logged in".format(self.request.user.username))) - response.set_cookie('userLoggedIn', 'true') - response.setdefault('X-API-Session-Cookie-Name', getattr(settings, 'SESSION_COOKIE_NAME', 'awx_sessionid')) - return response - - -sso_complete = CompleteView.as_view() - - -class MetadataView(View): - def get(self, request, *args, **kwargs): - from social_django.utils import load_backend, load_strategy - - complete_url = reverse('social:complete', args=('saml',)) - try: - saml_backend = load_backend(load_strategy(request), 'saml', redirect_uri=complete_url) - metadata, errors = saml_backend.generate_metadata_xml() - except Exception as e: - logger.exception('unable to generate SAML metadata') - errors = e - if not errors: - return HttpResponse(content=metadata, content_type='text/xml') - else: - return HttpResponse(content=str(errors), content_type='text/plain') - - -saml_metadata = MetadataView.as_view() diff --git a/awx/static/RedHatDisplay-Medium.ttf b/awx/static/RedHatDisplay-Medium.ttf new file mode 100644 index 000000000000..a3adad30a5fd Binary files /dev/null and b/awx/static/RedHatDisplay-Medium.ttf differ diff --git a/awx/static/RedHatDisplay-Regular.ttf b/awx/static/RedHatDisplay-Regular.ttf new file mode 100644 index 000000000000..546554484b68 Binary files /dev/null and b/awx/static/RedHatDisplay-Regular.ttf differ diff --git a/awx/static/api/api.js b/awx/static/api/api.js index 67053ae2f626..98d803ad9f0c 100644 --- a/awx/static/api/api.js +++ b/awx/static/api/api.js @@ -14,7 +14,7 @@ $(function() { $('span.str').each(function() { var s = $(this).html(); if (s.match(/^\"\/.+\/\"$/) || s.match(/^\"\/.+\/\?.*\"$/)) { - $(this).html('"' + s.replace(/\"/g, '') + '"'); + $(this).html('"' + s.replaceAll('"', '') + '"'); } }); @@ -27,7 +27,7 @@ $(function() { }).each(function() { $(this).nextUntil('span.pun:contains("]")').filter('span.str').each(function() { if ($(this).text().match(/^\".+\"$/)) { - var s = $(this).text().replace(/\"/g, ''); + var s = $(this).text().replaceAll('"', ''); $(this).html('"' + s + '"'); } else if ($(this).text() !== '"') { diff --git a/awx/static/awx-spud-reading.svg b/awx/static/awx-spud-reading.svg new file mode 100644 index 000000000000..9e1a02dffff8 --- /dev/null +++ b/awx/static/awx-spud-reading.svg @@ -0,0 +1,383 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/awx/static/custom_404.html b/awx/static/custom_404.html new file mode 100644 index 000000000000..9e22cc0767d3 --- /dev/null +++ b/awx/static/custom_404.html @@ -0,0 +1,8 @@ + + + + Redirecting + + + Redirecting + diff --git a/awx/static/custom_502.html b/awx/static/custom_502.html new file mode 100644 index 000000000000..5fc541245a3c --- /dev/null +++ b/awx/static/custom_502.html @@ -0,0 +1,21 @@ + + + + On Break... + + + + +
+
+ AWX mascot reading a book + 502 +
+
+
HTTP Response: 502
+
The spud is taking a much needed break...
+
Please check back later.
+
+
+ + diff --git a/awx/static/custom_504.html b/awx/static/custom_504.html new file mode 100644 index 000000000000..5f39b7f28d6b --- /dev/null +++ b/awx/static/custom_504.html @@ -0,0 +1,21 @@ + + + + On Break... + + + + +
+
+ AWX mascot reading a book + 504 +
+
+
HTTP Response: 504
+
The spud is taking a much needed break...
+
Please check back later.
+
+
+ + diff --git a/awx/static/custom_error.css b/awx/static/custom_error.css new file mode 100644 index 000000000000..94401bb3937b --- /dev/null +++ b/awx/static/custom_error.css @@ -0,0 +1,81 @@ +@font-face { + font-family: redhat-display-medium; + src: url('./RedHatDisplay-Medium.ttf'); +} + +@font-face { + font-family: redhat-display-regular; + src: url('./RedHatDisplay-Regular.ttf'); +} + +html, body { + height:100%; + width:100%; +} + +body { + background-color: #F0F0F0; +} + +.container { + position: absolute; + top: 24px; + right: 24px; + bottom: 24px; + left: 24px; +} + +.upper_div { + background-color: #F8EBA7; + justify-content: center; + text-align: center; + height: 50%; + align-items: flex-end; + display: flex; + min-height: 450px; + width: 100%; +} + +.main_image { + height: 450px; + width:auto; +} + +.error_number { + position: absolute; + top: 23px; + right: 90px; + font-size:200px; + color: #FDBA48; + font-family: Impact, Haettenschweiler, "Franklin Gothic Bold", Charcoal, "Helvetica Inserat", "Bitstream Vera Sans Bold", "Arial Black", sans-serif; +} + +.message_div { + background-color: #FFFFFF; + border: 1px solid #D2D2D2; + text-align: center; + height: 50%; + vertical-align: top; +} + +.m1,.m2,.m3 { + color: #151515; + width: 100%; + font-family: redhat-display-medium, sans-serif; +} + +.m1 { + font-size: 24px; + padding-top: 24px; +} + +.m2 { + font-size: 20px; + padding-top: 20px; +} + +.m3 { + font-size: 16px; + padding-top: 20px; + font-family: redhat-display-regular, sans-serif; +} diff --git a/awx/templates/error.html b/awx/templates/error.html index 815235ebfc85..8f6dcc754aeb 100644 --- a/awx/templates/error.html +++ b/awx/templates/error.html @@ -18,7 +18,7 @@ @@ -74,5 +81,14 @@ {{ block.super }} + +{% is_proxied_request as proxied %} +{% if proxied %} + +{% else %} +{% endif %} {% endblock %} diff --git a/awx/templates/rest_framework/login.html b/awx/templates/rest_framework/login.html index 343d8a6ce0bb..00031dcc8ff8 100644 --- a/awx/templates/rest_framework/login.html +++ b/awx/templates/rest_framework/login.html @@ -9,7 +9,7 @@
-
+ {% csrf_token %}
{% if form.username.errors %}

{{ form.username.errors|striptags }}

@@ -31,7 +31,8 @@
+ autocorrect="off" class="form-control textinput textInput" id="id_password" + autocomplete="off" required> {% if form.password.errors %}

{{ form.password.errors|striptags }}

{% endif %} diff --git a/awx/ui/.babel.rc b/awx/ui/.babel.rc deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/awx/ui/.eslintignore b/awx/ui/.eslintignore deleted file mode 100644 index bc21e465196d..000000000000 --- a/awx/ui/.eslintignore +++ /dev/null @@ -1,11 +0,0 @@ -jest.*.js -webpack.*.js - -etc -coverage -build -node_modules -dist -images -instrumented -*test*.js diff --git a/awx/ui/.eslintrc.json b/awx/ui/.eslintrc.json deleted file mode 100644 index 7cf4965cbd80..000000000000 --- a/awx/ui/.eslintrc.json +++ /dev/null @@ -1,164 +0,0 @@ -{ - "parser": "@babel/eslint-parser", - "ignorePatterns": ["./node_modules/"], - "parserOptions": { - "requireConfigFile": false, - "ecmaVersion": 6, - "sourceType": "module", - "ecmaFeatures": { - "jsx": true, - "modules": true - }, - "babelOptions": { - "presets": ["@babel/preset-react"] - } - }, - "plugins": ["react-hooks", "jsx-a11y", "i18next", "@babel"], - "extends": [ - "airbnb", - "prettier", - "plugin:jsx-a11y/strict", - "plugin:i18next/recommended" - ], - "settings": { - "react": { - "version": "detect" - }, - "import/resolver": { - "node": { - "paths": ["src"] - } - } - }, - "env": { - "browser": true, - "node": true, - "jest": true - }, - "globals": { - "window": true - }, - "rules": { - "i18next/no-literal-string": [ - 2, - { - "markupOnly": true, - "ignoreAttribute": [ - "dateFieldName", - "timeFieldName", - "to", - "streamType", - "path", - "component", - "variant", - "key", - "position", - "promptName", - "color", - "promptId", - "headingLevel", - "size", - "target", - "autoComplete", - "trigger", - "from", - "name", - "fieldId", - "css", - "gutter", - "dataCy", - "tooltipMaxWidth", - "mode", - "aria-labelledby", - "aria-hidden", - "aria-controls", - "aria-pressed", - "sortKey", - "ouiaId", - "credentialTypeNamespace", - "link", - "value", - "credentialTypeKind", - "linkTo", - "scrollToAlignment", - "displayKey", - "sortedColumnKey", - "maxHeight", - "role", - "aria-haspopup", - "dropDirection", - "resizeOrientation", - "src", - "theme", - "gridColumns", - "rows", - "href", - "modifier", - "data-cy", - "fieldName", - "splitButtonVariant", - "pageKey" - ], - "ignore": [ - "Ansible", - "Tower", - "JSON", - "YAML", - "lg", - "hh:mm AM/PM", - "Twilio" - ], - "ignoreComponent": [ - "AboutModal", - "code", - "Omit", - "PotentialLink", - "TypeRedirect", - "Radio", - "RunOnRadio", - "NodeTypeLetter", - "SelectableItem", - "Dash", - "Plural" - ], - "ignoreCallee": ["describe"] - } - ], - "camelcase": "off", - "arrow-parens": "off", - "comma-dangle": "off", - // https://github.com/benmosher/eslint-plugin-import/issues/479#issuecomment-252500896 - "import/no-extraneous-dependencies": "off", - "max-len": [ - "error", - { - "code": 100, - "ignoreStrings": true, - "ignoreTemplateLiterals": true - } - ], - "no-continue": "off", - "no-debugger": "off", - "no-mixed-operators": "off", - "no-param-reassign": "off", - "no-plusplus": "off", - "no-underscore-dangle": "off", - "no-use-before-define": "off", - "no-multiple-empty-lines": ["error", { "max": 1 }], - "object-curly-newline": "off", - "no-trailing-spaces": ["error"], - "no-unused-expressions": ["error", { "allowShortCircuit": true }], - "react/jsx-props-no-spreading": ["off"], - "react/prefer-stateless-function": "off", - "react/prop-types": "off", - "react/sort-comp": ["error", {}], - "jsx-a11y/label-has-for": "off", - "jsx-a11y/label-has-associated-control": "off", - "react-hooks/rules-of-hooks": "error", - "react-hooks/exhaustive-deps": "warn", - "react/jsx-filename-extension": "off", - "no-restricted-exports": "off", - "react/function-component-definition": "off", - "prefer-regex-literals": "off" - } -} diff --git a/awx/ui/.linguirc b/awx/ui/.linguirc deleted file mode 100644 index 9d8897f81ecf..000000000000 --- a/awx/ui/.linguirc +++ /dev/null @@ -1,17 +0,0 @@ -{"catalogs":[{ - "path": "/locales/{locale}/messages", - "include": [""], - "exclude": ["**/node_modules/**"] -}], -"compileNamespace": "cjs", -"extractBabelOptions": {}, -"compilerBabelOptions": {}, -"fallbackLocales": { "default": "en"}, -"format": "po", -"locales": ["en","es","fr","ko","nl","zh","ja","zu"], -"orderBy": "messageId", -"pseudoLocale": "zu", -"rootDir": "./src", -"runtimeConfigModule": ["@lingui/core", "i18n"], -"sourceLocale": "en" -} diff --git a/awx/ui/.npmrc b/awx/ui/.npmrc deleted file mode 100644 index c42da845b449..000000000000 --- a/awx/ui/.npmrc +++ /dev/null @@ -1 +0,0 @@ -engine-strict = true diff --git a/awx/ui/.prettierignore b/awx/ui/.prettierignore deleted file mode 100644 index 692588cdabc6..000000000000 --- a/awx/ui/.prettierignore +++ /dev/null @@ -1,2 +0,0 @@ -build -src/locales diff --git a/awx/ui/.prettierrc b/awx/ui/.prettierrc deleted file mode 100644 index 93b2f46c80a0..000000000000 --- a/awx/ui/.prettierrc +++ /dev/null @@ -1,8 +0,0 @@ -{ - "printWidth": 80, - "tabWidth": 2, - "semi": true, - "singleQuote": true, - "trailingComma": "es5", - "bracketSpacing": true -} diff --git a/awx/ui/CONTRIBUTING.md b/awx/ui/CONTRIBUTING.md deleted file mode 100644 index dba8b13423ef..000000000000 --- a/awx/ui/CONTRIBUTING.md +++ /dev/null @@ -1,363 +0,0 @@ -# Ansible AWX UI With PatternFly - -Hi there! We're excited to have you as a contributor. - -Have questions about this document or anything not covered here? Feel free to reach out to any of the contributors of this repository. - -## Table of contents - -- [Ansible AWX UI With PatternFly](#ansible-awx-ui-with-patternfly) - - [Table of contents](#table-of-contents) - - [Things to know prior to submitting code](#things-to-know-prior-to-submitting-code) - - [Setting up your development environment](#setting-up-your-development-environment) - - [Prerequisites](#prerequisites) - - [Node and npm](#node-and-npm) - - [Build the User Interface](#build-the-user-interface) - - [Accessing the AWX web interface](#accessing-the-awx-web-interface) - - [AWX REST API Interaction](#awx-rest-api-interaction) - - [Handling API Errors](#handling-api-errors) - - [Forms](#forms) - - [Working with React](#working-with-react) - - [App structure](#app-structure) - - [Patterns](#patterns) - - [Bootstrapping the application (root src/ files)](#bootstrapping-the-application-root-src-files) - - [Naming files](#naming-files) - - [Naming components that use the context api](#naming-components-that-use-the-context-api) - - [Class constructors vs Class properties](#class-constructors-vs-class-properties) - - [Binding](#binding) - - [Typechecking with PropTypes](#typechecking-with-proptypes) - - [Custom Hooks](#custom-hooks) - - [Naming Functions](#naming-functions) - - [Default State Initialization](#default-state-initialization) - - [Testing components that use contexts](#testing-components-that-use-contexts) - - [Internationalization](#internationalization) - - [Marking strings for translation and replacement in the UI](#marking-strings-for-translation-and-replacement-in-the-ui) - - [Setting up .po files to give to translation team](#setting-up-po-files-to-give-to-translation-team) - - [Marking an issue to be translated](#marking-an-issue-to-be-translated) - -## Things to know prior to submitting code - -- All code submissions are done through pull requests against the `devel` branch. -- If collaborating with someone else on the same branch, please use `--force-with-lease` instead of `--force` when pushing up code. This will prevent you from accidentally overwriting commits pushed by someone else. For more information, see https://git-scm.com/docs/git-push#git-push---force-with-leaseltrefnamegt -- We use a [code formatter](https://prettier.io/). Before adding a new commit or opening a PR, please apply the formatter using `npm run prettier` -- We adopt the following code style guide: - - functions should adopt camelCase - - constructors/classes should adopt PascalCase - - constants to be exported should adopt UPPERCASE -- For strings, we adopt the `sentence capitalization` since it is a [Patternfly style guide](https://www.patternfly.org/v4/ux-writing/capitalization). - -## Setting up your development environment - -The UI is built using [ReactJS](https://reactjs.org/docs/getting-started.html) and [Patternfly](https://www.patternfly.org/). - -### Prerequisites - -#### Node and npm - -The AWX UI requires the following: - -- Node >= 16.13.1 LTS -- NPM 8.x - -Run the following to install all the dependencies: - -```bash -(host) $ npm install -``` - -#### Build the User Interface - -Run the following to build the AWX UI: - -```bash -(host) $ npm run start -``` - -## Accessing the AWX web interface - -You can now log into the AWX web interface at [https://127.0.0.1:3001](https://127.0.0.1:3001). - -## AWX REST API Interaction - -This interface is built on top of the AWX REST API. If a component needs to interact with the API then the model that corresponds to that base endpoint will need to be imported from the api module. - -Example: - -`import { OrganizationsAPI, UsersAPI } from '../../../api';` - -All models extend a `Base` class which provides an interface to the standard HTTP methods (GET, POST, PUT etc). Methods that are specific to that endpoint should be added directly to model's class. - -**Mixins** - For related endpoints that apply to several different models a mixin should be used. Mixins are classes with a number of methods and can be used to avoid adding the same methods to a number of different models. A good example of this is the Notifications mixin. This mixin provides generic methods for reading notification templates and toggling them on and off. -Note that mixins can be chained. See the example below. - -Example of a model using multiple mixins: - -```javascript -import NotificationsMixin from '../mixins/Notifications.mixin'; -import InstanceGroupsMixin from '../mixins/InstanceGroups.mixin'; - -class Organizations extends InstanceGroupsMixin(NotificationsMixin(Base)) { - ... -} - -export default Organizations; -``` - -**Testing** - The easiest way to mock the api module in tests is to use jest's [automatic mock](https://jestjs.io/docs/en/es6-class-mocks#automatic-mock). This syntax will replace the class with a mock constructor and mock out all methods to return undefined by default. If necessary, you can still override these mocks for specific tests. See the example below. - -Example of mocking a specific method for every test in a suite: - -```javascript -import { OrganizationsAPI } from '../../../../src/api'; - -// Mocks out all available methods. Comparable to: -// OrganizationsAPI.readAccessList = jest.fn(); -// but for every available method -jest.mock('../../../../src/api'); - -// Return a specific mock value for the readAccessList method -beforeEach(() => { - OrganizationsAPI.readAccessList.mockReturnValue({ foo: 'bar' }); -}); - -// Reset mocks -afterEach(() => { - jest.clearAllMocks(); -}); - -... -``` - -**Test Attributes** - -It should be noted that the `dataCy` prop, as well as its equivalent attribute `data-cy`, are used as flags for any UI test that wants to avoid relying on brittle CSS selectors such as `nth-of-type()`. - -## Handling API Errors - -API requests can and will fail occasionally so they should include explicit error handling. The three _main_ categories of errors from our perspective are: content loading errors, form submission errors, and other errors. The patterns currently in place for these are described below: - -- **content loading errors** - These are any errors that occur when fetching data to initialize a page or populate a list. For these, we conditionally render a _content error component_ in place of the unresolved content. - -- **form submission errors** - If an error is encountered when submitting a form, we display the error message on the form. For field-specific validation errors, we display the error message beneath the specific field(s). For general errors, we display the error message at the bottom of the form near the action buttons. An error that happens when requesting data to populate a form is not a form submission error, it is still a content error and is handled as such (see above). - -- **other errors** - Most errors will fall into the first two categories, but for miscellaneous actions like toggling notifications, deleting a list item, etc. we display an alert modal to notify the user that their requested action couldn't be performed. - -## Forms - -Our forms should have a known, consistent, and fully-resolved starting state before it is possible for a user, keyboard-mouse, screen reader, or automated test to interact with them. If multiple network calls are needed to populate a form, resolve them all before displaying the form or showing a content error. When multiple requests are needed to create or update the resources represented by a form, resolve them all before transitioning the ui to a success or failure state. - -## Working with React - -### App structure - -All source code lives in the `/src` directory and all tests are colocated with the components that they test. - -Inside these folders, the internal structure is: - -- **/api** - All classes used to interact with API's are found here. See [AWX REST API Interaction](#awx-rest-api-interaction) for more information. -- **/components** - All generic components that are meant to be used in multiple contexts throughout awx. Things like buttons, tabs go here. -- **/contexts** - Components which utilize react's context api. -- **/hooks** - Custom react [hooks](https://reactjs.org/docs/hooks-custom.html) -- **/locales** - [Internationalization](#internationalization) config and source files. -- **/screens** - Based on the various routes of awx. - - **/shared** - Components that are meant to be used specifically by a particular route, but might be sharable across pages of that route. For example, a form component which is used on both add and edit screens. -- **/util** - Stateless helper functions that aren't tied to react. - -### Patterns - -- A **screen** shouldn't import from another screen. If a component _needs_ to be shared between two or more screens, it is a generic and should be moved to `src/components`. - -#### Bootstrapping the application (root src/ files) - -In the root of `/src`, there are a few files which are used to initialize the react app. These are - -- **index.js** - - Connects react app to root dom node. - - Sets up root route structure, navigation grouping and login modal - - Calls base context providers - - Imports .scss styles. -- **app.js** - - Sets standard page layout, about modal, and root dialog modal. -- **RootProvider.js** - - Sets up all context providers. - - Initializes i18n and router - -### Naming files - -Ideally, files should be named the same as the component they export, and tests with `.test` appended. In other words, `` would be defined in `FooBar.js`, and its tests would be defined in `FooBar.test.js`. - -#### Naming components that use the context api - -**File naming** - Since contexts export both consumer and provider (and potentially in withContext function form), the file can be simplified to be named after the consumer export. In other words, the file containing the `Network` context components would be named `Network.js`. - -**Component naming and conventions** - In order to provide a consistent interface with react-router and [lingui](https://lingui.js.org/), as well as make their usage easier and less verbose, context components follow these conventions: - -- Providers are wrapped in a component in the `FooProvider` format. - - The value prop of the provider should be pulled from state. This is recommended by the react docs, [here](https://reactjs.org/docs/context.html#caveats). - - The provider should also be able to accept its value by prop for testing. - - Any sort of code related to grabbing data to put on the context should be done in this component. -- Consumers are wrapped in a component in the `Foo` format. -- If it makes sense, consumers can be exported as a function in the `withFoo()` format. If a component is wrapped in this function, its context values are available on the component as props. - -### Class constructors vs Class properties - -It is good practice to use constructor-bound instance methods rather than methods as class properties. Methods as arrow functions provide lexical scope and are bound to the Component class instance instead of the class itself. This makes it so we cannot easily test a Component's methods without invoking an instance of the Component and calling the method directly within our tests. - -BAD: - -```javascript -class MyComponent extends React.Component { - constructor(props) { - super(props); - } - - myEventHandler = () => { - // do a thing - }; -} -``` - -GOOD: - -```javascript -class MyComponent extends React.Component { - constructor(props) { - super(props); - this.myEventHandler = this.myEventHandler.bind(this); - } - - myEventHandler() { - // do a thing - } -} -``` - -### Binding - -It is good practice to bind our class methods within our class constructor method for the following reasons: - -1. Avoid defining the method every time `render()` is called. -2. [Performance advantages](https://stackoverflow.com/a/44844916). -3. Ease of [testing](https://github.com/airbnb/enzyme/issues/365). - -### Typechecking with PropTypes - -Shared components should have their prop values typechecked. This will help catch bugs when components get refactored/renamed. - -```javascript -About.propTypes = { - ansible_version: PropTypes.string, - isOpen: PropTypes.bool, - onClose: PropTypes.func.isRequired, - version: PropTypes.string, -}; - -About.defaultProps = { - ansible_version: null, - isOpen: false, - version: null, -}; -``` - -### Custom Hooks - -There are currently a few custom hooks: - -1. [useRequest](https://github.com/ansible/awx/blob/devel/awx/ui/src/util/useRequest.js#L21) encapsulates main actions related to requests. -2. [useDismissableError](https://github.com/ansible/awx/blob/devel/awx/ui/src/util/useRequest.js#L71) provides controls for "dismissing" an error message. -3. [useDeleteItems](https://github.com/ansible/awx/blob/devel/awx/ui/src/util/useRequest.js#L98) handles deletion of items from a paginated item list. -4. [useSelected](https://github.com/ansible/awx/blob/devel/awx/ui/src/util/useSelected.js#L14) provides a way to read and update a selected list. - -### Naming Functions - -Here are the guidelines for how to name functions. - -| Naming Convention | Description | -| ----------------- | --------------------------------------------------------------------------------- | -| `handle` | Use for methods that process events | -| `on` | Use for component prop names | -| `toggle` | Use for methods that flip one value to the opposite value | -| `show` | Use for methods that always set a value to show or add an element | -| `hide` | Use for methods that always set a value to hide or remove an element | -| `create` | Use for methods that make API `POST` requests | -| `read` | Use for methods that make API `GET` requests | -| `update` | Use for methods that make API `PATCH` requests | -| `destroy` | Use for methods that make API `DESTROY` requests | -| `replace` | Use for methods that make API `PUT` requests | -| `disassociate` | Use for methods that pass `{ disassociate: true }` as a data param to an endpoint | -| `associate` | Use for methods that pass a resource id as a data param to an endpoint | -| `can` | Use for props dealing with RBAC to denote whether a user has access to something | - -### Default State Initialization - -When declaring empty initial states, prefer the following instead of leaving them undefined: - -```javascript -this.state = { - somethingA: null, - somethingB: [], - somethingC: 0, - somethingD: {}, - somethingE: '', -}; -``` - -### Testing components that use contexts - -We have several React contexts that wrap much of the app, including those from react-router, lingui, and some of our own. When testing a component that depends on one or more of these, you can use the `mountWithContexts()` helper function found in `testUtils/enzymeHelpers.js`. This can be used just like Enzyme's `mount()` function, except it will wrap the component tree with the necessary context providers and basic stub data. - -If you want to stub the value of a context, or assert actions taken on it, you can customize a contexts value by passing a second parameter to `mountWithContexts`. For example, this provides a custom value for the `Config` context: - -```javascript -const config = { - custom_virtualenvs: ['foo', 'bar'], -}; -mountWithContexts(, { - context: { config }, -}); -``` - -Now that these custom virtual environments are available in this `OrganizationForm` test we can assert that the component that displays -them is rendering properly. - -The object containing context values looks for five known contexts, identified by the keys `linguiPublisher`, `router`, `config`, `network`, and `dialog` — the latter three each referring to the contexts defined in `src/contexts`. You can pass `false` for any of these values, and the corresponding context will be omitted from your test. For example, this will mount your component without the dialog context: - -```javascript -mountWithContexts(< { - context: { - dialog: false, - } -}); -``` - -## Internationalization - -Internationalization leans on the [lingui](https://github.com/lingui/js-lingui) project. [Official documentation here](https://lingui.js.org/). We use this library to mark our strings for translation. If you want to see this in action you'll need to take the following steps: - -### Marking strings for translation and replacement in the UI - -The lingui library provides various React helpers for dealing with both marking strings for translation, and replacing strings that have been translated. For consistency and ease of use, we have consolidated on one pattern for the codebase. To set strings to be translated in the UI: - -- import the t template tag function from the @lingui/macro package. -- wrap your string using the following format: `` t`String to be translated` `` - -**Note:** If you have a variable string with text that needs translating, you must wrap it in `` t`${variable} string` `` where it is defined. Then you must run `npm run extract-strings` to generate new `.po` files and submit those files along with your pull request. - -**Note:** We try to avoid the `I18n` consumer, or `i18nMark` function lingui gives us access to in this repo. i18nMark does not actually replace the string in the UI (leading to the potential for untranslated bugs), and the other helpers are redundant. Settling on a consistent, single pattern helps us ease the mental overhead of the need to understand the ins and outs of the lingui API. - -**Note:** Pluralization can be complicated so it is best to allow lingui handle cases where we have a string that may need to be pluralized based on number of items, or count. In that case lingui provides a `` component, and a `plural()` function. When adding or updating strings in a `` tag you must run `npm run extra-strings` and submit the new `.po` files with your pull request. See documentation [here](https://lingui.js.org/guides/plurals.html?highlight=pluralization). - -You can learn more about the ways lingui and its React helpers at [this link](https://lingui.js.org/tutorials/react-patterns.html). - -### Setting up .po files to give to translation team - -1. Make sure that the languages you intend to translate are set correctly in the `.linguirc` configuration file. -2. `npm run extract-strings` to create .po files for each language specified. The .po files will be placed in src/locales. When updating strings that are used by `` or `plural()` you will need to run this command to get the strings to render properly. This command will create `.po` files for each of the supported languages that will need to be committed with your PR. -3. Open up the .po file for the language you want to test and add some translations. In production we would pass this .po file off to the translation team. -4. Once you've edited your .po file (or we've gotten a .po file back from the translation team) run `npm run compile-strings`. This command takes the .po files and turns them into a minified JSON object and can be seen in the `messages.js` file in each locale directory. These files get loaded at the App root level (see: App.js). -5. Change the language in your browser and reload the page. You should see your specified translations in place of English strings. - -### Marking an issue to be translated - -1. Issues marked with `component:I10n` should not be closed after the issue was fixed. -2. Remove the label `state:needs_devel`. -3. Add the label `state:pending_translations`. At this point, the translations will be batch translated by a maintainer, creating relevant entries in the PO files. Then after those translations have been merged, the issue can be closed. diff --git a/awx/ui/Dockerfile b/awx/ui/Dockerfile deleted file mode 100644 index fda48b9c9276..000000000000 --- a/awx/ui/Dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM node:16.13.1 -ARG NPMRC_FILE=.npmrc -ENV NPMRC_FILE=${NPMRC_FILE} -ARG TARGET='https://awx:8043' -ENV TARGET=${TARGET} -ENV CI=true -WORKDIR /ui -ADD .eslintignore .eslintignore -ADD .eslintrc.json .eslintrc.json -ADD .linguirc .linguirc -ADD jsconfig.json jsconfig.json -ADD public public -ADD package.json package.json -ADD package-lock.json package-lock.json -COPY ${NPMRC_FILE} .npmrc -RUN npm install -ADD src src -EXPOSE 3001 -CMD [ "npm", "start" ] diff --git a/awx/ui/Makefile b/awx/ui/Makefile new file mode 100644 index 000000000000..53b498d20bc7 --- /dev/null +++ b/awx/ui/Makefile @@ -0,0 +1,123 @@ +## UI_DIR: Relative path to the directory containing this Makefile +UI_DIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST)))) + +## Path to your local clone of the UI repo +# NOTE: you will not be able to build within the docker-compose development environment if you use this option +UI_LOCAL ?= + +## Git repo and branch to the UI repo +UI_GIT_REPO ?= https://github.com/ansible/ansible-ui.git +UI_GIT_BRANCH ?= main + +## Product name to display on the UI used in UI build process +PRODUCT ?= AWX + +.PHONY: ui +## Default build target of ui Makefile, builds ui/build +ui: ui/build + +.PHONY: ui/build +## Build ui/build +ui/build: $(UI_DIR)/build + +## True build target for ui. +$(UI_DIR)/build: + @$(MAKE) $(UI_DIR)/src/build/awx + @echo "=== Copying $(UI_DIR)/src/build to $(UI_DIR)/build ===" + @rm -rf $(UI_DIR)/build + @cp -r $(UI_DIR)/src/build $(UI_DIR) + @echo "=== Done building $(UI_DIR)/build ===" + +.PHONY: ui/src/build +## Build ui/src/build +ui/src/build: $(UI_DIR)/src/build/awx + +## True target for ui/src/build. Build ui from source. +$(UI_DIR)/src/build/awx: $(UI_DIR)/src $(UI_DIR)/src/node_modules/webpack + @echo "=== Building ui ===" + @cd $(UI_DIR)/src && PRODUCT="$(PRODUCT)" PUBLIC_PATH=/static/awx/ ROUTE_PREFIX=/ npm run build:awx + @mv $(UI_DIR)/src/build/awx/index.html $(UI_DIR)/src/build/awx/index_awx.html + +.PHONY: ui/src +## Clone or link src of UI to ui/src, will re-clone/link/update if necessary. +ui/src: $(UI_DIR)/src + +# TODO: Rewrite this big bash script in a more readable way. +## True target for ui/src. +$(UI_DIR)/src: + @echo "=== Setting up $(UI_DIR)/src ===" + @if [ ! -z "$(UI_LOCAL)" ]; then \ + if [ -d $(UI_DIR)/src ]; then \ + if [ "$$(readlink $(UI_DIR)/src)" = "$(UI_LOCAL)" ]; then \ + echo "SKIP: ui/src. $(UI_DIR)/src already linked to $(UI_LOCAL)."; \ + else \ + echo "=== Linking $(UI_DIR)/src to $(UI_LOCAL) ==="; \ + rm -rf $(UI_DIR)/src; \ + ln -s $(UI_LOCAL) $(UI_DIR)/src; \ + fi; \ + else \ + echo "=== Linking $(UI_DIR)/src to $(UI_LOCAL) ==="; \ + ln -s $(UI_LOCAL) $(UI_DIR)/src; \ + fi; \ + elif [ ! -z "$(UI_GIT_REPO)" ]; then \ + if [ -d $(UI_DIR)/src ]; then \ + GIT_REMOTE_ORIGIN=$$(cd $(UI_DIR)/src && git remote get-url origin); \ + GIT_REMOTE_BRANCH=$$(cd $(UI_DIR)/src && git rev-parse --abbrev-ref HEAD); \ + if [ "$$GIT_REMOTE_ORIGIN" = "$(UI_GIT_REPO)" ] && [ "$$GIT_REMOTE_BRANCH" = "$(UI_GIT_BRANCH)" ]; then \ + echo "=== Updating $(UI_DIR)/src from $(UI_GIT_BRANCH) of $(UI_GIT_REPO) ==="; \ + git fetch && git pull; \ + else \ + echo "=== Cloning $(UI_DIR)/src from $(UI_GIT_BRANCH) of $(UI_GIT_REPO) ==="; \ + rm -rf $(UI_DIR)/src; \ + git clone --depth 1 --branch $(UI_GIT_BRANCH) $(UI_GIT_REPO) $(UI_DIR)/src || true; \ + fi; \ + else \ + echo "=== Cloning $(UI_DIR)/src from $(UI_GIT_BRANCH) of $(UI_GIT_REPO) ==="; \ + git clone --depth 1 --branch $(UI_GIT_BRANCH) $(UI_GIT_REPO) $(UI_DIR)/src || true; \ + fi; \ + else \ + echo "FAILED: ui/src. UI_LOCAL and UI_GIT_REPO are not set."; \ + exit 1; \ + fi + +.PHONY: ui/src/webpack +## Install webpack. +ui/src/webpack: $(UI_DIR)/src/node_modules/webpack + +## True target for ui/src/webpack. +$(UI_DIR)/src/node_modules/webpack: + @echo "=== Installing webpack ===" + @cd $(UI_DIR)/src && \ + maj=$$(node -p "process.versions.node.split('.')[0]"); \ + if [ "$$maj" != "18" ]; then \ + echo "Error: Need Node 18.x; found $$(node -v)" >&2; \ + exit 1; \ + fi; \ + npm install webpack + + +.PHONY: clean/ui +## Clean ui +clean/ui: clean/ui/build clean/ui/src + +.PHONY: clean/ui/src +## Clean ui src +clean/ui/src: + rm -rf $(UI_DIR)/src + +.PHONY: clean/ui/build +## Clean ui build +clean/ui/build: + rm -rf $(UI_DIR)/build + +.PHONY: $(UI_DIR)/clean +## Alias for clean/ui, so we can run `make clean` directly in ui +$(UI_DIR)/clean: clean/ui + +.PHONY: $(UI_DIR)/clean/src +## Alias for clean/ui/src, so we can run `make clean/src` directly in ui +$(UI_DIR)/clean/src: clean/ui/src + +.PHONY: $(UI_DIR)/clean/build +## Alias for clean/ui/build, so we can run `make clean/build` directly in ui +$(UI_DIR)/clean/build: clean/ui/build diff --git a/awx/ui/README.md b/awx/ui/README.md index 4c7bb9d58025..2b0cf61329c4 100644 --- a/awx/ui/README.md +++ b/awx/ui/README.md @@ -1,115 +1,47 @@ -# AWX-UI +# Instruction to build ui directly from this directory -## Requirements -- node >= 16.13.1, npm >= 8.x make, git +## Set src of the ui repo -## Development -The API development server will need to be running. See [CONTRIBUTING.md](../../CONTRIBUTING.md). +### Via GIT -```shell -# install -npm --prefix=awx/ui install - -# Start the ui development server. While running, the ui will be reachable -# at https://127.0.0.1:3001 and updated automatically when code changes. -npm --prefix=awx/ui start +```bash +export UI_GIT_REPO=https:// ``` -### Build for the Development Containers -If you just want to build a ui for the container-based awx development -environment and do not need to work on the ui code, use these make targets: - -```shell -# The ui will be reachable at https://localhost:8043 or -# http://localhost:8013 -make ui-devel +or -# clean up -make clean-ui +```bash +export UI_GIT_REPO=git@ ``` -### Using an External Server -If you normally run awx on an external host/server (in this example, `awx.local`), -you'll need use the `TARGET` environment variable when starting the ui development -server: +optionally set branch (default is main) -```shell -TARGET='https://awx.local:8043' npm --prefix awx/ui start +```bash +export UI_GIT_BRANCH=main ``` -## Testing -```shell -# run code formatting check -npm --prefix awx/ui run prettier-check - -# run lint checks -npm --prefix awx/ui run lint - -# run all unit tests -npm --prefix awx/ui run test +### Via symlink to existing clone -# run a single test (in this case the login page test): -npm --prefix awx/ui test -- src/screens/Login/Login.test.jsx +NOTE: UI_LOCAL have higher precedence than UI_GIT_REPO, if UI_LOCAL is set, UI_GIT_REPO will be ignored. -# start the test watcher and run tests on files that you've changed -npm --prefix awx/ui run test-watch - -# start the tests and get the coverage report after the tests have completed -npm --prefix awx/ui run test -- --coverage +```bash +export UI_LOCAL = /path/to/your/ui ``` -#### Note: -- Once the test watcher is up and running you can hit `a` to run all the tests. -- All commands are run on your host machine and not in the api development containers. - - -## Updating Dependencies -It is not uncommon to run the ui development tooling outside of the awx development -container. That said, dependencies should always be modified from within the -container to ensure consistency. - -```shell -# make sure the awx development container is running and open a shell -docker exec -it tools_awx_1 bash -# start with a fresh install of the current dependencies -(tools_awx_1)$ make clean-ui && npm --prefix=awx/ui ci +## Build -# add an exact development dependency -(tools_awx_1)$ npm --prefix awx/ui install --save-dev --save-exact dev-package@1.2.3 - -# add an exact production dependency -(tools_awx_1)$ npm --prefix awx/ui install --save --save-exact prod-package@1.23 - -# remove a development dependency -(tools_awx_1)$ npm --prefix awx/ui uninstall --save-dev dev-package - -# remove a production dependency -(tools_awx_1)$ npm --prefix awx/ui uninstall --save prod-package +```bash +make ui +``` -# exit the container -(tools_awx_1)$ exit +## Rebuild -# add the updated package.json and package-lock.json files to scm -git add awx/ui/package.json awx/ui/package-lock.json +```bash +make -B ui ``` -#### Note: -- Building the ui can use up a lot of resources. If you're running docker for mac or similar -virtualization, the default memory limit may not be enough and you should increase it. - -## Building for Production -```shell -# built files are placed in awx/ui/build -npm --prefix awx/ui run build -``` - -## CI Container -To run: +## Clean -```shell -cd awx/awx/ui -docker build -t awx-ui . -docker run --name tools_ui_1 --network _sources_default --link 'tools_awx_1:awx' -e TARGET="https://awx:8043" -p '3001:3001' --rm -v $(pwd)/src:/ui/src awx-ui +```bash +make clean/ui ``` - -**Note:** This is for CI, test systems, zuul, etc. For local development, see [usage](https://github.com/ansible/awx/blob/devel/awx/ui/README.md#Development) diff --git a/awx/ui/SEARCH.md b/awx/ui/SEARCH.md deleted file mode 100644 index 4893b5ba131b..000000000000 --- a/awx/ui/SEARCH.md +++ /dev/null @@ -1,416 +0,0 @@ -# Simple Search - -## UX Considerations - -Historically, the code that powers search in the AngularJS version of the AWX UI is very complex and prone to bugs. In order to reduce that complexity, we've made some UX decisions to help make the code easier to maintain. - -**ALL query params namespaced and in url bar** - -This includes lists that aren't necessarily hyperlinked, like lookup lists. The reason behind this is so we can treat the url bar as the source of truth for queries always. Any params that have both a key AND value that is in the defaultParams section of the qs config are stripped out of the search string (see "Encoding for UI vs. API" for more info on this point) - -**Django fuzzy search (`?search=`) is not accessible outside of "advanced search"** - -In current smart search typing a term with no key utilizes `?search=` i.e. for "foo" tag, `?search=foo` is given. `?search=` looks on a static list of field name "guesses" (such as name, description, etc.), as well as specific fields as defined for each endpoint (for example, the events endpoint looks for a "stdout" field as well). Due to the fact a key will always be present on the left-hand of simple search, it doesn't make sense to use `?search=` as the default. - -We may allow passing of `?search=` through our future advanced search interface. Some details that were gathered in planning phases about `?search=` that might be helpful in the future: - -- `?search=` tags are OR'd together (union is returned). -- `?search=foo&name=bar` returns items that have a name field of bar (not case insensitive) AND some text field with foo on it -- `?search=foo&search=bar&name=baz` returns (foo in name OR foo in description OR ...) AND (bar in name OR bar in description OR ...) AND (baz in name) -- similarly `?related__search=` looks on the static list of "guesses" for models related to the endpoint. The specific fields are not "searched" for `?related__search=`. -- `?related__search=` not currently used in awx ui - -**A note on clicking a tag to putting it back into the search bar** - -This was brought up as a nice to have when we were discussing our initial implementation of search in the new application. Since there isn't a way we would be able to know if the user created the tag from the simple or advanced search interface, we wouldn't know where to put it back. This breaks our idea of using the query params as the exclusive source of truth, so we've decided against implementing it for now. - -## Tasklist - -### DONE - -- DONE update handleSearch to follow handleSort param -- DONE update qsConfig columns to utilize isSearchable bool (just like isSortable bool) -- DONE enter keydown in text search bar to search -- DONE get decoded params and write test -- DONE make list header component -- DONE make filter component -- DONE make filters show up for empty list -- DONE make clear all button -- DONE styling of FilterTags component -- DONE clear out text input after tag has been made -- DONE deal with duplicate key tags being added/removed in qs util file -- DONE deal with widgetry changing between one dropdown option to the left of search and many -- DONE bug: figure out why ?name=org returning just org not “org 2” -- DONE update contrib file to have the first section with updated text as is in this pr description. -- DONE rebase with latest awx-pf changes -- DONE styling of search bar -- DONE make filter and list header tests -- DONE change api paramsSerializer to handle duplicate key stuff -- DONE update qs update function to be smaller, simple param functions, as opposed to one big one with a lot of params -- DONE add search filter removal test for qs. -- DONE remove button for search tags of duplicate keys are broken, fix that - -### TODO pre-holiday break - -- Update COLUMNS to SORT_COLUMNS and SEARCH_COLUMNS -- Update to using new PF Toolbar component (currently an experimental component) -- Change the right-hand input based on the type of key selected on the left-hand side. In addition to text input, for our MVP we will support: - - number input - - select input (multiple-choice configured from UI or Options) -- Update the following lists to have the following keys: - -**Jobs list** (signed off earlier in chat) - -- Name (which is also the name of the job template) - search is ?name=jt -- Job ID - search is ?id=13 -- Label name - search is ?labels\_\_name=foo -- Job type (dropdown on right with the different types) ?type = job -- Created by (username) - search is ?created_by\_\_username=admin -- Status - search (dropdown on right with different statuses) is ?status=successful - -Instances of jobs list include: - -- Jobs list -- Host completed jobs list -- JT completed jobs list - -**Organization list** - -- Name - search is ?name=org -- ? Team name (of a team in the org) - search is ?teams\_\_name=ansible -- ? Username (of a user in the org) - search is ?users\_\_username=johndoe - -Instances of orgs list include: - -- Orgs list -- User orgs list -- Lookup on Project -- Lookup on Credential -- Lookup on Inventory -- User access add wizard list -- Team access add wizard list - -**Instance Groups list** - -- Name - search is ?name=ig -- ? is_container_group boolean choice (doesn't work right now in API but will soon) - search is ?is_container_group=true -- ? credential name - search is ?credentials\_\_name=kubey - -Instance of instance groups list include: - -- Lookup on Org -- Lookup on JT -- Lookup on Inventory - -**Users list** - -- Username - search is ?username=johndoe -- First Name - search is ?first_name=John -- Last Name - search is ?last_name=Doe -- ? (if not superfluous, would not include on Team users list) Team Name - search is ?teams\_\_name=team_of_john_does (note API issue: User has no field named "teams") -- ? (only for access or permissions list) Role Name - search is ?roles\_\_name=Admin (note API issue: Role has no field "name") -- ? (if not superfluous, would not include on Organization users list) ORg Name - search is ?organizations\_\_name=org_of_jhn_does - -Instance of user lists include: - -- User list -- Org user list -- Access list for Org, JT, Project, Credential, Inventory, User and Team -- Access list for JT -- Access list Project -- Access list for Credential -- Access list for Inventory -- Access list for User -- Access list for Team -- Team add users list -- Users list in access wizard (to add new roles for a particular list) for Org -- Users list in access wizard (to add new roles for a particular list) for JT -- Users list in access wizard (to add new roles for a particular list) for Project -- Users list in access wizard (to add new roles for a particular list) for Credential -- Users list in access wizard (to add new roles for a particular list) for Inventory - -**Teams list** - -- Name - search is ?name=teamname -- ? Username (of a user in the team) - search is ?users\_\_username=johndoe -- ? (if not superfluous, would not include on Organizations teams list) Org Name - search is ?organizations\_\_name=org_of_john_does - -Instance of team lists include: - -- Team list -- Org team list -- User team list -- Team list in access wizard (to add new roles for a particular list) for Org -- Team list in access wizard (to add new roles for a particular list) for JT -- Team list in access wizard (to add new roles for a particular list) for Project -- Team list in access wizard (to add new roles for a particular list) for Credential -- Team list in access wizard (to add new roles for a particular list) for Inventory - -**Credentials list** - -- Name -- ? Type (dropdown on right with different types) -- ? Created by (username) -- ? Modified by (username) - -Instance of credential lists include: - -- Credential list -- Lookup for JT -- Lookup for Project -- User access add wizard list -- Team access add wizard list - -**Projects list** - -- Name - search is ?name=proj -- ? Type (dropdown on right with different types) - search is scm_type=git -- ? SCM URL - search is ?scm_url=github.com/ansible/test-playbooks -- ? Created by (username) - search is ?created_by\_\_username=admin -- ? Modified by (username) - search is ?modified_by\_\_username=admin - -Instance of project lists include: - -- Project list -- Lookup for JT -- User access add wizard list -- Team access add wizard list - -**Templates list** - -- Name - search is ?name=cleanup -- ? Type (dropdown on right with different types) - search is ?type=playbook_run -- ? Playbook name - search is ?job_template\_\_playbook=debug.yml -- ? Created by (username) - search is ?created_by\_\_username=admin -- ? Modified by (username) - search is ?modified_by\_\_username=admin - -Instance of template lists include: - -- Template list -- Project Templates list - -**Inventories list** - -- Name - search is ?name=inv -- ? Created by (username) - search is ?created_by\_\_username=admin -- ? Modified by (username) - search is ?modified_by\_\_username=admin - -Instance of inventory lists include: - -- Inventory list -- Lookup for JT -- User access add wizard list -- Team access add wizard list - -**Groups list** - -- Name - search is ?name=group_name -- ? Created by (username) - search is ?created_by\_\_username=admin -- ? Modified by (username) - search is ?modified_by\_\_username=admin - -Instance of group lists include: - -- Group list - -**Hosts list** - -- Name - search is ?name=hostname -- ? Created by (username) - search is ?created_by\_\_username=admin -- ? Modified by (username) - search is ?modified_by\_\_username=admin - -Instance of host lists include: - -- Host list - -**Notifications list** - -- Name - search is ?name=notification_template_name -- ? Type (dropdown on right with different types) - search is ?type=slack -- ? Created by (username) - search is ?created_by\_\_username=admin -- ? Modified by (username) - search is ?modified_by\_\_username=admin - -Instance of notification lists include: - -- Org notification list -- JT notification list -- Project notification list - -### TODO backlog - -- Change the right-hand input based on the type of key selected on the left-hand side. We will eventually want to support: - - lookup input (selection of particular resources, based on API list endpoints) - - date picker input -- Update the following lists to have the following keys: - - Update all **name and **username related field search-based keys to be type-ahead lookup based searches - -## Code Details - -### Search component - -The component looks like this: - -``` - -``` - -**qsConfig** is used to get namespace so that multiple lists can be on the page. When tags are modified they append namespace to query params. The qsConfig is also used to get "type" of fields in order to correctly parse values as int or date as it is translating. - -**columns** are passed as an array, as defined in the screen where the list is located. You pass a bool `isDefault` to indicate that should be the key that shows up in the left-hand dropdown as default in the UI. If you don't pass any columns, a default of `isDefault=true` will be added to a name column, which is nearly universally shared throughout the models of awx. - -There is a type attribute that can be `'string'`, `'number'` or `'choice'` (and in the future, `'date'` and `'lookup'`), which will change the type of input on the right-hand side of the search bar. For a key that has a set number of choices, you will pass a choices attribute, which is an array in the format choices: [{label: 'Foo', value: 'foo'}] - -**onSearch** calls the `mergeParams` qs util in order to add new tags to the queryset. mergeParams is used so that we can support duplicate keys (see mergeParams vs. replaceParams for more info). - -### ListHeader component - -`DataListToolbar`, `EmptyListControls`, and `FilterTags` components were created or moved to a new sub-component of `PaginatedDataList`, `ListHeader`. This allowed us to consolidate the logic between both lists with data (which need to show search, sort, any search tags currently active, and actions) as well as empty lists (which need to show search tags currently active so they can be removed, potentially getting you back to a "list-has-data" state, as well as a subset of options still valid, such as "add"). - -The ability to search and remove filters, as well as sort the list is handled through callbacks which are passed from functions defined in `ListHeader`. These are the following: - -- `handleSort(key, direction)` - use key and direction of sort to change the order_by value in the queryset -- `handleSearch(key, value)` - use key and value to push a new value to the param -- `handleRemove(key, value)` - use key and value to remove a value to the param -- `handleRemoveAll()` - remove all non-default params - -All of these functions act on the react-router history using the `pushHistoryState` function. This causes the query params in the url to update, which in turn triggers change handlers that will re-fetch data for the lists. - -**a note on sort_columns and search_columns** - -We have split out column configuration into separate search and sort column array props--these are passed to the search and sort columns. Both accept an isDefault prop for one of the items in the array to be the default option selected when going to the page. Sort column items can pass an isNumeric boolean in order to chnage the iconography of the sort UI element. Search column items can pass type and if applicable choices, in order to configure the right-hand side of the search bar. - -### FilterTags component - -Similar to the way the list grabs data based on changes to the react-router params, the `FilterTags` component updates when new params are added. This component is a fairly straight-forward map (only slightly complex, because it needed to do a nested map over any values with duplicate keys that were represented by an inner-array). Both key and value are displayed for the tag. - -### qs utility - -The qs (queryset) utility is used to make the search speak the language of the REST API. The main functions of the utilities are to: - -- add, replace and remove filters -- translate filters as url params (for linking and maintaining state), in-memory representation (as JS objects), and params that Django REST Framework understands. - -More info in the below sections: - -#### Encoding for UI vs. API - -For the UI url params, we want to only encode those params that aren't defaults, as the default behavior was defined through configuration and we don't need these in the url as a source of truth. For the API, we need to pass these params so that they are taken into account when the response is built. - -#### mergeParams vs. replaceParams - -**mergeParams** is used to suppport putting values with the same key - -From a UX perspective, we wanted to be able to support searching on the same key multiple times (i.e. searching for things like `?foo=bar&foo=baz`). We do this by creating an array of all values. i.e.: - -``` -{ - foo: ['bar', 'baz'] -} -``` - -Concatenating terms in this way gives you the intersection of both terms (i.e. foo must be "bar" and "baz"). This is helpful for the most-common type of searching, substring (`__icontains`) searches. This will increase filtering, allowing the user to drill-down into the list as terms are added. - -**replaceParams** is used to support sorting, setting page_size, etc. These params only allow one choice, and we need to replace a particular key's value if one is passed. - -#### Working with REST API - -The REST API is coupled with the qs util through the `paramsSerializer`, due to the fact we need axios to support the array for duplicate key values in the object representation of the params to pass to the get request. This is done where axios is configured in the Base.js file, so all requests and request types should support our array syntax for duplicate keys automatically. - -# Advanced Search - this section is a mess, update eventually - -**a note on typing in a smart search query** - -In order to not support a special "language" or "syntax" for crafting the query like we have now (and is the cause of a large amount of bugs), we will not support the old way of typing in a filter like in the current implementation of search. - -Since all search bars are represented in the url, for users who want to input a string to filter results in a single step, typing directly in the url to achieve the filter is acceptable. - -# Advanced search notes - -Current thinking is Advanced Search will be post-3.6, or at least late 3.6 after awx features and "simple search" with the left dropdown and right input for the above phase 1 lists. - -That being said, we want to plan it out so we make sure the infrastructure of how we set up adding/removing tags, what shows up in the url bar, etc. all doesn't have to be redone. - -Users will get to advanced search with a button to the right of search bar. When selected type-ahead key thing opens, left dropdown of search bar goes away, and x is given to get back to regular search (this is in the mockups) - -It is okay to only make this typing representation available initially (i.e. they start doing stuff with the type-ahead and the phases, no more typing in to make a query that way). - -when you click through or type in the search bar for the various phases of crafting the query ("not", "related resource project", "related resource key name", "value foo") which might be represented in the top bar as a series of tags that can be added and removed before submitting the tag. - -We will try to form options data from a static file. Because options data is static, we may be able to generate and store as a static file of some sort (that we can use for managing smart search). Alan had ideas around this. If we do this it will mean we don't have to make a ton of requests as we craft smart search filters. It sounds like the cli may start using something similar. - -## Smart search flow - -Smart search will be able to craft the tag through various states. Note that the phases don't necessarily need to be completed in sequential order. - -PHASE 1: prefix operators - -**TODO: Double check there's no reason we need to include or** and chain** and can just do not\_\_** - -- not\_\_ -- or\_\_ -- chain\_\_ - -how these work: - -To exclude results matching certain criteria, prefix the field parameter with not\_\_: - -?not**field=value -By default, all query string filters are AND'ed together, so only the results matching all filters will be returned. To combine results matching any one of multiple criteria, prefix each query string parameter with or**: - -?or**field=value&or**field=othervalue -?or**not**field=value&or**field=othervalue -(Added in Ansible Controller 1.4.5) The default AND filtering applies all filters simultaneously to each related object being filtered across database relationships. The chain filter instead applies filters separately for each related object. To use, prefix the query string parameter with chain**: - -?chain**related**field=value&chain**related**field2=othervalue -?chain**not**related**field=value&chain**related**field2=othervalue -If the first query above were written as ?related**field=value&related\_\_field2=othervalue, it would return only the primary objects where the same related object satisfied both conditions. As written using the chain filter, it would return the intersection of primary objects matching each condition. - -PHASE 2: related fields, given by array, where \_\_search is appended to them, i.e. - -``` -"related_search_fields": [ - "credentials__search", - "labels__search", - "created_by__search", - "modified_by__search", - "notification_templates__search", - "custom_inventory_scripts__search", - "notification_templates_error__search", - "notification_templates_success__search", - "notification_templates_any__search", - "teams__search", - "projects__search", - "inventories__search", - "applications__search", - "workflows__search", - "instance_groups__search" - ], -``` - -PHASE 3: keys, give by object key names for data.actions.GET - type is given for each key which we could use to help craft the value - -PHASE 4: after key postfix operators can be - -**TODO: will need to figure out which ones we support** - -- exact: Exact match (default lookup if not specified). -- iexact: Case-insensitive version of exact. -- contains: Field contains value. -- icontains: Case-insensitive version of contains. -- startswith: Field starts with value. -- istartswith: Case-insensitive version of startswith. -- endswith: Field ends with value. -- iendswith: Case-insensitive version of endswith. -- regex: Field matches the given regular expression. -- iregex: Case-insensitive version of regex. -- gt: Greater than comparison. -- gte: Greater than or equal to comparison. -- lt: Less than comparison. -- lte: Less than or equal to comparison. -- isnull: Check whether the given field or related object is null; expects a boolean value. -- in: Check whether the given field's value is present in the list provided; expects a list of items. - -PHASE 5: The value. Based on options, we can give hints or validation based on type of value (like number fields don't accept "foo" or whatever) diff --git a/awx/ui/conf.py b/awx/ui/conf.py index 9f1cef04fc09..a666f07dbdfd 100644 --- a/awx/ui/conf.py +++ b/awx/ui/conf.py @@ -8,7 +8,6 @@ from awx.conf import register, fields from awx.ui.fields import PendoTrackingStateField, CustomLogoField # noqa - register( 'PENDO_TRACKING_STATE', field_class=PendoTrackingStateField, @@ -56,16 +55,18 @@ field_class=fields.IntegerField, min_value=100, label=_('Max Job Events Retrieved by UI'), - help_text=_('Maximum number of job events for the UI to retrieve within a ' 'single request.'), + help_text=_('Maximum number of job events for the UI to retrieve within a single request.'), category=_('UI'), category_slug='ui', + hidden=True, ) register( 'UI_LIVE_UPDATES_ENABLED', field_class=fields.BooleanField, label=_('Enable Live Updates in the UI'), - help_text=_('If disabled, the page will not refresh when events are received. ' 'Reloading the page will be required to get the latest details.'), + help_text=_('If disabled, the page will not refresh when events are received. Reloading the page will be required to get the latest details.'), category=_('UI'), category_slug='ui', + hidden=True, ) diff --git a/awx/ui/docs/APP_ARCHITECTURE.md b/awx/ui/docs/APP_ARCHITECTURE.md deleted file mode 100644 index 4be18f17d23e..000000000000 --- a/awx/ui/docs/APP_ARCHITECTURE.md +++ /dev/null @@ -1,27 +0,0 @@ -# Application Architecture - -## Local Storage Integration -The `useStorage` hook integrates with the browser's localStorage api. -It accepts a localStorage key as its only argument and returns a state -variable and setter function for that state variable. The hook enables -bidirectional data transfer between tabs via an event listener that -is registered with the Web Storage api. - - -![Sequence Diagram for useStorage](images/useStorage.png) - -The `useStorage` hook currently lives in the `AppContainer` component. It -can be relocated to a more general location should and if the need -ever arise - -## Session Expiration -Session timeout state is communicated to the client in the HTTP(S) -response headers. Every HTTP(S) response is intercepted to read the -session expiration time before being passed into the rest of the -application. A timeout date is computed from the intercepted HTTP(S) -headers and is pushed into local storage, where it can be read using -standard Web Storage apis or other utilities, such as `useStorage`. - - -![Sequence Diagram for session expiration](images/sessionExpiration.png) - diff --git a/awx/ui/docs/JobOutput.md b/awx/ui/docs/JobOutput.md deleted file mode 100644 index 8cdba2c2b641..000000000000 --- a/awx/ui/docs/JobOutput.md +++ /dev/null @@ -1,64 +0,0 @@ -This document is meant to provide some guidance into the functionality of Job Output and its features. - -## Overview of the feature/screen. Summary of what it does/is - -Joboutput is a feature that allows users to see how their job is doing as it is being run. -This feature displays data sent to the UI via websockets that are connected to several -different endpoints in the API. - -The job output has 2 different states that result in different functionality. One state -is when, the job is actively running. There is limited functionality because of how the -job events are processed when they reach the UI. While the job is running, and -output is coming into the UI, the following features turn off: - -1. [Search](#Search)- The ability to search the output of a job. -2. [Expand/Collapse](#Expand/Collapse)- The ability to expand and collapse job events, tasks, plays, or even the - job itself. The only part of the job ouput that is not collapsable is the playbook summary (only jobs that - are executed from a Job Template have Expand/Collapse functionality). - -The following features are enabled: - -1. Follow/unfollow - `Follow` indicates you are streaming the output on the screen - as it comes into the UI. If you see some output that you want to examine closer while the job is running - scroll to it, and click `Unfollow`, and the output will stop streaming onto the screen. This feature is only - enabled when the job is running and is not complete. If the user scrolls up in the output the UI will unfollow. -2. Page up and page down buttons- Use these buttons to navigate quickly up and down the output. - -![Running job](images/JobOutput-running.png) - -After the job is complete, the Follow/Unfollow button disabled, and Expand/Collapse and Search become enabled. -![Finished job](images/JobOutput-complete.png) - -Not all job types are created equal. Some jobs have a concept of parent-child events. Job events can be inside a Task, -a Task can be inside a Play, and a Play inside a Playbook. Leveraging this concept to enable Expand/Collapse for these -job types, allows you to collapse and hide the children of a particular line of output. This parent-child event -relationship only exists on jobs executed from a job template. All other types of jobs do not -have this event concept, and therefore, do not have Expand/Collapse functionality. By default all job -events are expanded. - -## How output works generally. - -1. Explain the different state components -2. Page up and page down and what’s happening in the background. - -## Different type of job events, and how they relate to the state object - -1. Tasks -2. plays -3. events - -## Non-standard cases - -1. When an event comes into the output that has a parent, but the parent hasn’t arrived yet. -2. When an event with children arrives in output, but the children are not yet present. - -## Expand/Collapse - -### Expand collapse a single event - how it works and how it changes the state object - -### Expand collapse all - how it works and how it changes the state object - -## Search - -1. During job run -2. After job run diff --git a/awx/ui/docs/images/JobOutput-complete.png b/awx/ui/docs/images/JobOutput-complete.png deleted file mode 100644 index 3c076fe305d8..000000000000 Binary files a/awx/ui/docs/images/JobOutput-complete.png and /dev/null differ diff --git a/awx/ui/docs/images/JobOutput-running.png b/awx/ui/docs/images/JobOutput-running.png deleted file mode 100644 index 4e54ce26b2a3..000000000000 Binary files a/awx/ui/docs/images/JobOutput-running.png and /dev/null differ diff --git a/awx/ui/docs/images/sessionExpiration.png b/awx/ui/docs/images/sessionExpiration.png deleted file mode 100644 index fa740c44a5a6..000000000000 Binary files a/awx/ui/docs/images/sessionExpiration.png and /dev/null differ diff --git a/awx/ui/docs/images/useStorage.png b/awx/ui/docs/images/useStorage.png deleted file mode 100644 index 712b47712162..000000000000 Binary files a/awx/ui/docs/images/useStorage.png and /dev/null differ diff --git a/awx/ui/jsconfig.json b/awx/ui/jsconfig.json deleted file mode 100644 index ec2332eb49cc..000000000000 --- a/awx/ui/jsconfig.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "compilerOptions": { - "baseUrl": "src" - } -} diff --git a/awx/ui/package-lock.json b/awx/ui/package-lock.json deleted file mode 100644 index db3110e7af7c..000000000000 --- a/awx/ui/package-lock.json +++ /dev/null @@ -1,39727 +0,0 @@ -{ - "name": "ui", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "ui", - "dependencies": { - "@lingui/react": "3.14.0", - "@patternfly/patternfly": "4.217.1", - "@patternfly/react-core": "^4.264.0", - "@patternfly/react-icons": "4.92.10", - "@patternfly/react-table": "4.108.0", - "ace-builds": "^1.10.1", - "ansi-to-html": "0.7.2", - "axios": "0.27.2", - "codemirror": "^6.0.1", - "d3": "7.6.1", - "dagre": "^0.8.4", - "dompurify": "2.4.0", - "formik": "2.2.9", - "has-ansi": "5.0.1", - "html-entities": "2.3.2", - "js-yaml": "4.1.0", - "luxon": "^3.1.1", - "prop-types": "^15.8.1", - "react": "17.0.2", - "react-ace": "^10.1.0", - "react-dom": "17.0.2", - "react-error-boundary": "^3.1.4", - "react-router-dom": "^5.3.3", - "react-virtualized": "^9.21.1", - "rrule": "2.7.1", - "styled-components": "5.3.6" - }, - "devDependencies": { - "@babel/core": "^7.16.10", - "@babel/eslint-parser": "^7.16.5", - "@babel/eslint-plugin": "^7.16.5", - "@babel/plugin-syntax-jsx": "7.16.7", - "@babel/polyfill": "^7.8.7", - "@babel/preset-react": "7.16.7", - "@cypress/instrument-cra": "^1.4.0", - "@lingui/cli": "^3.7.1", - "@lingui/loader": "3.15.0", - "@lingui/macro": "^3.7.1", - "@nteract/mockument": "^1.0.4", - "@testing-library/jest-dom": "^5.16.2", - "@testing-library/react": "^12.1.5", - "@testing-library/user-event": "14.4.3", - "@wojtekmaj/enzyme-adapter-react-17": "0.6.5", - "babel-plugin-macros": "3.1.0", - "enzyme": "^3.10.0", - "enzyme-adapter-react-16": "^1.14.0", - "enzyme-to-json": "^3.3.5", - "eslint": "^8.7.0", - "eslint-config-airbnb": "19.0.4", - "eslint-config-prettier": "8.3.0", - "eslint-import-resolver-webpack": "0.13.2", - "eslint-plugin-i18next": "5.2.1", - "eslint-plugin-import": "2.25.4", - "eslint-plugin-jsx-a11y": "6.5.1", - "eslint-plugin-react": "7.28.0", - "eslint-plugin-react-hooks": "4.3.0", - "http-proxy-middleware": "^1.0.3", - "jest-websocket-mock": "^2.0.2", - "mock-socket": "^9.1.3", - "prettier": "2.3.2", - "react-scripts": "5.0.1" - }, - "engines": { - "node": ">=16.13.1" - } - }, - "node_modules/@adobe/css-tools": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.0.1.tgz", - "integrity": "sha512-+u76oB43nOHrF4DDWRLWDCtci7f3QJoEBigemIdIeTi1ODqjx6Tad9NCVnPRwewWlKkVab5PlK8DCtPTyX7S8g==", - "dev": true - }, - "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dependencies": { - "@babel/highlight": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.5.tgz", - "integrity": "sha512-KZXo2t10+/jxmkhNXc7pZTqRvSOIvVv/+lJwHS+B2rErwOyjuVRh60yVpb7liQ1U5t7lLJ1bz+t8tSypUZdm0g==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.10.tgz", - "integrity": "sha512-pbiIdZbCiMx/MM6toR+OfXarYix3uz0oVsnNtfdAGTcCTu3w/JGF8JhirevXLBJUu0WguSZI12qpKnx7EeMyLA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.16.8", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helpers": "^7.16.7", - "@babel/parser": "^7.16.10", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.10", - "@babel/types": "^7.16.8", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0", - "source-map": "^0.5.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@babel/eslint-parser": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.16.5.tgz", - "integrity": "sha512-mUqYa46lgWqHKQ33Q6LNCGp/wPR3eqOYTUixHFsfrSQqRxH0+WOzca75iEjFr5RDGH1dDz622LaHhLOzOuQRUA==", - "dev": true, - "dependencies": { - "eslint-scope": "^5.1.1", - "eslint-visitor-keys": "^2.1.0", - "semver": "^6.3.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || >=14.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.11.0", - "eslint": "^7.5.0 || ^8.0.0" - } - }, - "node_modules/@babel/eslint-plugin": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/eslint-plugin/-/eslint-plugin-7.16.5.tgz", - "integrity": "sha512-R1p6RMyU1Xl1U/NNr+D4+HjkQzN5dQOX0MpjW9WLWhHDjhzN9gso96MxxOFvPh0fKF/mMH8TGW2kuqQ2eK2s9A==", - "dev": true, - "dependencies": { - "eslint-rule-composer": "^0.3.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || >=14.0.0" - }, - "peerDependencies": { - "@babel/eslint-parser": ">=7.11.0", - "eslint": ">=7.5.0" - } - }, - "node_modules/@babel/generator": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.5.tgz", - "integrity": "sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==", - "dependencies": { - "@babel/types": "^7.20.5", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", - "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", - "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", - "dev": true, - "dependencies": { - "@babel/helper-explode-assignable-expression": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz", - "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.20.0", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.5.tgz", - "integrity": "sha512-3RCdA/EmEaikrhayahwToF0fpweU/8o2p8vhc1c/1kftHOdTKuC65kik/TLc+qfbS8JKw4qqJbne4ovICDhmww==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-member-expression-to-functions": "^7.18.9", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-replace-supers": "^7.19.1", - "@babel/helper-split-export-declaration": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.16.7.tgz", - "integrity": "sha512-fk5A6ymfp+O5+p2yCkXAu5Kyj6v0xh0RBeNcAkYUMDvvAAoxvSKXn+Jb37t/yWFiQVDFK1ELpUTD8/aLhCPu+g==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "regexpu-core": "^4.7.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", - "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", - "dev": true, - "dependencies": { - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-plugin-utils": "^7.16.7", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - }, - "peerDependencies": { - "@babel/core": "^7.4.0-0" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-explode-assignable-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", - "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", - "dependencies": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", - "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz", - "integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", - "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", - "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", - "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-wrap-function": "^7.16.8", - "@babel/types": "^7.16.8" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz", - "integrity": "sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-member-expression-to-functions": "^7.18.9", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/traverse": "^7.19.1", - "@babel/types": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", - "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", - "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz", - "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==", - "dev": true, - "dependencies": { - "@babel/helper-function-name": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.8", - "@babel/types": "^7.16.8" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.7.tgz", - "integrity": "sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw==", - "dev": true, - "dependencies": { - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz", - "integrity": "sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz", - "integrity": "sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.13.0" - } - }, - "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz", - "integrity": "sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8", - "@babel/plugin-syntax-async-generators": "^7.8.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz", - "integrity": "sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-class-static-block": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.7.tgz", - "integrity": "sha512-dgqJJrcZoG/4CkMopzhPJjGxsIe9A8RlkQLnL/Vhhx8AA9ZuaRwGSlscSh42hazc7WSrya/IK7mTeoF0DP9tEw==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" - } - }, - "node_modules/@babel/plugin-proposal-decorators": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.20.5.tgz", - "integrity": "sha512-Lac7PpRJXcC3s9cKsBfl+uc+DYXU5FD06BrTFunQO6QIQT+DwyzDPURAowI3bcvD1dZF/ank1Z5rstUJn3Hn4Q==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.20.5", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-replace-supers": "^7.19.1", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/plugin-syntax-decorators": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-dynamic-import": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", - "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-export-namespace-from": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz", - "integrity": "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-json-strings": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz", - "integrity": "sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-json-strings": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz", - "integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz", - "integrity": "sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-numeric-separator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", - "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.7.tgz", - "integrity": "sha512-3O0Y4+dw94HA86qSg9IHfyPktgR7q3gpNVAeiKQd+8jBKFaU5NQS1Yatgo4wY+UFNuLjvxcSmzcsHqrhgTyBUA==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.16.4", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-catch-binding": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", - "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz", - "integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-private-methods": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.7.tgz", - "integrity": "sha512-7twV3pzhrRxSwHeIvFE6coPgvo+exNDOiGUMg39o2LiLo1Y+4aKpfkcLGcg1UHonzorCt7SNXnoMyCnnIOA8Sw==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz", - "integrity": "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-unicode-property-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz", - "integrity": "sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-decorators": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.19.0.tgz", - "integrity": "sha512-xaBZUEDntt4faL1yN8oIFlhfXeQAWJW7CLKYsHTUqriCUbj8xOra8bfxxKGi/UwExPFBuPdH4XfHc9rGQhrVkQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-flow": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.18.6.tgz", - "integrity": "sha512-LUbR+KNTBWCUAqRG9ex5Gnzu2IOkt8jRJbHHXFT9q+L9zm7M/QQbEqXyw1n1pohYvOyWC8CjeyjrSaIwiYjK7A==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz", - "integrity": "sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", - "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz", - "integrity": "sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz", - "integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", - "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz", - "integrity": "sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz", - "integrity": "sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz", - "integrity": "sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.7.tgz", - "integrity": "sha512-VqAwhTHBnu5xBVDCvrvqJbtLUa++qZaWC0Fgr2mqokBlulZARGyIvZDoqbPlPaKImQ9dKAcCzbv+ul//uqu70A==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", - "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz", - "integrity": "sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", - "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", - "dev": true, - "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-flow-strip-types": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.19.0.tgz", - "integrity": "sha512-sgeMlNaQVbCSpgLSKP4ZZKfsJVnFnNQlUSk6gPYzR/q7tzCgQF2t8RBKAP6cKJeZdveei7Q7Jm527xepI8lNLg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/plugin-syntax-flow": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz", - "integrity": "sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", - "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", - "dev": true, - "dependencies": { - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz", - "integrity": "sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", - "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz", - "integrity": "sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz", - "integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz", - "integrity": "sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw==", - "dev": true, - "dependencies": { - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz", - "integrity": "sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz", - "integrity": "sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz", - "integrity": "sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", - "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz", - "integrity": "sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", - "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-constant-elements": { - "version": "7.13.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.13.13.tgz", - "integrity": "sha512-SNJU53VM/SjQL0bZhyU+f4kJQz7bQQajnrZRSaU21hruG/NWY41AEM9AWXeXX90pYr/C2yAmTgI6yW3LlLrAUQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.13.0" - } - }, - "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.7.tgz", - "integrity": "sha512-qgIg8BcZgd0G/Cz916D5+9kqX0c7nPZyXaP8R2tLNN5tkyIZdG5fEwBrxwplzSnjC1jvQmyMNVwUCZPcbGY7Pg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.16.7.tgz", - "integrity": "sha512-8D16ye66fxiE8m890w0BpPpngG9o9OVBBy0gH2E+2AR7qMR2ZpTYJEqLxAsoroenMId0p/wMW+Blc0meDgu0Ag==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-jsx": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-development": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.7.tgz", - "integrity": "sha512-RMvQWvpla+xy6MlBpPlrKZCMRs2AGiHOGHY3xRwl0pEeim348dDyxeH4xBsMPbIMhujeq7ihE702eM2Ew0Wo+A==", - "dev": true, - "dependencies": { - "@babel/plugin-transform-react-jsx": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-pure-annotations": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.7.tgz", - "integrity": "sha512-hs71ToC97k3QWxswh2ElzMFABXHvGiJ01IB1TbYQDGeWRKWz/MPUTh5jGExdHvosYKpnJW5Pm3S4+TA3FyX+GA==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz", - "integrity": "sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q==", - "dev": true, - "dependencies": { - "regenerator-transform": "^0.14.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz", - "integrity": "sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-runtime": { - "version": "7.19.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.6.tgz", - "integrity": "sha512-PRH37lz4JU156lYFW1p8OxE5i7d6Sl/zV58ooyr+q1J1lnQPyg5tIiXlIwNVhJaY4W3TmOtdc8jqdXQcB1v5Yw==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.19.0", - "babel-plugin-polyfill-corejs2": "^0.3.3", - "babel-plugin-polyfill-corejs3": "^0.6.0", - "babel-plugin-polyfill-regenerator": "^0.4.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-runtime/node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", - "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", - "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.3", - "core-js-compat": "^3.25.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-runtime/node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", - "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", - "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", - "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz", - "integrity": "sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", - "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz", - "integrity": "sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz", - "integrity": "sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typescript": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.20.2.tgz", - "integrity": "sha512-jvS+ngBfrnTUBfOQq8NfGnSbF9BrqlR6hjJ2yVxMkmO5nL/cdifNbI30EfjRlN4g5wYWNnMPyj5Sa6R1pbLeag==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.20.2", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-typescript": "^7.20.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", - "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", - "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/polyfill": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.12.1.tgz", - "integrity": "sha512-X0pi0V6gxLi6lFZpGmeNa4zxtwEmCs42isWLNjZZDE0Y8yVfgu0T2OAHlzBbdYlqbW/YXVvoBHpATEM+goCj8g==", - "dev": true, - "dependencies": { - "core-js": "^2.6.5", - "regenerator-runtime": "^0.13.4" - } - }, - "node_modules/@babel/preset-env": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.10.tgz", - "integrity": "sha512-iCac3fZn9oOcLqc1N2/copPiX7aoxzsvjeDdXoZobrlbQ6YGgS3bL9HyldOJ8V8AY5P7pFynCATrn7M4dMw0Yg==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.16.8", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-async-generator-functions": "^7.16.8", - "@babel/plugin-proposal-class-properties": "^7.16.7", - "@babel/plugin-proposal-class-static-block": "^7.16.7", - "@babel/plugin-proposal-dynamic-import": "^7.16.7", - "@babel/plugin-proposal-export-namespace-from": "^7.16.7", - "@babel/plugin-proposal-json-strings": "^7.16.7", - "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", - "@babel/plugin-proposal-numeric-separator": "^7.16.7", - "@babel/plugin-proposal-object-rest-spread": "^7.16.7", - "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", - "@babel/plugin-proposal-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-private-methods": "^7.16.7", - "@babel/plugin-proposal-private-property-in-object": "^7.16.7", - "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.16.7", - "@babel/plugin-transform-async-to-generator": "^7.16.8", - "@babel/plugin-transform-block-scoped-functions": "^7.16.7", - "@babel/plugin-transform-block-scoping": "^7.16.7", - "@babel/plugin-transform-classes": "^7.16.7", - "@babel/plugin-transform-computed-properties": "^7.16.7", - "@babel/plugin-transform-destructuring": "^7.16.7", - "@babel/plugin-transform-dotall-regex": "^7.16.7", - "@babel/plugin-transform-duplicate-keys": "^7.16.7", - "@babel/plugin-transform-exponentiation-operator": "^7.16.7", - "@babel/plugin-transform-for-of": "^7.16.7", - "@babel/plugin-transform-function-name": "^7.16.7", - "@babel/plugin-transform-literals": "^7.16.7", - "@babel/plugin-transform-member-expression-literals": "^7.16.7", - "@babel/plugin-transform-modules-amd": "^7.16.7", - "@babel/plugin-transform-modules-commonjs": "^7.16.8", - "@babel/plugin-transform-modules-systemjs": "^7.16.7", - "@babel/plugin-transform-modules-umd": "^7.16.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.8", - "@babel/plugin-transform-new-target": "^7.16.7", - "@babel/plugin-transform-object-super": "^7.16.7", - "@babel/plugin-transform-parameters": "^7.16.7", - "@babel/plugin-transform-property-literals": "^7.16.7", - "@babel/plugin-transform-regenerator": "^7.16.7", - "@babel/plugin-transform-reserved-words": "^7.16.7", - "@babel/plugin-transform-shorthand-properties": "^7.16.7", - "@babel/plugin-transform-spread": "^7.16.7", - "@babel/plugin-transform-sticky-regex": "^7.16.7", - "@babel/plugin-transform-template-literals": "^7.16.7", - "@babel/plugin-transform-typeof-symbol": "^7.16.7", - "@babel/plugin-transform-unicode-escapes": "^7.16.7", - "@babel/plugin-transform-unicode-regex": "^7.16.7", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.16.8", - "babel-plugin-polyfill-corejs2": "^0.3.0", - "babel-plugin-polyfill-corejs3": "^0.5.0", - "babel-plugin-polyfill-regenerator": "^0.3.0", - "core-js-compat": "^3.20.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-modules": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-react": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.16.7.tgz", - "integrity": "sha512-fWpyI8UM/HE6DfPBzD8LnhQ/OcH8AgTaqcqP2nGOXEUV+VKBR5JRN9hCk9ai+zQQ57vtm9oWeXguBCPNUjytgA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-transform-react-display-name": "^7.16.7", - "@babel/plugin-transform-react-jsx": "^7.16.7", - "@babel/plugin-transform-react-jsx-development": "^7.16.7", - "@babel/plugin-transform-react-pure-annotations": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-typescript": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.18.6.tgz", - "integrity": "sha512-s9ik86kXBAnD760aybBucdpnLsAt0jK1xqJn2juOn9lkOvSHV60os5hxoVJsPzMQxvnUJFAlkont2DvvaYEBtQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-validator-option": "^7.18.6", - "@babel/plugin-transform-typescript": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.7.tgz", - "integrity": "sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==", - "dependencies": { - "regenerator-runtime": "^0.13.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/runtime-corejs3": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.14.0.tgz", - "integrity": "sha512-0R0HTZWHLk6G8jIk0FtoX+AatCtKnswS98VhXwGImFc759PJRp4Tru0PQYZofyijTFUr+gT8Mu7sgXVJLQ0ceg==", - "dev": true, - "dependencies": { - "core-js-pure": "^3.0.0", - "regenerator-runtime": "^0.13.4" - } - }, - "node_modules/@babel/template": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.5.tgz", - "integrity": "sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==", - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.5", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.5", - "@babel/types": "^7.20.5", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "node_modules/@codemirror/autocomplete": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.0.2.tgz", - "integrity": "sha512-9PDjnllmXan/7Uax87KGORbxerDJ/cu10SB+n4Jz0zXMEvIh3+TGgZxhIvDOtaQ4jDBQEM7kHYW4vLdQB0DGZQ==", - "dependencies": { - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "@lezer/common": "^1.0.0" - }, - "peerDependencies": { - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "@lezer/common": "^1.0.0" - } - }, - "node_modules/@codemirror/commands": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.0.1.tgz", - "integrity": "sha512-iNHDByicYqQjs0Wo1MKGfqNbMYMyhS9WV6EwMVwsHXImlFemgEUC+c5X22bXKBStN3qnwg4fArNZM+gkv22baQ==", - "dependencies": { - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "@lezer/common": "^1.0.0" - } - }, - "node_modules/@codemirror/language": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.2.0.tgz", - "integrity": "sha512-tabB0Ef/BflwoEmTB4a//WZ9P90UQyne9qWB9YFsmeS4bnEqSys7UpGk/da1URMXhyfuzWCwp+AQNMhvu8SfnA==", - "dependencies": { - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "@lezer/common": "^1.0.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0", - "style-mod": "^4.0.0" - } - }, - "node_modules/@codemirror/lint": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.0.0.tgz", - "integrity": "sha512-nUUXcJW1Xp54kNs+a1ToPLK8MadO0rMTnJB8Zk4Z8gBdrN0kqV7uvUraU/T2yqg+grDNR38Vmy/MrhQN/RgwiA==", - "dependencies": { - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "crelt": "^1.0.5" - } - }, - "node_modules/@codemirror/search": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.0.0.tgz", - "integrity": "sha512-rL0rd3AhI0TAsaJPUaEwC63KHLO7KL0Z/dYozXj6E7L3wNHRyx7RfE0/j5HsIf912EE5n2PCb4Vg0rGYmDv4UQ==", - "dependencies": { - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "crelt": "^1.0.5" - } - }, - "node_modules/@codemirror/state": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.1.0.tgz", - "integrity": "sha512-qbUr94DZTe6/V1VS7LDLz11rM/1t/nJxR1El4I6UaxDEdc0aZZvq6JCLJWiRmUf95NRAnDH6fhXn+PWp9wGCIg==" - }, - "node_modules/@codemirror/view": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.0.2.tgz", - "integrity": "sha512-mnVT/q1JvKPjpmjXJNeCi/xHyaJ3abGJsumIVpdQ1nE1MXAyHf7GHWt8QpWMUvDiqF0j+inkhVR2OviTdFFX7Q==", - "dependencies": { - "@codemirror/state": "^6.0.0", - "style-mod": "^4.0.0", - "w3c-keyname": "^2.2.4" - } - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@csstools/normalize.css": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-12.0.0.tgz", - "integrity": "sha512-M0qqxAcwCsIVfpFQSlGN5XjXWu8l5JDZN+fPt1LeW5SZexQTgnaEvgXAY+CeygRw0EeppWHi12JxESWiWrB0Sg==", - "dev": true - }, - "node_modules/@cypress/instrument-cra": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@cypress/instrument-cra/-/instrument-cra-1.4.0.tgz", - "integrity": "sha512-gXf540xL0jcUXkWyrA2Ug9rzs+jRkc9EPhnRi8XfbnRjdF4lvnn108N6x0lgTApMTbbpCDbVuskHGXDmIuD3CQ==", - "dev": true, - "dependencies": { - "babel-plugin-istanbul": "6.0.0", - "debug": "4.2.0", - "find-yarn-workspace-root": "^2.0.0" - } - }, - "node_modules/@cypress/instrument-cra/node_modules/debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/@emotion/is-prop-valid": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.1.2.tgz", - "integrity": "sha512-3QnhqeL+WW88YjYbQL5gUIkthuMw7a0NGbZ7wfFVk2kg/CK5w8w5FFa0RzWjyY1+sujN0NWbtSHH6OJmWHtJpQ==", - "dependencies": { - "@emotion/memoize": "^0.7.4" - } - }, - "node_modules/@emotion/memoize": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.5.tgz", - "integrity": "sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==" - }, - "node_modules/@emotion/stylis": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz", - "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==" - }, - "node_modules/@emotion/unitless": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", - "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" - }, - "node_modules/@eslint/eslintrc": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.5.tgz", - "integrity": "sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.2.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz", - "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/@eslint/eslintrc/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.2.tgz", - "integrity": "sha512-UXOuFCGcwciWckOpmfKDq/GyhlTf9pN/BzG//x8p8zTOFEcGuA68ANXheFS0AGvy3qgZqLBUkMs7hqzqCKOVwA==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.4.6.tgz", - "integrity": "sha512-jauXyacQD33n47A44KrlOVeiXHEXDqapSdfb9kTekOchH/Pd18kBIO1+xxJQRLuG+LUuljFCwTG92ra4NW7SpA==", - "dev": true, - "dependencies": { - "@jest/types": "^27.4.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^27.4.6", - "jest-util": "^27.4.2", - "slash": "^3.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/console/node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/console/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/console/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/console/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/console/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/console/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/console/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/core": { - "version": "27.4.7", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.4.7.tgz", - "integrity": "sha512-n181PurSJkVMS+kClIFSX/LLvw9ExSb+4IMtD6YnfxZVerw9ANYtW0bPrm0MJu2pfe9SY9FJ9FtQ+MdZkrZwjg==", - "dev": true, - "dependencies": { - "@jest/console": "^27.4.6", - "@jest/reporters": "^27.4.6", - "@jest/test-result": "^27.4.6", - "@jest/transform": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.8.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-changed-files": "^27.4.2", - "jest-config": "^27.4.7", - "jest-haste-map": "^27.4.6", - "jest-message-util": "^27.4.6", - "jest-regex-util": "^27.4.0", - "jest-resolve": "^27.4.6", - "jest-resolve-dependencies": "^27.4.6", - "jest-runner": "^27.4.6", - "jest-runtime": "^27.4.6", - "jest-snapshot": "^27.4.6", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.6", - "jest-watcher": "^27.4.6", - "micromatch": "^4.0.4", - "rimraf": "^3.0.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/core/node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/core/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/core/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/core/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/core/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@jest/core/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/core/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/core/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/core/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/core/node_modules/jest-get-type": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", - "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", - "dev": true, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/core/node_modules/jest-validate": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.4.6.tgz", - "integrity": "sha512-872mEmCPVlBqbA5dToC57vA3yJaMRfIdpCoD3cyHWJOMx+SJwLNw0I71EkWs41oza/Er9Zno9XuTkRYCPDUJXQ==", - "dev": true, - "dependencies": { - "@jest/types": "^27.4.2", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", - "leven": "^3.1.0", - "pretty-format": "^27.4.6" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/core/node_modules/pretty-format": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz", - "integrity": "sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/core/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/core/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/@jest/core/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/environment": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.4.6.tgz", - "integrity": "sha512-E6t+RXPfATEEGVidr84WngLNWZ8ffCPky8RqqRK6u1Bn0LK92INe0MDttyPl/JOzaq92BmDzOeuqk09TvM22Sg==", - "dev": true, - "dependencies": { - "@jest/fake-timers": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/node": "*", - "jest-mock": "^27.4.6" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/environment/node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/environment/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/environment/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/environment/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/environment/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/environment/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/environment/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/environment/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/fake-timers": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.4.6.tgz", - "integrity": "sha512-mfaethuYF8scV8ntPpiVGIHQgS0XIALbpY2jt2l7wb/bvq4Q5pDLk4EP4D7SAvYT1QrPOPVZAtbdGAOOyIgs7A==", - "dev": true, - "dependencies": { - "@jest/types": "^27.4.2", - "@sinonjs/fake-timers": "^8.0.1", - "@types/node": "*", - "jest-message-util": "^27.4.6", - "jest-mock": "^27.4.6", - "jest-util": "^27.4.2" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/fake-timers/node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/fake-timers/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/fake-timers/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/fake-timers/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/fake-timers/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/fake-timers/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/fake-timers/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/fake-timers/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/globals": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.4.6.tgz", - "integrity": "sha512-kAiwMGZ7UxrgPzu8Yv9uvWmXXxsy0GciNejlHvfPIfWkSxChzv6bgTS3YqBkGuHcis+ouMFI2696n2t+XYIeFw==", - "dev": true, - "dependencies": { - "@jest/environment": "^27.4.6", - "@jest/types": "^27.4.2", - "expect": "^27.4.6" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/globals/node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/globals/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/globals/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/globals/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/globals/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/globals/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/globals/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/globals/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/reporters": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.4.6.tgz", - "integrity": "sha512-+Zo9gV81R14+PSq4wzee4GC2mhAN9i9a7qgJWL90Gpx7fHYkWpTBvwWNZUXvJByYR9tAVBdc8VxDWqfJyIUrIQ==", - "dev": true, - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^27.4.6", - "@jest/test-result": "^27.4.6", - "@jest/transform": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.2.4", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-haste-map": "^27.4.6", - "jest-resolve": "^27.4.6", - "jest-util": "^27.4.2", - "jest-worker": "^27.4.6", - "slash": "^3.0.0", - "source-map": "^0.6.0", - "string-length": "^4.0.1", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^8.1.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/reporters/node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/reporters/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/reporters/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/reporters/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/reporters/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/reporters/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/reporters/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/reporters/node_modules/istanbul-lib-instrument": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", - "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/reporters/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/source-map": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.4.0.tgz", - "integrity": "sha512-Ntjx9jzP26Bvhbm93z/AKcPRj/9wrkI88/gK60glXDx1q+IeI0rf7Lw2c89Ch6ofonB0On/iRDreQuQ6te9pgQ==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0", - "graceful-fs": "^4.2.4", - "source-map": "^0.6.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/test-result": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.4.6.tgz", - "integrity": "sha512-fi9IGj3fkOrlMmhQqa/t9xum8jaJOOAi/lZlm6JXSc55rJMXKHxNDN1oCP39B0/DhNOa2OMupF9BcKZnNtXMOQ==", - "dev": true, - "dependencies": { - "@jest/console": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/test-result/node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/test-result/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/test-result/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/test-result/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/test-result/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/test-result/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/test-result/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/test-result/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.4.6.tgz", - "integrity": "sha512-3GL+nsf6E1PsyNsJuvPyIz+DwFuCtBdtvPpm/LMXVkBJbdFvQYCDpccYT56qq5BGniXWlE81n2qk1sdXfZebnw==", - "dev": true, - "dependencies": { - "@jest/test-result": "^27.4.6", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.6", - "jest-runtime": "^27.4.6" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/transform": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.4.6.tgz", - "integrity": "sha512-9MsufmJC8t5JTpWEQJ0OcOOAXaH5ioaIX6uHVBLBMoCZPfKKQF+EqP8kACAvCZ0Y1h2Zr3uOccg8re+Dr5jxyw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.1.0", - "@jest/types": "^27.4.2", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.6", - "jest-regex-util": "^27.4.0", - "jest-util": "^27.4.2", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/transform/node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/transform/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/transform/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/transform/node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/transform/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/transform/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/transform/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/transform/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/transform/node_modules/istanbul-lib-instrument": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", - "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/transform/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@jest/types/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/types/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@jest/types/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/types/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/types/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/types/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", - "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - } - }, - "node_modules/@lezer/common": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.0.tgz", - "integrity": "sha512-ohydQe+Hb+w4oMDvXzs8uuJd2NoA3D8YDcLiuDsLqH+yflDTPEpgCsWI3/6rH5C3BAedtH1/R51dxENldQceEA==" - }, - "node_modules/@lezer/highlight": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.0.0.tgz", - "integrity": "sha512-nsCnNtim90UKsB5YxoX65v3GEIw3iCHw9RM2DtdgkiqAbKh9pCdvi8AWNwkYf10Lu6fxNhXPpkpHbW6mihhvJA==", - "dependencies": { - "@lezer/common": "^1.0.0" - } - }, - "node_modules/@lezer/lr": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.1.0.tgz", - "integrity": "sha512-Iad04uVwk1PvSnj25mqj7zEEIRAsasbsTRmVzI0AUTs/+1Dz1//iYAaoLr7A+Xa7bZDfql5MKTxZmSlkYZD3Dg==", - "dependencies": { - "@lezer/common": "^1.0.0" - } - }, - "node_modules/@lingui/babel-plugin-extract-messages": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/@lingui/babel-plugin-extract-messages/-/babel-plugin-extract-messages-3.15.0.tgz", - "integrity": "sha512-iMQmJIkC18Zwc/IDpm3Oclj3KMDQuvipCS2yVHr0MyaeOCeOZ3ZoLVeaa8pfE5pImzlHJ0ss8RRm/St54JElhw==", - "dev": true, - "dependencies": { - "@babel/generator": "^7.11.6", - "@babel/runtime": "^7.11.2", - "@lingui/conf": "^3.15.0", - "mkdirp": "^1.0.4" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/@lingui/cli": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/@lingui/cli/-/cli-3.15.0.tgz", - "integrity": "sha512-6arKc0Mc1z3ABHobjPkhViV+7VUjBhwFwoU0VlT7HBmtrOYad9CBwWEiD+oiEhiHYzLTR7lHTVf674IjTuVvJQ==", - "dev": true, - "dependencies": { - "@babel/generator": "^7.11.6", - "@babel/parser": "^7.11.5", - "@babel/plugin-syntax-jsx": "^7.10.4", - "@babel/runtime": "^7.11.2", - "@babel/types": "^7.11.5", - "@lingui/babel-plugin-extract-messages": "^3.15.0", - "@lingui/conf": "^3.15.0", - "babel-plugin-macros": "^3.0.1", - "bcp-47": "^1.0.7", - "chalk": "^4.1.0", - "chokidar": "3.5.1", - "cli-table": "0.3.6", - "commander": "^6.1.0", - "date-fns": "^2.16.1", - "fs-extra": "^9.0.1", - "fuzzaldrin": "^2.1.0", - "glob": "^7.1.4", - "inquirer": "^7.3.3", - "make-plural": "^6.2.2", - "messageformat-parser": "^4.1.3", - "micromatch": "4.0.2", - "mkdirp": "^1.0.4", - "node-gettext": "^3.0.0", - "normalize-path": "^3.0.0", - "ora": "^5.1.0", - "papaparse": "^5.3.0", - "pkg-up": "^3.1.0", - "plurals-cldr": "^1.0.4", - "pofile": "^1.1.0", - "pseudolocale": "^1.1.0", - "ramda": "^0.27.1" - }, - "bin": { - "lingui": "lingui.js" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0", - "babel-plugin-macros": "2 || 3", - "typescript": "2 || 3 || 4" - } - }, - "node_modules/@lingui/cli/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@lingui/cli/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@lingui/cli/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@lingui/cli/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@lingui/cli/node_modules/commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@lingui/cli/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@lingui/cli/node_modules/micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@lingui/cli/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@lingui/conf": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/@lingui/conf/-/conf-3.15.0.tgz", - "integrity": "sha512-gDGBbqWo6+B3PNjxTGl2asVdd8hC6w+iGsEPonvMw7GFmXb99qybBGdV2ofDlwlT9vChcPwMVtrYE6H0fTZuzA==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.11.2", - "chalk": "^4.1.0", - "cosmiconfig": "^7.0.0", - "cosmiconfig-typescript-loader": "^2.0.1", - "jest-validate": "^26.5.2", - "lodash.get": "^4.4.2" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/@lingui/conf/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@lingui/conf/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@lingui/conf/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@lingui/conf/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@lingui/conf/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@lingui/conf/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@lingui/core": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/@lingui/core/-/core-3.14.0.tgz", - "integrity": "sha512-ertREq9oi9B/umxpd/pInm9uFO8FLK2/0FXfDmMqvH5ydswWn/c9nY5YO4W1h4/8LWO45mewypOIyjoue4De1w==", - "dependencies": { - "@babel/runtime": "^7.11.2", - "make-plural": "^6.2.2", - "messageformat-parser": "^4.1.3" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/@lingui/loader": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/@lingui/loader/-/loader-3.15.0.tgz", - "integrity": "sha512-Yg7KhinDQmRfqr51bofvD50CuzC1rF8nlFoPsZgLSjpIn4xKdzoCpRaRftRc6sOS5EnoKaK92QwXNv2Ayalz6A==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.11.2", - "@lingui/cli": "^3.15.0", - "@lingui/conf": "^3.15.0", - "loader-utils": "^2.0.0" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" - } - }, - "node_modules/@lingui/macro": { - "version": "3.8.10", - "resolved": "https://registry.npmjs.org/@lingui/macro/-/macro-3.8.10.tgz", - "integrity": "sha512-oZZ/F7HsNQkDsnHFroxzGFuEIXM624H72RIj8j2ClpR64nt+xYDxXYC6TYFicQLtBGcKKBTBoM+zbDaoIv74qQ==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.11.2", - "@lingui/conf": "^3.8.10", - "ramda": "^0.27.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/@lingui/react": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/@lingui/react/-/react-3.14.0.tgz", - "integrity": "sha512-ow9Mtru7f0T2S9AwnPWRejppcucCW0LmoDR3P4wqHjL+eH5f8a6nxd2doxGieC91/2i4qqW88y4K/zXJxwRSQw==", - "dependencies": { - "@babel/runtime": "^7.11.2", - "@lingui/core": "^3.14.0" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nteract/mockument": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@nteract/mockument/-/mockument-1.0.4.tgz", - "integrity": "sha1-9/hf2T5Dgo7HQcX0xXMRgu2w7LI=", - "dev": true - }, - "node_modules/@patternfly/patternfly": { - "version": "4.217.1", - "resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-4.217.1.tgz", - "integrity": "sha512-uN7JgfQsyR16YHkuGRCTIcBcnyKIqKjGkB2SGk9x1XXH3yYGenL83kpAavX9Xtozqp17KppOlybJuzcKvZMrgw==" - }, - "node_modules/@patternfly/react-core": { - "version": "4.264.0", - "resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-4.264.0.tgz", - "integrity": "sha512-tK0BMWxw8nhukev40HZ6q6d02pDnjX7oyA91vHa18aakJUKBWMaerqpG4NZVMoh0tPKX3aLNj+zyCwDALFAZZw==", - "dependencies": { - "@patternfly/react-icons": "^4.93.0", - "@patternfly/react-styles": "^4.92.0", - "@patternfly/react-tokens": "^4.94.0", - "focus-trap": "6.9.2", - "react-dropzone": "9.0.0", - "tippy.js": "5.1.2", - "tslib": "^2.0.0" - }, - "peerDependencies": { - "react": "^16.8 || ^17 || ^18", - "react-dom": "^16.8 || ^17 || ^18" - } - }, - "node_modules/@patternfly/react-core/node_modules/@patternfly/react-icons": { - "version": "4.93.0", - "resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-4.93.0.tgz", - "integrity": "sha512-OH0vORVioL+HLWMEog8/3u8jsiMCeJ0pFpvRKRhy5Uk4CdAe40k1SOBvXJP6opr+O8TLbz0q3bm8Jsh/bPaCuQ==", - "peerDependencies": { - "react": "^16.8 || ^17 || ^18", - "react-dom": "^16.8 || ^17 || ^18" - } - }, - "node_modules/@patternfly/react-core/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" - }, - "node_modules/@patternfly/react-icons": { - "version": "4.92.10", - "resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-4.92.10.tgz", - "integrity": "sha512-vwCy7b+OyyuvLDSLqLUG2DkJZgMDogjld8tJTdAaG8HiEhC1sJPZac+5wD7AuS3ym/sQolS4vYtNiVDnMEORxA==", - "peerDependencies": { - "react": "^16.8 || ^17 || ^18", - "react-dom": "^16.8 || ^17 || ^18" - } - }, - "node_modules/@patternfly/react-styles": { - "version": "4.92.0", - "resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-4.92.0.tgz", - "integrity": "sha512-B/f6iyu8UEN1+wRxdC4sLIhvJeyL8SqInDXZmwOIqK8uPJ8Lze7qrbVhkkVzbMF37/oDPVa6dZH8qZFq062LEA==" - }, - "node_modules/@patternfly/react-table": { - "version": "4.108.0", - "resolved": "https://registry.npmjs.org/@patternfly/react-table/-/react-table-4.108.0.tgz", - "integrity": "sha512-EUvd3rlkE1UXobAm7L6JHgNE3TW8IYTaVwwH/px4Mkn5mBayDO6f+w6QM3OeoDQVZcXK6IYFe7QQaYd/vWIJCQ==", - "dependencies": { - "@patternfly/react-core": "^4.239.0", - "@patternfly/react-icons": "^4.90.0", - "@patternfly/react-styles": "^4.89.0", - "@patternfly/react-tokens": "^4.91.0", - "lodash": "^4.17.19", - "tslib": "^2.0.0" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" - } - }, - "node_modules/@patternfly/react-table/node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" - }, - "node_modules/@patternfly/react-tokens": { - "version": "4.94.0", - "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-4.94.0.tgz", - "integrity": "sha512-fYXxUJZnzpn89K2zzHF0cSncZZVGKrohdb5f5T1wzxwU2NZPVGpvr88xhm+V2Y/fSrrTPwXcP3IIdtNOOtJdZw==" - }, - "node_modules/@pmmmwh/react-refresh-webpack-plugin": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.4.tgz", - "integrity": "sha512-zZbZeHQDnoTlt2AF+diQT0wsSXpvWiaIOZwBRdltNFhG1+I3ozyaw7U/nBiUwyJ0D+zwdXp0E3bWOl38Ag2BMw==", - "dev": true, - "dependencies": { - "ansi-html-community": "^0.0.8", - "common-path-prefix": "^3.0.0", - "core-js-pure": "^3.8.1", - "error-stack-parser": "^2.0.6", - "find-up": "^5.0.0", - "html-entities": "^2.1.0", - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0", - "source-map": "^0.7.3" - }, - "engines": { - "node": ">= 10.13" - }, - "peerDependencies": { - "@types/webpack": "4.x || 5.x", - "react-refresh": ">=0.10.0 <1.0.0", - "sockjs-client": "^1.4.0", - "type-fest": ">=0.17.0 <3.0.0", - "webpack": ">=4.43.0 <6.0.0", - "webpack-dev-server": "3.x || 4.x", - "webpack-hot-middleware": "2.x", - "webpack-plugin-serve": "0.x || 1.x" - }, - "peerDependenciesMeta": { - "@types/webpack": { - "optional": true - }, - "sockjs-client": { - "optional": true - }, - "type-fest": { - "optional": true - }, - "webpack-dev-server": { - "optional": true - }, - "webpack-hot-middleware": { - "optional": true - }, - "webpack-plugin-serve": { - "optional": true - } - } - }, - "node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@rollup/plugin-babel": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.0.tgz", - "integrity": "sha512-9uIC8HZOnVLrLHxayq/PTzw+uS25E14KPUBh5ktF+18Mjo5yK0ToMMx6epY0uEgkjwJw0aBW4x2horYXh8juWw==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.10.4", - "@rollup/pluginutils": "^3.1.0" - }, - "engines": { - "node": ">= 10.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0", - "@types/babel__core": "^7.1.9", - "rollup": "^1.20.0||^2.0.0" - }, - "peerDependenciesMeta": { - "@types/babel__core": { - "optional": true - } - } - }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "11.2.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", - "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "builtin-modules": "^3.1.0", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.19.0" - }, - "engines": { - "node": ">= 10.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" - } - }, - "node_modules/@rollup/plugin-node-resolve/node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@rollup/plugin-replace": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", - "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "magic-string": "^0.25.7" - }, - "peerDependencies": { - "rollup": "^1.20.0 || ^2.0.0" - } - }, - "node_modules/@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", - "dev": true, - "dependencies": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - }, - "engines": { - "node": ">= 8.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" - } - }, - "node_modules/@rollup/pluginutils/node_modules/@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "dev": true - }, - "node_modules/@rushstack/eslint-patch": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz", - "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==", - "dev": true - }, - "node_modules/@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", - "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^1.7.0" - } - }, - "node_modules/@surma/rollup-plugin-off-main-thread": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", - "integrity": "sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==", - "dev": true, - "dependencies": { - "ejs": "^3.1.6", - "json5": "^2.2.0", - "magic-string": "^0.25.0", - "string.prototype.matchall": "^4.0.6" - } - }, - "node_modules/@svgr/babel-plugin-add-jsx-attribute": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz", - "integrity": "sha512-ZFf2gs/8/6B8PnSofI0inYXr2SDNTDScPXhN7k5EqD4aZ3gi6u+rbmZHVB8IM3wDyx8ntKACZbtXSm7oZGRqVg==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-5.4.0.tgz", - "integrity": "sha512-yaS4o2PgUtwLFGTKbsiAy6D0o3ugcUhWK0Z45umJ66EPWunAz9fuFw2gJuje6wqQvQWOTJvIahUwndOXb7QCPg==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-5.0.1.tgz", - "integrity": "sha512-LA72+88A11ND/yFIMzyuLRSMJ+tRKeYKeQ+mR3DcAZ5I4h5CPWN9AHyUzJbWSYp/u2u0xhmgOe0+E41+GjEueA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-5.0.1.tgz", - "integrity": "sha512-PoiE6ZD2Eiy5mK+fjHqwGOS+IXX0wq/YDtNyIgOrc6ejFnxN4b13pRpiIPbtPwHEc+NT2KCjteAcq33/F1Y9KQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/@svgr/babel-plugin-svg-dynamic-title": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-5.4.0.tgz", - "integrity": "sha512-zSOZH8PdZOpuG1ZVx/cLVePB2ibo3WPpqo7gFIjLV9a0QsuQAzJiwwqmuEdTaW2pegyBE17Uu15mOgOcgabQZg==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/@svgr/babel-plugin-svg-em-dimensions": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-5.4.0.tgz", - "integrity": "sha512-cPzDbDA5oT/sPXDCUYoVXEmm3VIoAWAPT6mSPTJNbQaBNUuEKVKyGH93oDY4e42PYHRW67N5alJx/eEol20abw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/@svgr/babel-plugin-transform-react-native-svg": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-5.4.0.tgz", - "integrity": "sha512-3eYP/SaopZ41GHwXma7Rmxcv9uRslRDTY1estspeB1w1ueZWd/tPlMfEOoccYpEMZU3jD4OU7YitnXcF5hLW2Q==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/@svgr/babel-plugin-transform-svg-component": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-5.5.0.tgz", - "integrity": "sha512-q4jSH1UUvbrsOtlo/tKcgSeiCHRSBdXoIoqX1pgcKK/aU3JD27wmMKwGtpB8qRYUYoyXvfGxUVKchLuR5pB3rQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/@svgr/babel-preset": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-5.5.0.tgz", - "integrity": "sha512-4FiXBjvQ+z2j7yASeGPEi8VD/5rrGQk4Xrq3EdJmoZgz/tpqChpo5hgXDvmEauwtvOc52q8ghhZK4Oy7qph4ig==", - "dev": true, - "dependencies": { - "@svgr/babel-plugin-add-jsx-attribute": "^5.4.0", - "@svgr/babel-plugin-remove-jsx-attribute": "^5.4.0", - "@svgr/babel-plugin-remove-jsx-empty-expression": "^5.0.1", - "@svgr/babel-plugin-replace-jsx-attribute-value": "^5.0.1", - "@svgr/babel-plugin-svg-dynamic-title": "^5.4.0", - "@svgr/babel-plugin-svg-em-dimensions": "^5.4.0", - "@svgr/babel-plugin-transform-react-native-svg": "^5.4.0", - "@svgr/babel-plugin-transform-svg-component": "^5.5.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@svgr/core": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/core/-/core-5.5.0.tgz", - "integrity": "sha512-q52VOcsJPvV3jO1wkPtzTuKlvX7Y3xIcWRpCMtBF3MrteZJtBfQw/+u0B1BHy5ColpQc1/YVTrPEtSYIMNZlrQ==", - "dev": true, - "dependencies": { - "@svgr/plugin-jsx": "^5.5.0", - "camelcase": "^6.2.0", - "cosmiconfig": "^7.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@svgr/core/node_modules/camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/@svgr/hast-util-to-babel-ast": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.5.0.tgz", - "integrity": "sha512-cAaR/CAiZRB8GP32N+1jocovUtvlj0+e65TB50/6Lcime+EA49m/8l+P2ko+XPJ4dw3xaPS3jOL4F2X4KWxoeQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.12.6" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@svgr/plugin-jsx": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-5.5.0.tgz", - "integrity": "sha512-V/wVh33j12hGh05IDg8GpIUXbjAPnTdPTKuP4VNLggnwaHMPNQNae2pRnyTAILWCQdz5GyMqtO488g7CKM8CBA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@svgr/babel-preset": "^5.5.0", - "@svgr/hast-util-to-babel-ast": "^5.5.0", - "svg-parser": "^2.0.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@svgr/plugin-svgo": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-5.5.0.tgz", - "integrity": "sha512-r5swKk46GuQl4RrVejVwpeeJaydoxkdwkM1mBKOgJLBUJPGaLci6ylg/IjhrRsREKDkr4kbMWdgOtbXEh0fyLQ==", - "dev": true, - "dependencies": { - "cosmiconfig": "^7.0.0", - "deepmerge": "^4.2.2", - "svgo": "^1.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@svgr/plugin-svgo/node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@svgr/webpack": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-5.5.0.tgz", - "integrity": "sha512-DOBOK255wfQxguUta2INKkzPj6AIS6iafZYiYmHn6W3pHlycSRRlvWKCfLDG10fXfLWqE3DJHgRUOyJYmARa7g==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/plugin-transform-react-constant-elements": "^7.12.1", - "@babel/preset-env": "^7.12.1", - "@babel/preset-react": "^7.12.5", - "@svgr/core": "^5.5.0", - "@svgr/plugin-jsx": "^5.5.0", - "@svgr/plugin-svgo": "^5.5.0", - "loader-utils": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@testing-library/dom": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.11.3.tgz", - "integrity": "sha512-9LId28I+lx70wUiZjLvi1DB/WT2zGOxUh46glrSNMaWVx849kKAluezVzZrXJfTKKoQTmEOutLes/bHg4Bj3aA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^4.2.0", - "aria-query": "^5.0.0", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.4.4", - "pretty-format": "^27.0.2" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@testing-library/dom/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@testing-library/dom/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@testing-library/dom/node_modules/aria-query": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.0.0.tgz", - "integrity": "sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg==", - "dev": true, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/@testing-library/dom/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@testing-library/dom/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@testing-library/dom/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@testing-library/dom/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@testing-library/dom/node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@testing-library/dom/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@testing-library/dom/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/@testing-library/dom/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@testing-library/jest-dom": { - "version": "5.16.5", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz", - "integrity": "sha512-N5ixQ2qKpi5OLYfwQmUb/5mSV9LneAcaUfp32pn4yCnpb8r/Yz0pXFPck21dIicKmi+ta5WRAknkZCfA8refMA==", - "dev": true, - "dependencies": { - "@adobe/css-tools": "^4.0.1", - "@babel/runtime": "^7.9.2", - "@types/testing-library__jest-dom": "^5.9.1", - "aria-query": "^5.0.0", - "chalk": "^3.0.0", - "css.escape": "^1.5.1", - "dom-accessibility-api": "^0.5.6", - "lodash": "^4.17.15", - "redent": "^3.0.0" - }, - "engines": { - "node": ">=8", - "npm": ">=6", - "yarn": ">=1" - } - }, - "node_modules/@testing-library/jest-dom/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@testing-library/jest-dom/node_modules/aria-query": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.0.0.tgz", - "integrity": "sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg==", - "dev": true, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/@testing-library/jest-dom/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@testing-library/jest-dom/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@testing-library/jest-dom/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@testing-library/jest-dom/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@testing-library/jest-dom/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@testing-library/react": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-12.1.5.tgz", - "integrity": "sha512-OfTXCJUFgjd/digLUuPxa0+/3ZxsQmE7ub9kcbW/wi96Bh3o/p5vrETcBGfP17NWPGqeYYl5LTRpwyGoMC4ysg==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^8.0.0", - "@types/react-dom": "<18.0.0" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "react": "<18.0.0", - "react-dom": "<18.0.0" - } - }, - "node_modules/@testing-library/user-event": { - "version": "14.4.3", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.4.3.tgz", - "integrity": "sha512-kCUc5MEwaEMakkO5x7aoD+DLi02ehmEM2QCGWvNqAS1dV/fAvORWEjnjsEIvml59M7Y5kCkWN6fCCyPOe8OL6Q==", - "dev": true, - "engines": { - "node": ">=12", - "npm": ">=6" - }, - "peerDependencies": { - "@testing-library/dom": ">=7.21.4" - } - }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@trysound/sax": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", - "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", - "dev": true, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", - "dev": true - }, - "node_modules/@types/aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", - "dev": true - }, - "node_modules/@types/babel__core": { - "version": "7.1.18", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.18.tgz", - "integrity": "sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", - "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.3.0" - } - }, - "node_modules/@types/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", - "dev": true, - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/bonjour": { - "version": "3.5.10", - "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", - "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/cheerio": { - "version": "0.22.28", - "resolved": "https://registry.npmjs.org/@types/cheerio/-/cheerio-0.22.28.tgz", - "integrity": "sha512-ehUMGSW5IeDxJjbru4awKYMlKGmo1wSSGUVqXtYwlgmUM8X1a0PZttEIm6yEY7vHsY/hh6iPnklF213G0UColw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/connect-history-api-fallback": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz", - "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==", - "dev": true, - "dependencies": { - "@types/express-serve-static-core": "*", - "@types/node": "*" - } - }, - "node_modules/@types/eslint": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.2.2.tgz", - "integrity": "sha512-nQxgB8/Sg+QKhnV8e0WzPpxjIGT3tuJDDzybkDi8ItE/IgTlHo07U0shaIjzhcvQxlq9SDRE42lsJ23uvEgJ2A==", - "dev": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", - "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", - "dev": true, - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "node_modules/@types/estree": { - "version": "0.0.50", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz", - "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==", - "dev": true - }, - "node_modules/@types/express": { - "version": "4.17.13", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", - "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", - "dev": true, - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.18", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.17.28", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", - "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", - "dev": true, - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", - "dev": true - }, - "node_modules/@types/http-proxy": { - "version": "1.17.5", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.5.tgz", - "integrity": "sha512-GNkDE7bTv6Sf8JbV2GksknKOsk7OznNYHSdrtvPJXO0qJ9odZig6IZKUi5RFGi6d1bf6dgIAe4uXi3DBc7069Q==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", - "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", - "dev": true - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz", - "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/jest": { - "version": "27.4.1", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.4.1.tgz", - "integrity": "sha512-23iPJADSmicDVrWk+HT58LMJtzLAnB2AgIzplQuq/bSrGaxCrlvRFjGbXmamnnk/mAmCdLStiGqggu28ocUyiw==", - "dev": true, - "dependencies": { - "jest-matcher-utils": "^27.0.0", - "pretty-format": "^27.0.0" - } - }, - "node_modules/@types/jest/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@types/jest/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@types/jest/node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@types/jest/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", - "dev": true - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", - "dev": true - }, - "node_modules/@types/mime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", - "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", - "dev": true - }, - "node_modules/@types/node": { - "version": "15.0.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.0.2.tgz", - "integrity": "sha512-p68+a+KoxpoB47015IeYZYRrdqMUcpbK8re/zpFB8Ld46LHC1lPEbp3EXgkEhAYEcPvjJF6ZO+869SQ0aH1dcA==", - "dev": true - }, - "node_modules/@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true - }, - "node_modules/@types/prettier": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.3.tgz", - "integrity": "sha512-QzSuZMBuG5u8HqYz01qtMdg/Jfctlnvj1z/lYnIDXs/golxw0fxtRAHd9KrzjR7Yxz1qVeI00o0kiO3PmVdJ9w==", - "dev": true - }, - "node_modules/@types/prop-types": { - "version": "15.7.4", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz", - "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==", - "dev": true - }, - "node_modules/@types/q": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz", - "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==", - "dev": true - }, - "node_modules/@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", - "dev": true - }, - "node_modules/@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", - "dev": true - }, - "node_modules/@types/react": { - "version": "17.0.41", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.41.tgz", - "integrity": "sha512-chYZ9ogWUodyC7VUTRBfblysKLjnohhFY9bGLwvnUFFy48+vB9DikmB3lW0qTFmBcKSzmdglcvkHK71IioOlDA==", - "dev": true, - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "17.0.14", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.14.tgz", - "integrity": "sha512-H03xwEP1oXmSfl3iobtmQ/2dHF5aBHr8aUMwyGZya6OW45G+xtdzmq6HkncefiBt5JU8DVyaWl/nWZbjZCnzAQ==", - "dev": true, - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/retry": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", - "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==", - "dev": true - }, - "node_modules/@types/scheduler": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", - "dev": true - }, - "node_modules/@types/semver": { - "version": "7.3.13", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", - "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", - "dev": true - }, - "node_modules/@types/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", - "dev": true, - "dependencies": { - "@types/express": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "1.13.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", - "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", - "dev": true, - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "node_modules/@types/sockjs": { - "version": "0.3.33", - "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", - "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "node_modules/@types/testing-library__jest-dom": { - "version": "5.14.3", - "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.3.tgz", - "integrity": "sha512-oKZe+Mf4ioWlMuzVBaXQ9WDnEm1+umLx0InILg+yvZVBBDmzV5KfZyLrCvadtWcx8+916jLmHafcmqqffl+iIw==", - "dev": true, - "dependencies": { - "@types/jest": "*" - } - }, - "node_modules/@types/trusted-types": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz", - "integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==", - "dev": true - }, - "node_modules/@types/ws": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.2.2.tgz", - "integrity": "sha512-NOn5eIcgWLOo6qW8AcuLZ7G8PycXu0xTxxkS6Q18VWFxgPUSOwV0pBj2a/4viNZVu25i7RIB7GttdkAIUUXOOg==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/yargs": { - "version": "15.0.13", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz", - "integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "20.2.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", - "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==", - "dev": true - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.45.0.tgz", - "integrity": "sha512-CXXHNlf0oL+Yg021cxgOdMHNTXD17rHkq7iW6RFHoybdFgQBjU3yIXhhcPpGwr1CjZlo6ET8C6tzX5juQoXeGA==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.45.0", - "@typescript-eslint/type-utils": "5.45.0", - "@typescript-eslint/utils": "5.45.0", - "debug": "^4.3.4", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "regexpp": "^3.2.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/experimental-utils": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.45.0.tgz", - "integrity": "sha512-DnRQg5+3uHHt/gaifTjwg9OKbg9/TWehfJzYHQIDJboPEbF897BKDE/qoqMhW7nf0jWRV1mwVXTaUvtB1/9Gwg==", - "dev": true, - "dependencies": { - "@typescript-eslint/utils": "5.45.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.45.0.tgz", - "integrity": "sha512-brvs/WSM4fKUmF5Ot/gEve6qYiCMjm6w4HkHPfS6ZNmxTS0m0iNN4yOChImaCkqc1hRwFGqUyanMXuGal6oyyQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.45.0", - "@typescript-eslint/types": "5.45.0", - "@typescript-eslint/typescript-estree": "5.45.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.45.0.tgz", - "integrity": "sha512-noDMjr87Arp/PuVrtvN3dXiJstQR1+XlQ4R1EvzG+NMgXi8CuMCXpb8JqNtFHKceVSQ985BZhfRdowJzbv4yKw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.45.0", - "@typescript-eslint/visitor-keys": "5.45.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.45.0.tgz", - "integrity": "sha512-DY7BXVFSIGRGFZ574hTEyLPRiQIvI/9oGcN8t1A7f6zIs6ftbrU0nhyV26ZW//6f85avkwrLag424n+fkuoJ1Q==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "5.45.0", - "@typescript-eslint/utils": "5.45.0", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.45.0.tgz", - "integrity": "sha512-QQij+u/vgskA66azc9dCmx+rev79PzX8uDHpsqSjEFtfF2gBUTRCpvYMh2gw2ghkJabNkPlSUCimsyBEQZd1DA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.45.0.tgz", - "integrity": "sha512-maRhLGSzqUpFcZgXxg1qc/+H0bT36lHK4APhp0AEUVrpSwXiRAomm/JGjSG+kNUio5kAa3uekCYu/47cnGn5EQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.45.0", - "@typescript-eslint/visitor-keys": "5.45.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.45.0.tgz", - "integrity": "sha512-OUg2JvsVI1oIee/SwiejTot2OxwU8a7UfTFMOdlhD2y+Hl6memUSL4s98bpUTo8EpVEr0lmwlU7JSu/p2QpSvA==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.45.0", - "@typescript-eslint/types": "5.45.0", - "@typescript-eslint/typescript-estree": "5.45.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0", - "semver": "^7.3.7" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.45.0.tgz", - "integrity": "sha512-jc6Eccbn2RtQPr1s7th6jJWQHBHI6GBVQkCHoJFQ5UreaKm59Vxw+ynQUPPY2u2Amquc+7tmEoC2G52ApsGNNg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.45.0", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", - "dev": true, - "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" - } - }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", - "dev": true, - "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" - } - }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", - "dev": true, - "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", - "dev": true, - "dependencies": { - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", - "dev": true - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@wojtekmaj/enzyme-adapter-react-17": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/@wojtekmaj/enzyme-adapter-react-17/-/enzyme-adapter-react-17-0.6.5.tgz", - "integrity": "sha512-ChIObUiXXYUiqzXPqOai+p6KF5dlbItpDDYsftUOQiAiygbMDlLeJIjynC6ZrJIa2U2MpRp4YJmtR2GQyIHjgA==", - "dev": true, - "dependencies": { - "@wojtekmaj/enzyme-adapter-utils": "^0.1.1", - "enzyme-shallow-equal": "^1.0.0", - "has": "^1.0.0", - "object.assign": "^4.1.0", - "object.values": "^1.1.0", - "prop-types": "^15.7.0", - "react-is": "^17.0.2", - "react-test-renderer": "^17.0.0" - }, - "peerDependencies": { - "enzyme": "^3.0.0", - "react": "^17.0.0-0", - "react-dom": "^17.0.0-0" - } - }, - "node_modules/@wojtekmaj/enzyme-adapter-react-17/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/@wojtekmaj/enzyme-adapter-utils": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@wojtekmaj/enzyme-adapter-utils/-/enzyme-adapter-utils-0.1.1.tgz", - "integrity": "sha512-bNPWtN/d8huKOkC6j1E3EkSamnRrHHT7YuR6f9JppAQqtoAm3v4/vERe4J14jQKmHLCyEBHXrlgb7H6l817hVg==", - "dev": true, - "dependencies": { - "function.prototype.name": "^1.1.0", - "has": "^1.0.0", - "object.assign": "^4.1.0", - "object.fromentries": "^2.0.0", - "prop-types": "^15.7.0" - }, - "peerDependencies": { - "react": "^17.0.0-0" - } - }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true - }, - "node_modules/abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", - "dev": true - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dev": true, - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/ace-builds": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.10.1.tgz", - "integrity": "sha512-w8Xj6lZUtOYAquVYvdpZhb0GxXrZ+qpVfgj5LP2FwUbXE8fPrCmfu86FjwOiSphx/8PMbXXVldFLD2+RIXayyA==" - }, - "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "dev": true, - "dependencies": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-node": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", - "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", - "dev": true, - "dependencies": { - "acorn": "^7.0.0", - "acorn-walk": "^7.0.0", - "xtend": "^4.0.2" - } - }, - "node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/address": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/address/-/address-1.2.1.tgz", - "integrity": "sha512-B+6bi5D34+fDYENiH5qOlA0cV2rAGKuWZ9LeyUUehbXy8e0VS9e498yO0Jeeh+iM+6KbfudHTFjXw2MmJD4QRA==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/adjust-sourcemap-loader": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", - "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", - "dev": true, - "dependencies": { - "loader-utils": "^2.0.0", - "regex-parser": "^2.2.11" - }, - "engines": { - "node": ">=8.9" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dev": true, - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.9.0.tgz", - "integrity": "sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/alphanum-sort": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", - "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", - "dev": true - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-html-community": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", - "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", - "dev": true, - "engines": [ - "node >= 0.8.0" - ], - "bin": { - "ansi-html": "bin/ansi-html" - } - }, - "node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/ansi-to-html": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/ansi-to-html/-/ansi-to-html-0.7.2.tgz", - "integrity": "sha512-v6MqmEpNlxF+POuyhKkidusCHWWkaLcGRURzivcU3I9tv7k4JVhFcnukrM5Rlk2rUywdZuzYAZ+kbZqWCnfN3g==", - "dependencies": { - "entities": "^2.2.0" - }, - "bin": { - "ansi-to-html": "bin/ansi-to-html" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "node_modules/aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.10.2", - "@babel/runtime-corejs3": "^7.10.2" - }, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/array-filter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-1.0.0.tgz", - "integrity": "sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=", - "dev": true - }, - "node_modules/array-find": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-find/-/array-find-1.0.0.tgz", - "integrity": "sha1-bI4obRHtdoMn+OYuzuhzU8o+eLg=", - "dev": true - }, - "node_modules/array-flatten": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", - "dev": true - }, - "node_modules/array-includes": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", - "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", - "get-intrinsic": "^1.1.1", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/array.prototype.find": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array.prototype.find/-/array.prototype.find-2.1.2.tgz", - "integrity": "sha512-00S1O4ewO95OmmJW7EesWfQlrCrLEL8kZ40w3+GkLX2yTt0m2ggcePPa2uHPJ9KUmJvwRq+lCV9bD8Yim23x/Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", - "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz", - "integrity": "sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", - "dev": true - }, - "node_modules/ast-types-flow": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", - "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=", - "dev": true - }, - "node_modules/async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "dev": true, - "dependencies": { - "lodash": "^4.17.14" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/attr-accept": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-1.1.3.tgz", - "integrity": "sha512-iT40nudw8zmCweivz6j58g+RT33I4KbaIvRUhjNmDwO2WmsQUxFEZZYZ5w3vXe5x5MX9D7mfvA/XaLOZYFR9EQ==", - "dependencies": { - "core-js": "^2.5.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/autoprefixer": { - "version": "10.4.2", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.2.tgz", - "integrity": "sha512-9fOPpHKuDW1w/0EKfRmVnxTDt8166MAnLI3mgZ1JCnhNtYWxcJ6Ud5CO/AVOZi/AvFa8DY9RTy3h3+tFBlrrdQ==", - "dev": true, - "dependencies": { - "browserslist": "^4.19.1", - "caniuse-lite": "^1.0.30001297", - "fraction.js": "^4.1.2", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/axe-core": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.3.5.tgz", - "integrity": "sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/axios": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", - "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", - "dependencies": { - "follow-redirects": "^1.14.9", - "form-data": "^4.0.0" - } - }, - "node_modules/axios/node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/axobject-query": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", - "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==", - "dev": true - }, - "node_modules/babel-jest": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.4.6.tgz", - "integrity": "sha512-qZL0JT0HS1L+lOuH+xC2DVASR3nunZi/ozGhpgauJHgmI7f8rudxf6hUjEHympdQ/J64CdKmPkgfJ+A3U6QCrg==", - "dev": true, - "dependencies": { - "@jest/transform": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^27.4.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "slash": "^3.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/babel-jest/node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/babel-jest/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/babel-jest/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/babel-jest/node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-jest/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/babel-jest/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/babel-jest/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/babel-jest/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-jest/node_modules/istanbul-lib-instrument": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", - "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-jest/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-loader": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.3.tgz", - "integrity": "sha512-n4Zeta8NC3QAsuyiizu0GkmRcQ6clkV9WFUnUf1iXP//IeSKbWjofW3UHyZVwlOB4y039YQKefawyTn64Zwbuw==", - "dev": true, - "dependencies": { - "find-cache-dir": "^3.3.1", - "loader-utils": "^1.4.0", - "make-dir": "^3.1.0", - "schema-utils": "^2.6.5" - }, - "engines": { - "node": ">= 8.9" - }, - "peerDependencies": { - "@babel/core": "^7.0.0", - "webpack": ">=2" - } - }, - "node_modules/babel-loader/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/babel-loader/node_modules/loader-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", - "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", - "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/babel-loader/node_modules/schema-utils": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", - "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.5", - "ajv": "^6.12.4", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 8.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "dev": true, - "dependencies": { - "object.assign": "^4.1.0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", - "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^4.0.0", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.4.0.tgz", - "integrity": "sha512-Jcu7qS4OX5kTWBc45Hz7BMmgXuJqRnhatqpUhnzGC3OBYpOmf2tv6jFNwZpwM7wU7MUuv2r9IPS/ZlYOuburVw==", - "dev": true, - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/babel-plugin-macros": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", - "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.12.5", - "cosmiconfig": "^7.0.0", - "resolve": "^1.19.0" - }, - "engines": { - "node": ">=10", - "npm": ">=6" - } - }, - "node_modules/babel-plugin-named-asset-import": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.8.tgz", - "integrity": "sha512-WXiAc++qo7XcJ1ZnTYGtLxmBCVbddAml3CEXgWaBzNzLNoxtQ8AiGEFDMOhot9XjTCQbvP5E77Fj9Gk924f00Q==", - "dev": true, - "peerDependencies": { - "@babel/core": "^7.1.0" - } - }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", - "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.17.7", - "@babel/helper-define-polyfill-provider": "^0.3.3", - "semver": "^6.1.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.1.tgz", - "integrity": "sha512-TihqEe4sQcb/QcPJvxe94/9RZuLQuF1+To4WqQcRvc+3J3gLCPIPgDKzGLG6zmQLfH3nn25heRuDNkS2KR4I8A==", - "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.1", - "core-js-compat": "^3.20.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", - "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", - "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-styled-components": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-1.12.0.tgz", - "integrity": "sha512-FEiD7l5ZABdJPpLssKXjBUJMYqzbcNzBowfXDCdJhOpbhWiewapUaY+LZGT8R4Jg2TwOjGjG4RKeyrO5p9sBkA==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-module-imports": "^7.0.0", - "babel-plugin-syntax-jsx": "^6.18.0", - "lodash": "^4.17.11" - } - }, - "node_modules/babel-plugin-syntax-jsx": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", - "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=" - }, - "node_modules/babel-plugin-transform-react-remove-prop-types": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz", - "integrity": "sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA==", - "dev": true - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-preset-jest": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.4.0.tgz", - "integrity": "sha512-NK4jGYpnBvNxcGo7/ZpZJr51jCGT+3bwwpVIDY2oNfTxJJldRtB4VAcYdgp1loDE50ODuTu+yBjpMAswv5tlpg==", - "dev": true, - "dependencies": { - "babel-plugin-jest-hoist": "^27.4.0", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-preset-react-app": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-react-app/-/babel-preset-react-app-10.0.1.tgz", - "integrity": "sha512-b0D9IZ1WhhCWkrTXyFuIIgqGzSkRIH5D5AmB0bXbzYAB1OBAwHcUeyWW2LorutLWF5btNo/N7r/cIdmvvKJlYg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.16.0", - "@babel/plugin-proposal-class-properties": "^7.16.0", - "@babel/plugin-proposal-decorators": "^7.16.4", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.0", - "@babel/plugin-proposal-numeric-separator": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.0", - "@babel/plugin-proposal-private-methods": "^7.16.0", - "@babel/plugin-transform-flow-strip-types": "^7.16.0", - "@babel/plugin-transform-react-display-name": "^7.16.0", - "@babel/plugin-transform-runtime": "^7.16.4", - "@babel/preset-env": "^7.16.4", - "@babel/preset-react": "^7.16.0", - "@babel/preset-typescript": "^7.16.0", - "@babel/runtime": "^7.16.3", - "babel-plugin-macros": "^3.1.0", - "babel-plugin-transform-react-remove-prop-types": "^0.4.24" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true - }, - "node_modules/batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", - "dev": true - }, - "node_modules/bcp-47": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/bcp-47/-/bcp-47-1.0.8.tgz", - "integrity": "sha512-Y9y1QNBBtYtv7hcmoX0tR+tUNSFZGZ6OL6vKPObq8BbOhkCoyayF6ogfLTgAli/KuAEbsYHYUNq2AQuY6IuLag==", - "dev": true, - "dependencies": { - "is-alphabetical": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-decimal": "^1.0.0" - } - }, - "node_modules/bfj": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/bfj/-/bfj-7.0.2.tgz", - "integrity": "sha512-+e/UqUzwmzJamNF50tBV6tZPTORow7gQ96iFow+8b562OdMpEK0BcJEq2OSPEDmAbSMBQ7PKZ87ubFkgxpYWgw==", - "dev": true, - "dependencies": { - "bluebird": "^3.5.5", - "check-types": "^11.1.1", - "hoopy": "^0.1.4", - "tryer": "^1.0.1" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, - "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", - "dev": true, - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/body-parser/node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/bonjour": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", - "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", - "dev": true, - "dependencies": { - "array-flatten": "^2.1.0", - "deep-equal": "^1.0.1", - "dns-equal": "^1.0.0", - "dns-txt": "^2.0.2", - "multicast-dns": "^6.0.1", - "multicast-dns-service-types": "^1.1.0" - } - }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, - "node_modules/browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true - }, - "node_modules/buffer-indexof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", - "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", - "dev": true - }, - "node_modules/builtin-modules": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", - "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camel-case": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", - "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", - "dev": true, - "dependencies": { - "pascal-case": "^3.1.2", - "tslib": "^2.0.3" - } - }, - "node_modules/camel-case/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/camelize": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", - "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=" - }, - "node_modules/caniuse-api": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", - "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", - "dev": true, - "dependencies": { - "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001434", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001434.tgz", - "integrity": "sha512-aOBHrLmTQw//WFa2rcF1If9fa3ypkC1wzqqiKHgfdrXTWcU8C4gKVZT77eQAPWN1APys3+uQ0Df07rKauXGEYA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - } - ] - }, - "node_modules/case-sensitive-paths-webpack-plugin": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", - "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "node_modules/check-types": { - "version": "11.1.2", - "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.1.2.tgz", - "integrity": "sha512-tzWzvgePgLORb9/3a0YenggReLKAIb2owL03H2Xdoe5pKcUyWRSEQ8xfCar8t2SIAuEDwtmx2da1YB52YuHQMQ==", - "dev": true - }, - "node_modules/cheerio": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.9.tgz", - "integrity": "sha512-QF6XVdrLONO6DXRF5iaolY+odmhj2CLj+xzNod7INPWMi/x9X4SOylH0S/vaPpX+AUU6t04s34SQNh7DbkuCng==", - "dev": true, - "dependencies": { - "cheerio-select": "^1.4.0", - "dom-serializer": "^1.3.1", - "domhandler": "^4.2.0", - "htmlparser2": "^6.1.0", - "parse5": "^6.0.1", - "parse5-htmlparser2-tree-adapter": "^6.0.1", - "tslib": "^2.2.0" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/cheerio-select": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.4.0.tgz", - "integrity": "sha512-sobR3Yqz27L553Qa7cK6rtJlMDbiKPdNywtR95Sj/YgfpLfy0u6CGJuaBKe5YE/vTc23SCRKxWSdlon/w6I/Ew==", - "dev": true, - "dependencies": { - "css-select": "^4.1.2", - "css-what": "^5.0.0", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0", - "domutils": "^2.6.0" - } - }, - "node_modules/cheerio/node_modules/tslib": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz", - "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==", - "dev": true - }, - "node_modules/chokidar": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", - "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", - "dev": true, - "dependencies": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.5.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.1" - } - }, - "node_modules/chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", - "dev": true, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/ci-info": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", - "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", - "dev": true - }, - "node_modules/cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "node_modules/clean-css": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.2.2.tgz", - "integrity": "sha512-/eR8ru5zyxKzpBLv9YZvMXgTSSQn7AdkMItMYynsFgGwTveCRVam9IUPFloE85B4vAIj05IuKmmEoV7/AQjT0w==", - "dev": true, - "dependencies": { - "source-map": "~0.6.0" - }, - "engines": { - "node": ">= 10.0" - } - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "dependencies": { - "restore-cursor": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-spinners": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.0.tgz", - "integrity": "sha512-t+4/y50K/+4xcCRosKkA7W4gTr1MySvLV0q+PxmG7FJ5g+66ChKurYjxBCjHggHH3HA5Hh9cy+lcUGWDqVH+4Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/cli-table": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.6.tgz", - "integrity": "sha512-ZkNZbnZjKERTY5NwC2SeMeLeifSPq/pubeRoTpdr3WchLlnZg6hEgvHkK5zL7KNFdd9PmHN8lxrENUwI3cE8vQ==", - "dev": true, - "dependencies": { - "colors": "1.0.3" - }, - "engines": { - "node": ">= 0.2.0" - } - }, - "node_modules/cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/clsx": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz", - "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true, - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/coa": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", - "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", - "dev": true, - "dependencies": { - "@types/q": "^1.5.1", - "chalk": "^2.4.1", - "q": "^1.1.2" - }, - "engines": { - "node": ">= 4.0" - } - }, - "node_modules/codemirror": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz", - "integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==", - "dependencies": { - "@codemirror/autocomplete": "^6.0.0", - "@codemirror/commands": "^6.0.0", - "@codemirror/language": "^6.0.0", - "@codemirror/lint": "^6.0.0", - "@codemirror/search": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "node_modules/colord": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.2.tgz", - "integrity": "sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ==", - "dev": true - }, - "node_modules/colorette": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", - "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", - "dev": true - }, - "node_modules/colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", - "dev": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/common-path-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", - "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", - "dev": true - }, - "node_modules/common-tags": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", - "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "node_modules/compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "dev": true, - "dependencies": { - "mime-db": ">= 1.43.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", - "dev": true, - "dependencies": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", - "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/compression/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/compression/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/confusing-browser-globals": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", - "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", - "dev": true - }, - "node_modules/connect-history-api-fallback": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", - "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dev": true, - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-disposition/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.1" - } - }, - "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", - "dev": true - }, - "node_modules/core-js": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", - "hasInstallScript": true - }, - "node_modules/core-js-compat": { - "version": "3.26.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.26.1.tgz", - "integrity": "sha512-622/KzTudvXCDLRw70iHW4KKs1aGpcRcowGWyYJr2DEBfRrd6hNJybxSWJFuZYD4ma86xhrwDDHxmDaIq4EA8A==", - "dev": true, - "dependencies": { - "browserslist": "^4.21.4" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/core-js-pure": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.12.1.tgz", - "integrity": "sha512-1cch+qads4JnDSWsvc7d6nzlKAippwjUlf6vykkTLW53VSV+NkE6muGBToAjEA8pG90cSfcud3JgVmW2ds5TaQ==", - "dev": true, - "hasInstallScript": true - }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "node_modules/cosmiconfig": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", - "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", - "dev": true, - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/cosmiconfig-typescript-loader": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-2.0.2.tgz", - "integrity": "sha512-KmE+bMjWMXJbkWCeY4FJX/npHuZPNr9XF9q9CIQ/bpFwi1qHfCmSiKarrCcRa0LO4fWjk93pVoeRtJAkTGcYNw==", - "dev": true, - "dependencies": { - "cosmiconfig": "^7", - "ts-node": "^10.8.1" - }, - "engines": { - "node": ">=12", - "npm": ">=6" - }, - "peerDependencies": { - "@types/node": "*", - "cosmiconfig": ">=7", - "typescript": ">=3" - } - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "node_modules/crelt": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.5.tgz", - "integrity": "sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA==" - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/css-blank-pseudo": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-3.0.2.tgz", - "integrity": "sha512-hOb1LFjRR+8ocA071xUSmg5VslJ8NGo/I2qpUpdeAYyBVCgupS5O8SEVo4SxEMYyFBNodBkzG3T1iqW9HCXxew==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.8" - }, - "bin": { - "css-blank-pseudo": "dist/cli.cjs" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.3" - } - }, - "node_modules/css-color-keywords": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", - "integrity": "sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU=", - "engines": { - "node": ">=4" - } - }, - "node_modules/css-declaration-sorter": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.1.4.tgz", - "integrity": "sha512-lpfkqS0fctcmZotJGhnxkIyJWvBXgpyi2wsFd4J8VB7wzyrT6Ch/3Q+FMNJpjK4gu1+GN5khOnpU2ZVKrLbhCw==", - "dev": true, - "dependencies": { - "timsort": "^0.3.0" - }, - "engines": { - "node": ">= 10" - }, - "peerDependencies": { - "postcss": "^8.0.9" - } - }, - "node_modules/css-has-pseudo": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-3.0.3.tgz", - "integrity": "sha512-0gDYWEKaGacwxCqvQ3Ypg6wGdD1AztbMm5h1JsactG2hP2eiflj808QITmuWBpE7sjSEVrAlZhPTVd/nNMj/hQ==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.8" - }, - "bin": { - "css-has-pseudo": "dist/cli.cjs" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.3" - } - }, - "node_modules/css-loader": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.5.1.tgz", - "integrity": "sha512-gEy2w9AnJNnD9Kuo4XAP9VflW/ujKoS9c/syO+uWMlm5igc7LysKzPXaDoR2vroROkSwsTS2tGr1yGGEbZOYZQ==", - "dev": true, - "dependencies": { - "icss-utils": "^5.1.0", - "postcss": "^8.2.15", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.0", - "postcss-modules-scope": "^3.0.0", - "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.1.0", - "semver": "^7.3.5" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/css-loader/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/css-minimizer-webpack-plugin": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.4.1.tgz", - "integrity": "sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q==", - "dev": true, - "dependencies": { - "cssnano": "^5.0.6", - "jest-worker": "^27.0.2", - "postcss": "^8.3.5", - "schema-utils": "^4.0.0", - "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "@parcel/css": { - "optional": true - }, - "clean-css": { - "optional": true - }, - "csso": { - "optional": true - }, - "esbuild": { - "optional": true - } - } - }, - "node_modules/css-minimizer-webpack-plugin/node_modules/ajv": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.9.0.tgz", - "integrity": "sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/css-minimizer-webpack-plugin/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/css-minimizer-webpack-plugin/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/css-minimizer-webpack-plugin/node_modules/schema-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/css-prefers-color-scheme": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.2.tgz", - "integrity": "sha512-gv0KQBEM+q/XdoKyznovq3KW7ocO7k+FhPP+hQR1MenJdu0uPGS6IZa9PzlbqBeS6XcZJNAoqoFxlAUW461CrA==", - "dev": true, - "bin": { - "css-prefers-color-scheme": "dist/cli.cjs" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.3" - } - }, - "node_modules/css-select": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz", - "integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^5.1.0", - "domhandler": "^4.3.0", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-select-base-adapter": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", - "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", - "dev": true - }, - "node_modules/css-to-react-native": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.0.0.tgz", - "integrity": "sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ==", - "dependencies": { - "camelize": "^1.0.0", - "css-color-keywords": "^1.0.0", - "postcss-value-parser": "^4.0.2" - } - }, - "node_modules/css-tree": { - "version": "1.0.0-alpha.37", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", - "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", - "dev": true, - "dependencies": { - "mdn-data": "2.0.4", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/css-what": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", - "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==", - "dev": true, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css.escape": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s=", - "dev": true - }, - "node_modules/cssdb": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-5.1.0.tgz", - "integrity": "sha512-/vqjXhv1x9eGkE/zO6o8ZOI7dgdZbLVLUGyVRbPgk6YipXbW87YzUCcO+Jrmi5bwJlAH6oD+MNeZyRgXea1GZw==", - "dev": true - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cssnano": { - "version": "5.0.15", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.0.15.tgz", - "integrity": "sha512-ppZsS7oPpi2sfiyV5+i+NbB/3GtQ+ab2Vs1azrZaXWujUSN4o+WdTxlCZIMcT9yLW3VO/5yX3vpyDaQ1nIn8CQ==", - "dev": true, - "dependencies": { - "cssnano-preset-default": "^5.1.10", - "lilconfig": "^2.0.3", - "yaml": "^1.10.2" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/cssnano" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/cssnano-preset-default": { - "version": "5.1.10", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.1.10.tgz", - "integrity": "sha512-BcpSzUVygHMOnp9uG5rfPzTOCb0GAHQkqtUQx8j1oMNF9A1Q8hziOOhiM4bdICpmrBIU85BE64RD5XGYsVQZNA==", - "dev": true, - "dependencies": { - "css-declaration-sorter": "^6.0.3", - "cssnano-utils": "^3.0.0", - "postcss-calc": "^8.2.0", - "postcss-colormin": "^5.2.3", - "postcss-convert-values": "^5.0.2", - "postcss-discard-comments": "^5.0.1", - "postcss-discard-duplicates": "^5.0.1", - "postcss-discard-empty": "^5.0.1", - "postcss-discard-overridden": "^5.0.2", - "postcss-merge-longhand": "^5.0.4", - "postcss-merge-rules": "^5.0.4", - "postcss-minify-font-values": "^5.0.2", - "postcss-minify-gradients": "^5.0.4", - "postcss-minify-params": "^5.0.3", - "postcss-minify-selectors": "^5.1.1", - "postcss-normalize-charset": "^5.0.1", - "postcss-normalize-display-values": "^5.0.2", - "postcss-normalize-positions": "^5.0.2", - "postcss-normalize-repeat-style": "^5.0.2", - "postcss-normalize-string": "^5.0.2", - "postcss-normalize-timing-functions": "^5.0.2", - "postcss-normalize-unicode": "^5.0.2", - "postcss-normalize-url": "^5.0.4", - "postcss-normalize-whitespace": "^5.0.2", - "postcss-ordered-values": "^5.0.3", - "postcss-reduce-initial": "^5.0.2", - "postcss-reduce-transforms": "^5.0.2", - "postcss-svgo": "^5.0.3", - "postcss-unique-selectors": "^5.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/cssnano-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.0.0.tgz", - "integrity": "sha512-Pzs7/BZ6OgT+tXXuF12DKR8SmSbzUeVYCtMBbS8lI0uAm3mrYmkyqCXXPsQESI6kmLfEVBppbdVY/el3hg3nAA==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/csso": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", - "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", - "dev": true, - "dependencies": { - "css-tree": "^1.1.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/csso/node_modules/css-tree": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", - "dev": true, - "dependencies": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/csso/node_modules/mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", - "dev": true - }, - "node_modules/cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true - }, - "node_modules/cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "dependencies": { - "cssom": "~0.3.6" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cssstyle/node_modules/cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - }, - "node_modules/csstype": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz", - "integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==" - }, - "node_modules/d3": { - "version": "7.6.1", - "resolved": "https://registry.npmjs.org/d3/-/d3-7.6.1.tgz", - "integrity": "sha512-txMTdIHFbcpLx+8a0IFhZsbp+PfBBPt8yfbmukZTQFroKuFqIwqswF0qE5JXWefylaAVpSXFoKm3yP+jpNLFLw==", - "dependencies": { - "d3-array": "3", - "d3-axis": "3", - "d3-brush": "3", - "d3-chord": "3", - "d3-color": "3", - "d3-contour": "4", - "d3-delaunay": "6", - "d3-dispatch": "3", - "d3-drag": "3", - "d3-dsv": "3", - "d3-ease": "3", - "d3-fetch": "3", - "d3-force": "3", - "d3-format": "3", - "d3-geo": "3", - "d3-hierarchy": "3", - "d3-interpolate": "3", - "d3-path": "3", - "d3-polygon": "3", - "d3-quadtree": "3", - "d3-random": "3", - "d3-scale": "4", - "d3-scale-chromatic": "3", - "d3-selection": "3", - "d3-shape": "3", - "d3-time": "3", - "d3-time-format": "4", - "d3-timer": "3", - "d3-transition": "3", - "d3-zoom": "3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-array": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.0.tgz", - "integrity": "sha512-3yXFQo0oG3QCxbF06rMPFyGRMGJNS7NvsV1+2joOjbBE+9xvWQ8+GcMJAjRCzw06zQ3/arXeJgbPYcjUCuC+3g==", - "dependencies": { - "internmap": "1 - 2" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-axis": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", - "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-brush": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", - "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-drag": "2 - 3", - "d3-interpolate": "1 - 3", - "d3-selection": "3", - "d3-transition": "3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-chord": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", - "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", - "dependencies": { - "d3-path": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-color": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", - "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-contour": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.0.tgz", - "integrity": "sha512-7aQo0QHUTu/Ko3cP9YK9yUTxtoDEiDGwnBHyLxG5M4vqlBkO/uixMRele3nfsfj6UXOcuReVpVXzAboGraYIJw==", - "dependencies": { - "d3-array": "^3.2.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-delaunay": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.2.tgz", - "integrity": "sha512-IMLNldruDQScrcfT+MWnazhHbDJhcRJyOEBAJfwQnHle1RPh6WDuLvxNArUju2VSMSUuKlY5BGHRJ2cYyoFLQQ==", - "dependencies": { - "delaunator": "5" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-dispatch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", - "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-drag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", - "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-selection": "3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-dsv": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", - "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", - "dependencies": { - "commander": "7", - "iconv-lite": "0.6", - "rw": "1" - }, - "bin": { - "csv2json": "bin/dsv2json.js", - "csv2tsv": "bin/dsv2dsv.js", - "dsv2dsv": "bin/dsv2dsv.js", - "dsv2json": "bin/dsv2json.js", - "json2csv": "bin/json2dsv.js", - "json2dsv": "bin/json2dsv.js", - "json2tsv": "bin/json2dsv.js", - "tsv2csv": "bin/dsv2dsv.js", - "tsv2json": "bin/dsv2json.js" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-dsv/node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "engines": { - "node": ">= 10" - } - }, - "node_modules/d3-dsv/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/d3-ease": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", - "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-fetch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", - "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", - "dependencies": { - "d3-dsv": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-force": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", - "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-quadtree": "1 - 3", - "d3-timer": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-format": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.0.1.tgz", - "integrity": "sha512-hdL7+HBIohpgfolhBxr1KX47VMD6+vVD/oEFrxk5yhmzV2prk99EkFKYpXuhVkFpTgHdJ6/4bYcjdLPPXV4tIA==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-geo": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.0.1.tgz", - "integrity": "sha512-Wt23xBych5tSy9IYAM1FR2rWIBFWa52B/oF/GYe5zbdHrg08FU8+BuI6X4PvTwPDdqdAdq04fuWJpELtsaEjeA==", - "dependencies": { - "d3-array": "2.5.0 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-hierarchy": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.0.1.tgz", - "integrity": "sha512-RlLTaofEoOrMK1JoXYIGhKTkJFI/6rFrYPgxy6QlZo2BcVc4HGTqEU0rPpzuMq5T/5XcMtAzv1XiLA3zRTfygw==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-interpolate": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", - "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", - "dependencies": { - "d3-color": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-path": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.0.1.tgz", - "integrity": "sha512-gq6gZom9AFZby0YLduxT1qmrp4xpBA1YZr19OI717WIdKE2OM5ETq5qrHLb301IgxhLwcuxvGZVLeeWc/k1I6w==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-polygon": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", - "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-quadtree": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", - "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-random": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", - "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-scale": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", - "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", - "dependencies": { - "d3-array": "2.10.0 - 3", - "d3-format": "1 - 3", - "d3-interpolate": "1.2.0 - 3", - "d3-time": "2.1.1 - 3", - "d3-time-format": "2 - 4" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-scale-chromatic": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", - "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==", - "dependencies": { - "d3-color": "1 - 3", - "d3-interpolate": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-selection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", - "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-shape": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.0.1.tgz", - "integrity": "sha512-HNZNEQoDhuCrDWEc/BMbF/hKtzMZVoe64TvisFLDp2Iyj0UShB/E6/lBsLlJTfBMbYgftHj90cXJ0SEitlE6Xw==", - "dependencies": { - "d3-path": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-time": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.0.0.tgz", - "integrity": "sha512-zmV3lRnlaLI08y9IMRXSDshQb5Nj77smnfpnd2LrBa/2K281Jijactokeak14QacHs/kKq0AQ121nidNYlarbQ==", - "dependencies": { - "d3-array": "2 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-time-format": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.0.0.tgz", - "integrity": "sha512-nzaCwlj+ZVBIlFuVOT1RmU+6xb/7D5IcnhHzHQcBgS/aTa5K9fWZNN5LCXA27LgF5WxoSNJqKBbLcGMtM6Ca6A==", - "dependencies": { - "d3-time": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-timer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", - "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-transition": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", - "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", - "dependencies": { - "d3-color": "1 - 3", - "d3-dispatch": "1 - 3", - "d3-ease": "1 - 3", - "d3-interpolate": "1 - 3", - "d3-timer": "1 - 3" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "d3-selection": "2 - 3" - } - }, - "node_modules/d3-zoom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", - "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-drag": "2 - 3", - "d3-interpolate": "1 - 3", - "d3-selection": "2 - 3", - "d3-transition": "2 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/dagre": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.5.tgz", - "integrity": "sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==", - "dependencies": { - "graphlib": "^2.1.8", - "lodash": "^4.17.15" - } - }, - "node_modules/damerau-levenshtein": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz", - "integrity": "sha512-VvdQIPGdWP0SqFXghj79Wf/5LArmreyMsGLa6FG6iC4t3j7j5s71TrwWmT/4akbDQIqjfACkLZmjXhA7g2oUZw==", - "dev": true - }, - "node_modules/data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", - "dev": true, - "dependencies": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/date-fns": { - "version": "2.21.3", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.21.3.tgz", - "integrity": "sha512-HeYdzCaFflc1i4tGbj7JKMjM4cKGYoyxwcIIkHzNgCkX8xXDNJDZXgDDVchIWpN4eQc3lH37WarduXFZJOtxfw==", - "dev": true, - "engines": { - "node": ">=0.11" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decimal.js": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", - "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", - "dev": true - }, - "node_modules/dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", - "dev": true - }, - "node_modules/deep-equal": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", - "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", - "dev": true, - "dependencies": { - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.1", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.2.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "node_modules/deepmerge": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.2.1.tgz", - "integrity": "sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/default-gateway": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", - "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", - "dev": true, - "dependencies": { - "execa": "^5.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/defaults": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", - "dev": true, - "dependencies": { - "clone": "^1.0.2" - } - }, - "node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "dependencies": { - "object-keys": "^1.0.12" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/defined": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", - "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", - "dev": true - }, - "node_modules/del": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz", - "integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==", - "dev": true, - "dependencies": { - "globby": "^11.0.1", - "graceful-fs": "^4.2.4", - "is-glob": "^4.0.1", - "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.2", - "p-map": "^4.0.0", - "rimraf": "^3.0.2", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/delaunator": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", - "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==", - "dependencies": { - "robust-predicates": "^3.0.0" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true - }, - "node_modules/detect-port-alt": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", - "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", - "dev": true, - "dependencies": { - "address": "^1.0.1", - "debug": "^2.6.0" - }, - "bin": { - "detect": "bin/detect-port", - "detect-port": "bin/detect-port" - }, - "engines": { - "node": ">= 4.2.1" - } - }, - "node_modules/detect-port-alt/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/detect-port-alt/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/detective": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", - "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==", - "dev": true, - "dependencies": { - "acorn-node": "^1.6.1", - "defined": "^1.0.0", - "minimist": "^1.1.1" - }, - "bin": { - "detective": "bin/detective.js" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/diff-match-patch": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz", - "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==" - }, - "node_modules/diff-sequences": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.4.0.tgz", - "integrity": "sha512-YqiQzkrsmHMH5uuh8OdQFU9/ZpADnwzml8z0O5HvRNda+5UZsaX/xN+AAxfR2hWq1Y7HZnAzO9J5lJXOuDz2Ww==", - "dev": true, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/discontinuous-range": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz", - "integrity": "sha1-44Mx8IRLukm5qctxx3FYWqsbxlo=", - "dev": true - }, - "node_modules/dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true - }, - "node_modules/dns-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", - "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", - "dev": true - }, - "node_modules/dns-packet": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz", - "integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==", - "dev": true, - "dependencies": { - "ip": "^1.1.0", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/dns-txt": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", - "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", - "dev": true, - "dependencies": { - "buffer-indexof": "^1.0.0" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dom-accessibility-api": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.13.tgz", - "integrity": "sha512-R305kwb5CcMDIpSHUnLyIAp7SrSPBx6F0VfQFB3M75xVMHhXJJIdePYgbPPh1o57vCHNu5QztokWUPsLjWzFqw==", - "dev": true - }, - "node_modules/dom-converter": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", - "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", - "dev": true, - "dependencies": { - "utila": "~0.4" - } - }, - "node_modules/dom-helpers": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", - "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", - "dependencies": { - "@babel/runtime": "^7.8.7", - "csstype": "^3.0.2" - } - }, - "node_modules/dom-serializer": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.1.tgz", - "integrity": "sha512-Pv2ZluG5ife96udGgEDovOOOA5UELkltfJpnIExPrAk1LTvecolUGn6lIaoLh86d83GiB86CjzciMd9BuRB71Q==", - "dev": true, - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "entities": "^2.0.0" - } - }, - "node_modules/domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "dev": true - }, - "node_modules/domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", - "dev": true, - "dependencies": { - "webidl-conversions": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/domexception/node_modules/webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/domhandler": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", - "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", - "dev": true, - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/dompurify": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.0.tgz", - "integrity": "sha512-Be9tbQMZds4a3C6xTmz68NlMfeONA//4dOavl/1rNw50E+/QO0KVpbcU0PcaW0nsQxurXls9ZocqFxk8R2mWEA==" - }, - "node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dev": true, - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/dot-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", - "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", - "dev": true, - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/dot-case/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - }, - "node_modules/dotenv": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/dotenv-expand": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", - "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", - "dev": true - }, - "node_modules/duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true - }, - "node_modules/ejs": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz", - "integrity": "sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==", - "dev": true, - "dependencies": { - "jake": "^10.8.5" - }, - "bin": { - "ejs": "bin/cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.284", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", - "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", - "dev": true - }, - "node_modules/emittery": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", - "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/enhanced-resolve": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz", - "integrity": "sha1-TW5omzcl+GCQknzMhs2fFjW4ni4=", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.2.0", - "tapable": "^0.1.8" - }, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/enzyme": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/enzyme/-/enzyme-3.11.0.tgz", - "integrity": "sha512-Dw8/Gs4vRjxY6/6i9wU0V+utmQO9kvh9XLnz3LIudviOnVYDEe2ec+0k+NQoMamn1VrjKgCUOWj5jG/5M5M0Qw==", - "dev": true, - "dependencies": { - "array.prototype.flat": "^1.2.3", - "cheerio": "^1.0.0-rc.3", - "enzyme-shallow-equal": "^1.0.1", - "function.prototype.name": "^1.1.2", - "has": "^1.0.3", - "html-element-map": "^1.2.0", - "is-boolean-object": "^1.0.1", - "is-callable": "^1.1.5", - "is-number-object": "^1.0.4", - "is-regex": "^1.0.5", - "is-string": "^1.0.5", - "is-subset": "^0.1.1", - "lodash.escape": "^4.0.1", - "lodash.isequal": "^4.5.0", - "object-inspect": "^1.7.0", - "object-is": "^1.0.2", - "object.assign": "^4.1.0", - "object.entries": "^1.1.1", - "object.values": "^1.1.1", - "raf": "^3.4.1", - "rst-selector-parser": "^2.2.3", - "string.prototype.trim": "^1.2.1" - } - }, - "node_modules/enzyme-adapter-react-16": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.15.6.tgz", - "integrity": "sha512-yFlVJCXh8T+mcQo8M6my9sPgeGzj85HSHi6Apgf1Cvq/7EL/J9+1JoJmJsRxZgyTvPMAqOEpRSu/Ii/ZpyOk0g==", - "dev": true, - "dependencies": { - "enzyme-adapter-utils": "^1.14.0", - "enzyme-shallow-equal": "^1.0.4", - "has": "^1.0.3", - "object.assign": "^4.1.2", - "object.values": "^1.1.2", - "prop-types": "^15.7.2", - "react-is": "^16.13.1", - "react-test-renderer": "^16.0.0-0", - "semver": "^5.7.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - }, - "peerDependencies": { - "enzyme": "^3.0.0", - "react": "^16.0.0-0", - "react-dom": "^16.0.0-0" - } - }, - "node_modules/enzyme-adapter-react-16/node_modules/airbnb-prop-types": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/airbnb-prop-types/-/airbnb-prop-types-2.16.0.tgz", - "integrity": "sha512-7WHOFolP/6cS96PhKNrslCLMYAI8yB1Pp6u6XmxozQOiZbsI5ycglZr5cHhBFfuRcQQjzCMith5ZPZdYiJCxUg==", - "dev": true, - "dependencies": { - "array.prototype.find": "^2.1.1", - "function.prototype.name": "^1.1.2", - "is-regex": "^1.1.0", - "object-is": "^1.1.2", - "object.assign": "^4.1.0", - "object.entries": "^1.1.2", - "prop-types": "^15.7.2", - "prop-types-exact": "^1.2.0", - "react-is": "^16.13.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - }, - "peerDependencies": { - "react": "^0.14 || ^15.0.0 || ^16.0.0-alpha" - } - }, - "node_modules/enzyme-adapter-react-16/node_modules/enzyme-adapter-utils": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/enzyme-adapter-utils/-/enzyme-adapter-utils-1.14.0.tgz", - "integrity": "sha512-F/z/7SeLt+reKFcb7597IThpDp0bmzcH1E9Oabqv+o01cID2/YInlqHbFl7HzWBl4h3OdZYedtwNDOmSKkk0bg==", - "dev": true, - "dependencies": { - "airbnb-prop-types": "^2.16.0", - "function.prototype.name": "^1.1.3", - "has": "^1.0.3", - "object.assign": "^4.1.2", - "object.fromentries": "^2.0.3", - "prop-types": "^15.7.2", - "semver": "^5.7.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - }, - "peerDependencies": { - "react": "0.13.x || 0.14.x || ^15.0.0-0 || ^16.0.0-0" - } - }, - "node_modules/enzyme-adapter-react-16/node_modules/react-test-renderer": { - "version": "16.14.0", - "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.14.0.tgz", - "integrity": "sha512-L8yPjqPE5CZO6rKsKXRO/rVPiaCOy0tQQJbC+UjPNlobl5mad59lvPjwFsQHTvL03caVDIVr9x9/OSgDe6I5Eg==", - "dev": true, - "dependencies": { - "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "react-is": "^16.8.6", - "scheduler": "^0.19.1" - }, - "peerDependencies": { - "react": "^16.14.0" - } - }, - "node_modules/enzyme-adapter-react-16/node_modules/scheduler": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", - "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", - "dev": true, - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "node_modules/enzyme-adapter-react-16/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/enzyme-shallow-equal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/enzyme-shallow-equal/-/enzyme-shallow-equal-1.0.4.tgz", - "integrity": "sha512-MttIwB8kKxypwHvRynuC3ahyNc+cFbR8mjVIltnmzQ0uKGqmsfO4bfBuLxb0beLNPhjblUEYvEbsg+VSygvF1Q==", - "dev": true, - "dependencies": { - "has": "^1.0.3", - "object-is": "^1.1.2" - } - }, - "node_modules/enzyme-to-json": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/enzyme-to-json/-/enzyme-to-json-3.6.2.tgz", - "integrity": "sha512-Ynm6Z6R6iwQ0g2g1YToz6DWhxVnt8Dy1ijR2zynRKxTyBGA8rCDXU3rs2Qc4OKvUvc2Qoe1bcFK6bnPs20TrTg==", - "dev": true, - "dependencies": { - "@types/cheerio": "^0.22.22", - "lodash": "^4.17.21", - "react-is": "^16.12.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/error-stack-parser": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.6.tgz", - "integrity": "sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ==", - "dev": true, - "dependencies": { - "stackframe": "^1.1.1" - } - }, - "node_modules/es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", - "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-module-lexer": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", - "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", - "dev": true - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", - "dev": true - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "dev": true, - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/escodegen/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/escodegen/node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/eslint": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.7.0.tgz", - "integrity": "sha512-ifHYzkBGrzS2iDU7KjhCAVMGCvF6M3Xfs8X8b37cgrUlDt6bWRTpRh6T/gtSXv1HJ/BUGgmjvNvOEGu85Iif7w==", - "dev": true, - "dependencies": { - "@eslint/eslintrc": "^1.0.5", - "@humanwhocodes/config-array": "^0.9.2", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.0", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.2.0", - "espree": "^9.3.0", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", - "globals": "^13.6.0", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-airbnb": { - "version": "19.0.4", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-19.0.4.tgz", - "integrity": "sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==", - "dev": true, - "dependencies": { - "eslint-config-airbnb-base": "^15.0.0", - "object.assign": "^4.1.2", - "object.entries": "^1.1.5" - }, - "engines": { - "node": "^10.12.0 || ^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^7.32.0 || ^8.2.0", - "eslint-plugin-import": "^2.25.3", - "eslint-plugin-jsx-a11y": "^6.5.1", - "eslint-plugin-react": "^7.28.0", - "eslint-plugin-react-hooks": "^4.3.0" - } - }, - "node_modules/eslint-config-airbnb-base": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", - "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", - "dev": true, - "dependencies": { - "confusing-browser-globals": "^1.0.10", - "object.assign": "^4.1.2", - "object.entries": "^1.1.5", - "semver": "^6.3.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "peerDependencies": { - "eslint": "^7.32.0 || ^8.2.0", - "eslint-plugin-import": "^2.25.2" - } - }, - "node_modules/eslint-config-prettier": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", - "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", - "dev": true, - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-config-react-app": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-7.0.1.tgz", - "integrity": "sha512-K6rNzvkIeHaTd8m/QEh1Zko0KI7BACWkkneSs6s9cKZC/J27X3eZR6Upt1jkmZ/4FK+XUOPPxMEN7+lbUXfSlA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.16.0", - "@babel/eslint-parser": "^7.16.3", - "@rushstack/eslint-patch": "^1.1.0", - "@typescript-eslint/eslint-plugin": "^5.5.0", - "@typescript-eslint/parser": "^5.5.0", - "babel-preset-react-app": "^10.0.1", - "confusing-browser-globals": "^1.0.11", - "eslint-plugin-flowtype": "^8.0.3", - "eslint-plugin-import": "^2.25.3", - "eslint-plugin-jest": "^25.3.0", - "eslint-plugin-jsx-a11y": "^6.5.1", - "eslint-plugin-react": "^7.27.1", - "eslint-plugin-react-hooks": "^4.3.0", - "eslint-plugin-testing-library": "^5.0.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "eslint": "^8.0.0" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "resolve": "^1.20.0" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-import-resolver-webpack": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.13.2.tgz", - "integrity": "sha512-XodIPyg1OgE2h5BDErz3WJoK7lawxKTJNhgPNafRST6csC/MZC+L5P6kKqsZGRInpbgc02s/WZMrb4uGJzcuRg==", - "dev": true, - "dependencies": { - "array-find": "^1.0.0", - "debug": "^3.2.7", - "enhanced-resolve": "^0.9.1", - "find-root": "^1.1.0", - "has": "^1.0.3", - "interpret": "^1.4.0", - "is-core-module": "^2.7.0", - "is-regex": "^1.1.4", - "lodash": "^4.17.21", - "resolve": "^1.20.0", - "semver": "^5.7.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "eslint-plugin-import": ">=1.4.0", - "webpack": ">=1.11.0" - } - }, - "node_modules/eslint-import-resolver-webpack/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-import-resolver-webpack/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/eslint-module-utils": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.2.tgz", - "integrity": "sha512-zquepFnWCY2ISMFwD/DqzaM++H+7PDzOpUvotJWm/y1BAFt5R4oeULgdrTejKqLkz7MA/tgstsUMNYc7wNdTrg==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "find-up": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-module-utils/node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "dependencies": { - "locate-path": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-module-utils/node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-module-utils/node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "dependencies": { - "p-try": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-module-utils/node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "dependencies": { - "p-limit": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-module-utils/node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-module-utils/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-plugin-flowtype": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-8.0.3.tgz", - "integrity": "sha512-dX8l6qUL6O+fYPtpNRideCFSpmWOUVx5QcaGLVqe/vlDiBSe4vYljDWDETwnyFzpl7By/WVIu6rcrniCgH9BqQ==", - "dev": true, - "dependencies": { - "lodash": "^4.17.21", - "string-natural-compare": "^3.0.1" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "@babel/plugin-syntax-flow": "^7.14.5", - "@babel/plugin-transform-react-jsx": "^7.14.9", - "eslint": "^8.1.0" - } - }, - "node_modules/eslint-plugin-i18next": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-i18next/-/eslint-plugin-i18next-5.2.1.tgz", - "integrity": "sha512-yXlWOMiyWz9aCGVrLeFijt+LsCXZj9QoddYXmxUeFZrqst4Z2j6vAMBn2iSE2JTNbPDyrdGl3H03UCo+CbdKbQ==", - "dev": true, - "dependencies": { - "requireindex": "~1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.25.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz", - "integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.2", - "has": "^1.0.3", - "is-core-module": "^2.8.0", - "is-glob": "^4.0.3", - "minimatch": "^3.0.4", - "object.values": "^1.1.5", - "resolve": "^1.20.0", - "tsconfig-paths": "^3.12.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/eslint-plugin-jest": { - "version": "25.7.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-25.7.0.tgz", - "integrity": "sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/experimental-utils": "^5.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - }, - "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^4.0.0 || ^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "@typescript-eslint/eslint-plugin": { - "optional": true - }, - "jest": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-jsx-a11y": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.5.1.tgz", - "integrity": "sha512-sVCFKX9fllURnXT2JwLN5Qgo24Ug5NF6dxhkmxsMEUZhXRcGg+X3e1JbJ84YePQKBl5E0ZjAH5Q4rkdcGY99+g==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.16.3", - "aria-query": "^4.2.2", - "array-includes": "^3.1.4", - "ast-types-flow": "^0.0.7", - "axe-core": "^4.3.5", - "axobject-query": "^2.2.0", - "damerau-levenshtein": "^1.0.7", - "emoji-regex": "^9.2.2", - "has": "^1.0.3", - "jsx-ast-utils": "^3.2.1", - "language-tags": "^1.0.5", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=4.0" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" - } - }, - "node_modules/eslint-plugin-jsx-a11y/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "node_modules/eslint-plugin-react": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.28.0.tgz", - "integrity": "sha512-IOlFIRHzWfEQQKcAD4iyYDndHwTQiCMcJVJjxempf203jnNLUnW34AXLrV33+nEXoifJE2ZEGmcjKPL8957eSw==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.4", - "array.prototype.flatmap": "^1.2.5", - "doctrine": "^2.1.0", - "estraverse": "^5.3.0", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.0.4", - "object.entries": "^1.1.5", - "object.fromentries": "^2.0.5", - "object.hasown": "^1.1.0", - "object.values": "^1.1.5", - "prop-types": "^15.7.2", - "resolve": "^2.0.0-next.3", - "semver": "^6.3.0", - "string.prototype.matchall": "^4.0.6" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" - } - }, - "node_modules/eslint-plugin-react-hooks": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.3.0.tgz", - "integrity": "sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" - } - }, - "node_modules/eslint-plugin-react/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-react/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.3", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", - "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==", - "dev": true, - "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - } - }, - "node_modules/eslint-plugin-testing-library": { - "version": "5.9.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.9.1.tgz", - "integrity": "sha512-6BQp3tmb79jLLasPHJmy8DnxREe+2Pgf7L+7o09TSWPfdqqtQfRZmZNetr5mOs3yqZk/MRNxpN3RUpJe0wB4LQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/utils": "^5.13.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0", - "npm": ">=6" - }, - "peerDependencies": { - "eslint": "^7.5.0 || ^8.0.0" - } - }, - "node_modules/eslint-rule-composer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", - "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/eslint/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.0.tgz", - "integrity": "sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.2.0.tgz", - "integrity": "sha512-IOzT0X126zn7ALX0dwFiUQEdsfzrm4+ISsQS8nukaJXwEyYKRSnEIIDULYg1mCtGp7UUXgfGl7BIolXREQK+XQ==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/eslint/node_modules/globals": { - "version": "13.8.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.8.0.tgz", - "integrity": "sha512-rHtdA6+PDBIjeEvA91rpqzEvk/k3/i7EeNQiryiWuJH0Hw9cpyJMAt2jtbAwUaRdhD+573X4vWw6IcjKPasi9Q==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/espree": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.0.tgz", - "integrity": "sha512-d/5nCsb0JcqsSEeQzFZ8DH1RmxPcglRWh24EFTlUEmCKoehXGdpsx0RkHDubqUI8LSAIKMQp4r9SzQ3n+sm4HQ==", - "dev": true, - "dependencies": { - "acorn": "^8.7.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^3.1.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/espree/node_modules/acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.2.0.tgz", - "integrity": "sha512-IOzT0X126zn7ALX0dwFiUQEdsfzrm4+ISsQS8nukaJXwEyYKRSnEIIDULYg1mCtGp7UUXgfGl7BIolXREQK+XQ==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", - "dev": true - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expect": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.4.6.tgz", - "integrity": "sha512-1M/0kAALIaj5LaG66sFJTbRsWTADnylly82cu4bspI0nl+pgP4E6Bh/aqdHlTUjul06K7xQnnrAoqfxVU0+/ag==", - "dev": true, - "dependencies": { - "@jest/types": "^27.4.2", - "jest-get-type": "^27.4.0", - "jest-matcher-utils": "^27.4.6", - "jest-message-util": "^27.4.6" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/expect/node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/expect/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/expect/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/expect/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/expect/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/expect/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/expect/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/expect/node_modules/jest-get-type": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", - "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", - "dev": true, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/expect/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", - "dev": true, - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.1", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/express/node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", - "dev": true - }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express/node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/express/node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", - "dev": true - }, - "node_modules/express/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/express/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", - "dev": true, - "dependencies": { - "websocket-driver": ">=0.5.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", - "dev": true, - "dependencies": { - "bser": "2.1.1" - } - }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/file-loader": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", - "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", - "dev": true, - "dependencies": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" - } - }, - "node_modules/file-selector": { - "version": "0.1.19", - "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.1.19.tgz", - "integrity": "sha512-kCWw3+Aai8Uox+5tHCNgMFaUdgidxvMnLWO6fM5sZ0hA2wlHP5/DHGF0ECe84BiB95qdJbKNEJhWKVDvMN+JDQ==", - "dependencies": { - "tslib": "^2.0.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/file-selector/node_modules/tslib": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz", - "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==" - }, - "node_modules/filelist": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", - "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", - "dev": true, - "dependencies": { - "minimatch": "^5.0.1" - } - }, - "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", - "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/filesize": { - "version": "8.0.7", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", - "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "dev": true, - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/finalhandler/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", - "dev": true, - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" - } - }, - "node_modules/find-cache-dir/node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-root": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", - "dev": true - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-yarn-workspace-root": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz", - "integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==", - "dev": true, - "dependencies": { - "micromatch": "^4.0.2" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", - "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", - "dev": true - }, - "node_modules/focus-trap": { - "version": "6.9.2", - "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-6.9.2.tgz", - "integrity": "sha512-gBEuXOPNOKPrLdZpMFUSTyIo1eT2NSZRrwZ9r/0Jqw5tmT3Yvxfmu8KBHw8xW2XQkw6E/JoG+OlEq7UDtSUNgw==", - "dependencies": { - "tabbable": "^5.3.2" - } - }, - "node_modules/follow-redirects": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", - "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/fork-ts-checker-webpack-plugin": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.2.tgz", - "integrity": "sha512-m5cUmF30xkZ7h4tWUgTAcEaKmUW7tfyUyTqNNOz7OxWJ0v1VWKTcOvH8FWHUwSjlW/356Ijc9vi3XfcPstpQKA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.8.3", - "@types/json-schema": "^7.0.5", - "chalk": "^4.1.0", - "chokidar": "^3.4.2", - "cosmiconfig": "^6.0.0", - "deepmerge": "^4.2.2", - "fs-extra": "^9.0.0", - "glob": "^7.1.6", - "memfs": "^3.1.2", - "minimatch": "^3.0.4", - "schema-utils": "2.7.0", - "semver": "^7.3.2", - "tapable": "^1.0.0" - }, - "engines": { - "node": ">=10", - "yarn": ">=1.0.0" - }, - "peerDependencies": { - "eslint": ">= 6", - "typescript": ">= 2.7", - "vue-template-compiler": "*", - "webpack": ">= 4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - }, - "vue-template-compiler": { - "optional": true - } - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/cosmiconfig": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", - "dev": true, - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.7.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", - "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.4", - "ajv": "^6.12.2", - "ajv-keywords": "^3.4.1" - }, - "engines": { - "node": ">= 8.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/tapable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", - "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/formik": { - "version": "2.2.9", - "resolved": "https://registry.npmjs.org/formik/-/formik-2.2.9.tgz", - "integrity": "sha512-LQLcISMmf1r5at4/gyJigGn0gOwFbeEAlji+N9InZF6LIMXnFNkO42sCI8Jt84YZggpD4cPWObAZaxpEFtSzNA==", - "funding": [ - { - "type": "individual", - "url": "https://opencollective.com/formik" - } - ], - "dependencies": { - "deepmerge": "^2.1.1", - "hoist-non-react-statics": "^3.3.0", - "lodash": "^4.17.21", - "lodash-es": "^4.17.21", - "react-fast-compare": "^2.0.1", - "tiny-warning": "^1.0.2", - "tslib": "^1.10.0" - }, - "peerDependencies": { - "react": ">=16.8.0" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fraction.js": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.2.tgz", - "integrity": "sha512-o2RiJQ6DZaR/5+Si0qJUIy637QMRudSi9kU/FFzx9EZazrIdnBgpU+3sEWCxAVhH2RtxW2Oz+T4p2o8uOPVcgA==", - "dev": true, - "engines": { - "node": "*" - }, - "funding": { - "type": "patreon", - "url": "https://www.patreon.com/infusion" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/fs-monkey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", - "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==", - "dev": true - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/function.prototype.name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.4.tgz", - "integrity": "sha512-iqy1pIotY/RmhdFZygSSlW0wko2yxkSCKqsuv4pr8QESohpYyG/Z7B/XXvPRKTJS//960rgguE5mSRUsDdaJrQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "node_modules/functions-have-names": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.2.tgz", - "integrity": "sha512-bLgc3asbWdwPbx2mNk2S49kmJCuQeu0nfmaOgbs8WIyzzkw3r4htszdIi9Q9EMezDPTYuJx2wvjZ/EwgAthpnA==", - "dev": true - }, - "node_modules/fuzzaldrin": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fuzzaldrin/-/fuzzaldrin-2.1.0.tgz", - "integrity": "sha1-kCBMPi/appQbso0WZF1BgGOpDps=", - "dev": true - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "node_modules/get-own-enumerable-property-symbols": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", - "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", - "dev": true - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true - }, - "node_modules/global-modules": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", - "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", - "dev": true, - "dependencies": { - "global-prefix": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/global-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", - "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", - "dev": true, - "dependencies": { - "ini": "^1.3.5", - "kind-of": "^6.0.2", - "which": "^1.3.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/global-prefix/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", - "dev": true - }, - "node_modules/graphlib": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz", - "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==", - "dependencies": { - "lodash": "^4.17.15" - } - }, - "node_modules/gzip-size": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", - "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", - "dev": true, - "dependencies": { - "duplexer": "^0.1.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/handle-thing": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true - }, - "node_modules/harmony-reflect": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz", - "integrity": "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-ansi": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-5.0.1.tgz", - "integrity": "sha512-Fp2IsZDnnyoJkKg22ZyQFvD7QRCcMTsLAtloKXyXWJ1joGLtItRU9Bv/k1o0tELL2NF3ZZBcycSKryZUM+Yl3g==", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/has-ansi?sponsor=1" - } - }, - "node_modules/has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "dev": true - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "engines": { - "node": ">=4" - } - }, - "node_modules/has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } - }, - "node_modules/history": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", - "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", - "dependencies": { - "@babel/runtime": "^7.1.2", - "loose-envify": "^1.2.0", - "resolve-pathname": "^3.0.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0", - "value-equal": "^1.0.1" - } - }, - "node_modules/hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "dependencies": { - "react-is": "^16.7.0" - } - }, - "node_modules/hoopy": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", - "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==", - "dev": true, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - } - }, - "node_modules/hpack.js/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "node_modules/hpack.js/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/hpack.js/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/html-element-map": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/html-element-map/-/html-element-map-1.3.0.tgz", - "integrity": "sha512-AqCt/m9YaiMwaaAyOPdq4Ga0cM+jdDWWGueUMkdROZcTeClaGpN0AQeyGchZhTegQoABmc6+IqH7oCR/8vhQYg==", - "dev": true, - "dependencies": { - "array-filter": "^1.0.0", - "call-bind": "^1.0.2" - } - }, - "node_modules/html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", - "dev": true, - "dependencies": { - "whatwg-encoding": "^1.0.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/html-entities": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.2.tgz", - "integrity": "sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==" - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", - "dev": true, - "dependencies": { - "camel-case": "^4.1.2", - "clean-css": "^5.2.2", - "commander": "^8.3.0", - "he": "^1.2.0", - "param-case": "^3.0.4", - "relateurl": "^0.2.7", - "terser": "^5.10.0" - }, - "bin": { - "html-minifier-terser": "cli.js" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/html-minifier-terser/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "dev": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/html-webpack-plugin": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz", - "integrity": "sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw==", - "dev": true, - "dependencies": { - "@types/html-minifier-terser": "^6.0.0", - "html-minifier-terser": "^6.0.2", - "lodash": "^4.17.21", - "pretty-error": "^4.0.0", - "tapable": "^2.0.0" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/html-webpack-plugin" - }, - "peerDependencies": { - "webpack": "^5.20.0" - } - }, - "node_modules/html-webpack-plugin/node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "dev": true, - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, - "node_modules/http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", - "dev": true - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dev": true, - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-errors/node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-errors/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-parser-js": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.5.tgz", - "integrity": "sha512-x+JVEkO2PoM8qqpbPbOL3cqHPwerep7OwzK7Ay+sMQjKzaKCqWvjoXm5tqMP9tXWWTnTzAjIhXg+J99XYuPhPA==", - "dev": true - }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dev": true, - "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dev": true, - "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/http-proxy-middleware": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-1.3.1.tgz", - "integrity": "sha512-13eVVDYS4z79w7f1+NPllJtOQFx/FdUW4btIvVRMaRlUY9VGstAbo5MOhLEuUgZFRHn3x50ufn25zkj/boZnEg==", - "dev": true, - "dependencies": { - "@types/http-proxy": "^1.17.5", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dev": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/icss-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/idb": { - "version": "6.1.5", - "resolved": "https://registry.npmjs.org/idb/-/idb-6.1.5.tgz", - "integrity": "sha512-IJtugpKkiVXQn5Y+LteyBCNk1N8xpGV3wWZk9EVtZWH8DYkjBn0bX1XnGP9RkyZF0sAcywa6unHqSWKe7q4LGw==", - "dev": true - }, - "node_modules/identity-obj-proxy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", - "integrity": "sha1-lNK9qWCERT7zb7xarsN+D3nx/BQ=", - "dev": true, - "dependencies": { - "harmony-reflect": "^1.4.6" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true - }, - "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/immer": { - "version": "9.0.16", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.16.tgz", - "integrity": "sha512-qenGE7CstVm1NrHQbMh8YaSzTZTFNP3zPqr3YU0S0UY441j4bJTg4A2Hh5KAhwgaiU6ZZ1Ar6y/2f4TblnMReQ==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-local/node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "node_modules/inquirer": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", - "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.19", - "mute-stream": "0.0.8", - "run-async": "^2.4.0", - "rxjs": "^6.6.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/inquirer/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/inquirer/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/inquirer/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/inquirer/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/inquirer/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/inquirer/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/internmap": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", - "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", - "engines": { - "node": ">=12" - } - }, - "node_modules/interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", - "dev": true - }, - "node_modules/ipaddr.js": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", - "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/is-alphabetical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", - "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", - "dev": true - }, - "node_modules/is-alphanumerical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", - "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", - "dev": true, - "dependencies": { - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0" - } - }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "node_modules/is-bigint": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz", - "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==", - "dev": true - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz", - "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.4.tgz", - "integrity": "sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-decimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", - "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", - "dev": true - }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", - "dev": true - }, - "node_modules/is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz", - "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-root": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", - "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-subset": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-subset/-/is-subset-0.1.1.tgz", - "integrity": "sha1-ilkRfZMt4d4A8kX83TnOQ/HpOaY=", - "dev": true - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/is-weakref": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz", - "integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", - "dev": true, - "dependencies": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.3.tgz", - "integrity": "sha512-x9LtDVtfm/t1GFiLl3NffC7hz+I1ragvgX1P/Lg1NlIagifZDKUkuuaAxH/qpwj2IuEfD8G2Bs/UKp+sZ/pKkg==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jake": { - "version": "10.8.5", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", - "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==", - "dev": true, - "dependencies": { - "async": "^3.2.3", - "chalk": "^4.0.2", - "filelist": "^1.0.1", - "minimatch": "^3.0.4" - }, - "bin": { - "jake": "bin/cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jake/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jake/node_modules/async": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", - "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", - "dev": true - }, - "node_modules/jake/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jake/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jake/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jake/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jake/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest": { - "version": "27.4.7", - "resolved": "https://registry.npmjs.org/jest/-/jest-27.4.7.tgz", - "integrity": "sha512-8heYvsx7nV/m8m24Vk26Y87g73Ba6ueUd0MWed/NXMhSZIm62U/llVbS0PJe1SHunbyXjJ/BqG1z9bFjGUIvTg==", - "dev": true, - "dependencies": { - "@jest/core": "^27.4.7", - "import-local": "^3.0.2", - "jest-cli": "^27.4.7" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-changed-files": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.4.2.tgz", - "integrity": "sha512-/9x8MjekuzUQoPjDHbBiXbNEBauhrPU2ct7m8TfCg69ywt1y/N+yYwGh3gCpnqUS3klYWDU/lSNgv+JhoD2k1A==", - "dev": true, - "dependencies": { - "@jest/types": "^27.4.2", - "execa": "^5.0.0", - "throat": "^6.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-changed-files/node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-changed-files/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-changed-files/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-changed-files/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-changed-files/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-changed-files/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-changed-files/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-changed-files/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-circus": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.4.6.tgz", - "integrity": "sha512-UA7AI5HZrW4wRM72Ro80uRR2Fg+7nR0GESbSI/2M+ambbzVuA63mn5T1p3Z/wlhntzGpIG1xx78GP2YIkf6PhQ==", - "dev": true, - "dependencies": { - "@jest/environment": "^27.4.6", - "@jest/test-result": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "expect": "^27.4.6", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.4.6", - "jest-matcher-utils": "^27.4.6", - "jest-message-util": "^27.4.6", - "jest-runtime": "^27.4.6", - "jest-snapshot": "^27.4.6", - "jest-util": "^27.4.2", - "pretty-format": "^27.4.6", - "slash": "^3.0.0", - "stack-utils": "^2.0.3", - "throat": "^6.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-circus/node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-circus/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-circus/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-circus/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-circus/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-circus/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-circus/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-circus/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-circus/node_modules/pretty-format": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz", - "integrity": "sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-circus/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-circus/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/jest-circus/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-cli": { - "version": "27.4.7", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.4.7.tgz", - "integrity": "sha512-zREYhvjjqe1KsGV15mdnxjThKNDgza1fhDT+iUsXWLCq3sxe9w5xnvyctcYVT5PcdLSjv7Y5dCwTS3FCF1tiuw==", - "dev": true, - "dependencies": { - "@jest/core": "^27.4.7", - "@jest/test-result": "^27.4.6", - "@jest/types": "^27.4.2", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "import-local": "^3.0.2", - "jest-config": "^27.4.7", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.6", - "prompts": "^2.0.1", - "yargs": "^16.2.0" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-cli/node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-cli/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-cli/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-cli/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-cli/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-cli/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-cli/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-cli/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-cli/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-cli/node_modules/jest-get-type": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", - "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", - "dev": true, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-cli/node_modules/jest-validate": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.4.6.tgz", - "integrity": "sha512-872mEmCPVlBqbA5dToC57vA3yJaMRfIdpCoD3cyHWJOMx+SJwLNw0I71EkWs41oza/Er9Zno9XuTkRYCPDUJXQ==", - "dev": true, - "dependencies": { - "@jest/types": "^27.4.2", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", - "leven": "^3.1.0", - "pretty-format": "^27.4.6" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-cli/node_modules/pretty-format": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz", - "integrity": "sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-cli/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-cli/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/jest-cli/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-config": { - "version": "27.4.7", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.4.7.tgz", - "integrity": "sha512-xz/o/KJJEedHMrIY9v2ParIoYSrSVY6IVeE4z5Z3i101GoA5XgfbJz+1C8EYPsv7u7f39dS8F9v46BHDhn0vlw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.8.0", - "@jest/test-sequencer": "^27.4.6", - "@jest/types": "^27.4.2", - "babel-jest": "^27.4.6", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.4", - "jest-circus": "^27.4.6", - "jest-environment-jsdom": "^27.4.6", - "jest-environment-node": "^27.4.6", - "jest-get-type": "^27.4.0", - "jest-jasmine2": "^27.4.6", - "jest-regex-util": "^27.4.0", - "jest-resolve": "^27.4.6", - "jest-runner": "^27.4.6", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.6", - "micromatch": "^4.0.4", - "pretty-format": "^27.4.6", - "slash": "^3.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-config/node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-config/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-config/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-config/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-config/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-config/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-config/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-config/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-config/node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jest-config/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-config/node_modules/jest-get-type": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", - "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", - "dev": true, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-config/node_modules/jest-validate": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.4.6.tgz", - "integrity": "sha512-872mEmCPVlBqbA5dToC57vA3yJaMRfIdpCoD3cyHWJOMx+SJwLNw0I71EkWs41oza/Er9Zno9XuTkRYCPDUJXQ==", - "dev": true, - "dependencies": { - "@jest/types": "^27.4.2", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", - "leven": "^3.1.0", - "pretty-format": "^27.4.6" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-config/node_modules/pretty-format": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz", - "integrity": "sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-config/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-config/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/jest-config/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-diff": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.4.6.tgz", - "integrity": "sha512-zjaB0sh0Lb13VyPsd92V7HkqF6yKRH9vm33rwBt7rPYrpQvS1nCvlIy2pICbKta+ZjWngYLNn4cCK4nyZkjS/w==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^27.4.0", - "jest-get-type": "^27.4.0", - "pretty-format": "^27.4.6" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-diff/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-diff/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-diff/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-diff/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-diff/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-diff/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-diff/node_modules/jest-get-type": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", - "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", - "dev": true, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-diff/node_modules/pretty-format": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz", - "integrity": "sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-diff/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-diff/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/jest-diff/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-docblock": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.4.0.tgz", - "integrity": "sha512-7TBazUdCKGV7svZ+gh7C8esAnweJoG+SvcF6Cjqj4l17zA2q1cMwx2JObSioubk317H+cjcHgP+7fTs60paulg==", - "dev": true, - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-each": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.4.6.tgz", - "integrity": "sha512-n6QDq8y2Hsmn22tRkgAk+z6MCX7MeVlAzxmZDshfS2jLcaBlyhpF3tZSJLR+kXmh23GEvS0ojMR8i6ZeRvpQcA==", - "dev": true, - "dependencies": { - "@jest/types": "^27.4.2", - "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", - "jest-util": "^27.4.2", - "pretty-format": "^27.4.6" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-each/node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-each/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-each/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-each/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-each/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-each/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-each/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-each/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-each/node_modules/jest-get-type": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", - "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", - "dev": true, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-each/node_modules/pretty-format": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz", - "integrity": "sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-each/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-each/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/jest-each/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-environment-jsdom": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.4.6.tgz", - "integrity": "sha512-o3dx5p/kHPbUlRvSNjypEcEtgs6LmvESMzgRFQE6c+Prwl2JLA4RZ7qAnxc5VM8kutsGRTB15jXeeSbJsKN9iA==", - "dev": true, - "dependencies": { - "@jest/environment": "^27.4.6", - "@jest/fake-timers": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/node": "*", - "jest-mock": "^27.4.6", - "jest-util": "^27.4.2", - "jsdom": "^16.6.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-environment-jsdom/node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-environment-jsdom/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-environment-jsdom/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-environment-jsdom/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-environment-jsdom/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-environment-jsdom/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-environment-jsdom/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-environment-jsdom/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-environment-node": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.4.6.tgz", - "integrity": "sha512-yfHlZ9m+kzTKZV0hVfhVu6GuDxKAYeFHrfulmy7Jxwsq4V7+ZK7f+c0XP/tbVDMQW7E4neG2u147hFkuVz0MlQ==", - "dev": true, - "dependencies": { - "@jest/environment": "^27.4.6", - "@jest/fake-timers": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/node": "*", - "jest-mock": "^27.4.6", - "jest-util": "^27.4.2" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-environment-node/node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-environment-node/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-environment-node/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-environment-node/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-environment-node/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-environment-node/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-environment-node/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-environment-node/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", - "dev": true, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-haste-map": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.4.6.tgz", - "integrity": "sha512-0tNpgxg7BKurZeFkIOvGCkbmOHbLFf4LUQOxrQSMjvrQaQe3l6E8x6jYC1NuWkGo5WDdbr8FEzUxV2+LWNawKQ==", - "dev": true, - "dependencies": { - "@jest/types": "^27.4.2", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-regex-util": "^27.4.0", - "jest-serializer": "^27.4.0", - "jest-util": "^27.4.2", - "jest-worker": "^27.4.6", - "micromatch": "^4.0.4", - "walker": "^1.0.7" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-haste-map/node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-haste-map/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-haste-map/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-haste-map/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-haste-map/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-haste-map/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-haste-map/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-haste-map/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-jasmine2": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.4.6.tgz", - "integrity": "sha512-uAGNXF644I/whzhsf7/qf74gqy9OuhvJ0XYp8SDecX2ooGeaPnmJMjXjKt0mqh1Rl5dtRGxJgNrHlBQIBfS5Nw==", - "dev": true, - "dependencies": { - "@jest/environment": "^27.4.6", - "@jest/source-map": "^27.4.0", - "@jest/test-result": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^27.4.6", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.4.6", - "jest-matcher-utils": "^27.4.6", - "jest-message-util": "^27.4.6", - "jest-runtime": "^27.4.6", - "jest-snapshot": "^27.4.6", - "jest-util": "^27.4.2", - "pretty-format": "^27.4.6", - "throat": "^6.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-jasmine2/node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-jasmine2/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-jasmine2/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-jasmine2/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-jasmine2/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-jasmine2/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-jasmine2/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-jasmine2/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-jasmine2/node_modules/pretty-format": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz", - "integrity": "sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-jasmine2/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-jasmine2/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/jest-jasmine2/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-leak-detector": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.4.6.tgz", - "integrity": "sha512-kkaGixDf9R7CjHm2pOzfTxZTQQQ2gHTIWKY/JZSiYTc90bZp8kSZnUMS3uLAfwTZwc0tcMRoEX74e14LG1WapA==", - "dev": true, - "dependencies": { - "jest-get-type": "^27.4.0", - "pretty-format": "^27.4.6" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-leak-detector/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-leak-detector/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-leak-detector/node_modules/jest-get-type": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", - "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", - "dev": true, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-leak-detector/node_modules/pretty-format": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz", - "integrity": "sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-leak-detector/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/jest-matcher-utils": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.4.6.tgz", - "integrity": "sha512-XD4PKT3Wn1LQnRAq7ZsTI0VRuEc9OrCPFiO1XL7bftTGmfNF0DcEwMHRgqiu7NGf8ZoZDREpGrCniDkjt79WbA==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^27.4.6", - "jest-get-type": "^27.4.0", - "pretty-format": "^27.4.6" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-matcher-utils/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-matcher-utils/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-matcher-utils/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-matcher-utils/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-matcher-utils/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-matcher-utils/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-matcher-utils/node_modules/jest-get-type": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", - "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", - "dev": true, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-matcher-utils/node_modules/pretty-format": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz", - "integrity": "sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-matcher-utils/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-matcher-utils/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/jest-matcher-utils/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-message-util": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.4.6.tgz", - "integrity": "sha512-0p5szriFU0U74czRSFjH6RyS7UYIAkn/ntwMuOwTGWrQIOh5NzXXrq72LOqIkJKKvFbPq+byZKuBz78fjBERBA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.4.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.4", - "pretty-format": "^27.4.6", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-message-util/node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-message-util/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-message-util/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-message-util/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-message-util/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-message-util/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-message-util/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-message-util/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-message-util/node_modules/pretty-format": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz", - "integrity": "sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-message-util/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-message-util/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/jest-message-util/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-mock": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.4.6.tgz", - "integrity": "sha512-kvojdYRkst8iVSZ1EJ+vc1RRD9llueBjKzXzeCytH3dMM7zvPV/ULcfI2nr0v0VUgm3Bjt3hBCQvOeaBz+ZTHw==", - "dev": true, - "dependencies": { - "@jest/types": "^27.4.2", - "@types/node": "*" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-mock/node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-mock/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-mock/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-mock/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-mock/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-mock/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-mock/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-mock/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-regex-util": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.4.0.tgz", - "integrity": "sha512-WeCpMpNnqJYMQoOjm1nTtsgbR4XHAk1u00qDoNBQoykM280+/TmgA5Qh5giC1ecy6a5d4hbSsHzpBtu5yvlbEg==", - "dev": true, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-resolve": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.4.6.tgz", - "integrity": "sha512-SFfITVApqtirbITKFAO7jOVN45UgFzcRdQanOFzjnbd+CACDoyeX7206JyU92l4cRr73+Qy/TlW51+4vHGt+zw==", - "dev": true, - "dependencies": { - "@jest/types": "^27.4.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.6", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.6", - "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.4.6.tgz", - "integrity": "sha512-W85uJZcFXEVZ7+MZqIPCscdjuctruNGXUZ3OHSXOfXR9ITgbUKeHj+uGcies+0SsvI5GtUfTw4dY7u9qjTvQOw==", - "dev": true, - "dependencies": { - "@jest/types": "^27.4.2", - "jest-regex-util": "^27.4.0", - "jest-snapshot": "^27.4.6" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-resolve-dependencies/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-resolve/node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-resolve/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-resolve/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-resolve/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-resolve/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-resolve/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-resolve/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-resolve/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-resolve/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-resolve/node_modules/jest-get-type": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", - "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", - "dev": true, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-resolve/node_modules/jest-validate": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.4.6.tgz", - "integrity": "sha512-872mEmCPVlBqbA5dToC57vA3yJaMRfIdpCoD3cyHWJOMx+SJwLNw0I71EkWs41oza/Er9Zno9XuTkRYCPDUJXQ==", - "dev": true, - "dependencies": { - "@jest/types": "^27.4.2", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", - "leven": "^3.1.0", - "pretty-format": "^27.4.6" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-resolve/node_modules/pretty-format": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz", - "integrity": "sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-resolve/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-resolve/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/jest-resolve/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runner": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.4.6.tgz", - "integrity": "sha512-IDeFt2SG4DzqalYBZRgbbPmpwV3X0DcntjezPBERvnhwKGWTW7C5pbbA5lVkmvgteeNfdd/23gwqv3aiilpYPg==", - "dev": true, - "dependencies": { - "@jest/console": "^27.4.6", - "@jest/environment": "^27.4.6", - "@jest/test-result": "^27.4.6", - "@jest/transform": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.8.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-docblock": "^27.4.0", - "jest-environment-jsdom": "^27.4.6", - "jest-environment-node": "^27.4.6", - "jest-haste-map": "^27.4.6", - "jest-leak-detector": "^27.4.6", - "jest-message-util": "^27.4.6", - "jest-resolve": "^27.4.6", - "jest-runtime": "^27.4.6", - "jest-util": "^27.4.2", - "jest-worker": "^27.4.6", - "source-map-support": "^0.5.6", - "throat": "^6.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-runner/node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-runner/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-runner/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-runner/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-runner/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-runner/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-runner/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runner/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runtime": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.4.6.tgz", - "integrity": "sha512-eXYeoR/MbIpVDrjqy5d6cGCFOYBFFDeKaNWqTp0h6E74dK0zLHzASQXJpl5a2/40euBmKnprNLJ0Kh0LCndnWQ==", - "dev": true, - "dependencies": { - "@jest/environment": "^27.4.6", - "@jest/fake-timers": "^27.4.6", - "@jest/globals": "^27.4.6", - "@jest/source-map": "^27.4.0", - "@jest/test-result": "^27.4.6", - "@jest/transform": "^27.4.6", - "@jest/types": "^27.4.2", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "execa": "^5.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.6", - "jest-message-util": "^27.4.6", - "jest-mock": "^27.4.6", - "jest-regex-util": "^27.4.0", - "jest-resolve": "^27.4.6", - "jest-snapshot": "^27.4.6", - "jest-util": "^27.4.2", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-runtime/node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-runtime/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-runtime/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-runtime/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-runtime/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-runtime/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-runtime/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runtime/node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runtime/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-serializer": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.4.0.tgz", - "integrity": "sha512-RDhpcn5f1JYTX2pvJAGDcnsNTnsV9bjYPU8xcV+xPwOXnUPOQwf4ZEuiU6G9H1UztH+OapMgu/ckEVwO87PwnQ==", - "dev": true, - "dependencies": { - "@types/node": "*", - "graceful-fs": "^4.2.4" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-snapshot": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.4.6.tgz", - "integrity": "sha512-fafUCDLQfzuNP9IRcEqaFAMzEe7u5BF7mude51wyWv7VRex60WznZIC7DfKTgSIlJa8aFzYmXclmN328aqSDmQ==", - "dev": true, - "dependencies": { - "@babel/core": "^7.7.2", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.0.0", - "@jest/transform": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^27.4.6", - "graceful-fs": "^4.2.4", - "jest-diff": "^27.4.6", - "jest-get-type": "^27.4.0", - "jest-haste-map": "^27.4.6", - "jest-matcher-utils": "^27.4.6", - "jest-message-util": "^27.4.6", - "jest-util": "^27.4.2", - "natural-compare": "^1.4.0", - "pretty-format": "^27.4.6", - "semver": "^7.3.2" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-snapshot/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-snapshot/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-snapshot/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-snapshot/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-snapshot/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-snapshot/node_modules/jest-get-type": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", - "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", - "dev": true, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/pretty-format": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz", - "integrity": "sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-snapshot/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-snapshot/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-util": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.4.2.tgz", - "integrity": "sha512-YuxxpXU6nlMan9qyLuxHaMMOzXAl5aGZWCSzben5DhLHemYQxCc4YK+4L3ZrCutT8GPQ+ui9k5D8rUJoDioMnA==", - "dev": true, - "dependencies": { - "@jest/types": "^27.4.2", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.4", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-util/node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-util/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-util/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-util/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-util/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-util/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-util/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-util/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-validate": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-26.6.2.tgz", - "integrity": "sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "camelcase": "^6.0.0", - "chalk": "^4.0.0", - "jest-get-type": "^26.3.0", - "leven": "^3.1.0", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-validate/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-validate/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-validate/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-validate/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-validate/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-validate/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-watch-typeahead": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/jest-watch-typeahead/-/jest-watch-typeahead-1.0.0.tgz", - "integrity": "sha512-jxoszalAb394WElmiJTFBMzie/RDCF+W7Q29n5LzOPtcoQoHWfdUtHFkbhgf5NwWe8uMOxvKb/g7ea7CshfkTw==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.3.1", - "chalk": "^4.0.0", - "jest-regex-util": "^27.0.0", - "jest-watcher": "^27.0.0", - "slash": "^4.0.0", - "string-length": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "jest": "^27.0.0" - } - }, - "node_modules/jest-watch-typeahead/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-watch-typeahead/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-watch-typeahead/node_modules/char-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-2.0.0.tgz", - "integrity": "sha512-oGu2QekBMXgyQNWPDRQ001bjvDnZe4/zBTz37TMbiKz1NbNiyiH5hRkobe7npRN6GfbGbxMYFck/vQ1r9c1VMA==", - "dev": true, - "engines": { - "node": ">=12.20" - } - }, - "node_modules/jest-watch-typeahead/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-watch-typeahead/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-watch-typeahead/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-watch-typeahead/node_modules/slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-watch-typeahead/node_modules/string-length": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-5.0.1.tgz", - "integrity": "sha512-9Ep08KAMUn0OadnVaBuRdE2l615CQ508kr0XMadjClfYpdCyvrbFp6Taebo8yyxokQ4viUd/xPPUA4FGgUa0ow==", - "dev": true, - "dependencies": { - "char-regex": "^2.0.0", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-watch-typeahead/node_modules/strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/jest-watch-typeahead/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-watcher": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.4.6.tgz", - "integrity": "sha512-yKQ20OMBiCDigbD0quhQKLkBO+ObGN79MO4nT7YaCuQ5SM+dkBNWE8cZX0FjU6czwMvWw6StWbe+Wv4jJPJ+fw==", - "dev": true, - "dependencies": { - "@jest/test-result": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "jest-util": "^27.4.2", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-watcher/node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-watcher/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-watcher/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-watcher/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-watcher/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-watcher/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-watcher/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-watcher/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-websocket-mock": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/jest-websocket-mock/-/jest-websocket-mock-2.2.0.tgz", - "integrity": "sha512-lc3wwXOEyNa4ZpcgJtUG3mmKMAq5FAsKYiZph0p/+PAJrAPuX4JCIfJMdJ/urRsLBG51fwm/wlVPNbR6s2nzNw==", - "dev": true - }, - "node_modules/jest-worker": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.6.tgz", - "integrity": "sha512-gHWJF/6Xi5CTG5QCvROr6GcmpIqNYpDJyc8A1h/DyXqH1tD6SnRCM0d3U5msV31D2LB/U+E0M+W4oyvKV44oNw==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/jest-worker/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsdom": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", - "dev": true, - "dependencies": { - "abab": "^2.0.5", - "acorn": "^8.2.4", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.3.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.1", - "domexception": "^2.0.1", - "escodegen": "^2.0.0", - "form-data": "^3.0.0", - "html-encoding-sniffer": "^2.0.1", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.5.0", - "ws": "^7.4.6", - "xml-name-validator": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "canvas": "^2.5.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/jsdom/node_modules/acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "node_modules/jsonpointer": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.0.tgz", - "integrity": "sha512-PNYZIdMjVIvVgDSYKTT63Y+KZ6IZvGRNNWcxwD+GNnUz1MKPfv30J8ueCjdwcN0nDx2SlshgyB7Oy0epAzVRRg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jsx-ast-utils": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz", - "integrity": "sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.3", - "object.assign": "^4.1.2" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/klona": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", - "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/language-subtag-registry": { - "version": "0.3.21", - "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz", - "integrity": "sha512-L0IqwlIXjilBVVYKFT37X9Ih11Um5NEl9cbJIuU/SwP/zEEAbBPOnEeeuxVMf45ydWQRDQN3Nqc96OgbH1K+Pg==", - "dev": true - }, - "node_modules/language-tags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", - "integrity": "sha1-0yHbxNowuovzAk4ED6XBRmH5GTo=", - "dev": true, - "dependencies": { - "language-subtag-registry": "~0.3.2" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lilconfig": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz", - "integrity": "sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", - "dev": true - }, - "node_modules/loader-runner": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", - "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", - "dev": true, - "engines": { - "node": ">=6.11.5" - } - }, - "node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", - "dev": true - }, - "node_modules/lodash.escape": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-4.0.1.tgz", - "integrity": "sha1-yQRGkMIeBClL6qUXcS/e0fqI3pg=", - "dev": true - }, - "node_modules/lodash.flattendeep": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", - "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", - "dev": true - }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" - }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" - }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true - }, - "node_modules/lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", - "dev": true - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/log-symbols/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/log-symbols/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/log-symbols/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/log-symbols/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/log-symbols/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lower-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "dev": true, - "dependencies": { - "tslib": "^2.0.3" - } - }, - "node_modules/lower-case/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/luxon": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.2.1.tgz", - "integrity": "sha512-QrwPArQCNLAKGO/C+ZIilgIuDnEnKx5QYODdDtbFaxzsbZcc/a7WFq7MhsVYgRlwawLtvOUESTlfJ+hc/USqPg==", - "engines": { - "node": ">=12" - } - }, - "node_modules/lz-string": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", - "integrity": "sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=", - "dev": true, - "bin": { - "lz-string": "bin/bin.js" - } - }, - "node_modules/magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", - "dev": true, - "dependencies": { - "sourcemap-codec": "^1.4.4" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/make-plural": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/make-plural/-/make-plural-6.2.2.tgz", - "integrity": "sha512-8iTuFioatnTTmb/YJjywkVIHLjcwkFD9Ms0JpxjEm9Mo8eQYkh1z+55dwv4yc1jQ8ftVBxWQbihvZL1DfzGGWA==" - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "dependencies": { - "tmpl": "1.0.5" - } - }, - "node_modules/mdn-data": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", - "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", - "dev": true - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/memfs": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.1.tgz", - "integrity": "sha512-1c9VPVvW5P7I85c35zAdEr1TD5+F11IToIHIlrVIcflfnzPkJa0ZoYEoEdYDP8KgPFoSZ/opDrUsAoZWym3mtw==", - "dev": true, - "dependencies": { - "fs-monkey": "1.0.3" - }, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/memory-fs": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.2.0.tgz", - "integrity": "sha1-8rslNovBIeORwlIN6Slpyu4KApA=", - "dev": true - }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", - "dev": true - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/messageformat-parser": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/messageformat-parser/-/messageformat-parser-4.1.3.tgz", - "integrity": "sha512-2fU3XDCanRqeOCkn7R5zW5VQHWf+T3hH65SzuqRvjatBK7r4uyFa5mEX+k6F9Bd04LVM5G4/BHBTUJsOdW7uyg==" - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", - "dependencies": { - "mime-db": "1.51.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/mini-create-react-context": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz", - "integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==", - "dependencies": { - "@babel/runtime": "^7.12.1", - "tiny-warning": "^1.0.3" - }, - "peerDependencies": { - "prop-types": "^15.0.0", - "react": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" - } - }, - "node_modules/mini-css-extract-plugin": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.5.2.tgz", - "integrity": "sha512-Lwgq9qLNyBK6yNLgzssXnq4r2+mB9Mz3cJWlM8kseysHIvTicFhDNimFgY94jjqlwhNzLPsq8wv4X+vOHtMdYA==", - "dev": true, - "dependencies": { - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/mini-css-extract-plugin/node_modules/ajv": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.9.0.tgz", - "integrity": "sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/mini-css-extract-plugin/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/mini-css-extract-plugin/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mock-socket": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/mock-socket/-/mock-socket-9.1.3.tgz", - "integrity": "sha512-uz8lx8c5wuJYJ21f5UtovqpV0+KJuVwE7cVOLNhrl2QW/CvmstOLRfjXnLSbfFHZtJtiaSGQu0oCJA8SmRcK6A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/moo": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.1.tgz", - "integrity": "sha512-I1mnb5xn4fO80BH9BLcF0yLypy2UKl+Cb01Fu0hJRkJjlCRtxZMWkTdAtDd5ZqCOxtCkhmRwyI57vWT+1iZ67w==", - "dev": true - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/multicast-dns": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", - "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", - "dev": true, - "dependencies": { - "dns-packet": "^1.3.1", - "thunky": "^1.0.2" - }, - "bin": { - "multicast-dns": "cli.js" - } - }, - "node_modules/multicast-dns-service-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", - "dev": true - }, - "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", - "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, - "node_modules/nearley": { - "version": "2.20.1", - "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.20.1.tgz", - "integrity": "sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==", - "dev": true, - "dependencies": { - "commander": "^2.19.0", - "moo": "^0.5.0", - "railroad-diagrams": "^1.0.0", - "randexp": "0.4.6" - }, - "bin": { - "nearley-railroad": "bin/nearley-railroad.js", - "nearley-test": "bin/nearley-test.js", - "nearley-unparse": "bin/nearley-unparse.js", - "nearleyc": "bin/nearleyc.js" - } - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "node_modules/no-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", - "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", - "dev": true, - "dependencies": { - "lower-case": "^2.0.2", - "tslib": "^2.0.3" - } - }, - "node_modules/no-case/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - }, - "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", - "dev": true, - "engines": { - "node": ">= 6.13.0" - } - }, - "node_modules/node-gettext": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/node-gettext/-/node-gettext-3.0.0.tgz", - "integrity": "sha512-/VRYibXmVoN6tnSAY2JWhNRhWYJ8Cd844jrZU/DwLVoI4vBI6ceYbd8i42sYZ9uOgDH3S7vslIKOWV/ZrT2YBA==", - "dev": true, - "dependencies": { - "lodash.get": "^4.4.2" - } - }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "node_modules/nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", - "dev": true - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-hash": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", - "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/object-inspect": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.1.tgz", - "integrity": "sha512-If7BjFlpkzzBeV1cqgT3OSWT3azyoxDGajR+iGnFBfVV2EWyDyWaZZW2ERDjUaY2QM8i5jI3Sj7mhsM4DDAqWA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.entries": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", - "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", - "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.getownpropertydescriptors": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz", - "integrity": "sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/object.hasown": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.0.tgz", - "integrity": "sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.values": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", - "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dev": true, - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/open": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", - "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", - "dev": true, - "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/ora": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.0.tgz", - "integrity": "sha512-1StwyXQGoU6gdjYkyVcqOLnVlbKj+6yPNNOxJVgpt9t4eksKjiriiHuxktLYkgllwk+D6MbC4ihH84L1udRXPg==", - "dev": true, - "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ora/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ora/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ora/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/ora/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/ora/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ora/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-retry": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.1.tgz", - "integrity": "sha512-e2xXGNhZOZ0lfgR9kL34iGlU8N/KO0xZnQxVEwdeOvpqNDQfdnxIYizvWtK8RglUa3bGqI8g0R/BdfzLMxRkiA==", - "dev": true, - "dependencies": { - "@types/retry": "^0.12.0", - "retry": "^0.13.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/papaparse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.3.0.tgz", - "integrity": "sha512-Lb7jN/4bTpiuGPrYy4tkKoUS8sTki8zacB5ke1p5zolhcSE4TlWgrlsxjrDTbG/dFVh07ck7X36hUf/b5V68pg==", - "dev": true - }, - "node_modules/param-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", - "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", - "dev": true, - "dependencies": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/param-case/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, - "node_modules/parse5-htmlparser2-tree-adapter": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", - "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", - "dev": true, - "dependencies": { - "parse5": "^6.0.1" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/pascal-case": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", - "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", - "dev": true, - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/pascal-case/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "dependencies": { - "isarray": "0.0.1" - } - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz", - "integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==", - "dev": true, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/pirates": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.4.tgz", - "integrity": "sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-up": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", - "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", - "dev": true, - "dependencies": { - "find-up": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-up/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-up/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-up/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-up/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/plurals-cldr": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/plurals-cldr/-/plurals-cldr-1.0.4.tgz", - "integrity": "sha512-4nLXqtel7fsCgzi8dvRZvUjfL8SXpP982sKg7b2TgpnR8rDnes06iuQ83trQ/+XdtyMIQkBBbKzX6x97eLfsJQ==", - "dev": true - }, - "node_modules/pofile": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pofile/-/pofile-1.1.1.tgz", - "integrity": "sha512-RVAzFGo1Mx9+YukVKSgTLut6r4ZVBW8IVrqGHAPfEsVJN93WSp5HRD6+qNa7av1q/joPKDNJd55m5AJl9GBQGA==", - "dev": true - }, - "node_modules/popper.js": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", - "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==" - }, - "node_modules/portfinder": { - "version": "1.0.28", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", - "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", - "dev": true, - "dependencies": { - "async": "^2.6.2", - "debug": "^3.1.1", - "mkdirp": "^0.5.5" - }, - "engines": { - "node": ">= 0.12.0" - } - }, - "node_modules/portfinder/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/portfinder/node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/postcss": { - "version": "8.4.5", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", - "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", - "dev": true, - "dependencies": { - "nanoid": "^3.1.30", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-attribute-case-insensitive": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.0.tgz", - "integrity": "sha512-b4g9eagFGq9T5SWX4+USfVyjIb3liPnjhHHRMP7FMB2kFVpYyfEscV0wP3eaXhKlcHKUut8lt5BGoeylWA/dBQ==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.2" - }, - "peerDependencies": { - "postcss": "^8.0.2" - } - }, - "node_modules/postcss-browser-comments": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-browser-comments/-/postcss-browser-comments-4.0.0.tgz", - "integrity": "sha512-X9X9/WN3KIvY9+hNERUqX9gncsgBA25XaeR+jshHz2j8+sYyHktHw1JdKuMjeLpGktXidqDhA7b/qm1mrBDmgg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "peerDependencies": { - "browserslist": ">=4", - "postcss": ">=8" - } - }, - "node_modules/postcss-calc": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.2.tgz", - "integrity": "sha512-B5R0UeB4zLJvxNt1FVCaDZULdzsKLPc6FhjFJ+xwFiq7VG4i9cuaJLxVjNtExNK8ocm3n2o4unXXLiVX1SCqxA==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.0.2" - }, - "peerDependencies": { - "postcss": "^8.2.2" - } - }, - "node_modules/postcss-color-functional-notation": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.1.tgz", - "integrity": "sha512-62OBIXCjRXpQZcFOYIXwXBlpAVWrYk8ek1rcjvMING4Q2cf0ipyN9qT+BhHA6HmftGSEnFQu2qgKO3gMscl3Rw==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.3" - } - }, - "node_modules/postcss-color-hex-alpha": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-8.0.2.tgz", - "integrity": "sha512-gyx8RgqSmGVK156NAdKcsfkY3KPGHhKqvHTL3hhveFrBBToguKFzhyiuk3cljH6L4fJ0Kv+JENuPXs1Wij27Zw==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.3" - } - }, - "node_modules/postcss-color-rebeccapurple": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-7.0.2.tgz", - "integrity": "sha512-SFc3MaocHaQ6k3oZaFwH8io6MdypkUtEy/eXzXEB1vEQlO3S3oDc/FSZA8AsS04Z25RirQhlDlHLh3dn7XewWw==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.3" - } - }, - "node_modules/postcss-colormin": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.2.3.tgz", - "integrity": "sha512-dra4xoAjub2wha6RUXAgadHEn2lGxbj8drhFcIGLOMn914Eu7DkPUurugDXgstwttCYkJtZ/+PkWRWdp3UHRIA==", - "dev": true, - "dependencies": { - "browserslist": "^4.16.6", - "caniuse-api": "^3.0.0", - "colord": "^2.9.1", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-convert-values": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.0.2.tgz", - "integrity": "sha512-KQ04E2yadmfa1LqXm7UIDwW1ftxU/QWZmz6NKnHnUvJ3LEYbbcX6i329f/ig+WnEByHegulocXrECaZGLpL8Zg==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.1.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-custom-media": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-8.0.0.tgz", - "integrity": "sha512-FvO2GzMUaTN0t1fBULDeIvxr5IvbDXcIatt6pnJghc736nqNgsGao5NT+5+WVLAQiTt6Cb3YUms0jiPaXhL//g==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-custom-properties": { - "version": "12.1.3", - "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.3.tgz", - "integrity": "sha512-rtu3otIeY532PnEuuBrIIe+N+pcdbX/7JMZfrcL09wc78YayrHw5E8UkDfvnlOhEUrI4ptCuzXQfj+Or6spbGA==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.3" - } - }, - "node_modules/postcss-custom-selectors": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-6.0.0.tgz", - "integrity": "sha512-/1iyBhz/W8jUepjGyu7V1OPcGbc636snN1yXEQCinb6Bwt7KxsiU7/bLQlp8GwAXzCh7cobBU5odNn/2zQWR8Q==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.4" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "postcss": "^8.1.2" - } - }, - "node_modules/postcss-dir-pseudo-class": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-6.0.3.tgz", - "integrity": "sha512-qiPm+CNAlgXiMf0J5IbBBEXA9l/Q5HGsNGkL3znIwT2ZFRLGY9U2fTUpa4lqCUXQOxaLimpacHeQC80BD2qbDw==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.8" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.3" - } - }, - "node_modules/postcss-discard-comments": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.0.1.tgz", - "integrity": "sha512-lgZBPTDvWrbAYY1v5GYEv8fEO/WhKOu/hmZqmCYfrpD6eyDWWzAOsl2rF29lpvziKO02Gc5GJQtlpkTmakwOWg==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-discard-duplicates": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.0.1.tgz", - "integrity": "sha512-svx747PWHKOGpAXXQkCc4k/DsWo+6bc5LsVrAsw+OU+Ibi7klFZCyX54gjYzX4TH+f2uzXjRviLARxkMurA2bA==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-discard-empty": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.0.1.tgz", - "integrity": "sha512-vfU8CxAQ6YpMxV2SvMcMIyF2LX1ZzWpy0lqHDsOdaKKLQVQGVP1pzhrI9JlsO65s66uQTfkQBKBD/A5gp9STFw==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-discard-overridden": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.0.2.tgz", - "integrity": "sha512-+56BLP6NSSUuWUXjRgAQuho1p5xs/hU5Sw7+xt9S3JSg+7R6+WMGnJW7Hre/6tTuZ2xiXMB42ObkiZJ2hy/Pew==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-double-position-gradients": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-3.0.4.tgz", - "integrity": "sha512-qz+s5vhKJlsHw8HjSs+HVk2QGFdRyC68KGRQGX3i+GcnUjhWhXQEmCXW6siOJkZ1giu0ddPwSO6I6JdVVVPoog==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.3" - } - }, - "node_modules/postcss-env-function": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-4.0.4.tgz", - "integrity": "sha512-0ltahRTPtXSIlEZFv7zIvdEib7HN0ZbUQxrxIKn8KbiRyhALo854I/CggU5lyZe6ZBvSTJ6Al2vkZecI2OhneQ==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.3" - } - }, - "node_modules/postcss-flexbugs-fixes": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-5.0.2.tgz", - "integrity": "sha512-18f9voByak7bTktR2QgDveglpn9DTbBWPUzSOe9g0N4WR/2eSt6Vrcbf0hmspvMI6YWGywz6B9f7jzpFNJJgnQ==", - "dev": true, - "peerDependencies": { - "postcss": "^8.1.4" - } - }, - "node_modules/postcss-focus-visible": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-6.0.3.tgz", - "integrity": "sha512-ozOsg+L1U8S+rxSHnJJiET6dNLyADcPHhEarhhtCI9DBLGOPG/2i4ddVoFch9LzrBgb8uDaaRI4nuid2OM82ZA==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.8" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.3" - } - }, - "node_modules/postcss-focus-within": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-5.0.3.tgz", - "integrity": "sha512-fk9y2uFS6/Kpp7/A9Hz9Z4rlFQ8+tzgBcQCXAFSrXFGAbKx+4ZZOmmfHuYjCOMegPWoz0pnC6fNzi8j7Xyqp5Q==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.8" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.3" - } - }, - "node_modules/postcss-font-variant": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", - "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", - "dev": true, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-gap-properties": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.2.tgz", - "integrity": "sha512-EaMy/pbxtQnKDsnbEjdqlkCkROTQZzolcLKgIE+3b7EuJfJydH55cZeHfm+MtIezXRqhR80VKgaztO/vHq94Fw==", - "dev": true, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.3" - } - }, - "node_modules/postcss-image-set-function": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-4.0.4.tgz", - "integrity": "sha512-BlEo9gSTj66lXjRNByvkMK9dEdEGFXRfGjKRi9fo8s0/P3oEk74cAoonl/utiM50E2OPVb/XSu+lWvdW4KtE/Q==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.3" - } - }, - "node_modules/postcss-initial": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz", - "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==", - "dev": true, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/postcss-js": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.0.tgz", - "integrity": "sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==", - "dev": true, - "dependencies": { - "camelcase-css": "^2.0.1" - }, - "engines": { - "node": "^12 || ^14 || >= 16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.3.3" - } - }, - "node_modules/postcss-lab-function": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-4.0.3.tgz", - "integrity": "sha512-MH4tymWmefdZQ7uVG/4icfLjAQmH6o2NRYyVh2mKoB4RXJp9PjsyhZwhH4ouaCQHvg+qJVj3RzeAR1EQpIlXZA==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.3" - } - }, - "node_modules/postcss-load-config": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.1.tgz", - "integrity": "sha512-c/9XYboIbSEUZpiD1UQD0IKiUe8n9WHYV7YFe7X7J+ZwCsEKkUJSFWjS9hBU1RR9THR7jMXst8sxiqP0jjo2mg==", - "dev": true, - "dependencies": { - "lilconfig": "^2.0.4", - "yaml": "^1.10.2" - }, - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "ts-node": { - "optional": true - } - } - }, - "node_modules/postcss-loader": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz", - "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==", - "dev": true, - "dependencies": { - "cosmiconfig": "^7.0.0", - "klona": "^2.0.5", - "semver": "^7.3.5" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "postcss": "^7.0.0 || ^8.0.1", - "webpack": "^5.0.0" - } - }, - "node_modules/postcss-loader/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/postcss-logical": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.3.tgz", - "integrity": "sha512-P5NcHWYrif0vK8rgOy/T87vg0WRIj3HSknrvp1wzDbiBeoDPVmiVRmkown2eSQdpPveat/MC1ess5uhzZFVnqQ==", - "dev": true, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.3" - } - }, - "node_modules/postcss-media-minmax": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz", - "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-merge-longhand": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.0.4.tgz", - "integrity": "sha512-2lZrOVD+d81aoYkZDpWu6+3dTAAGkCKbV5DoRhnIR7KOULVrI/R7bcMjhrH9KTRy6iiHKqmtG+n/MMj1WmqHFw==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.1.0", - "stylehacks": "^5.0.1" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-merge-rules": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.0.4.tgz", - "integrity": "sha512-yOj7bW3NxlQxaERBB0lEY1sH5y+RzevjbdH4DBJurjKERNpknRByFNdNe+V72i5pIZL12woM9uGdS5xbSB+kDQ==", - "dev": true, - "dependencies": { - "browserslist": "^4.16.6", - "caniuse-api": "^3.0.0", - "cssnano-utils": "^3.0.0", - "postcss-selector-parser": "^6.0.5" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-minify-font-values": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.0.2.tgz", - "integrity": "sha512-R6MJZryq28Cw0AmnyhXrM7naqJZZLoa1paBltIzh2wM7yb4D45TLur+eubTQ4jCmZU9SGeZdWsc5KcSoqTMeTg==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-minify-gradients": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.0.4.tgz", - "integrity": "sha512-RVwZA7NC4R4J76u8X0Q0j+J7ItKUWAeBUJ8oEEZWmtv3Xoh19uNJaJwzNpsydQjk6PkuhRrK+YwwMf+c+68EYg==", - "dev": true, - "dependencies": { - "colord": "^2.9.1", - "cssnano-utils": "^3.0.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-minify-params": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.0.3.tgz", - "integrity": "sha512-NY92FUikE+wralaiVexFd5gwb7oJTIDhgTNeIw89i1Ymsgt4RWiPXfz3bg7hDy4NL6gepcThJwOYNtZO/eNi7Q==", - "dev": true, - "dependencies": { - "alphanum-sort": "^1.0.2", - "browserslist": "^4.16.6", - "cssnano-utils": "^3.0.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-minify-selectors": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.1.1.tgz", - "integrity": "sha512-TOzqOPXt91O2luJInaVPiivh90a2SIK5Nf1Ea7yEIM/5w+XA5BGrZGUSW8aEx9pJ/oNj7ZJBhjvigSiBV+bC1Q==", - "dev": true, - "dependencies": { - "alphanum-sort": "^1.0.2", - "postcss-selector-parser": "^6.0.5" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-modules-extract-imports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-local-by-default": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", - "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", - "dev": true, - "dependencies": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.1.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-scope": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", - "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.4" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-values": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", - "dev": true, - "dependencies": { - "icss-utils": "^5.0.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-nested": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.6.tgz", - "integrity": "sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.6" - }, - "engines": { - "node": ">=12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.2.14" - } - }, - "node_modules/postcss-nesting": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.1.2.tgz", - "integrity": "sha512-dJGmgmsvpzKoVMtDMQQG/T6FSqs6kDtUDirIfl4KnjMCiY9/ETX8jdKyCd20swSRAbUYkaBKV20pxkzxoOXLqQ==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.8" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.3" - } - }, - "node_modules/postcss-normalize": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize/-/postcss-normalize-10.0.1.tgz", - "integrity": "sha512-+5w18/rDev5mqERcG3W5GZNMJa1eoYYNGo8gB7tEwaos0ajk3ZXAI4mHGcNT47NE+ZnZD1pEpUOFLvltIwmeJA==", - "dev": true, - "dependencies": { - "@csstools/normalize.css": "*", - "postcss-browser-comments": "^4", - "sanitize.css": "*" - }, - "engines": { - "node": ">= 12" - }, - "peerDependencies": { - "browserslist": ">= 4", - "postcss": ">= 8" - } - }, - "node_modules/postcss-normalize-charset": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.0.1.tgz", - "integrity": "sha512-6J40l6LNYnBdPSk+BHZ8SF+HAkS4q2twe5jnocgd+xWpz/mx/5Sa32m3W1AA8uE8XaXN+eg8trIlfu8V9x61eg==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-display-values": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.0.2.tgz", - "integrity": "sha512-RxXoJPUR0shSjkMMzgEZDjGPrgXUVYyWA/YwQRicb48H15OClPuaDR7tYokLAlGZ2tCSENEN5WxjgxSD5m4cUw==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-positions": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.0.2.tgz", - "integrity": "sha512-tqghWFVDp2btqFg1gYob1etPNxXLNh3uVeWgZE2AQGh6b2F8AK2Gj36v5Vhyh+APwIzNjmt6jwZ9pTBP+/OM8g==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-repeat-style": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.0.2.tgz", - "integrity": "sha512-/rIZn8X9bBzC7KvY4iKUhXUGW3MmbXwfPF23jC9wT9xTi7kAvgj8sEgwxjixBmoL6MVa4WOgxNz2hAR6wTK8tw==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-string": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.0.2.tgz", - "integrity": "sha512-zaI1yzwL+a/FkIzUWMQoH25YwCYxi917J4pYm1nRXtdgiCdnlTkx5eRzqWEC64HtRa06WCJ9TIutpb6GmW4gFw==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-timing-functions": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.0.2.tgz", - "integrity": "sha512-Ao0PP6MoYsRU1LxeVUW740ioknvdIUmfr6uAA3xWlQJ9s69/Tupy8qwhuKG3xWfl+KvLMAP9p2WXF9cwuk/7Bg==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-unicode": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.0.2.tgz", - "integrity": "sha512-3y/V+vjZ19HNcTizeqwrbZSUsE69ZMRHfiiyLAJb7C7hJtYmM4Gsbajy7gKagu97E8q5rlS9k8FhojA8cpGhWw==", - "dev": true, - "dependencies": { - "browserslist": "^4.16.6", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-url": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.0.4.tgz", - "integrity": "sha512-cNj3RzK2pgQQyNp7dzq0dqpUpQ/wYtdDZM3DepPmFjCmYIfceuD9VIAcOdvrNetjIU65g1B4uwdP/Krf6AFdXg==", - "dev": true, - "dependencies": { - "normalize-url": "^6.0.1", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-whitespace": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.0.2.tgz", - "integrity": "sha512-CXBx+9fVlzSgbk0IXA/dcZn9lXixnQRndnsPC5ht3HxlQ1bVh77KQDL1GffJx1LTzzfae8ftMulsjYmO2yegxA==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-ordered-values": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.0.3.tgz", - "integrity": "sha512-T9pDS+P9bWeFvqivXd5ACzQmrCmHjv3ZP+djn8E1UZY7iK79pFSm7i3WbKw2VSmFmdbMm8sQ12OPcNpzBo3Z2w==", - "dev": true, - "dependencies": { - "cssnano-utils": "^3.0.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-overflow-shorthand": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.2.tgz", - "integrity": "sha512-odBMVt6PTX7jOE9UNvmnLrFzA9pXS44Jd5shFGGtSHY80QCuJF+14McSy0iavZggRZ9Oj//C9vOKQmexvyEJMg==", - "dev": true, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.3" - } - }, - "node_modules/postcss-page-break": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", - "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", - "dev": true, - "peerDependencies": { - "postcss": "^8" - } - }, - "node_modules/postcss-place": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-7.0.3.tgz", - "integrity": "sha512-tDQ3m+GYoOar+KoQgj+pwPAvGHAp/Sby6vrFiyrELrMKQJ4AejL0NcS0mm296OKKYA2SRg9ism/hlT/OLhBrdQ==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.3" - } - }, - "node_modules/postcss-preset-env": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.2.3.tgz", - "integrity": "sha512-Ok0DhLfwrcNGrBn8sNdy1uZqWRk/9FId0GiQ39W4ILop5GHtjJs8bu1MY9isPwHInpVEPWjb4CEcEaSbBLpfwA==", - "dev": true, - "dependencies": { - "autoprefixer": "^10.4.2", - "browserslist": "^4.19.1", - "caniuse-lite": "^1.0.30001299", - "css-blank-pseudo": "^3.0.2", - "css-has-pseudo": "^3.0.3", - "css-prefers-color-scheme": "^6.0.2", - "cssdb": "^5.0.0", - "postcss-attribute-case-insensitive": "^5.0.0", - "postcss-color-functional-notation": "^4.2.1", - "postcss-color-hex-alpha": "^8.0.2", - "postcss-color-rebeccapurple": "^7.0.2", - "postcss-custom-media": "^8.0.0", - "postcss-custom-properties": "^12.1.2", - "postcss-custom-selectors": "^6.0.0", - "postcss-dir-pseudo-class": "^6.0.3", - "postcss-double-position-gradients": "^3.0.4", - "postcss-env-function": "^4.0.4", - "postcss-focus-visible": "^6.0.3", - "postcss-focus-within": "^5.0.3", - "postcss-font-variant": "^5.0.0", - "postcss-gap-properties": "^3.0.2", - "postcss-image-set-function": "^4.0.4", - "postcss-initial": "^4.0.1", - "postcss-lab-function": "^4.0.3", - "postcss-logical": "^5.0.3", - "postcss-media-minmax": "^5.0.0", - "postcss-nesting": "^10.1.2", - "postcss-overflow-shorthand": "^3.0.2", - "postcss-page-break": "^3.0.4", - "postcss-place": "^7.0.3", - "postcss-pseudo-class-any-link": "^7.0.2", - "postcss-replace-overflow-wrap": "^4.0.0", - "postcss-selector-not": "^5.0.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-pseudo-class-any-link": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.0.2.tgz", - "integrity": "sha512-CG35J1COUH7OOBgpw5O+0koOLUd5N4vUGKUqSAuIe4GiuLHWU96Pqp+UPC8QITTd12zYAFx76pV7qWT/0Aj/TA==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.8" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.3" - } - }, - "node_modules/postcss-reduce-initial": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.0.2.tgz", - "integrity": "sha512-v/kbAAQ+S1V5v9TJvbGkV98V2ERPdU6XvMcKMjqAlYiJ2NtsHGlKYLPjWWcXlaTKNxooId7BGxeraK8qXvzKtw==", - "dev": true, - "dependencies": { - "browserslist": "^4.16.6", - "caniuse-api": "^3.0.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-reduce-transforms": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.0.2.tgz", - "integrity": "sha512-25HeDeFsgiPSUx69jJXZn8I06tMxLQJJNF5h7i9gsUg8iP4KOOJ8EX8fj3seeoLt3SLU2YDD6UPnDYVGUO7DEA==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-replace-overflow-wrap": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", - "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", - "dev": true, - "peerDependencies": { - "postcss": "^8.0.3" - } - }, - "node_modules/postcss-selector-not": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-5.0.0.tgz", - "integrity": "sha512-/2K3A4TCP9orP4TNS7u3tGdRFVKqz/E6pX3aGnriPG0jU78of8wsUcqE4QAhWEU0d+WnMSF93Ah3F//vUtK+iQ==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.0.8", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.8.tgz", - "integrity": "sha512-D5PG53d209Z1Uhcc0qAZ5U3t5HagH3cxu+WLZ22jt3gLUpXM4eXXfiO14jiDWST3NNooX/E8wISfOhZ9eIjGTQ==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-svgo": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.0.3.tgz", - "integrity": "sha512-41XZUA1wNDAZrQ3XgWREL/M2zSw8LJPvb5ZWivljBsUQAGoEKMYm6okHsTjJxKYI4M75RQEH4KYlEM52VwdXVA==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.1.0", - "svgo": "^2.7.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-svgo/node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/postcss-svgo/node_modules/css-tree": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", - "dev": true, - "dependencies": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/postcss-svgo/node_modules/mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", - "dev": true - }, - "node_modules/postcss-svgo/node_modules/svgo": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", - "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", - "dev": true, - "dependencies": { - "@trysound/sax": "0.2.0", - "commander": "^7.2.0", - "css-select": "^4.1.3", - "css-tree": "^1.1.3", - "csso": "^4.2.0", - "picocolors": "^1.0.0", - "stable": "^0.1.8" - }, - "bin": { - "svgo": "bin/svgo" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/postcss-unique-selectors": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.0.2.tgz", - "integrity": "sha512-w3zBVlrtZm7loQWRPVC0yjUwwpty7OM6DnEHkxcSQXO1bMS3RJ+JUS5LFMSDZHJcvGsRwhZinCWVqn8Kej4EDA==", - "dev": true, - "dependencies": { - "alphanum-sort": "^1.0.2", - "postcss-selector-parser": "^6.0.5" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.2.tgz", - "integrity": "sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/pretty-bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pretty-error": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", - "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", - "dev": true, - "dependencies": { - "lodash": "^4.17.20", - "renderkid": "^3.0.0" - } - }, - "node_modules/pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/pretty-format/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pretty-format/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/pretty-format/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/pretty-format/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "node_modules/promise": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz", - "integrity": "sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==", - "dev": true, - "dependencies": { - "asap": "~2.0.6" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/prop-types-exact": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/prop-types-exact/-/prop-types-exact-1.2.0.tgz", - "integrity": "sha512-K+Tk3Kd9V0odiXFP9fwDHUYRyvK3Nun3GVyPapSIs5OBkITAm15W0CPFD/YKTkMUAbc0b9CUwRQp2ybiBIq+eA==", - "dev": true, - "dependencies": { - "has": "^1.0.3", - "object.assign": "^4.1.0", - "reflect.ownkeys": "^0.2.0" - } - }, - "node_modules/prop-types-extra": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz", - "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==", - "dependencies": { - "react-is": "^16.3.2", - "warning": "^4.0.0" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dev": true, - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxy-addr/node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/pseudolocale": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pseudolocale/-/pseudolocale-1.2.0.tgz", - "integrity": "sha512-k0OQFvIlvpRdzR0dPVrrbWX7eE9EaZ6gpZtTlFSDi1Gf9tMy9wiANCNu7JZ0drcKgUri/39a2mBbH0goiQmrmQ==", - "dev": true, - "dependencies": { - "commander": "*" - } - }, - "node_modules/psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", - "dev": true, - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, - "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/raf": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", - "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", - "dev": true, - "dependencies": { - "performance-now": "^2.1.0" - } - }, - "node_modules/railroad-diagrams": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz", - "integrity": "sha1-635iZ1SN3t+4mcG5Dlc3RVnN234=", - "dev": true - }, - "node_modules/ramda": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.1.tgz", - "integrity": "sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw==", - "dev": true - }, - "node_modules/randexp": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz", - "integrity": "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==", - "dev": true, - "dependencies": { - "discontinuous-range": "1.0.0", - "ret": "~0.1.10" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "dev": true, - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/raw-body/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-ace": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/react-ace/-/react-ace-10.1.0.tgz", - "integrity": "sha512-VkvUjZNhdYTuKOKQpMIZi7uzZZVgzCjM7cLYu6F64V0mejY8a2XTyPUIMszC6A4trbeMIHbK5fYFcT/wkP/8VA==", - "dependencies": { - "ace-builds": "^1.4.14", - "diff-match-patch": "^1.0.5", - "lodash.get": "^4.4.2", - "lodash.isequal": "^4.5.0", - "prop-types": "^15.7.2" - }, - "peerDependencies": { - "react": "^0.13.0 || ^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^0.13.0 || ^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/react-app-polyfill": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-3.0.0.tgz", - "integrity": "sha512-sZ41cxiU5llIB003yxxQBYrARBqe0repqPTTYBTmMqTz9szeBbE37BehCE891NZsmdZqqP+xWKdT3eo3vOzN8w==", - "dev": true, - "dependencies": { - "core-js": "^3.19.2", - "object-assign": "^4.1.1", - "promise": "^8.1.0", - "raf": "^3.4.1", - "regenerator-runtime": "^0.13.9", - "whatwg-fetch": "^3.6.2" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/react-app-polyfill/node_modules/core-js": { - "version": "3.20.3", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.20.3.tgz", - "integrity": "sha512-vVl8j8ph6tRS3B8qir40H7yw7voy17xL0piAjlbBUsH7WIfzoedL/ZOr1OV9FyZQLWXsayOJyV4tnRyXR85/ag==", - "dev": true, - "hasInstallScript": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/react-dev-utils": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", - "integrity": "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.16.0", - "address": "^1.1.2", - "browserslist": "^4.18.1", - "chalk": "^4.1.2", - "cross-spawn": "^7.0.3", - "detect-port-alt": "^1.1.6", - "escape-string-regexp": "^4.0.0", - "filesize": "^8.0.6", - "find-up": "^5.0.0", - "fork-ts-checker-webpack-plugin": "^6.5.0", - "global-modules": "^2.0.0", - "globby": "^11.0.4", - "gzip-size": "^6.0.0", - "immer": "^9.0.7", - "is-root": "^2.1.0", - "loader-utils": "^3.2.0", - "open": "^8.4.0", - "pkg-up": "^3.1.0", - "prompts": "^2.4.2", - "react-error-overlay": "^6.0.11", - "recursive-readdir": "^2.2.2", - "shell-quote": "^1.7.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/react-dev-utils/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/react-dev-utils/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/react-dev-utils/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/react-dev-utils/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/react-dev-utils/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/react-dev-utils/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/react-dev-utils/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/react-dev-utils/node_modules/loader-utils": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", - "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", - "dev": true, - "engines": { - "node": ">= 12.13.0" - } - }, - "node_modules/react-dev-utils/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/react-dev-utils/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/react-dev-utils/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/react-dev-utils/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/react-dom": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", - "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" - }, - "peerDependencies": { - "react": "17.0.2" - } - }, - "node_modules/react-dropzone": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-9.0.0.tgz", - "integrity": "sha512-wZ2o9B2qkdE3RumWhfyZT9swgJYJPeU5qHEcMU8weYpmLex1eeWX0CC32/Y0VutB+BBi2D+iePV/YZIiB4kZGw==", - "dependencies": { - "attr-accept": "^1.1.3", - "file-selector": "^0.1.8", - "prop-types": "^15.6.2", - "prop-types-extra": "^1.1.0" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/react-error-boundary": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-3.1.4.tgz", - "integrity": "sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==", - "dependencies": { - "@babel/runtime": "^7.12.5" - }, - "engines": { - "node": ">=10", - "npm": ">=6" - }, - "peerDependencies": { - "react": ">=16.13.1" - } - }, - "node_modules/react-error-overlay": { - "version": "6.0.11", - "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", - "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==", - "dev": true - }, - "node_modules/react-fast-compare": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz", - "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==" - }, - "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "node_modules/react-lifecycles-compat": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", - "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" - }, - "node_modules/react-refresh": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", - "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-router": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.3.tgz", - "integrity": "sha512-mzQGUvS3bM84TnbtMYR8ZjKnuPJ71IjSzR+DE6UkUqvN4czWIqEs17yLL8xkAycv4ev0AiN+IGrWu88vJs/p2w==", - "dependencies": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "hoist-non-react-statics": "^3.1.0", - "loose-envify": "^1.3.1", - "mini-create-react-context": "^0.4.0", - "path-to-regexp": "^1.7.0", - "prop-types": "^15.6.2", - "react-is": "^16.6.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" - }, - "peerDependencies": { - "react": ">=15" - } - }, - "node_modules/react-router-dom": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.3.tgz", - "integrity": "sha512-Ov0tGPMBgqmbu5CDmN++tv2HQ9HlWDuWIIqn4b88gjlAN5IHI+4ZUZRcpz9Hl0azFIwihbLDYw1OiHGRo7ZIng==", - "dependencies": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "loose-envify": "^1.3.1", - "prop-types": "^15.6.2", - "react-router": "5.3.3", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" - }, - "peerDependencies": { - "react": ">=15" - } - }, - "node_modules/react-scripts": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", - "integrity": "sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==", - "dev": true, - "dependencies": { - "@babel/core": "^7.16.0", - "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", - "@svgr/webpack": "^5.5.0", - "babel-jest": "^27.4.2", - "babel-loader": "^8.2.3", - "babel-plugin-named-asset-import": "^0.3.8", - "babel-preset-react-app": "^10.0.1", - "bfj": "^7.0.2", - "browserslist": "^4.18.1", - "camelcase": "^6.2.1", - "case-sensitive-paths-webpack-plugin": "^2.4.0", - "css-loader": "^6.5.1", - "css-minimizer-webpack-plugin": "^3.2.0", - "dotenv": "^10.0.0", - "dotenv-expand": "^5.1.0", - "eslint": "^8.3.0", - "eslint-config-react-app": "^7.0.1", - "eslint-webpack-plugin": "^3.1.1", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "html-webpack-plugin": "^5.5.0", - "identity-obj-proxy": "^3.0.0", - "jest": "^27.4.3", - "jest-resolve": "^27.4.2", - "jest-watch-typeahead": "^1.0.0", - "mini-css-extract-plugin": "^2.4.5", - "postcss": "^8.4.4", - "postcss-flexbugs-fixes": "^5.0.2", - "postcss-loader": "^6.2.1", - "postcss-normalize": "^10.0.1", - "postcss-preset-env": "^7.0.1", - "prompts": "^2.4.2", - "react-app-polyfill": "^3.0.0", - "react-dev-utils": "^12.0.1", - "react-refresh": "^0.11.0", - "resolve": "^1.20.0", - "resolve-url-loader": "^4.0.0", - "sass-loader": "^12.3.0", - "semver": "^7.3.5", - "source-map-loader": "^3.0.0", - "style-loader": "^3.3.1", - "tailwindcss": "^3.0.2", - "terser-webpack-plugin": "^5.2.5", - "webpack": "^5.64.4", - "webpack-dev-server": "^4.6.0", - "webpack-manifest-plugin": "^4.0.2", - "workbox-webpack-plugin": "^6.4.1" - }, - "bin": { - "react-scripts": "bin/react-scripts.js" - }, - "engines": { - "node": ">=14.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - }, - "peerDependencies": { - "react": ">= 16", - "typescript": "^3.2.1 || ^4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/react-scripts/node_modules/@types/eslint": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.29.0.tgz", - "integrity": "sha512-VNcvioYDH8/FxaeTKkM4/TiTwt6pBV9E3OfGmvaw8tPl0rrHCJ4Ll15HRT+pMiFAf/MLQvAzC+6RzUMEL9Ceng==", - "dev": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/react-scripts/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/react-scripts/node_modules/eslint-webpack-plugin": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.1.1.tgz", - "integrity": "sha512-xSucskTN9tOkfW7so4EaiFIkulWLXwCB/15H917lR6pTv0Zot6/fetFucmENRb7J5whVSFKIvwnrnsa78SG2yg==", - "dev": true, - "dependencies": { - "@types/eslint": "^7.28.2", - "jest-worker": "^27.3.1", - "micromatch": "^4.0.4", - "normalize-path": "^3.0.0", - "schema-utils": "^3.1.1" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0", - "webpack": "^5.0.0" - } - }, - "node_modules/react-scripts/node_modules/fs-extra": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", - "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/react-scripts/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/react-shallow-renderer": { - "version": "16.14.1", - "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.14.1.tgz", - "integrity": "sha512-rkIMcQi01/+kxiTE9D3fdS959U1g7gs+/rborw++42m1O9FAQiNI/UNRZExVUoAOprn4umcXf+pFRou8i4zuBg==", - "dev": true, - "dependencies": { - "object-assign": "^4.1.1", - "react-is": "^16.12.0 || ^17.0.0" - }, - "peerDependencies": { - "react": "^16.0.0 || ^17.0.0" - } - }, - "node_modules/react-test-renderer": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-17.0.2.tgz", - "integrity": "sha512-yaQ9cB89c17PUb0x6UfWRs7kQCorVdHlutU1boVPEsB8IDZH6n9tHxMacc3y0JoXOJUsZb/t/Mb8FUWMKaM7iQ==", - "dev": true, - "dependencies": { - "object-assign": "^4.1.1", - "react-is": "^17.0.2", - "react-shallow-renderer": "^16.13.1", - "scheduler": "^0.20.2" - }, - "peerDependencies": { - "react": "17.0.2" - } - }, - "node_modules/react-test-renderer/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/react-virtualized": { - "version": "9.22.3", - "resolved": "https://registry.npmjs.org/react-virtualized/-/react-virtualized-9.22.3.tgz", - "integrity": "sha512-MKovKMxWTcwPSxE1kK1HcheQTWfuCxAuBoSTf2gwyMM21NdX/PXUhnoP8Uc5dRKd+nKm8v41R36OellhdCpkrw==", - "dependencies": { - "@babel/runtime": "^7.7.2", - "clsx": "^1.0.4", - "dom-helpers": "^5.1.3", - "loose-envify": "^1.4.0", - "prop-types": "^15.7.2", - "react-lifecycles-compat": "^3.0.4" - } - }, - "node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdirp": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", - "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/recursive-readdir": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", - "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", - "dev": true, - "dependencies": { - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "dev": true, - "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/reflect.ownkeys": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/reflect.ownkeys/-/reflect.ownkeys-0.2.0.tgz", - "integrity": "sha1-dJrO7H8/34tj+SegSAnpDFwLNGA=", - "dev": true - }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true - }, - "node_modules/regenerate-unicode-properties": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz", - "integrity": "sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA==", - "dev": true, - "dependencies": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" - }, - "node_modules/regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.8.4" - } - }, - "node_modules/regex-parser": { - "version": "2.2.11", - "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", - "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==", - "dev": true - }, - "node_modules/regexp.prototype.flags": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", - "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/regexpu-core": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.8.0.tgz", - "integrity": "sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg==", - "dev": true, - "dependencies": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^9.0.0", - "regjsgen": "^0.5.2", - "regjsparser": "^0.7.0", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regjsgen": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", - "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==", - "dev": true - }, - "node_modules/regjsparser": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.7.0.tgz", - "integrity": "sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ==", - "dev": true, - "dependencies": { - "jsesc": "~0.5.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - } - }, - "node_modules/relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/renderkid": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", - "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", - "dev": true, - "dependencies": { - "css-select": "^4.1.3", - "dom-converter": "^0.2.0", - "htmlparser2": "^6.1.0", - "lodash": "^4.17.21", - "strip-ansi": "^6.0.1" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/requireindex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.1.0.tgz", - "integrity": "sha1-5UBLgVV+91225JxacgBIk/4D4WI=", - "dev": true, - "engines": { - "node": ">=0.10.5" - } - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", - "dev": true - }, - "node_modules/resolve": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.21.0.tgz", - "integrity": "sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA==", - "dev": true, - "dependencies": { - "is-core-module": "^2.8.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-cwd/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve-pathname": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", - "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" - }, - "node_modules/resolve-url-loader": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-4.0.0.tgz", - "integrity": "sha512-05VEMczVREcbtT7Bz+C+96eUO5HDNvdthIiMB34t7FcF8ehcu4wC0sSgPUubs3XW2Q3CNLJk/BJrCU9wVRymiA==", - "dev": true, - "dependencies": { - "adjust-sourcemap-loader": "^4.0.0", - "convert-source-map": "^1.7.0", - "loader-utils": "^2.0.0", - "postcss": "^7.0.35", - "source-map": "0.6.1" - }, - "engines": { - "node": ">=8.9" - }, - "peerDependencies": { - "rework": "1.0.1", - "rework-visit": "1.0.0" - }, - "peerDependenciesMeta": { - "rework": { - "optional": true - }, - "rework-visit": { - "optional": true - } - } - }, - "node_modules/resolve-url-loader/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true - }, - "node_modules/resolve-url-loader/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dev": true, - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/resolve.exports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/robust-predicates": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.1.tgz", - "integrity": "sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g==" - }, - "node_modules/rollup": { - "version": "2.64.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.64.0.tgz", - "integrity": "sha512-+c+lbw1lexBKSMb1yxGDVfJ+vchJH3qLbmavR+awDinTDA2C5Ug9u7lkOzj62SCu0PKUExsW36tpgW7Fmpn3yQ==", - "dev": true, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=10.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/rollup-plugin-terser": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", - "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "jest-worker": "^26.2.1", - "serialize-javascript": "^4.0.0", - "terser": "^5.0.0" - }, - "peerDependencies": { - "rollup": "^2.0.0" - } - }, - "node_modules/rollup-plugin-terser/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/rollup-plugin-terser/node_modules/jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/rollup-plugin-terser/node_modules/serialize-javascript": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/rollup-plugin-terser/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/rrule": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rrule/-/rrule-2.7.1.tgz", - "integrity": "sha512-4p20u/1U7WqR3Nb1hOUrm0u1nSI7sO93ZUVZEZ5HeF6Gr5OlJuyhwEGRvUHq8ZfrPsq5gfa5b9dqnUs/kPqpIw==", - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/rrule/node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" - }, - "node_modules/rst-selector-parser": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/rst-selector-parser/-/rst-selector-parser-2.2.3.tgz", - "integrity": "sha1-gbIw6i/MYGbInjRy3nlChdmwPZE=", - "dev": true, - "dependencies": { - "lodash.flattendeep": "^4.4.0", - "nearley": "^2.7.10" - } - }, - "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/rw": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=" - }, - "node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/sanitize.css": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-13.0.0.tgz", - "integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==", - "dev": true - }, - "node_modules/sass-loader": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.4.0.tgz", - "integrity": "sha512-7xN+8khDIzym1oL9XyS6zP6Ges+Bo2B2xbPrjdMHEYyV3AQYhd/wXeru++3ODHF0zMjYmVadblSKrPrjEkL8mg==", - "dev": true, - "dependencies": { - "klona": "^2.0.4", - "neo-async": "^2.6.2" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "fibers": ">= 3.1.0", - "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", - "sass": "^1.3.0", - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "fibers": { - "optional": true - }, - "node-sass": { - "optional": true - }, - "sass": { - "optional": true - } - } - }, - "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "node_modules/saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "dev": true, - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "node_modules/schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", - "dev": true - }, - "node_modules/selfsigned": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.0.0.tgz", - "integrity": "sha512-cUdFiCbKoa1mZ6osuJs2uDHrs0k0oprsKveFiiaBKCNq3SYyb5gs2HxhQyDNLCmL51ZZThqi4YNDpCK6GOP1iQ==", - "dev": true, - "dependencies": { - "node-forge": "^1.2.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dev": true, - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/send/node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/send/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", - "dev": true, - "dependencies": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/serve-index/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/serve-index/node_modules/http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", - "dev": true, - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-index/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "node_modules/serve-index/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/serve-index/node_modules/setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true - }, - "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "dev": true, - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true - }, - "node_modules/shallowequal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", - "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/shell-quote": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.4.tgz", - "integrity": "sha512-8o/QEhSSRb1a5i7TFR0iM4G16Z0vYB2OQVs4G3aAFXjn3T6yEx8AZxy1PgDF7I00LZHYA3WxaSYIf5e5sAX8Rw==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "node_modules/signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/sockjs": { - "version": "0.3.24", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", - "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", - "dev": true, - "dependencies": { - "faye-websocket": "^0.11.3", - "uuid": "^8.3.2", - "websocket-driver": "^0.7.4" - } - }, - "node_modules/source-list-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", - "dev": true - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-loader": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-3.0.1.tgz", - "integrity": "sha512-Vp1UsfyPvgujKQzi4pyDiTOnE3E4H+yHvkVRN3c/9PJmQS4CQJExvcDvaX/D+RV+xQben9HJ56jMJS3CgUeWyA==", - "dev": true, - "dependencies": { - "abab": "^2.0.5", - "iconv-lite": "^0.6.3", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/source-map-loader/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-url": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", - "deprecated": "See https://github.com/lydell/source-map-url#deprecated", - "dev": true - }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "dev": true - }, - "node_modules/spdy": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", - "dev": true, - "dependencies": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/spdy-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", - "dev": true, - "dependencies": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/stable": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", - "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", - "dev": true - }, - "node_modules/stack-utils": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", - "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/stackframe": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz", - "integrity": "sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA==", - "dev": true - }, - "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - }, - "node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/string-natural-compare": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz", - "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==", - "dev": true - }, - "node_modules/string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string.prototype.matchall": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz", - "integrity": "sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", - "get-intrinsic": "^1.1.1", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "regexp.prototype.flags": "^1.3.1", - "side-channel": "^1.0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.4.tgz", - "integrity": "sha512-hWCk/iqf7lp0/AgTF7/ddO1IWtSNPASjlzCicV5irAVdE1grjsneK26YG6xACMBEdCvO8fUST0UzDMh/2Qy+9Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "node_modules/stringify-object": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", - "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", - "dev": true, - "dependencies": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-2.0.1.tgz", - "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dev": true, - "dependencies": { - "min-indent": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/style-loader": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz", - "integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==", - "dev": true, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/style-mod": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.0.tgz", - "integrity": "sha512-OPhtyEjyyN9x3nhPsu76f52yUGXiZcgvsrFVtvTkyGRQJ0XK+GPc6ov1z+lRpbeabka+MYEQxOYRnt5nF30aMw==" - }, - "node_modules/styled-components": { - "version": "5.3.6", - "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.6.tgz", - "integrity": "sha512-hGTZquGAaTqhGWldX7hhfzjnIYBZ0IXQXkCYdvF1Sq3DsUaLx6+NTHC5Jj1ooM2F68sBiVz3lvhfwQs/S3l6qg==", - "hasInstallScript": true, - "dependencies": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/traverse": "^7.4.5", - "@emotion/is-prop-valid": "^1.1.0", - "@emotion/stylis": "^0.8.4", - "@emotion/unitless": "^0.7.4", - "babel-plugin-styled-components": ">= 1.12.0", - "css-to-react-native": "^3.0.0", - "hoist-non-react-statics": "^3.0.0", - "shallowequal": "^1.1.0", - "supports-color": "^5.5.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/styled-components" - }, - "peerDependencies": { - "react": ">= 16.8.0", - "react-dom": ">= 16.8.0", - "react-is": ">= 16.8.0" - } - }, - "node_modules/stylehacks": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.0.1.tgz", - "integrity": "sha512-Es0rVnHIqbWzveU1b24kbw92HsebBepxfcqe5iix7t9j0PQqhs0IxXVXv0pY2Bxa08CgMkzD6OWql7kbGOuEdA==", - "dev": true, - "dependencies": { - "browserslist": "^4.16.0", - "postcss-selector-parser": "^6.0.4" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-hyperlinks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", - "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-hyperlinks/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-hyperlinks/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/svg-parser": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", - "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", - "dev": true - }, - "node_modules/svgo": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", - "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.1", - "coa": "^2.0.2", - "css-select": "^2.0.0", - "css-select-base-adapter": "^0.1.1", - "css-tree": "1.0.0-alpha.37", - "csso": "^4.0.2", - "js-yaml": "^3.13.1", - "mkdirp": "~0.5.1", - "object.values": "^1.1.0", - "sax": "~1.2.4", - "stable": "^0.1.8", - "unquote": "~1.1.1", - "util.promisify": "~1.0.0" - }, - "bin": { - "svgo": "bin/svgo" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/svgo/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/svgo/node_modules/css-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", - "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^3.2.1", - "domutils": "^1.7.0", - "nth-check": "^1.0.2" - } - }, - "node_modules/svgo/node_modules/css-what": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", - "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/svgo/node_modules/dom-serializer": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", - "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", - "dev": true, - "dependencies": { - "domelementtype": "^2.0.1", - "entities": "^2.0.0" - } - }, - "node_modules/svgo/node_modules/dom-serializer/node_modules/domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "dev": true - }, - "node_modules/svgo/node_modules/domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", - "dev": true - }, - "node_modules/svgo/node_modules/domutils": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", - "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", - "dev": true, - "dependencies": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, - "node_modules/svgo/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/svgo/node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/svgo/node_modules/nth-check": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", - "dev": true, - "dependencies": { - "boolbase": "~1.0.0" - } - }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "node_modules/tabbable": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-5.3.3.tgz", - "integrity": "sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA==" - }, - "node_modules/tailwindcss": { - "version": "3.0.15", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.0.15.tgz", - "integrity": "sha512-bT2iy7FtjwgsXik4ZoJnHXR+SRCiGR1W95fVqpLZebr64m4ahwUwRbIAc5w5+2fzr1YF4Ct2eI7dojMRRl8sVQ==", - "dev": true, - "dependencies": { - "arg": "^5.0.1", - "chalk": "^4.1.2", - "chokidar": "^3.5.2", - "color-name": "^1.1.4", - "cosmiconfig": "^7.0.1", - "detective": "^5.2.0", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.2.7", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "normalize-path": "^3.0.0", - "object-hash": "^2.2.0", - "postcss-js": "^4.0.0", - "postcss-load-config": "^3.1.0", - "postcss-nested": "5.0.6", - "postcss-selector-parser": "^6.0.8", - "postcss-value-parser": "^4.2.0", - "quick-lru": "^5.1.1", - "resolve": "^1.21.0" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "engines": { - "node": ">=12.13.0" - }, - "peerDependencies": { - "autoprefixer": "^10.0.2", - "postcss": "^8.0.9" - } - }, - "node_modules/tailwindcss/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/tailwindcss/node_modules/arg": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.1.tgz", - "integrity": "sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA==", - "dev": true - }, - "node_modules/tailwindcss/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/tailwindcss/node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/tailwindcss/node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/tailwindcss/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/tailwindcss/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/tailwindcss/node_modules/cosmiconfig": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", - "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", - "dev": true, - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/tailwindcss/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/tailwindcss/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/tailwindcss/node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/tailwindcss/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tapable": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.1.10.tgz", - "integrity": "sha1-KcNXB8K3DlDQdIK10gLo7URtr9Q=", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/temp-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", - "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/tempy": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.6.0.tgz", - "integrity": "sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==", - "dev": true, - "dependencies": { - "is-stream": "^2.0.0", - "temp-dir": "^2.0.0", - "type-fest": "^0.16.0", - "unique-string": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tempy/node_modules/type-fest": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", - "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/terser": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.0.tgz", - "integrity": "sha512-KjTV81QKStSfwbNiwlBXfcgMcOloyuRdb62/iLFPGBcVNF4EXjhdYBhYHmbJpiBrVxZhDvltE11j+LBQUxEEJg==", - "dev": true, - "dependencies": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser-webpack-plugin": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.0.tgz", - "integrity": "sha512-LPIisi3Ol4chwAaPP8toUJ3L4qCM1G0wao7L3qNv57Drezxj6+VEyySpPw4B1HSO2Eg/hDY/MNF5XihCAoqnsQ==", - "dev": true, - "dependencies": { - "jest-worker": "^27.4.1", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1", - "terser": "^5.7.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } - } - }, - "node_modules/terser/node_modules/acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "node_modules/throat": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", - "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", - "dev": true - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "node_modules/thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true - }, - "node_modules/timsort": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", - "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", - "dev": true - }, - "node_modules/tiny-invariant": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz", - "integrity": "sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg==" - }, - "node_modules/tiny-warning": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", - "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" - }, - "node_modules/tippy.js": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-5.1.2.tgz", - "integrity": "sha512-Qtrv2wqbRbaKMUb6bWWBQWPayvcDKNrGlvihxtsyowhT7RLGEh1STWuy6EMXC6QLkfKPB2MLnf8W2mzql9VDAw==", - "dependencies": { - "popper.js": "^1.16.0" - } - }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tough-cookie": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", - "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", - "dev": true, - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.1.2" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tough-cookie/node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/tr46": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", - "dev": true, - "dependencies": { - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tryer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", - "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==", - "dev": true - }, - "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/ts-node/node_modules/acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ts-node/node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/tsconfig-paths": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz", - "integrity": "sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==", - "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.0", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/tslib": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", - "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==" - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dev": true, - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, - "node_modules/typescript": { - "version": "4.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", - "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==", - "dev": true, - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - } - }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "dev": true, - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", - "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", - "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "dev": true, - "dependencies": { - "crypto-random-string": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/unquote": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", - "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", - "dev": true - }, - "node_modules/upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "dev": true, - "engines": { - "node": ">=4", - "yarn": "*" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist-lint": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "node_modules/util.promisify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", - "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.2", - "has-symbols": "^1.0.1", - "object.getownpropertydescriptors": "^2.1.0" - } - }, - "node_modules/utila": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", - "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", - "dev": true - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "node_modules/v8-to-istanbul": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", - "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/v8-to-istanbul/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/value-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", - "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dev": true, - "dependencies": { - "browser-process-hrtime": "^1.0.0" - } - }, - "node_modules/w3c-keyname": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.4.tgz", - "integrity": "sha512-tOhfEwEzFLJzf6d1ZPkYfGj+FWhIpBux9ppoP3rlclw3Z0BZv3N7b7030Z1kYth+6rDuAsXUFr+d0VE6Ed1ikw==" - }, - "node_modules/w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", - "dev": true, - "dependencies": { - "xml-name-validator": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "dependencies": { - "makeerror": "1.0.12" - } - }, - "node_modules/warning": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", - "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", - "dependencies": { - "loose-envify": "^1.0.0" - } - }, - "node_modules/watchpack": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", - "integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==", - "dev": true, - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", - "dev": true, - "dependencies": { - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", - "dev": true, - "dependencies": { - "defaults": "^1.0.3" - } - }, - "node_modules/webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", - "dev": true, - "engines": { - "node": ">=10.4" - } - }, - "node_modules/webpack": { - "version": "5.66.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.66.0.tgz", - "integrity": "sha512-NJNtGT7IKpGzdW7Iwpn/09OXz9inIkeIQ/ibY6B+MdV1x6+uReqz/5z1L89ezWnpPDWpXF0TY5PCYKQdWVn8Vg==", - "dev": true, - "dependencies": { - "@types/eslint-scope": "^3.7.0", - "@types/estree": "^0.0.50", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.4.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.8.3", - "es-module-lexer": "^0.9.0", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-better-errors": "^1.0.2", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.3.1", - "webpack-sources": "^3.2.2" - }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-dev-middleware": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.0.tgz", - "integrity": "sha512-MouJz+rXAm9B1OTOYaJnn6rtD/lWZPy2ufQCH3BPs8Rloh/Du6Jze4p7AeLYHkVi0giJnYLaSGDC7S+GM9arhg==", - "dev": true, - "dependencies": { - "colorette": "^2.0.10", - "memfs": "^3.2.2", - "mime-types": "^2.1.31", - "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" - } - }, - "node_modules/webpack-dev-middleware/node_modules/ajv": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.9.0.tgz", - "integrity": "sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/webpack-dev-middleware/node_modules/schema-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/webpack-dev-server": { - "version": "4.7.3", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.7.3.tgz", - "integrity": "sha512-mlxq2AsIw2ag016nixkzUkdyOE8ST2GTy34uKSABp1c4nhjZvH90D5ZRR+UOLSsG4Z3TFahAi72a3ymRtfRm+Q==", - "dev": true, - "dependencies": { - "@types/bonjour": "^3.5.9", - "@types/connect-history-api-fallback": "^1.3.5", - "@types/serve-index": "^1.9.1", - "@types/sockjs": "^0.3.33", - "@types/ws": "^8.2.2", - "ansi-html-community": "^0.0.8", - "bonjour": "^3.5.0", - "chokidar": "^3.5.2", - "colorette": "^2.0.10", - "compression": "^1.7.4", - "connect-history-api-fallback": "^1.6.0", - "default-gateway": "^6.0.3", - "del": "^6.0.0", - "express": "^4.17.1", - "graceful-fs": "^4.2.6", - "html-entities": "^2.3.2", - "http-proxy-middleware": "^2.0.0", - "ipaddr.js": "^2.0.1", - "open": "^8.0.9", - "p-retry": "^4.5.0", - "portfinder": "^1.0.28", - "schema-utils": "^4.0.0", - "selfsigned": "^2.0.0", - "serve-index": "^1.9.1", - "sockjs": "^0.3.21", - "spdy": "^4.0.2", - "strip-ansi": "^7.0.0", - "webpack-dev-middleware": "^5.3.0", - "ws": "^8.1.0" - }, - "bin": { - "webpack-dev-server": "bin/webpack-dev-server.js" - }, - "engines": { - "node": ">= 12.13.0" - }, - "peerDependencies": { - "webpack": "^4.37.0 || ^5.0.0" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-dev-server/node_modules/ajv": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.9.0.tgz", - "integrity": "sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack-dev-server/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/webpack-dev-server/node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/webpack-dev-server/node_modules/http-proxy-middleware": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.1.tgz", - "integrity": "sha512-cfaXRVoZxSed/BmkA7SwBVNI9Kj7HFltaE5rqYOub5kWzWZ+gofV2koVN1j2rMW7pEfSSlCHGJ31xmuyFyfLOg==", - "dev": true, - "dependencies": { - "@types/http-proxy": "^1.17.5", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/webpack-dev-server/node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/webpack-dev-server/node_modules/schema-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/webpack-dev-server/node_modules/strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/webpack-dev-server/node_modules/ws": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.4.2.tgz", - "integrity": "sha512-Kbk4Nxyq7/ZWqr/tarI9yIt/+iNNFOjBXEWgTb4ydaNHBNGgvf2QHbS9fdfsndfjFlFwEd4Al+mw83YkaD10ZA==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/webpack-manifest-plugin": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-4.1.1.tgz", - "integrity": "sha512-YXUAwxtfKIJIKkhg03MKuiFAD72PlrqCiwdwO4VEXdRO5V0ORCNwaOwAZawPZalCbmH9kBDmXnNeQOw+BIEiow==", - "dev": true, - "dependencies": { - "tapable": "^2.0.0", - "webpack-sources": "^2.2.0" - }, - "engines": { - "node": ">=12.22.0" - }, - "peerDependencies": { - "webpack": "^4.44.2 || ^5.47.0" - } - }, - "node_modules/webpack-manifest-plugin/node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/webpack-manifest-plugin/node_modules/webpack-sources": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.3.1.tgz", - "integrity": "sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA==", - "dev": true, - "dependencies": { - "source-list-map": "^2.0.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "dev": true, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack/node_modules/acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/webpack/node_modules/acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", - "dev": true, - "peerDependencies": { - "acorn": "^8" - } - }, - "node_modules/webpack/node_modules/enhanced-resolve": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz", - "integrity": "sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack/node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", - "dev": true, - "dependencies": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dev": true, - "dependencies": { - "iconv-lite": "0.4.24" - } - }, - "node_modules/whatwg-fetch": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", - "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==", - "dev": true - }, - "node_modules/whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true - }, - "node_modules/whatwg-url": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", - "dev": true, - "dependencies": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/workbox-background-sync": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-6.4.2.tgz", - "integrity": "sha512-P7c8uG5X2k+DMICH9xeSA9eUlCOjHHYoB42Rq+RtUpuwBxUOflAXR1zdsMWj81LopE4gjKXlTw7BFd1BDAHo7g==", - "dev": true, - "dependencies": { - "idb": "^6.1.4", - "workbox-core": "6.4.2" - } - }, - "node_modules/workbox-broadcast-update": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-6.4.2.tgz", - "integrity": "sha512-qnBwQyE0+PWFFc/n4ISXINE49m44gbEreJUYt2ldGH3+CNrLmJ1egJOOyUqqu9R4Eb7QrXcmB34ClXG7S37LbA==", - "dev": true, - "dependencies": { - "workbox-core": "6.4.2" - } - }, - "node_modules/workbox-build": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-6.4.2.tgz", - "integrity": "sha512-WMdYLhDIsuzViOTXDH+tJ1GijkFp5khSYolnxR/11zmfhNDtuo7jof72xPGFy+KRpsz6tug39RhivCj77qqO0w==", - "dev": true, - "dependencies": { - "@apideck/better-ajv-errors": "^0.3.1", - "@babel/core": "^7.11.1", - "@babel/preset-env": "^7.11.0", - "@babel/runtime": "^7.11.2", - "@rollup/plugin-babel": "^5.2.0", - "@rollup/plugin-node-resolve": "^11.2.1", - "@rollup/plugin-replace": "^2.4.1", - "@surma/rollup-plugin-off-main-thread": "^2.2.3", - "ajv": "^8.6.0", - "common-tags": "^1.8.0", - "fast-json-stable-stringify": "^2.1.0", - "fs-extra": "^9.0.1", - "glob": "^7.1.6", - "lodash": "^4.17.20", - "pretty-bytes": "^5.3.0", - "rollup": "^2.43.1", - "rollup-plugin-terser": "^7.0.0", - "source-map": "^0.8.0-beta.0", - "source-map-url": "^0.4.0", - "stringify-object": "^3.3.0", - "strip-comments": "^2.0.1", - "tempy": "^0.6.0", - "upath": "^1.2.0", - "workbox-background-sync": "6.4.2", - "workbox-broadcast-update": "6.4.2", - "workbox-cacheable-response": "6.4.2", - "workbox-core": "6.4.2", - "workbox-expiration": "6.4.2", - "workbox-google-analytics": "6.4.2", - "workbox-navigation-preload": "6.4.2", - "workbox-precaching": "6.4.2", - "workbox-range-requests": "6.4.2", - "workbox-recipes": "6.4.2", - "workbox-routing": "6.4.2", - "workbox-strategies": "6.4.2", - "workbox-streams": "6.4.2", - "workbox-sw": "6.4.2", - "workbox-window": "6.4.2" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/workbox-build/node_modules/@apideck/better-ajv-errors": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.2.tgz", - "integrity": "sha512-JdEazx7qiVqTBzzBl5rolRwl5cmhihjfIcpqRzIZjtT6b18liVmDn/VlWpqW4C/qP2hrFFMLRV1wlex8ZVBPTg==", - "dev": true, - "dependencies": { - "json-schema": "^0.4.0", - "jsonpointer": "^5.0.0", - "leven": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "ajv": ">=8" - } - }, - "node_modules/workbox-build/node_modules/ajv": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.9.0.tgz", - "integrity": "sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/workbox-build/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/workbox-build/node_modules/source-map": { - "version": "0.8.0-beta.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", - "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", - "dev": true, - "dependencies": { - "whatwg-url": "^7.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/workbox-build/node_modules/tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/workbox-build/node_modules/webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true - }, - "node_modules/workbox-build/node_modules/whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "dev": true, - "dependencies": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, - "node_modules/workbox-cacheable-response": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-6.4.2.tgz", - "integrity": "sha512-9FE1W/cKffk1AJzImxgEN0ceWpyz1tqNjZVtA3/LAvYL3AC5SbIkhc7ZCO82WmO9IjTfu8Vut2X/C7ViMSF7TA==", - "dev": true, - "dependencies": { - "workbox-core": "6.4.2" - } - }, - "node_modules/workbox-core": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-6.4.2.tgz", - "integrity": "sha512-1U6cdEYPcajRXiboSlpJx6U7TvhIKbxRRerfepAJu2hniKwJ3DHILjpU/zx3yvzSBCWcNJDoFalf7Vgd7ey/rw==", - "dev": true - }, - "node_modules/workbox-expiration": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-6.4.2.tgz", - "integrity": "sha512-0hbpBj0tDnW+DZOUmwZqntB/8xrXOgO34i7s00Si/VlFJvvpRKg1leXdHHU8ykoSBd6+F2KDcMP3swoCi5guLw==", - "dev": true, - "dependencies": { - "idb": "^6.1.4", - "workbox-core": "6.4.2" - } - }, - "node_modules/workbox-google-analytics": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-6.4.2.tgz", - "integrity": "sha512-u+gxs3jXovPb1oul4CTBOb+T9fS1oZG+ZE6AzS7l40vnyfJV79DaLBvlpEZfXGv3CjMdV1sT/ltdOrKzo7HcGw==", - "dev": true, - "dependencies": { - "workbox-background-sync": "6.4.2", - "workbox-core": "6.4.2", - "workbox-routing": "6.4.2", - "workbox-strategies": "6.4.2" - } - }, - "node_modules/workbox-navigation-preload": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-6.4.2.tgz", - "integrity": "sha512-viyejlCtlKsbJCBHwhSBbWc57MwPXvUrc8P7d+87AxBGPU+JuWkT6nvBANgVgFz6FUhCvRC8aYt+B1helo166g==", - "dev": true, - "dependencies": { - "workbox-core": "6.4.2" - } - }, - "node_modules/workbox-precaching": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-6.4.2.tgz", - "integrity": "sha512-CZ6uwFN/2wb4noHVlALL7UqPFbLfez/9S2GAzGAb0Sk876ul9ukRKPJJ6gtsxfE2HSTwqwuyNVa6xWyeyJ1XSA==", - "dev": true, - "dependencies": { - "workbox-core": "6.4.2", - "workbox-routing": "6.4.2", - "workbox-strategies": "6.4.2" - } - }, - "node_modules/workbox-range-requests": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-6.4.2.tgz", - "integrity": "sha512-SowF3z69hr3Po/w7+xarWfzxJX/3Fo0uSG72Zg4g5FWWnHpq2zPvgbWerBZIa81zpJVUdYpMa3akJJsv+LaO1Q==", - "dev": true, - "dependencies": { - "workbox-core": "6.4.2" - } - }, - "node_modules/workbox-recipes": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-6.4.2.tgz", - "integrity": "sha512-/oVxlZFpAjFVbY+3PoGEXe8qyvtmqMrTdWhbOfbwokNFtUZ/JCtanDKgwDv9x3AebqGAoJRvQNSru0F4nG+gWA==", - "dev": true, - "dependencies": { - "workbox-cacheable-response": "6.4.2", - "workbox-core": "6.4.2", - "workbox-expiration": "6.4.2", - "workbox-precaching": "6.4.2", - "workbox-routing": "6.4.2", - "workbox-strategies": "6.4.2" - } - }, - "node_modules/workbox-routing": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-6.4.2.tgz", - "integrity": "sha512-0ss/n9PAcHjTy4Ad7l2puuod4WtsnRYu9BrmHcu6Dk4PgWeJo1t5VnGufPxNtcuyPGQ3OdnMdlmhMJ57sSrrSw==", - "dev": true, - "dependencies": { - "workbox-core": "6.4.2" - } - }, - "node_modules/workbox-strategies": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-6.4.2.tgz", - "integrity": "sha512-YXh9E9dZGEO1EiPC3jPe2CbztO5WT8Ruj8wiYZM56XqEJp5YlGTtqRjghV+JovWOqkWdR+amJpV31KPWQUvn1Q==", - "dev": true, - "dependencies": { - "workbox-core": "6.4.2" - } - }, - "node_modules/workbox-streams": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-6.4.2.tgz", - "integrity": "sha512-ROEGlZHGVEgpa5bOZefiJEVsi5PsFjJG9Xd+wnDbApsCO9xq9rYFopF+IRq9tChyYzhBnyk2hJxbQVWphz3sog==", - "dev": true, - "dependencies": { - "workbox-core": "6.4.2", - "workbox-routing": "6.4.2" - } - }, - "node_modules/workbox-sw": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-6.4.2.tgz", - "integrity": "sha512-A2qdu9TLktfIM5NE/8+yYwfWu+JgDaCkbo5ikrky2c7r9v2X6DcJ+zSLphNHHLwM/0eVk5XVf1mC5HGhYpMhhg==", - "dev": true - }, - "node_modules/workbox-webpack-plugin": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-6.4.2.tgz", - "integrity": "sha512-CiEwM6kaJRkx1cP5xHksn13abTzUqMHiMMlp5Eh/v4wRcedgDTyv6Uo8+Hg9MurRbHDosO5suaPyF9uwVr4/CQ==", - "dev": true, - "dependencies": { - "fast-json-stable-stringify": "^2.1.0", - "pretty-bytes": "^5.4.1", - "source-map-url": "^0.4.0", - "upath": "^1.2.0", - "webpack-sources": "^1.4.3", - "workbox-build": "6.4.2" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "webpack": "^4.4.0 || ^5.9.0" - } - }, - "node_modules/workbox-webpack-plugin/node_modules/webpack-sources": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", - "dev": true, - "dependencies": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" - } - }, - "node_modules/workbox-window": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-6.4.2.tgz", - "integrity": "sha512-KVyRKmrJg7iB+uym/B/CnEUEFG9CvnTU1Bq5xpXHbtgD9l+ShDekSl1wYpqw/O0JfeeQVOFb8CiNfvnwWwqnWQ==", - "dev": true, - "dependencies": { - "@types/trusted-types": "^2.0.2", - "workbox-core": "6.4.2" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/ws": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz", - "integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==", - "dev": true, - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true, - "engines": { - "node": ">=0.4" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, - "dependencies": { - "@adobe/css-tools": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.0.1.tgz", - "integrity": "sha512-+u76oB43nOHrF4DDWRLWDCtci7f3QJoEBigemIdIeTi1ODqjx6Tad9NCVnPRwewWlKkVab5PlK8DCtPTyX7S8g==", - "dev": true - }, - "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@babel/compat-data": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.5.tgz", - "integrity": "sha512-KZXo2t10+/jxmkhNXc7pZTqRvSOIvVv/+lJwHS+B2rErwOyjuVRh60yVpb7liQ1U5t7lLJ1bz+t8tSypUZdm0g==", - "dev": true - }, - "@babel/core": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.10.tgz", - "integrity": "sha512-pbiIdZbCiMx/MM6toR+OfXarYix3uz0oVsnNtfdAGTcCTu3w/JGF8JhirevXLBJUu0WguSZI12qpKnx7EeMyLA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.16.8", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helpers": "^7.16.7", - "@babel/parser": "^7.16.10", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.10", - "@babel/types": "^7.16.8", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0", - "source-map": "^0.5.0" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/eslint-parser": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.16.5.tgz", - "integrity": "sha512-mUqYa46lgWqHKQ33Q6LNCGp/wPR3eqOYTUixHFsfrSQqRxH0+WOzca75iEjFr5RDGH1dDz622LaHhLOzOuQRUA==", - "dev": true, - "requires": { - "eslint-scope": "^5.1.1", - "eslint-visitor-keys": "^2.1.0", - "semver": "^6.3.0" - } - }, - "@babel/eslint-plugin": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/eslint-plugin/-/eslint-plugin-7.16.5.tgz", - "integrity": "sha512-R1p6RMyU1Xl1U/NNr+D4+HjkQzN5dQOX0MpjW9WLWhHDjhzN9gso96MxxOFvPh0fKF/mMH8TGW2kuqQ2eK2s9A==", - "dev": true, - "requires": { - "eslint-rule-composer": "^0.3.0" - } - }, - "@babel/generator": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.5.tgz", - "integrity": "sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==", - "requires": { - "@babel/types": "^7.20.5", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" - } - }, - "@babel/helper-annotate-as-pure": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", - "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", - "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", - "dev": true, - "requires": { - "@babel/helper-explode-assignable-expression": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz", - "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.20.0", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "semver": "^6.3.0" - } - }, - "@babel/helper-create-class-features-plugin": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.5.tgz", - "integrity": "sha512-3RCdA/EmEaikrhayahwToF0fpweU/8o2p8vhc1c/1kftHOdTKuC65kik/TLc+qfbS8JKw4qqJbne4ovICDhmww==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-member-expression-to-functions": "^7.18.9", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-replace-supers": "^7.19.1", - "@babel/helper-split-export-declaration": "^7.18.6" - } - }, - "@babel/helper-create-regexp-features-plugin": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.16.7.tgz", - "integrity": "sha512-fk5A6ymfp+O5+p2yCkXAu5Kyj6v0xh0RBeNcAkYUMDvvAAoxvSKXn+Jb37t/yWFiQVDFK1ELpUTD8/aLhCPu+g==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "regexpu-core": "^4.7.1" - } - }, - "@babel/helper-define-polyfill-provider": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", - "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", - "dev": true, - "requires": { - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-plugin-utils": "^7.16.7", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - } - }, - "@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==" - }, - "@babel/helper-explode-assignable-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", - "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", - "requires": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", - "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", - "dev": true, - "requires": { - "@babel/types": "^7.18.9" - } - }, - "@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-module-transforms": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz", - "integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==", - "dev": true, - "requires": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", - "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", - "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", - "dev": true - }, - "@babel/helper-remap-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", - "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-wrap-function": "^7.16.8", - "@babel/types": "^7.16.8" - } - }, - "@babel/helper-replace-supers": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz", - "integrity": "sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==", - "dev": true, - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-member-expression-to-functions": "^7.18.9", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/traverse": "^7.19.1", - "@babel/types": "^7.19.0" - } - }, - "@babel/helper-simple-access": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", - "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", - "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", - "dev": true, - "requires": { - "@babel/types": "^7.16.0" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==" - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==" - }, - "@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", - "dev": true - }, - "@babel/helper-wrap-function": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz", - "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.8", - "@babel/types": "^7.16.8" - } - }, - "@babel/helpers": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.7.tgz", - "integrity": "sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw==", - "dev": true, - "requires": { - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==" - }, - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz", - "integrity": "sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz", - "integrity": "sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.7" - } - }, - "@babel/plugin-proposal-async-generator-functions": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz", - "integrity": "sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8", - "@babel/plugin-syntax-async-generators": "^7.8.4" - } - }, - "@babel/plugin-proposal-class-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz", - "integrity": "sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww==", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-proposal-class-static-block": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.7.tgz", - "integrity": "sha512-dgqJJrcZoG/4CkMopzhPJjGxsIe9A8RlkQLnL/Vhhx8AA9ZuaRwGSlscSh42hazc7WSrya/IK7mTeoF0DP9tEw==", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - } - }, - "@babel/plugin-proposal-decorators": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.20.5.tgz", - "integrity": "sha512-Lac7PpRJXcC3s9cKsBfl+uc+DYXU5FD06BrTFunQO6QIQT+DwyzDPURAowI3bcvD1dZF/ank1Z5rstUJn3Hn4Q==", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.20.5", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-replace-supers": "^7.19.1", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/plugin-syntax-decorators": "^7.19.0" - } - }, - "@babel/plugin-proposal-dynamic-import": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", - "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - } - }, - "@babel/plugin-proposal-export-namespace-from": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz", - "integrity": "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - } - }, - "@babel/plugin-proposal-json-strings": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz", - "integrity": "sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-json-strings": "^7.8.3" - } - }, - "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz", - "integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - } - }, - "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz", - "integrity": "sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - } - }, - "@babel/plugin-proposal-numeric-separator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", - "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - } - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.7.tgz", - "integrity": "sha512-3O0Y4+dw94HA86qSg9IHfyPktgR7q3gpNVAeiKQd+8jBKFaU5NQS1Yatgo4wY+UFNuLjvxcSmzcsHqrhgTyBUA==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.16.4", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.16.7" - } - }, - "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", - "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - } - }, - "@babel/plugin-proposal-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz", - "integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - } - }, - "@babel/plugin-proposal-private-methods": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.7.tgz", - "integrity": "sha512-7twV3pzhrRxSwHeIvFE6coPgvo+exNDOiGUMg39o2LiLo1Y+4aKpfkcLGcg1UHonzorCt7SNXnoMyCnnIOA8Sw==", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-proposal-private-property-in-object": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz", - "integrity": "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - } - }, - "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz", - "integrity": "sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-decorators": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.19.0.tgz", - "integrity": "sha512-xaBZUEDntt4faL1yN8oIFlhfXeQAWJW7CLKYsHTUqriCUbj8xOra8bfxxKGi/UwExPFBuPdH4XfHc9rGQhrVkQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.19.0" - } - }, - "@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" - } - }, - "@babel/plugin-syntax-flow": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.18.6.tgz", - "integrity": "sha512-LUbR+KNTBWCUAqRG9ex5Gnzu2IOkt8jRJbHHXFT9q+L9zm7M/QQbEqXyw1n1pohYvOyWC8CjeyjrSaIwiYjK7A==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz", - "integrity": "sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-typescript": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", - "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.19.0" - } - }, - "@babel/plugin-transform-arrow-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz", - "integrity": "sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz", - "integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8" - } - }, - "@babel/plugin-transform-block-scoped-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", - "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-block-scoping": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz", - "integrity": "sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-classes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz", - "integrity": "sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "globals": "^11.1.0" - } - }, - "@babel/plugin-transform-computed-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz", - "integrity": "sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-destructuring": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.7.tgz", - "integrity": "sha512-VqAwhTHBnu5xBVDCvrvqJbtLUa++qZaWC0Fgr2mqokBlulZARGyIvZDoqbPlPaKImQ9dKAcCzbv+ul//uqu70A==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-dotall-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", - "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-duplicate-keys": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz", - "integrity": "sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-exponentiation-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", - "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", - "dev": true, - "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-flow-strip-types": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.19.0.tgz", - "integrity": "sha512-sgeMlNaQVbCSpgLSKP4ZZKfsJVnFnNQlUSk6gPYzR/q7tzCgQF2t8RBKAP6cKJeZdveei7Q7Jm527xepI8lNLg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/plugin-syntax-flow": "^7.18.6" - } - }, - "@babel/plugin-transform-for-of": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz", - "integrity": "sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", - "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", - "dev": true, - "requires": { - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz", - "integrity": "sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-member-expression-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", - "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-modules-amd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz", - "integrity": "sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-commonjs": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz", - "integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-systemjs": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz", - "integrity": "sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw==", - "dev": true, - "requires": { - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-umd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz", - "integrity": "sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz", - "integrity": "sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7" - } - }, - "@babel/plugin-transform-new-target": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz", - "integrity": "sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-object-super": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", - "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7" - } - }, - "@babel/plugin-transform-parameters": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz", - "integrity": "sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-property-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", - "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-react-constant-elements": { - "version": "7.13.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.13.13.tgz", - "integrity": "sha512-SNJU53VM/SjQL0bZhyU+f4kJQz7bQQajnrZRSaU21hruG/NWY41AEM9AWXeXX90pYr/C2yAmTgI6yW3LlLrAUQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.13.0" - } - }, - "@babel/plugin-transform-react-display-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.7.tgz", - "integrity": "sha512-qgIg8BcZgd0G/Cz916D5+9kqX0c7nPZyXaP8R2tLNN5tkyIZdG5fEwBrxwplzSnjC1jvQmyMNVwUCZPcbGY7Pg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-react-jsx": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.16.7.tgz", - "integrity": "sha512-8D16ye66fxiE8m890w0BpPpngG9o9OVBBy0gH2E+2AR7qMR2ZpTYJEqLxAsoroenMId0p/wMW+Blc0meDgu0Ag==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-jsx": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/plugin-transform-react-jsx-development": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.7.tgz", - "integrity": "sha512-RMvQWvpla+xy6MlBpPlrKZCMRs2AGiHOGHY3xRwl0pEeim348dDyxeH4xBsMPbIMhujeq7ihE702eM2Ew0Wo+A==", - "dev": true, - "requires": { - "@babel/plugin-transform-react-jsx": "^7.16.7" - } - }, - "@babel/plugin-transform-react-pure-annotations": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.7.tgz", - "integrity": "sha512-hs71ToC97k3QWxswh2ElzMFABXHvGiJ01IB1TbYQDGeWRKWz/MPUTh5jGExdHvosYKpnJW5Pm3S4+TA3FyX+GA==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-regenerator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz", - "integrity": "sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q==", - "dev": true, - "requires": { - "regenerator-transform": "^0.14.2" - } - }, - "@babel/plugin-transform-reserved-words": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz", - "integrity": "sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-runtime": { - "version": "7.19.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.6.tgz", - "integrity": "sha512-PRH37lz4JU156lYFW1p8OxE5i7d6Sl/zV58ooyr+q1J1lnQPyg5tIiXlIwNVhJaY4W3TmOtdc8jqdXQcB1v5Yw==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.19.0", - "babel-plugin-polyfill-corejs2": "^0.3.3", - "babel-plugin-polyfill-corejs3": "^0.6.0", - "babel-plugin-polyfill-regenerator": "^0.4.1", - "semver": "^6.3.0" - }, - "dependencies": { - "babel-plugin-polyfill-corejs3": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", - "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", - "dev": true, - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.3", - "core-js-compat": "^3.25.1" - } - }, - "babel-plugin-polyfill-regenerator": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", - "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", - "dev": true, - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.3" - } - } - } - }, - "@babel/plugin-transform-shorthand-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", - "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-spread": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz", - "integrity": "sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" - } - }, - "@babel/plugin-transform-sticky-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", - "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-template-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz", - "integrity": "sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-typeof-symbol": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz", - "integrity": "sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-typescript": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.20.2.tgz", - "integrity": "sha512-jvS+ngBfrnTUBfOQq8NfGnSbF9BrqlR6hjJ2yVxMkmO5nL/cdifNbI30EfjRlN4g5wYWNnMPyj5Sa6R1pbLeag==", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.20.2", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-typescript": "^7.20.0" - } - }, - "@babel/plugin-transform-unicode-escapes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", - "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-unicode-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", - "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/polyfill": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.12.1.tgz", - "integrity": "sha512-X0pi0V6gxLi6lFZpGmeNa4zxtwEmCs42isWLNjZZDE0Y8yVfgu0T2OAHlzBbdYlqbW/YXVvoBHpATEM+goCj8g==", - "dev": true, - "requires": { - "core-js": "^2.6.5", - "regenerator-runtime": "^0.13.4" - } - }, - "@babel/preset-env": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.10.tgz", - "integrity": "sha512-iCac3fZn9oOcLqc1N2/copPiX7aoxzsvjeDdXoZobrlbQ6YGgS3bL9HyldOJ8V8AY5P7pFynCATrn7M4dMw0Yg==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.16.8", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-async-generator-functions": "^7.16.8", - "@babel/plugin-proposal-class-properties": "^7.16.7", - "@babel/plugin-proposal-class-static-block": "^7.16.7", - "@babel/plugin-proposal-dynamic-import": "^7.16.7", - "@babel/plugin-proposal-export-namespace-from": "^7.16.7", - "@babel/plugin-proposal-json-strings": "^7.16.7", - "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", - "@babel/plugin-proposal-numeric-separator": "^7.16.7", - "@babel/plugin-proposal-object-rest-spread": "^7.16.7", - "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", - "@babel/plugin-proposal-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-private-methods": "^7.16.7", - "@babel/plugin-proposal-private-property-in-object": "^7.16.7", - "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.16.7", - "@babel/plugin-transform-async-to-generator": "^7.16.8", - "@babel/plugin-transform-block-scoped-functions": "^7.16.7", - "@babel/plugin-transform-block-scoping": "^7.16.7", - "@babel/plugin-transform-classes": "^7.16.7", - "@babel/plugin-transform-computed-properties": "^7.16.7", - "@babel/plugin-transform-destructuring": "^7.16.7", - "@babel/plugin-transform-dotall-regex": "^7.16.7", - "@babel/plugin-transform-duplicate-keys": "^7.16.7", - "@babel/plugin-transform-exponentiation-operator": "^7.16.7", - "@babel/plugin-transform-for-of": "^7.16.7", - "@babel/plugin-transform-function-name": "^7.16.7", - "@babel/plugin-transform-literals": "^7.16.7", - "@babel/plugin-transform-member-expression-literals": "^7.16.7", - "@babel/plugin-transform-modules-amd": "^7.16.7", - "@babel/plugin-transform-modules-commonjs": "^7.16.8", - "@babel/plugin-transform-modules-systemjs": "^7.16.7", - "@babel/plugin-transform-modules-umd": "^7.16.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.8", - "@babel/plugin-transform-new-target": "^7.16.7", - "@babel/plugin-transform-object-super": "^7.16.7", - "@babel/plugin-transform-parameters": "^7.16.7", - "@babel/plugin-transform-property-literals": "^7.16.7", - "@babel/plugin-transform-regenerator": "^7.16.7", - "@babel/plugin-transform-reserved-words": "^7.16.7", - "@babel/plugin-transform-shorthand-properties": "^7.16.7", - "@babel/plugin-transform-spread": "^7.16.7", - "@babel/plugin-transform-sticky-regex": "^7.16.7", - "@babel/plugin-transform-template-literals": "^7.16.7", - "@babel/plugin-transform-typeof-symbol": "^7.16.7", - "@babel/plugin-transform-unicode-escapes": "^7.16.7", - "@babel/plugin-transform-unicode-regex": "^7.16.7", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.16.8", - "babel-plugin-polyfill-corejs2": "^0.3.0", - "babel-plugin-polyfill-corejs3": "^0.5.0", - "babel-plugin-polyfill-regenerator": "^0.3.0", - "core-js-compat": "^3.20.2", - "semver": "^6.3.0" - } - }, - "@babel/preset-modules": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - } - }, - "@babel/preset-react": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.16.7.tgz", - "integrity": "sha512-fWpyI8UM/HE6DfPBzD8LnhQ/OcH8AgTaqcqP2nGOXEUV+VKBR5JRN9hCk9ai+zQQ57vtm9oWeXguBCPNUjytgA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-transform-react-display-name": "^7.16.7", - "@babel/plugin-transform-react-jsx": "^7.16.7", - "@babel/plugin-transform-react-jsx-development": "^7.16.7", - "@babel/plugin-transform-react-pure-annotations": "^7.16.7" - } - }, - "@babel/preset-typescript": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.18.6.tgz", - "integrity": "sha512-s9ik86kXBAnD760aybBucdpnLsAt0jK1xqJn2juOn9lkOvSHV60os5hxoVJsPzMQxvnUJFAlkont2DvvaYEBtQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-validator-option": "^7.18.6", - "@babel/plugin-transform-typescript": "^7.18.6" - } - }, - "@babel/runtime": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.7.tgz", - "integrity": "sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==", - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, - "@babel/runtime-corejs3": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.14.0.tgz", - "integrity": "sha512-0R0HTZWHLk6G8jIk0FtoX+AatCtKnswS98VhXwGImFc759PJRp4Tru0PQYZofyijTFUr+gT8Mu7sgXVJLQ0ceg==", - "dev": true, - "requires": { - "core-js-pure": "^3.0.0", - "regenerator-runtime": "^0.13.4" - } - }, - "@babel/template": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" - } - }, - "@babel/traverse": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.5.tgz", - "integrity": "sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==", - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.5", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.5", - "@babel/types": "^7.20.5", - "debug": "^4.1.0", - "globals": "^11.1.0" - } - }, - "@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", - "requires": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - } - }, - "@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "@codemirror/autocomplete": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.0.2.tgz", - "integrity": "sha512-9PDjnllmXan/7Uax87KGORbxerDJ/cu10SB+n4Jz0zXMEvIh3+TGgZxhIvDOtaQ4jDBQEM7kHYW4vLdQB0DGZQ==", - "requires": { - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "@lezer/common": "^1.0.0" - } - }, - "@codemirror/commands": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.0.1.tgz", - "integrity": "sha512-iNHDByicYqQjs0Wo1MKGfqNbMYMyhS9WV6EwMVwsHXImlFemgEUC+c5X22bXKBStN3qnwg4fArNZM+gkv22baQ==", - "requires": { - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "@lezer/common": "^1.0.0" - } - }, - "@codemirror/language": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.2.0.tgz", - "integrity": "sha512-tabB0Ef/BflwoEmTB4a//WZ9P90UQyne9qWB9YFsmeS4bnEqSys7UpGk/da1URMXhyfuzWCwp+AQNMhvu8SfnA==", - "requires": { - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "@lezer/common": "^1.0.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0", - "style-mod": "^4.0.0" - } - }, - "@codemirror/lint": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.0.0.tgz", - "integrity": "sha512-nUUXcJW1Xp54kNs+a1ToPLK8MadO0rMTnJB8Zk4Z8gBdrN0kqV7uvUraU/T2yqg+grDNR38Vmy/MrhQN/RgwiA==", - "requires": { - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "crelt": "^1.0.5" - } - }, - "@codemirror/search": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.0.0.tgz", - "integrity": "sha512-rL0rd3AhI0TAsaJPUaEwC63KHLO7KL0Z/dYozXj6E7L3wNHRyx7RfE0/j5HsIf912EE5n2PCb4Vg0rGYmDv4UQ==", - "requires": { - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "crelt": "^1.0.5" - } - }, - "@codemirror/state": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.1.0.tgz", - "integrity": "sha512-qbUr94DZTe6/V1VS7LDLz11rM/1t/nJxR1El4I6UaxDEdc0aZZvq6JCLJWiRmUf95NRAnDH6fhXn+PWp9wGCIg==" - }, - "@codemirror/view": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.0.2.tgz", - "integrity": "sha512-mnVT/q1JvKPjpmjXJNeCi/xHyaJ3abGJsumIVpdQ1nE1MXAyHf7GHWt8QpWMUvDiqF0j+inkhVR2OviTdFFX7Q==", - "requires": { - "@codemirror/state": "^6.0.0", - "style-mod": "^4.0.0", - "w3c-keyname": "^2.2.4" - } - }, - "@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "dependencies": { - "@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - } - } - }, - "@csstools/normalize.css": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-12.0.0.tgz", - "integrity": "sha512-M0qqxAcwCsIVfpFQSlGN5XjXWu8l5JDZN+fPt1LeW5SZexQTgnaEvgXAY+CeygRw0EeppWHi12JxESWiWrB0Sg==", - "dev": true - }, - "@cypress/instrument-cra": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@cypress/instrument-cra/-/instrument-cra-1.4.0.tgz", - "integrity": "sha512-gXf540xL0jcUXkWyrA2Ug9rzs+jRkc9EPhnRi8XfbnRjdF4lvnn108N6x0lgTApMTbbpCDbVuskHGXDmIuD3CQ==", - "dev": true, - "requires": { - "babel-plugin-istanbul": "6.0.0", - "debug": "4.2.0", - "find-yarn-workspace-root": "^2.0.0" - }, - "dependencies": { - "debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - } - } - }, - "@emotion/is-prop-valid": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.1.2.tgz", - "integrity": "sha512-3QnhqeL+WW88YjYbQL5gUIkthuMw7a0NGbZ7wfFVk2kg/CK5w8w5FFa0RzWjyY1+sujN0NWbtSHH6OJmWHtJpQ==", - "requires": { - "@emotion/memoize": "^0.7.4" - } - }, - "@emotion/memoize": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.5.tgz", - "integrity": "sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==" - }, - "@emotion/stylis": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz", - "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==" - }, - "@emotion/unitless": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", - "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" - }, - "@eslint/eslintrc": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.5.tgz", - "integrity": "sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.2.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "globals": { - "version": "13.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz", - "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - } - } - }, - "@humanwhocodes/config-array": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.2.tgz", - "integrity": "sha512-UXOuFCGcwciWckOpmfKDq/GyhlTf9pN/BzG//x8p8zTOFEcGuA68ANXheFS0AGvy3qgZqLBUkMs7hqzqCKOVwA==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - } - }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "dependencies": { - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true - }, - "@jest/console": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.4.6.tgz", - "integrity": "sha512-jauXyacQD33n47A44KrlOVeiXHEXDqapSdfb9kTekOchH/Pd18kBIO1+xxJQRLuG+LUuljFCwTG92ra4NW7SpA==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^27.4.6", - "jest-util": "^27.4.2", - "slash": "^3.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/core": { - "version": "27.4.7", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.4.7.tgz", - "integrity": "sha512-n181PurSJkVMS+kClIFSX/LLvw9ExSb+4IMtD6YnfxZVerw9ANYtW0bPrm0MJu2pfe9SY9FJ9FtQ+MdZkrZwjg==", - "dev": true, - "requires": { - "@jest/console": "^27.4.6", - "@jest/reporters": "^27.4.6", - "@jest/test-result": "^27.4.6", - "@jest/transform": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.8.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-changed-files": "^27.4.2", - "jest-config": "^27.4.7", - "jest-haste-map": "^27.4.6", - "jest-message-util": "^27.4.6", - "jest-regex-util": "^27.4.0", - "jest-resolve": "^27.4.6", - "jest-resolve-dependencies": "^27.4.6", - "jest-runner": "^27.4.6", - "jest-runtime": "^27.4.6", - "jest-snapshot": "^27.4.6", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.6", - "jest-watcher": "^27.4.6", - "micromatch": "^4.0.4", - "rimraf": "^3.0.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "jest-get-type": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", - "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", - "dev": true - }, - "jest-validate": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.4.6.tgz", - "integrity": "sha512-872mEmCPVlBqbA5dToC57vA3yJaMRfIdpCoD3cyHWJOMx+SJwLNw0I71EkWs41oza/Er9Zno9XuTkRYCPDUJXQ==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", - "leven": "^3.1.0", - "pretty-format": "^27.4.6" - } - }, - "pretty-format": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz", - "integrity": "sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/environment": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.4.6.tgz", - "integrity": "sha512-E6t+RXPfATEEGVidr84WngLNWZ8ffCPky8RqqRK6u1Bn0LK92INe0MDttyPl/JOzaq92BmDzOeuqk09TvM22Sg==", - "dev": true, - "requires": { - "@jest/fake-timers": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/node": "*", - "jest-mock": "^27.4.6" - }, - "dependencies": { - "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/fake-timers": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.4.6.tgz", - "integrity": "sha512-mfaethuYF8scV8ntPpiVGIHQgS0XIALbpY2jt2l7wb/bvq4Q5pDLk4EP4D7SAvYT1QrPOPVZAtbdGAOOyIgs7A==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "@sinonjs/fake-timers": "^8.0.1", - "@types/node": "*", - "jest-message-util": "^27.4.6", - "jest-mock": "^27.4.6", - "jest-util": "^27.4.2" - }, - "dependencies": { - "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/globals": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.4.6.tgz", - "integrity": "sha512-kAiwMGZ7UxrgPzu8Yv9uvWmXXxsy0GciNejlHvfPIfWkSxChzv6bgTS3YqBkGuHcis+ouMFI2696n2t+XYIeFw==", - "dev": true, - "requires": { - "@jest/environment": "^27.4.6", - "@jest/types": "^27.4.2", - "expect": "^27.4.6" - }, - "dependencies": { - "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/reporters": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.4.6.tgz", - "integrity": "sha512-+Zo9gV81R14+PSq4wzee4GC2mhAN9i9a7qgJWL90Gpx7fHYkWpTBvwWNZUXvJByYR9tAVBdc8VxDWqfJyIUrIQ==", - "dev": true, - "requires": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^27.4.6", - "@jest/test-result": "^27.4.6", - "@jest/transform": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.2.4", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-haste-map": "^27.4.6", - "jest-resolve": "^27.4.6", - "jest-util": "^27.4.2", - "jest-worker": "^27.4.6", - "slash": "^3.0.0", - "source-map": "^0.6.0", - "string-length": "^4.0.1", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^8.1.0" - }, - "dependencies": { - "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", - "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/source-map": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.4.0.tgz", - "integrity": "sha512-Ntjx9jzP26Bvhbm93z/AKcPRj/9wrkI88/gK60glXDx1q+IeI0rf7Lw2c89Ch6ofonB0On/iRDreQuQ6te9pgQ==", - "dev": true, - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.2.4", - "source-map": "^0.6.0" - } - }, - "@jest/test-result": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.4.6.tgz", - "integrity": "sha512-fi9IGj3fkOrlMmhQqa/t9xum8jaJOOAi/lZlm6JXSc55rJMXKHxNDN1oCP39B0/DhNOa2OMupF9BcKZnNtXMOQ==", - "dev": true, - "requires": { - "@jest/console": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/test-sequencer": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.4.6.tgz", - "integrity": "sha512-3GL+nsf6E1PsyNsJuvPyIz+DwFuCtBdtvPpm/LMXVkBJbdFvQYCDpccYT56qq5BGniXWlE81n2qk1sdXfZebnw==", - "dev": true, - "requires": { - "@jest/test-result": "^27.4.6", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.6", - "jest-runtime": "^27.4.6" - } - }, - "@jest/transform": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.4.6.tgz", - "integrity": "sha512-9MsufmJC8t5JTpWEQJ0OcOOAXaH5ioaIX6uHVBLBMoCZPfKKQF+EqP8kACAvCZ0Y1h2Zr3uOccg8re+Dr5jxyw==", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/types": "^27.4.2", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.6", - "jest-regex-util": "^27.4.0", - "jest-util": "^27.4.2", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", - "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" - }, - "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" - }, - "@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", - "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" - }, - "@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", - "requires": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - } - }, - "@lezer/common": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.0.tgz", - "integrity": "sha512-ohydQe+Hb+w4oMDvXzs8uuJd2NoA3D8YDcLiuDsLqH+yflDTPEpgCsWI3/6rH5C3BAedtH1/R51dxENldQceEA==" - }, - "@lezer/highlight": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.0.0.tgz", - "integrity": "sha512-nsCnNtim90UKsB5YxoX65v3GEIw3iCHw9RM2DtdgkiqAbKh9pCdvi8AWNwkYf10Lu6fxNhXPpkpHbW6mihhvJA==", - "requires": { - "@lezer/common": "^1.0.0" - } - }, - "@lezer/lr": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.1.0.tgz", - "integrity": "sha512-Iad04uVwk1PvSnj25mqj7zEEIRAsasbsTRmVzI0AUTs/+1Dz1//iYAaoLr7A+Xa7bZDfql5MKTxZmSlkYZD3Dg==", - "requires": { - "@lezer/common": "^1.0.0" - } - }, - "@lingui/babel-plugin-extract-messages": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/@lingui/babel-plugin-extract-messages/-/babel-plugin-extract-messages-3.15.0.tgz", - "integrity": "sha512-iMQmJIkC18Zwc/IDpm3Oclj3KMDQuvipCS2yVHr0MyaeOCeOZ3ZoLVeaa8pfE5pImzlHJ0ss8RRm/St54JElhw==", - "dev": true, - "requires": { - "@babel/generator": "^7.11.6", - "@babel/runtime": "^7.11.2", - "@lingui/conf": "^3.15.0", - "mkdirp": "^1.0.4" - } - }, - "@lingui/cli": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/@lingui/cli/-/cli-3.15.0.tgz", - "integrity": "sha512-6arKc0Mc1z3ABHobjPkhViV+7VUjBhwFwoU0VlT7HBmtrOYad9CBwWEiD+oiEhiHYzLTR7lHTVf674IjTuVvJQ==", - "dev": true, - "requires": { - "@babel/generator": "^7.11.6", - "@babel/parser": "^7.11.5", - "@babel/plugin-syntax-jsx": "^7.10.4", - "@babel/runtime": "^7.11.2", - "@babel/types": "^7.11.5", - "@lingui/babel-plugin-extract-messages": "^3.15.0", - "@lingui/conf": "^3.15.0", - "babel-plugin-macros": "^3.0.1", - "bcp-47": "^1.0.7", - "chalk": "^4.1.0", - "chokidar": "3.5.1", - "cli-table": "0.3.6", - "commander": "^6.1.0", - "date-fns": "^2.16.1", - "fs-extra": "^9.0.1", - "fuzzaldrin": "^2.1.0", - "glob": "^7.1.4", - "inquirer": "^7.3.3", - "make-plural": "^6.2.2", - "messageformat-parser": "^4.1.3", - "micromatch": "4.0.2", - "mkdirp": "^1.0.4", - "node-gettext": "^3.0.0", - "normalize-path": "^3.0.0", - "ora": "^5.1.0", - "papaparse": "^5.3.0", - "pkg-up": "^3.1.0", - "plurals-cldr": "^1.0.4", - "pofile": "^1.1.0", - "pseudolocale": "^1.1.0", - "ramda": "^0.27.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@lingui/conf": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/@lingui/conf/-/conf-3.15.0.tgz", - "integrity": "sha512-gDGBbqWo6+B3PNjxTGl2asVdd8hC6w+iGsEPonvMw7GFmXb99qybBGdV2ofDlwlT9vChcPwMVtrYE6H0fTZuzA==", - "dev": true, - "requires": { - "@babel/runtime": "^7.11.2", - "chalk": "^4.1.0", - "cosmiconfig": "^7.0.0", - "cosmiconfig-typescript-loader": "^2.0.1", - "jest-validate": "^26.5.2", - "lodash.get": "^4.4.2" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@lingui/core": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/@lingui/core/-/core-3.14.0.tgz", - "integrity": "sha512-ertREq9oi9B/umxpd/pInm9uFO8FLK2/0FXfDmMqvH5ydswWn/c9nY5YO4W1h4/8LWO45mewypOIyjoue4De1w==", - "requires": { - "@babel/runtime": "^7.11.2", - "make-plural": "^6.2.2", - "messageformat-parser": "^4.1.3" - } - }, - "@lingui/loader": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/@lingui/loader/-/loader-3.15.0.tgz", - "integrity": "sha512-Yg7KhinDQmRfqr51bofvD50CuzC1rF8nlFoPsZgLSjpIn4xKdzoCpRaRftRc6sOS5EnoKaK92QwXNv2Ayalz6A==", - "dev": true, - "requires": { - "@babel/runtime": "^7.11.2", - "@lingui/cli": "^3.15.0", - "@lingui/conf": "^3.15.0", - "loader-utils": "^2.0.0" - } - }, - "@lingui/macro": { - "version": "3.8.10", - "resolved": "https://registry.npmjs.org/@lingui/macro/-/macro-3.8.10.tgz", - "integrity": "sha512-oZZ/F7HsNQkDsnHFroxzGFuEIXM624H72RIj8j2ClpR64nt+xYDxXYC6TYFicQLtBGcKKBTBoM+zbDaoIv74qQ==", - "dev": true, - "requires": { - "@babel/runtime": "^7.11.2", - "@lingui/conf": "^3.8.10", - "ramda": "^0.27.1" - } - }, - "@lingui/react": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/@lingui/react/-/react-3.14.0.tgz", - "integrity": "sha512-ow9Mtru7f0T2S9AwnPWRejppcucCW0LmoDR3P4wqHjL+eH5f8a6nxd2doxGieC91/2i4qqW88y4K/zXJxwRSQw==", - "requires": { - "@babel/runtime": "^7.11.2", - "@lingui/core": "^3.14.0" - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@nteract/mockument": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@nteract/mockument/-/mockument-1.0.4.tgz", - "integrity": "sha1-9/hf2T5Dgo7HQcX0xXMRgu2w7LI=", - "dev": true - }, - "@patternfly/patternfly": { - "version": "4.217.1", - "resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-4.217.1.tgz", - "integrity": "sha512-uN7JgfQsyR16YHkuGRCTIcBcnyKIqKjGkB2SGk9x1XXH3yYGenL83kpAavX9Xtozqp17KppOlybJuzcKvZMrgw==" - }, - "@patternfly/react-core": { - "version": "4.264.0", - "resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-4.264.0.tgz", - "integrity": "sha512-tK0BMWxw8nhukev40HZ6q6d02pDnjX7oyA91vHa18aakJUKBWMaerqpG4NZVMoh0tPKX3aLNj+zyCwDALFAZZw==", - "requires": { - "@patternfly/react-icons": "^4.93.0", - "@patternfly/react-styles": "^4.92.0", - "@patternfly/react-tokens": "^4.94.0", - "focus-trap": "6.9.2", - "react-dropzone": "9.0.0", - "tippy.js": "5.1.2", - "tslib": "^2.0.0" - }, - "dependencies": { - "@patternfly/react-icons": { - "version": "4.93.0", - "resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-4.93.0.tgz", - "integrity": "sha512-OH0vORVioL+HLWMEog8/3u8jsiMCeJ0pFpvRKRhy5Uk4CdAe40k1SOBvXJP6opr+O8TLbz0q3bm8Jsh/bPaCuQ==", - "requires": {} - }, - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" - } - } - }, - "@patternfly/react-icons": { - "version": "4.92.10", - "resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-4.92.10.tgz", - "integrity": "sha512-vwCy7b+OyyuvLDSLqLUG2DkJZgMDogjld8tJTdAaG8HiEhC1sJPZac+5wD7AuS3ym/sQolS4vYtNiVDnMEORxA==", - "requires": {} - }, - "@patternfly/react-styles": { - "version": "4.92.0", - "resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-4.92.0.tgz", - "integrity": "sha512-B/f6iyu8UEN1+wRxdC4sLIhvJeyL8SqInDXZmwOIqK8uPJ8Lze7qrbVhkkVzbMF37/oDPVa6dZH8qZFq062LEA==" - }, - "@patternfly/react-table": { - "version": "4.108.0", - "resolved": "https://registry.npmjs.org/@patternfly/react-table/-/react-table-4.108.0.tgz", - "integrity": "sha512-EUvd3rlkE1UXobAm7L6JHgNE3TW8IYTaVwwH/px4Mkn5mBayDO6f+w6QM3OeoDQVZcXK6IYFe7QQaYd/vWIJCQ==", - "requires": { - "@patternfly/react-core": "^4.239.0", - "@patternfly/react-icons": "^4.90.0", - "@patternfly/react-styles": "^4.89.0", - "@patternfly/react-tokens": "^4.91.0", - "lodash": "^4.17.19", - "tslib": "^2.0.0" - }, - "dependencies": { - "tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" - } - } - }, - "@patternfly/react-tokens": { - "version": "4.94.0", - "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-4.94.0.tgz", - "integrity": "sha512-fYXxUJZnzpn89K2zzHF0cSncZZVGKrohdb5f5T1wzxwU2NZPVGpvr88xhm+V2Y/fSrrTPwXcP3IIdtNOOtJdZw==" - }, - "@pmmmwh/react-refresh-webpack-plugin": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.4.tgz", - "integrity": "sha512-zZbZeHQDnoTlt2AF+diQT0wsSXpvWiaIOZwBRdltNFhG1+I3ozyaw7U/nBiUwyJ0D+zwdXp0E3bWOl38Ag2BMw==", - "dev": true, - "requires": { - "ansi-html-community": "^0.0.8", - "common-path-prefix": "^3.0.0", - "core-js-pure": "^3.8.1", - "error-stack-parser": "^2.0.6", - "find-up": "^5.0.0", - "html-entities": "^2.1.0", - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0", - "source-map": "^0.7.3" - }, - "dependencies": { - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true - } - } - }, - "@rollup/plugin-babel": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.0.tgz", - "integrity": "sha512-9uIC8HZOnVLrLHxayq/PTzw+uS25E14KPUBh5ktF+18Mjo5yK0ToMMx6epY0uEgkjwJw0aBW4x2horYXh8juWw==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.10.4", - "@rollup/pluginutils": "^3.1.0" - } - }, - "@rollup/plugin-node-resolve": { - "version": "11.2.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", - "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", - "dev": true, - "requires": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "builtin-modules": "^3.1.0", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.19.0" - }, - "dependencies": { - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true - } - } - }, - "@rollup/plugin-replace": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", - "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==", - "dev": true, - "requires": { - "@rollup/pluginutils": "^3.1.0", - "magic-string": "^0.25.7" - } - }, - "@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", - "dev": true, - "requires": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - }, - "dependencies": { - "@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "dev": true - } - } - }, - "@rushstack/eslint-patch": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz", - "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==", - "dev": true - }, - "@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/fake-timers": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", - "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0" - } - }, - "@surma/rollup-plugin-off-main-thread": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", - "integrity": "sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==", - "dev": true, - "requires": { - "ejs": "^3.1.6", - "json5": "^2.2.0", - "magic-string": "^0.25.0", - "string.prototype.matchall": "^4.0.6" - } - }, - "@svgr/babel-plugin-add-jsx-attribute": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz", - "integrity": "sha512-ZFf2gs/8/6B8PnSofI0inYXr2SDNTDScPXhN7k5EqD4aZ3gi6u+rbmZHVB8IM3wDyx8ntKACZbtXSm7oZGRqVg==", - "dev": true - }, - "@svgr/babel-plugin-remove-jsx-attribute": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-5.4.0.tgz", - "integrity": "sha512-yaS4o2PgUtwLFGTKbsiAy6D0o3ugcUhWK0Z45umJ66EPWunAz9fuFw2gJuje6wqQvQWOTJvIahUwndOXb7QCPg==", - "dev": true - }, - "@svgr/babel-plugin-remove-jsx-empty-expression": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-5.0.1.tgz", - "integrity": "sha512-LA72+88A11ND/yFIMzyuLRSMJ+tRKeYKeQ+mR3DcAZ5I4h5CPWN9AHyUzJbWSYp/u2u0xhmgOe0+E41+GjEueA==", - "dev": true - }, - "@svgr/babel-plugin-replace-jsx-attribute-value": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-5.0.1.tgz", - "integrity": "sha512-PoiE6ZD2Eiy5mK+fjHqwGOS+IXX0wq/YDtNyIgOrc6ejFnxN4b13pRpiIPbtPwHEc+NT2KCjteAcq33/F1Y9KQ==", - "dev": true - }, - "@svgr/babel-plugin-svg-dynamic-title": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-5.4.0.tgz", - "integrity": "sha512-zSOZH8PdZOpuG1ZVx/cLVePB2ibo3WPpqo7gFIjLV9a0QsuQAzJiwwqmuEdTaW2pegyBE17Uu15mOgOcgabQZg==", - "dev": true - }, - "@svgr/babel-plugin-svg-em-dimensions": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-5.4.0.tgz", - "integrity": "sha512-cPzDbDA5oT/sPXDCUYoVXEmm3VIoAWAPT6mSPTJNbQaBNUuEKVKyGH93oDY4e42PYHRW67N5alJx/eEol20abw==", - "dev": true - }, - "@svgr/babel-plugin-transform-react-native-svg": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-5.4.0.tgz", - "integrity": "sha512-3eYP/SaopZ41GHwXma7Rmxcv9uRslRDTY1estspeB1w1ueZWd/tPlMfEOoccYpEMZU3jD4OU7YitnXcF5hLW2Q==", - "dev": true - }, - "@svgr/babel-plugin-transform-svg-component": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-5.5.0.tgz", - "integrity": "sha512-q4jSH1UUvbrsOtlo/tKcgSeiCHRSBdXoIoqX1pgcKK/aU3JD27wmMKwGtpB8qRYUYoyXvfGxUVKchLuR5pB3rQ==", - "dev": true - }, - "@svgr/babel-preset": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-5.5.0.tgz", - "integrity": "sha512-4FiXBjvQ+z2j7yASeGPEi8VD/5rrGQk4Xrq3EdJmoZgz/tpqChpo5hgXDvmEauwtvOc52q8ghhZK4Oy7qph4ig==", - "dev": true, - "requires": { - "@svgr/babel-plugin-add-jsx-attribute": "^5.4.0", - "@svgr/babel-plugin-remove-jsx-attribute": "^5.4.0", - "@svgr/babel-plugin-remove-jsx-empty-expression": "^5.0.1", - "@svgr/babel-plugin-replace-jsx-attribute-value": "^5.0.1", - "@svgr/babel-plugin-svg-dynamic-title": "^5.4.0", - "@svgr/babel-plugin-svg-em-dimensions": "^5.4.0", - "@svgr/babel-plugin-transform-react-native-svg": "^5.4.0", - "@svgr/babel-plugin-transform-svg-component": "^5.5.0" - } - }, - "@svgr/core": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/core/-/core-5.5.0.tgz", - "integrity": "sha512-q52VOcsJPvV3jO1wkPtzTuKlvX7Y3xIcWRpCMtBF3MrteZJtBfQw/+u0B1BHy5ColpQc1/YVTrPEtSYIMNZlrQ==", - "dev": true, - "requires": { - "@svgr/plugin-jsx": "^5.5.0", - "camelcase": "^6.2.0", - "cosmiconfig": "^7.0.0" - }, - "dependencies": { - "camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", - "dev": true - } - } - }, - "@svgr/hast-util-to-babel-ast": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.5.0.tgz", - "integrity": "sha512-cAaR/CAiZRB8GP32N+1jocovUtvlj0+e65TB50/6Lcime+EA49m/8l+P2ko+XPJ4dw3xaPS3jOL4F2X4KWxoeQ==", - "dev": true, - "requires": { - "@babel/types": "^7.12.6" - } - }, - "@svgr/plugin-jsx": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-5.5.0.tgz", - "integrity": "sha512-V/wVh33j12hGh05IDg8GpIUXbjAPnTdPTKuP4VNLggnwaHMPNQNae2pRnyTAILWCQdz5GyMqtO488g7CKM8CBA==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@svgr/babel-preset": "^5.5.0", - "@svgr/hast-util-to-babel-ast": "^5.5.0", - "svg-parser": "^2.0.2" - } - }, - "@svgr/plugin-svgo": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-5.5.0.tgz", - "integrity": "sha512-r5swKk46GuQl4RrVejVwpeeJaydoxkdwkM1mBKOgJLBUJPGaLci6ylg/IjhrRsREKDkr4kbMWdgOtbXEh0fyLQ==", - "dev": true, - "requires": { - "cosmiconfig": "^7.0.0", - "deepmerge": "^4.2.2", - "svgo": "^1.2.2" - }, - "dependencies": { - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true - } - } - }, - "@svgr/webpack": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-5.5.0.tgz", - "integrity": "sha512-DOBOK255wfQxguUta2INKkzPj6AIS6iafZYiYmHn6W3pHlycSRRlvWKCfLDG10fXfLWqE3DJHgRUOyJYmARa7g==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/plugin-transform-react-constant-elements": "^7.12.1", - "@babel/preset-env": "^7.12.1", - "@babel/preset-react": "^7.12.5", - "@svgr/core": "^5.5.0", - "@svgr/plugin-jsx": "^5.5.0", - "@svgr/plugin-svgo": "^5.5.0", - "loader-utils": "^2.0.0" - } - }, - "@testing-library/dom": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.11.3.tgz", - "integrity": "sha512-9LId28I+lx70wUiZjLvi1DB/WT2zGOxUh46glrSNMaWVx849kKAluezVzZrXJfTKKoQTmEOutLes/bHg4Bj3aA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^4.2.0", - "aria-query": "^5.0.0", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.4.4", - "pretty-format": "^27.0.2" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "aria-query": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.0.0.tgz", - "integrity": "sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@testing-library/jest-dom": { - "version": "5.16.5", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz", - "integrity": "sha512-N5ixQ2qKpi5OLYfwQmUb/5mSV9LneAcaUfp32pn4yCnpb8r/Yz0pXFPck21dIicKmi+ta5WRAknkZCfA8refMA==", - "dev": true, - "requires": { - "@adobe/css-tools": "^4.0.1", - "@babel/runtime": "^7.9.2", - "@types/testing-library__jest-dom": "^5.9.1", - "aria-query": "^5.0.0", - "chalk": "^3.0.0", - "css.escape": "^1.5.1", - "dom-accessibility-api": "^0.5.6", - "lodash": "^4.17.15", - "redent": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "aria-query": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.0.0.tgz", - "integrity": "sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg==", - "dev": true - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@testing-library/react": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-12.1.5.tgz", - "integrity": "sha512-OfTXCJUFgjd/digLUuPxa0+/3ZxsQmE7ub9kcbW/wi96Bh3o/p5vrETcBGfP17NWPGqeYYl5LTRpwyGoMC4ysg==", - "dev": true, - "requires": { - "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^8.0.0", - "@types/react-dom": "<18.0.0" - } - }, - "@testing-library/user-event": { - "version": "14.4.3", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.4.3.tgz", - "integrity": "sha512-kCUc5MEwaEMakkO5x7aoD+DLi02ehmEM2QCGWvNqAS1dV/fAvORWEjnjsEIvml59M7Y5kCkWN6fCCyPOe8OL6Q==", - "dev": true, - "requires": {} - }, - "@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true - }, - "@trysound/sax": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", - "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", - "dev": true - }, - "@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true - }, - "@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", - "dev": true - }, - "@types/aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", - "dev": true - }, - "@types/babel__core": { - "version": "7.1.18", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.18.tgz", - "integrity": "sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@types/babel__traverse": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", - "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } - }, - "@types/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", - "dev": true, - "requires": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "@types/bonjour": { - "version": "3.5.10", - "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", - "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/cheerio": { - "version": "0.22.28", - "resolved": "https://registry.npmjs.org/@types/cheerio/-/cheerio-0.22.28.tgz", - "integrity": "sha512-ehUMGSW5IeDxJjbru4awKYMlKGmo1wSSGUVqXtYwlgmUM8X1a0PZttEIm6yEY7vHsY/hh6iPnklF213G0UColw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/connect-history-api-fallback": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz", - "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==", - "dev": true, - "requires": { - "@types/express-serve-static-core": "*", - "@types/node": "*" - } - }, - "@types/eslint": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.2.2.tgz", - "integrity": "sha512-nQxgB8/Sg+QKhnV8e0WzPpxjIGT3tuJDDzybkDi8ItE/IgTlHo07U0shaIjzhcvQxlq9SDRE42lsJ23uvEgJ2A==", - "dev": true, - "requires": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "@types/eslint-scope": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", - "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", - "dev": true, - "requires": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "@types/estree": { - "version": "0.0.50", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz", - "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==", - "dev": true - }, - "@types/express": { - "version": "4.17.13", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", - "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", - "dev": true, - "requires": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.18", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "@types/express-serve-static-core": { - "version": "4.17.28", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", - "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", - "dev": true, - "requires": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, - "@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", - "dev": true - }, - "@types/http-proxy": { - "version": "1.17.5", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.5.tgz", - "integrity": "sha512-GNkDE7bTv6Sf8JbV2GksknKOsk7OznNYHSdrtvPJXO0qJ9odZig6IZKUi5RFGi6d1bf6dgIAe4uXi3DBc7069Q==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", - "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", - "dev": true - }, - "@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz", - "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/jest": { - "version": "27.4.1", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.4.1.tgz", - "integrity": "sha512-23iPJADSmicDVrWk+HT58LMJtzLAnB2AgIzplQuq/bSrGaxCrlvRFjGbXmamnnk/mAmCdLStiGqggu28ocUyiw==", - "dev": true, - "requires": { - "jest-matcher-utils": "^27.0.0", - "pretty-format": "^27.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - }, - "pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - } - } - }, - "@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", - "dev": true - }, - "@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", - "dev": true - }, - "@types/mime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", - "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", - "dev": true - }, - "@types/node": { - "version": "15.0.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.0.2.tgz", - "integrity": "sha512-p68+a+KoxpoB47015IeYZYRrdqMUcpbK8re/zpFB8Ld46LHC1lPEbp3EXgkEhAYEcPvjJF6ZO+869SQ0aH1dcA==", - "dev": true - }, - "@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true - }, - "@types/prettier": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.3.tgz", - "integrity": "sha512-QzSuZMBuG5u8HqYz01qtMdg/Jfctlnvj1z/lYnIDXs/golxw0fxtRAHd9KrzjR7Yxz1qVeI00o0kiO3PmVdJ9w==", - "dev": true - }, - "@types/prop-types": { - "version": "15.7.4", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz", - "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==", - "dev": true - }, - "@types/q": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz", - "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==", - "dev": true - }, - "@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", - "dev": true - }, - "@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", - "dev": true - }, - "@types/react": { - "version": "17.0.41", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.41.tgz", - "integrity": "sha512-chYZ9ogWUodyC7VUTRBfblysKLjnohhFY9bGLwvnUFFy48+vB9DikmB3lW0qTFmBcKSzmdglcvkHK71IioOlDA==", - "dev": true, - "requires": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "@types/react-dom": { - "version": "17.0.14", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.14.tgz", - "integrity": "sha512-H03xwEP1oXmSfl3iobtmQ/2dHF5aBHr8aUMwyGZya6OW45G+xtdzmq6HkncefiBt5JU8DVyaWl/nWZbjZCnzAQ==", - "dev": true, - "requires": { - "@types/react": "*" - } - }, - "@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/retry": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", - "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==", - "dev": true - }, - "@types/scheduler": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", - "dev": true - }, - "@types/semver": { - "version": "7.3.13", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", - "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", - "dev": true - }, - "@types/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", - "dev": true, - "requires": { - "@types/express": "*" - } - }, - "@types/serve-static": { - "version": "1.13.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", - "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", - "dev": true, - "requires": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "@types/sockjs": { - "version": "0.3.33", - "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", - "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "@types/testing-library__jest-dom": { - "version": "5.14.3", - "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.3.tgz", - "integrity": "sha512-oKZe+Mf4ioWlMuzVBaXQ9WDnEm1+umLx0InILg+yvZVBBDmzV5KfZyLrCvadtWcx8+916jLmHafcmqqffl+iIw==", - "dev": true, - "requires": { - "@types/jest": "*" - } - }, - "@types/trusted-types": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz", - "integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==", - "dev": true - }, - "@types/ws": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.2.2.tgz", - "integrity": "sha512-NOn5eIcgWLOo6qW8AcuLZ7G8PycXu0xTxxkS6Q18VWFxgPUSOwV0pBj2a/4viNZVu25i7RIB7GttdkAIUUXOOg==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/yargs": { - "version": "15.0.13", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz", - "integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "20.2.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", - "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==", - "dev": true - }, - "@typescript-eslint/eslint-plugin": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.45.0.tgz", - "integrity": "sha512-CXXHNlf0oL+Yg021cxgOdMHNTXD17rHkq7iW6RFHoybdFgQBjU3yIXhhcPpGwr1CjZlo6ET8C6tzX5juQoXeGA==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "5.45.0", - "@typescript-eslint/type-utils": "5.45.0", - "@typescript-eslint/utils": "5.45.0", - "debug": "^4.3.4", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "regexpp": "^3.2.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "dependencies": { - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "@typescript-eslint/experimental-utils": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.45.0.tgz", - "integrity": "sha512-DnRQg5+3uHHt/gaifTjwg9OKbg9/TWehfJzYHQIDJboPEbF897BKDE/qoqMhW7nf0jWRV1mwVXTaUvtB1/9Gwg==", - "dev": true, - "requires": { - "@typescript-eslint/utils": "5.45.0" - } - }, - "@typescript-eslint/parser": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.45.0.tgz", - "integrity": "sha512-brvs/WSM4fKUmF5Ot/gEve6qYiCMjm6w4HkHPfS6ZNmxTS0m0iNN4yOChImaCkqc1hRwFGqUyanMXuGal6oyyQ==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "5.45.0", - "@typescript-eslint/types": "5.45.0", - "@typescript-eslint/typescript-estree": "5.45.0", - "debug": "^4.3.4" - } - }, - "@typescript-eslint/scope-manager": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.45.0.tgz", - "integrity": "sha512-noDMjr87Arp/PuVrtvN3dXiJstQR1+XlQ4R1EvzG+NMgXi8CuMCXpb8JqNtFHKceVSQ985BZhfRdowJzbv4yKw==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.45.0", - "@typescript-eslint/visitor-keys": "5.45.0" - } - }, - "@typescript-eslint/type-utils": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.45.0.tgz", - "integrity": "sha512-DY7BXVFSIGRGFZ574hTEyLPRiQIvI/9oGcN8t1A7f6zIs6ftbrU0nhyV26ZW//6f85avkwrLag424n+fkuoJ1Q==", - "dev": true, - "requires": { - "@typescript-eslint/typescript-estree": "5.45.0", - "@typescript-eslint/utils": "5.45.0", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/types": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.45.0.tgz", - "integrity": "sha512-QQij+u/vgskA66azc9dCmx+rev79PzX8uDHpsqSjEFtfF2gBUTRCpvYMh2gw2ghkJabNkPlSUCimsyBEQZd1DA==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.45.0.tgz", - "integrity": "sha512-maRhLGSzqUpFcZgXxg1qc/+H0bT36lHK4APhp0AEUVrpSwXiRAomm/JGjSG+kNUio5kAa3uekCYu/47cnGn5EQ==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.45.0", - "@typescript-eslint/visitor-keys": "5.45.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "dependencies": { - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "@typescript-eslint/utils": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.45.0.tgz", - "integrity": "sha512-OUg2JvsVI1oIee/SwiejTot2OxwU8a7UfTFMOdlhD2y+Hl6memUSL4s98bpUTo8EpVEr0lmwlU7JSu/p2QpSvA==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.45.0", - "@typescript-eslint/types": "5.45.0", - "@typescript-eslint/typescript-estree": "5.45.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0", - "semver": "^7.3.7" - }, - "dependencies": { - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "@typescript-eslint/visitor-keys": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.45.0.tgz", - "integrity": "sha512-jc6Eccbn2RtQPr1s7th6jJWQHBHI6GBVQkCHoJFQ5UreaKm59Vxw+ynQUPPY2u2Amquc+7tmEoC2G52ApsGNNg==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.45.0", - "eslint-visitor-keys": "^3.3.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true - } - } - }, - "@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", - "dev": true, - "requires": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" - } - }, - "@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", - "dev": true - }, - "@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", - "dev": true - }, - "@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", - "dev": true - }, - "@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", - "dev": true, - "requires": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", - "dev": true - }, - "@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" - } - }, - "@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", - "dev": true, - "requires": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", - "dev": true, - "requires": { - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", - "dev": true - }, - "@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" - } - }, - "@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" - } - }, - "@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "@wojtekmaj/enzyme-adapter-react-17": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/@wojtekmaj/enzyme-adapter-react-17/-/enzyme-adapter-react-17-0.6.5.tgz", - "integrity": "sha512-ChIObUiXXYUiqzXPqOai+p6KF5dlbItpDDYsftUOQiAiygbMDlLeJIjynC6ZrJIa2U2MpRp4YJmtR2GQyIHjgA==", - "dev": true, - "requires": { - "@wojtekmaj/enzyme-adapter-utils": "^0.1.1", - "enzyme-shallow-equal": "^1.0.0", - "has": "^1.0.0", - "object.assign": "^4.1.0", - "object.values": "^1.1.0", - "prop-types": "^15.7.0", - "react-is": "^17.0.2", - "react-test-renderer": "^17.0.0" - }, - "dependencies": { - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - } - } - }, - "@wojtekmaj/enzyme-adapter-utils": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@wojtekmaj/enzyme-adapter-utils/-/enzyme-adapter-utils-0.1.1.tgz", - "integrity": "sha512-bNPWtN/d8huKOkC6j1E3EkSamnRrHHT7YuR6f9JppAQqtoAm3v4/vERe4J14jQKmHLCyEBHXrlgb7H6l817hVg==", - "dev": true, - "requires": { - "function.prototype.name": "^1.1.0", - "has": "^1.0.0", - "object.assign": "^4.1.0", - "object.fromentries": "^2.0.0", - "prop-types": "^15.7.0" - } - }, - "@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true - }, - "@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true - }, - "abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", - "dev": true - }, - "accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dev": true, - "requires": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - } - }, - "ace-builds": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.10.1.tgz", - "integrity": "sha512-w8Xj6lZUtOYAquVYvdpZhb0GxXrZ+qpVfgj5LP2FwUbXE8fPrCmfu86FjwOiSphx/8PMbXXVldFLD2+RIXayyA==" - }, - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true - }, - "acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "dev": true, - "requires": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - } - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} - }, - "acorn-node": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", - "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", - "dev": true, - "requires": { - "acorn": "^7.0.0", - "acorn-walk": "^7.0.0", - "xtend": "^4.0.2" - } - }, - "acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true - }, - "address": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/address/-/address-1.2.1.tgz", - "integrity": "sha512-B+6bi5D34+fDYENiH5qOlA0cV2rAGKuWZ9LeyUUehbXy8e0VS9e498yO0Jeeh+iM+6KbfudHTFjXw2MmJD4QRA==", - "dev": true - }, - "adjust-sourcemap-loader": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", - "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", - "dev": true, - "requires": { - "loader-utils": "^2.0.0", - "regex-parser": "^2.2.11" - } - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "requires": { - "debug": "4" - } - }, - "aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dev": true, - "requires": { - "ajv": "^8.0.0" - }, - "dependencies": { - "ajv": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.9.0.tgz", - "integrity": "sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - } - } - }, - "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "requires": {} - }, - "alphanum-sort": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", - "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", - "dev": true - }, - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "requires": { - "type-fest": "^0.21.3" - } - }, - "ansi-html-community": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", - "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", - "dev": true - }, - "ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==" - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "ansi-to-html": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/ansi-to-html/-/ansi-to-html-0.7.2.tgz", - "integrity": "sha512-v6MqmEpNlxF+POuyhKkidusCHWWkaLcGRURzivcU3I9tv7k4JVhFcnukrM5Rlk2rUywdZuzYAZ+kbZqWCnfN3g==", - "requires": { - "entities": "^2.2.0" - } - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", - "dev": true, - "requires": { - "@babel/runtime": "^7.10.2", - "@babel/runtime-corejs3": "^7.10.2" - } - }, - "array-filter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-1.0.0.tgz", - "integrity": "sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=", - "dev": true - }, - "array-find": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-find/-/array-find-1.0.0.tgz", - "integrity": "sha1-bI4obRHtdoMn+OYuzuhzU8o+eLg=", - "dev": true - }, - "array-flatten": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", - "dev": true - }, - "array-includes": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", - "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", - "get-intrinsic": "^1.1.1", - "is-string": "^1.0.7" - } - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "array.prototype.find": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array.prototype.find/-/array.prototype.find-2.1.2.tgz", - "integrity": "sha512-00S1O4ewO95OmmJW7EesWfQlrCrLEL8kZ40w3+GkLX2yTt0m2ggcePPa2uHPJ9KUmJvwRq+lCV9bD8Yim23x/Q==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" - } - }, - "array.prototype.flat": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", - "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" - } - }, - "array.prototype.flatmap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz", - "integrity": "sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" - } - }, - "asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", - "dev": true - }, - "ast-types-flow": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", - "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=", - "dev": true - }, - "async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "dev": true, - "requires": { - "lodash": "^4.17.14" - } - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true - }, - "attr-accept": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-1.1.3.tgz", - "integrity": "sha512-iT40nudw8zmCweivz6j58g+RT33I4KbaIvRUhjNmDwO2WmsQUxFEZZYZ5w3vXe5x5MX9D7mfvA/XaLOZYFR9EQ==", - "requires": { - "core-js": "^2.5.0" - } - }, - "autoprefixer": { - "version": "10.4.2", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.2.tgz", - "integrity": "sha512-9fOPpHKuDW1w/0EKfRmVnxTDt8166MAnLI3mgZ1JCnhNtYWxcJ6Ud5CO/AVOZi/AvFa8DY9RTy3h3+tFBlrrdQ==", - "dev": true, - "requires": { - "browserslist": "^4.19.1", - "caniuse-lite": "^1.0.30001297", - "fraction.js": "^4.1.2", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - } - }, - "axe-core": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.3.5.tgz", - "integrity": "sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA==", - "dev": true - }, - "axios": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", - "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", - "requires": { - "follow-redirects": "^1.14.9", - "form-data": "^4.0.0" - }, - "dependencies": { - "form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - } - } - }, - "axobject-query": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", - "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==", - "dev": true - }, - "babel-jest": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.4.6.tgz", - "integrity": "sha512-qZL0JT0HS1L+lOuH+xC2DVASR3nunZi/ozGhpgauJHgmI7f8rudxf6hUjEHympdQ/J64CdKmPkgfJ+A3U6QCrg==", - "dev": true, - "requires": { - "@jest/transform": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^27.4.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "slash": "^3.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", - "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "babel-loader": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.3.tgz", - "integrity": "sha512-n4Zeta8NC3QAsuyiizu0GkmRcQ6clkV9WFUnUf1iXP//IeSKbWjofW3UHyZVwlOB4y039YQKefawyTn64Zwbuw==", - "dev": true, - "requires": { - "find-cache-dir": "^3.3.1", - "loader-utils": "^1.4.0", - "make-dir": "^3.1.0", - "schema-utils": "^2.6.5" - }, - "dependencies": { - "json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - }, - "loader-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", - "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" - } - }, - "schema-utils": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", - "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.5", - "ajv": "^6.12.4", - "ajv-keywords": "^3.5.2" - } - } - } - }, - "babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "dev": true, - "requires": { - "object.assign": "^4.1.0" - } - }, - "babel-plugin-istanbul": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", - "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^4.0.0", - "test-exclude": "^6.0.0" - } - }, - "babel-plugin-jest-hoist": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.4.0.tgz", - "integrity": "sha512-Jcu7qS4OX5kTWBc45Hz7BMmgXuJqRnhatqpUhnzGC3OBYpOmf2tv6jFNwZpwM7wU7MUuv2r9IPS/ZlYOuburVw==", - "dev": true, - "requires": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", - "@types/babel__traverse": "^7.0.6" - } - }, - "babel-plugin-macros": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", - "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", - "dev": true, - "requires": { - "@babel/runtime": "^7.12.5", - "cosmiconfig": "^7.0.0", - "resolve": "^1.19.0" - } - }, - "babel-plugin-named-asset-import": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.8.tgz", - "integrity": "sha512-WXiAc++qo7XcJ1ZnTYGtLxmBCVbddAml3CEXgWaBzNzLNoxtQ8AiGEFDMOhot9XjTCQbvP5E77Fj9Gk924f00Q==", - "dev": true, - "requires": {} - }, - "babel-plugin-polyfill-corejs2": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", - "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.17.7", - "@babel/helper-define-polyfill-provider": "^0.3.3", - "semver": "^6.1.1" - } - }, - "babel-plugin-polyfill-corejs3": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.1.tgz", - "integrity": "sha512-TihqEe4sQcb/QcPJvxe94/9RZuLQuF1+To4WqQcRvc+3J3gLCPIPgDKzGLG6zmQLfH3nn25heRuDNkS2KR4I8A==", - "dev": true, - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.1", - "core-js-compat": "^3.20.0" - } - }, - "babel-plugin-polyfill-regenerator": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", - "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", - "dev": true, - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.1" - } - }, - "babel-plugin-styled-components": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-1.12.0.tgz", - "integrity": "sha512-FEiD7l5ZABdJPpLssKXjBUJMYqzbcNzBowfXDCdJhOpbhWiewapUaY+LZGT8R4Jg2TwOjGjG4RKeyrO5p9sBkA==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-module-imports": "^7.0.0", - "babel-plugin-syntax-jsx": "^6.18.0", - "lodash": "^4.17.11" - } - }, - "babel-plugin-syntax-jsx": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", - "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=" - }, - "babel-plugin-transform-react-remove-prop-types": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz", - "integrity": "sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA==", - "dev": true - }, - "babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "requires": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - } - }, - "babel-preset-jest": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.4.0.tgz", - "integrity": "sha512-NK4jGYpnBvNxcGo7/ZpZJr51jCGT+3bwwpVIDY2oNfTxJJldRtB4VAcYdgp1loDE50ODuTu+yBjpMAswv5tlpg==", - "dev": true, - "requires": { - "babel-plugin-jest-hoist": "^27.4.0", - "babel-preset-current-node-syntax": "^1.0.0" - } - }, - "babel-preset-react-app": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-react-app/-/babel-preset-react-app-10.0.1.tgz", - "integrity": "sha512-b0D9IZ1WhhCWkrTXyFuIIgqGzSkRIH5D5AmB0bXbzYAB1OBAwHcUeyWW2LorutLWF5btNo/N7r/cIdmvvKJlYg==", - "dev": true, - "requires": { - "@babel/core": "^7.16.0", - "@babel/plugin-proposal-class-properties": "^7.16.0", - "@babel/plugin-proposal-decorators": "^7.16.4", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.0", - "@babel/plugin-proposal-numeric-separator": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.0", - "@babel/plugin-proposal-private-methods": "^7.16.0", - "@babel/plugin-transform-flow-strip-types": "^7.16.0", - "@babel/plugin-transform-react-display-name": "^7.16.0", - "@babel/plugin-transform-runtime": "^7.16.4", - "@babel/preset-env": "^7.16.4", - "@babel/preset-react": "^7.16.0", - "@babel/preset-typescript": "^7.16.0", - "@babel/runtime": "^7.16.3", - "babel-plugin-macros": "^3.1.0", - "babel-plugin-transform-react-remove-prop-types": "^0.4.24" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true - }, - "batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", - "dev": true - }, - "bcp-47": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/bcp-47/-/bcp-47-1.0.8.tgz", - "integrity": "sha512-Y9y1QNBBtYtv7hcmoX0tR+tUNSFZGZ6OL6vKPObq8BbOhkCoyayF6ogfLTgAli/KuAEbsYHYUNq2AQuY6IuLag==", - "dev": true, - "requires": { - "is-alphabetical": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-decimal": "^1.0.0" - } - }, - "bfj": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/bfj/-/bfj-7.0.2.tgz", - "integrity": "sha512-+e/UqUzwmzJamNF50tBV6tZPTORow7gQ96iFow+8b562OdMpEK0BcJEq2OSPEDmAbSMBQ7PKZ87ubFkgxpYWgw==", - "dev": true, - "requires": { - "bluebird": "^3.5.5", - "check-types": "^11.1.1", - "hoopy": "^0.1.4", - "tryer": "^1.0.1" - } - }, - "big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true - }, - "bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, - "body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", - "dev": true, - "requires": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "dependencies": { - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - } - } - }, - "bonjour": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", - "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", - "dev": true, - "requires": { - "array-flatten": "^2.1.0", - "deep-equal": "^1.0.1", - "dns-equal": "^1.0.0", - "dns-txt": "^2.0.2", - "multicast-dns": "^6.0.1", - "multicast-dns-service-types": "^1.1.0" - } - }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, - "browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" - } - }, - "bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "requires": { - "node-int64": "^0.4.0" - } - }, - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true - }, - "buffer-indexof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", - "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", - "dev": true - }, - "builtin-modules": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", - "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==", - "dev": true - }, - "bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", - "dev": true - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camel-case": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", - "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", - "dev": true, - "requires": { - "pascal-case": "^3.1.2", - "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - } - } - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "dev": true - }, - "camelize": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", - "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=" - }, - "caniuse-api": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", - "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" - } - }, - "caniuse-lite": { - "version": "1.0.30001434", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001434.tgz", - "integrity": "sha512-aOBHrLmTQw//WFa2rcF1If9fa3ypkC1wzqqiKHgfdrXTWcU8C4gKVZT77eQAPWN1APys3+uQ0Df07rKauXGEYA==", - "dev": true - }, - "case-sensitive-paths-webpack-plugin": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", - "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==", - "dev": true - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true - }, - "chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "check-types": { - "version": "11.1.2", - "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.1.2.tgz", - "integrity": "sha512-tzWzvgePgLORb9/3a0YenggReLKAIb2owL03H2Xdoe5pKcUyWRSEQ8xfCar8t2SIAuEDwtmx2da1YB52YuHQMQ==", - "dev": true - }, - "cheerio": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.9.tgz", - "integrity": "sha512-QF6XVdrLONO6DXRF5iaolY+odmhj2CLj+xzNod7INPWMi/x9X4SOylH0S/vaPpX+AUU6t04s34SQNh7DbkuCng==", - "dev": true, - "requires": { - "cheerio-select": "^1.4.0", - "dom-serializer": "^1.3.1", - "domhandler": "^4.2.0", - "htmlparser2": "^6.1.0", - "parse5": "^6.0.1", - "parse5-htmlparser2-tree-adapter": "^6.0.1", - "tslib": "^2.2.0" - }, - "dependencies": { - "tslib": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz", - "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==", - "dev": true - } - } - }, - "cheerio-select": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.4.0.tgz", - "integrity": "sha512-sobR3Yqz27L553Qa7cK6rtJlMDbiKPdNywtR95Sj/YgfpLfy0u6CGJuaBKe5YE/vTc23SCRKxWSdlon/w6I/Ew==", - "dev": true, - "requires": { - "css-select": "^4.1.2", - "css-what": "^5.0.0", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0", - "domutils": "^2.6.0" - } - }, - "chokidar": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", - "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", - "dev": true, - "requires": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "fsevents": "~2.3.1", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.5.0" - } - }, - "chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", - "dev": true - }, - "ci-info": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", - "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", - "dev": true - }, - "cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "clean-css": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.2.2.tgz", - "integrity": "sha512-/eR8ru5zyxKzpBLv9YZvMXgTSSQn7AdkMItMYynsFgGwTveCRVam9IUPFloE85B4vAIj05IuKmmEoV7/AQjT0w==", - "dev": true, - "requires": { - "source-map": "~0.6.0" - } - }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true - }, - "cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "requires": { - "restore-cursor": "^3.1.0" - } - }, - "cli-spinners": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.0.tgz", - "integrity": "sha512-t+4/y50K/+4xcCRosKkA7W4gTr1MySvLV0q+PxmG7FJ5g+66ChKurYjxBCjHggHH3HA5Hh9cy+lcUGWDqVH+4Q==", - "dev": true - }, - "cli-table": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.6.tgz", - "integrity": "sha512-ZkNZbnZjKERTY5NwC2SeMeLeifSPq/pubeRoTpdr3WchLlnZg6hEgvHkK5zL7KNFdd9PmHN8lxrENUwI3cE8vQ==", - "dev": true, - "requires": { - "colors": "1.0.3" - } - }, - "cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "dev": true - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", - "dev": true - }, - "clsx": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz", - "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==" - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, - "coa": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", - "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", - "dev": true, - "requires": { - "@types/q": "^1.5.1", - "chalk": "^2.4.1", - "q": "^1.1.2" - } - }, - "codemirror": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz", - "integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==", - "requires": { - "@codemirror/autocomplete": "^6.0.0", - "@codemirror/commands": "^6.0.0", - "@codemirror/language": "^6.0.0", - "@codemirror/lint": "^6.0.0", - "@codemirror/search": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0" - } - }, - "collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "colord": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.2.tgz", - "integrity": "sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ==", - "dev": true - }, - "colorette": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", - "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", - "dev": true - }, - "colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", - "dev": true - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "common-path-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", - "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", - "dev": true - }, - "common-tags": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", - "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", - "dev": true - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "dev": true, - "requires": { - "mime-db": ">= 1.43.0 < 2" - } - }, - "compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", - "dev": true, - "requires": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", - "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "confusing-browser-globals": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", - "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", - "dev": true - }, - "connect-history-api-fallback": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", - "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", - "dev": true - }, - "content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dev": true, - "requires": { - "safe-buffer": "5.2.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - } - } - }, - "content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "dev": true - }, - "convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", - "dev": true - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", - "dev": true - }, - "core-js": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==" - }, - "core-js-compat": { - "version": "3.26.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.26.1.tgz", - "integrity": "sha512-622/KzTudvXCDLRw70iHW4KKs1aGpcRcowGWyYJr2DEBfRrd6hNJybxSWJFuZYD4ma86xhrwDDHxmDaIq4EA8A==", - "dev": true, - "requires": { - "browserslist": "^4.21.4" - } - }, - "core-js-pure": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.12.1.tgz", - "integrity": "sha512-1cch+qads4JnDSWsvc7d6nzlKAippwjUlf6vykkTLW53VSV+NkE6muGBToAjEA8pG90cSfcud3JgVmW2ds5TaQ==", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "cosmiconfig": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", - "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", - "dev": true, - "requires": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - } - }, - "cosmiconfig-typescript-loader": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-2.0.2.tgz", - "integrity": "sha512-KmE+bMjWMXJbkWCeY4FJX/npHuZPNr9XF9q9CIQ/bpFwi1qHfCmSiKarrCcRa0LO4fWjk93pVoeRtJAkTGcYNw==", - "dev": true, - "requires": { - "cosmiconfig": "^7", - "ts-node": "^10.8.1" - } - }, - "create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "crelt": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.5.tgz", - "integrity": "sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA==" - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "dev": true - }, - "css-blank-pseudo": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-3.0.2.tgz", - "integrity": "sha512-hOb1LFjRR+8ocA071xUSmg5VslJ8NGo/I2qpUpdeAYyBVCgupS5O8SEVo4SxEMYyFBNodBkzG3T1iqW9HCXxew==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.8" - } - }, - "css-color-keywords": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", - "integrity": "sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU=" - }, - "css-declaration-sorter": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.1.4.tgz", - "integrity": "sha512-lpfkqS0fctcmZotJGhnxkIyJWvBXgpyi2wsFd4J8VB7wzyrT6Ch/3Q+FMNJpjK4gu1+GN5khOnpU2ZVKrLbhCw==", - "dev": true, - "requires": { - "timsort": "^0.3.0" - } - }, - "css-has-pseudo": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-3.0.3.tgz", - "integrity": "sha512-0gDYWEKaGacwxCqvQ3Ypg6wGdD1AztbMm5h1JsactG2hP2eiflj808QITmuWBpE7sjSEVrAlZhPTVd/nNMj/hQ==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.8" - } - }, - "css-loader": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.5.1.tgz", - "integrity": "sha512-gEy2w9AnJNnD9Kuo4XAP9VflW/ujKoS9c/syO+uWMlm5igc7LysKzPXaDoR2vroROkSwsTS2tGr1yGGEbZOYZQ==", - "dev": true, - "requires": { - "icss-utils": "^5.1.0", - "postcss": "^8.2.15", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.0", - "postcss-modules-scope": "^3.0.0", - "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.1.0", - "semver": "^7.3.5" - }, - "dependencies": { - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "css-minimizer-webpack-plugin": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.4.1.tgz", - "integrity": "sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q==", - "dev": true, - "requires": { - "cssnano": "^5.0.6", - "jest-worker": "^27.0.2", - "postcss": "^8.3.5", - "schema-utils": "^4.0.0", - "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1" - }, - "dependencies": { - "ajv": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.9.0.tgz", - "integrity": "sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.3" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "schema-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" - } - } - } - }, - "css-prefers-color-scheme": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.2.tgz", - "integrity": "sha512-gv0KQBEM+q/XdoKyznovq3KW7ocO7k+FhPP+hQR1MenJdu0uPGS6IZa9PzlbqBeS6XcZJNAoqoFxlAUW461CrA==", - "dev": true, - "requires": {} - }, - "css-select": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz", - "integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==", - "dev": true, - "requires": { - "boolbase": "^1.0.0", - "css-what": "^5.1.0", - "domhandler": "^4.3.0", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" - } - }, - "css-select-base-adapter": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", - "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", - "dev": true - }, - "css-to-react-native": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.0.0.tgz", - "integrity": "sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ==", - "requires": { - "camelize": "^1.0.0", - "css-color-keywords": "^1.0.0", - "postcss-value-parser": "^4.0.2" - } - }, - "css-tree": { - "version": "1.0.0-alpha.37", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", - "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", - "dev": true, - "requires": { - "mdn-data": "2.0.4", - "source-map": "^0.6.1" - } - }, - "css-what": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", - "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==", - "dev": true - }, - "css.escape": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s=", - "dev": true - }, - "cssdb": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-5.1.0.tgz", - "integrity": "sha512-/vqjXhv1x9eGkE/zO6o8ZOI7dgdZbLVLUGyVRbPgk6YipXbW87YzUCcO+Jrmi5bwJlAH6oD+MNeZyRgXea1GZw==", - "dev": true - }, - "cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true - }, - "cssnano": { - "version": "5.0.15", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.0.15.tgz", - "integrity": "sha512-ppZsS7oPpi2sfiyV5+i+NbB/3GtQ+ab2Vs1azrZaXWujUSN4o+WdTxlCZIMcT9yLW3VO/5yX3vpyDaQ1nIn8CQ==", - "dev": true, - "requires": { - "cssnano-preset-default": "^5.1.10", - "lilconfig": "^2.0.3", - "yaml": "^1.10.2" - } - }, - "cssnano-preset-default": { - "version": "5.1.10", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.1.10.tgz", - "integrity": "sha512-BcpSzUVygHMOnp9uG5rfPzTOCb0GAHQkqtUQx8j1oMNF9A1Q8hziOOhiM4bdICpmrBIU85BE64RD5XGYsVQZNA==", - "dev": true, - "requires": { - "css-declaration-sorter": "^6.0.3", - "cssnano-utils": "^3.0.0", - "postcss-calc": "^8.2.0", - "postcss-colormin": "^5.2.3", - "postcss-convert-values": "^5.0.2", - "postcss-discard-comments": "^5.0.1", - "postcss-discard-duplicates": "^5.0.1", - "postcss-discard-empty": "^5.0.1", - "postcss-discard-overridden": "^5.0.2", - "postcss-merge-longhand": "^5.0.4", - "postcss-merge-rules": "^5.0.4", - "postcss-minify-font-values": "^5.0.2", - "postcss-minify-gradients": "^5.0.4", - "postcss-minify-params": "^5.0.3", - "postcss-minify-selectors": "^5.1.1", - "postcss-normalize-charset": "^5.0.1", - "postcss-normalize-display-values": "^5.0.2", - "postcss-normalize-positions": "^5.0.2", - "postcss-normalize-repeat-style": "^5.0.2", - "postcss-normalize-string": "^5.0.2", - "postcss-normalize-timing-functions": "^5.0.2", - "postcss-normalize-unicode": "^5.0.2", - "postcss-normalize-url": "^5.0.4", - "postcss-normalize-whitespace": "^5.0.2", - "postcss-ordered-values": "^5.0.3", - "postcss-reduce-initial": "^5.0.2", - "postcss-reduce-transforms": "^5.0.2", - "postcss-svgo": "^5.0.3", - "postcss-unique-selectors": "^5.0.2" - } - }, - "cssnano-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.0.0.tgz", - "integrity": "sha512-Pzs7/BZ6OgT+tXXuF12DKR8SmSbzUeVYCtMBbS8lI0uAm3mrYmkyqCXXPsQESI6kmLfEVBppbdVY/el3hg3nAA==", - "dev": true, - "requires": {} - }, - "csso": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", - "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", - "dev": true, - "requires": { - "css-tree": "^1.1.2" - }, - "dependencies": { - "css-tree": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", - "dev": true, - "requires": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" - } - }, - "mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", - "dev": true - } - } - }, - "cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true - }, - "cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "requires": { - "cssom": "~0.3.6" - }, - "dependencies": { - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - } - } - }, - "csstype": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz", - "integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==" - }, - "d3": { - "version": "7.6.1", - "resolved": "https://registry.npmjs.org/d3/-/d3-7.6.1.tgz", - "integrity": "sha512-txMTdIHFbcpLx+8a0IFhZsbp+PfBBPt8yfbmukZTQFroKuFqIwqswF0qE5JXWefylaAVpSXFoKm3yP+jpNLFLw==", - "requires": { - "d3-array": "3", - "d3-axis": "3", - "d3-brush": "3", - "d3-chord": "3", - "d3-color": "3", - "d3-contour": "4", - "d3-delaunay": "6", - "d3-dispatch": "3", - "d3-drag": "3", - "d3-dsv": "3", - "d3-ease": "3", - "d3-fetch": "3", - "d3-force": "3", - "d3-format": "3", - "d3-geo": "3", - "d3-hierarchy": "3", - "d3-interpolate": "3", - "d3-path": "3", - "d3-polygon": "3", - "d3-quadtree": "3", - "d3-random": "3", - "d3-scale": "4", - "d3-scale-chromatic": "3", - "d3-selection": "3", - "d3-shape": "3", - "d3-time": "3", - "d3-time-format": "4", - "d3-timer": "3", - "d3-transition": "3", - "d3-zoom": "3" - } - }, - "d3-array": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.0.tgz", - "integrity": "sha512-3yXFQo0oG3QCxbF06rMPFyGRMGJNS7NvsV1+2joOjbBE+9xvWQ8+GcMJAjRCzw06zQ3/arXeJgbPYcjUCuC+3g==", - "requires": { - "internmap": "1 - 2" - } - }, - "d3-axis": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", - "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==" - }, - "d3-brush": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", - "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", - "requires": { - "d3-dispatch": "1 - 3", - "d3-drag": "2 - 3", - "d3-interpolate": "1 - 3", - "d3-selection": "3", - "d3-transition": "3" - } - }, - "d3-chord": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", - "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", - "requires": { - "d3-path": "1 - 3" - } - }, - "d3-color": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", - "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==" - }, - "d3-contour": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.0.tgz", - "integrity": "sha512-7aQo0QHUTu/Ko3cP9YK9yUTxtoDEiDGwnBHyLxG5M4vqlBkO/uixMRele3nfsfj6UXOcuReVpVXzAboGraYIJw==", - "requires": { - "d3-array": "^3.2.0" - } - }, - "d3-delaunay": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.2.tgz", - "integrity": "sha512-IMLNldruDQScrcfT+MWnazhHbDJhcRJyOEBAJfwQnHle1RPh6WDuLvxNArUju2VSMSUuKlY5BGHRJ2cYyoFLQQ==", - "requires": { - "delaunator": "5" - } - }, - "d3-dispatch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", - "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==" - }, - "d3-drag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", - "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", - "requires": { - "d3-dispatch": "1 - 3", - "d3-selection": "3" - } - }, - "d3-dsv": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", - "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", - "requires": { - "commander": "7", - "iconv-lite": "0.6", - "rw": "1" - }, - "dependencies": { - "commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" - }, - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - } - } - }, - "d3-ease": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", - "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==" - }, - "d3-fetch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", - "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", - "requires": { - "d3-dsv": "1 - 3" - } - }, - "d3-force": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", - "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", - "requires": { - "d3-dispatch": "1 - 3", - "d3-quadtree": "1 - 3", - "d3-timer": "1 - 3" - } - }, - "d3-format": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.0.1.tgz", - "integrity": "sha512-hdL7+HBIohpgfolhBxr1KX47VMD6+vVD/oEFrxk5yhmzV2prk99EkFKYpXuhVkFpTgHdJ6/4bYcjdLPPXV4tIA==" - }, - "d3-geo": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.0.1.tgz", - "integrity": "sha512-Wt23xBych5tSy9IYAM1FR2rWIBFWa52B/oF/GYe5zbdHrg08FU8+BuI6X4PvTwPDdqdAdq04fuWJpELtsaEjeA==", - "requires": { - "d3-array": "2.5.0 - 3" - } - }, - "d3-hierarchy": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.0.1.tgz", - "integrity": "sha512-RlLTaofEoOrMK1JoXYIGhKTkJFI/6rFrYPgxy6QlZo2BcVc4HGTqEU0rPpzuMq5T/5XcMtAzv1XiLA3zRTfygw==" - }, - "d3-interpolate": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", - "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", - "requires": { - "d3-color": "1 - 3" - } - }, - "d3-path": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.0.1.tgz", - "integrity": "sha512-gq6gZom9AFZby0YLduxT1qmrp4xpBA1YZr19OI717WIdKE2OM5ETq5qrHLb301IgxhLwcuxvGZVLeeWc/k1I6w==" - }, - "d3-polygon": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", - "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==" - }, - "d3-quadtree": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", - "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==" - }, - "d3-random": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", - "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==" - }, - "d3-scale": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", - "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", - "requires": { - "d3-array": "2.10.0 - 3", - "d3-format": "1 - 3", - "d3-interpolate": "1.2.0 - 3", - "d3-time": "2.1.1 - 3", - "d3-time-format": "2 - 4" - } - }, - "d3-scale-chromatic": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", - "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==", - "requires": { - "d3-color": "1 - 3", - "d3-interpolate": "1 - 3" - } - }, - "d3-selection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", - "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==" - }, - "d3-shape": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.0.1.tgz", - "integrity": "sha512-HNZNEQoDhuCrDWEc/BMbF/hKtzMZVoe64TvisFLDp2Iyj0UShB/E6/lBsLlJTfBMbYgftHj90cXJ0SEitlE6Xw==", - "requires": { - "d3-path": "1 - 3" - } - }, - "d3-time": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.0.0.tgz", - "integrity": "sha512-zmV3lRnlaLI08y9IMRXSDshQb5Nj77smnfpnd2LrBa/2K281Jijactokeak14QacHs/kKq0AQ121nidNYlarbQ==", - "requires": { - "d3-array": "2 - 3" - } - }, - "d3-time-format": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.0.0.tgz", - "integrity": "sha512-nzaCwlj+ZVBIlFuVOT1RmU+6xb/7D5IcnhHzHQcBgS/aTa5K9fWZNN5LCXA27LgF5WxoSNJqKBbLcGMtM6Ca6A==", - "requires": { - "d3-time": "1 - 3" - } - }, - "d3-timer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", - "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==" - }, - "d3-transition": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", - "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", - "requires": { - "d3-color": "1 - 3", - "d3-dispatch": "1 - 3", - "d3-ease": "1 - 3", - "d3-interpolate": "1 - 3", - "d3-timer": "1 - 3" - } - }, - "d3-zoom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", - "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", - "requires": { - "d3-dispatch": "1 - 3", - "d3-drag": "2 - 3", - "d3-interpolate": "1 - 3", - "d3-selection": "2 - 3", - "d3-transition": "2 - 3" - } - }, - "dagre": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.5.tgz", - "integrity": "sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==", - "requires": { - "graphlib": "^2.1.8", - "lodash": "^4.17.15" - } - }, - "damerau-levenshtein": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz", - "integrity": "sha512-VvdQIPGdWP0SqFXghj79Wf/5LArmreyMsGLa6FG6iC4t3j7j5s71TrwWmT/4akbDQIqjfACkLZmjXhA7g2oUZw==", - "dev": true - }, - "data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", - "dev": true, - "requires": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" - } - }, - "date-fns": { - "version": "2.21.3", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.21.3.tgz", - "integrity": "sha512-HeYdzCaFflc1i4tGbj7JKMjM4cKGYoyxwcIIkHzNgCkX8xXDNJDZXgDDVchIWpN4eQc3lH37WarduXFZJOtxfw==", - "dev": true - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - } - }, - "decimal.js": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", - "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", - "dev": true - }, - "dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", - "dev": true - }, - "deep-equal": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", - "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", - "dev": true, - "requires": { - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.1", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.2.0" - } - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "deepmerge": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.2.1.tgz", - "integrity": "sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==" - }, - "default-gateway": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", - "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", - "dev": true, - "requires": { - "execa": "^5.0.0" - } - }, - "defaults": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", - "dev": true, - "requires": { - "clone": "^1.0.2" - } - }, - "define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "dev": true - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, - "defined": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", - "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", - "dev": true - }, - "del": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz", - "integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==", - "dev": true, - "requires": { - "globby": "^11.0.1", - "graceful-fs": "^4.2.4", - "is-glob": "^4.0.1", - "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.2", - "p-map": "^4.0.0", - "rimraf": "^3.0.2", - "slash": "^3.0.0" - } - }, - "delaunator": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", - "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==", - "requires": { - "robust-predicates": "^3.0.0" - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "dev": true - }, - "destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true - }, - "detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true - }, - "detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true - }, - "detect-port-alt": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", - "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", - "dev": true, - "requires": { - "address": "^1.0.1", - "debug": "^2.6.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - } - } - }, - "detective": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", - "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==", - "dev": true, - "requires": { - "acorn-node": "^1.6.1", - "defined": "^1.0.0", - "minimist": "^1.1.1" - } - }, - "didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true - }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - }, - "diff-match-patch": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz", - "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==" - }, - "diff-sequences": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.4.0.tgz", - "integrity": "sha512-YqiQzkrsmHMH5uuh8OdQFU9/ZpADnwzml8z0O5HvRNda+5UZsaX/xN+AAxfR2hWq1Y7HZnAzO9J5lJXOuDz2Ww==", - "dev": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "discontinuous-range": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz", - "integrity": "sha1-44Mx8IRLukm5qctxx3FYWqsbxlo=", - "dev": true - }, - "dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true - }, - "dns-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", - "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", - "dev": true - }, - "dns-packet": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz", - "integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==", - "dev": true, - "requires": { - "ip": "^1.1.0", - "safe-buffer": "^5.0.1" - } - }, - "dns-txt": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", - "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", - "dev": true, - "requires": { - "buffer-indexof": "^1.0.0" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "dom-accessibility-api": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.13.tgz", - "integrity": "sha512-R305kwb5CcMDIpSHUnLyIAp7SrSPBx6F0VfQFB3M75xVMHhXJJIdePYgbPPh1o57vCHNu5QztokWUPsLjWzFqw==", - "dev": true - }, - "dom-converter": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", - "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", - "dev": true, - "requires": { - "utila": "~0.4" - } - }, - "dom-helpers": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", - "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", - "requires": { - "@babel/runtime": "^7.8.7", - "csstype": "^3.0.2" - } - }, - "dom-serializer": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.1.tgz", - "integrity": "sha512-Pv2ZluG5ife96udGgEDovOOOA5UELkltfJpnIExPrAk1LTvecolUGn6lIaoLh86d83GiB86CjzciMd9BuRB71Q==", - "dev": true, - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "entities": "^2.0.0" - } - }, - "domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "dev": true - }, - "domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", - "dev": true, - "requires": { - "webidl-conversions": "^5.0.0" - }, - "dependencies": { - "webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true - } - } - }, - "domhandler": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", - "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", - "dev": true, - "requires": { - "domelementtype": "^2.2.0" - } - }, - "dompurify": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.0.tgz", - "integrity": "sha512-Be9tbQMZds4a3C6xTmz68NlMfeONA//4dOavl/1rNw50E+/QO0KVpbcU0PcaW0nsQxurXls9ZocqFxk8R2mWEA==" - }, - "domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dev": true, - "requires": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - } - }, - "dot-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", - "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", - "dev": true, - "requires": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - } - } - }, - "dotenv": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", - "dev": true - }, - "dotenv-expand": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", - "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", - "dev": true - }, - "duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true - }, - "ejs": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz", - "integrity": "sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==", - "dev": true, - "requires": { - "jake": "^10.8.5" - } - }, - "electron-to-chromium": { - "version": "1.4.284", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", - "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", - "dev": true - }, - "emittery": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", - "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "dev": true - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true - }, - "enhanced-resolve": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz", - "integrity": "sha1-TW5omzcl+GCQknzMhs2fFjW4ni4=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.2.0", - "tapable": "^0.1.8" - } - }, - "entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" - }, - "enzyme": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/enzyme/-/enzyme-3.11.0.tgz", - "integrity": "sha512-Dw8/Gs4vRjxY6/6i9wU0V+utmQO9kvh9XLnz3LIudviOnVYDEe2ec+0k+NQoMamn1VrjKgCUOWj5jG/5M5M0Qw==", - "dev": true, - "requires": { - "array.prototype.flat": "^1.2.3", - "cheerio": "^1.0.0-rc.3", - "enzyme-shallow-equal": "^1.0.1", - "function.prototype.name": "^1.1.2", - "has": "^1.0.3", - "html-element-map": "^1.2.0", - "is-boolean-object": "^1.0.1", - "is-callable": "^1.1.5", - "is-number-object": "^1.0.4", - "is-regex": "^1.0.5", - "is-string": "^1.0.5", - "is-subset": "^0.1.1", - "lodash.escape": "^4.0.1", - "lodash.isequal": "^4.5.0", - "object-inspect": "^1.7.0", - "object-is": "^1.0.2", - "object.assign": "^4.1.0", - "object.entries": "^1.1.1", - "object.values": "^1.1.1", - "raf": "^3.4.1", - "rst-selector-parser": "^2.2.3", - "string.prototype.trim": "^1.2.1" - } - }, - "enzyme-adapter-react-16": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.15.6.tgz", - "integrity": "sha512-yFlVJCXh8T+mcQo8M6my9sPgeGzj85HSHi6Apgf1Cvq/7EL/J9+1JoJmJsRxZgyTvPMAqOEpRSu/Ii/ZpyOk0g==", - "dev": true, - "requires": { - "enzyme-adapter-utils": "^1.14.0", - "enzyme-shallow-equal": "^1.0.4", - "has": "^1.0.3", - "object.assign": "^4.1.2", - "object.values": "^1.1.2", - "prop-types": "^15.7.2", - "react-is": "^16.13.1", - "react-test-renderer": "^16.0.0-0", - "semver": "^5.7.0" - }, - "dependencies": { - "airbnb-prop-types": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/airbnb-prop-types/-/airbnb-prop-types-2.16.0.tgz", - "integrity": "sha512-7WHOFolP/6cS96PhKNrslCLMYAI8yB1Pp6u6XmxozQOiZbsI5ycglZr5cHhBFfuRcQQjzCMith5ZPZdYiJCxUg==", - "dev": true, - "requires": { - "array.prototype.find": "^2.1.1", - "function.prototype.name": "^1.1.2", - "is-regex": "^1.1.0", - "object-is": "^1.1.2", - "object.assign": "^4.1.0", - "object.entries": "^1.1.2", - "prop-types": "^15.7.2", - "prop-types-exact": "^1.2.0", - "react-is": "^16.13.1" - } - }, - "enzyme-adapter-utils": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/enzyme-adapter-utils/-/enzyme-adapter-utils-1.14.0.tgz", - "integrity": "sha512-F/z/7SeLt+reKFcb7597IThpDp0bmzcH1E9Oabqv+o01cID2/YInlqHbFl7HzWBl4h3OdZYedtwNDOmSKkk0bg==", - "dev": true, - "requires": { - "airbnb-prop-types": "^2.16.0", - "function.prototype.name": "^1.1.3", - "has": "^1.0.3", - "object.assign": "^4.1.2", - "object.fromentries": "^2.0.3", - "prop-types": "^15.7.2", - "semver": "^5.7.1" - } - }, - "react-test-renderer": { - "version": "16.14.0", - "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.14.0.tgz", - "integrity": "sha512-L8yPjqPE5CZO6rKsKXRO/rVPiaCOy0tQQJbC+UjPNlobl5mad59lvPjwFsQHTvL03caVDIVr9x9/OSgDe6I5Eg==", - "dev": true, - "requires": { - "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "react-is": "^16.8.6", - "scheduler": "^0.19.1" - } - }, - "scheduler": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", - "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", - "dev": true, - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "enzyme-shallow-equal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/enzyme-shallow-equal/-/enzyme-shallow-equal-1.0.4.tgz", - "integrity": "sha512-MttIwB8kKxypwHvRynuC3ahyNc+cFbR8mjVIltnmzQ0uKGqmsfO4bfBuLxb0beLNPhjblUEYvEbsg+VSygvF1Q==", - "dev": true, - "requires": { - "has": "^1.0.3", - "object-is": "^1.1.2" - } - }, - "enzyme-to-json": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/enzyme-to-json/-/enzyme-to-json-3.6.2.tgz", - "integrity": "sha512-Ynm6Z6R6iwQ0g2g1YToz6DWhxVnt8Dy1ijR2zynRKxTyBGA8rCDXU3rs2Qc4OKvUvc2Qoe1bcFK6bnPs20TrTg==", - "dev": true, - "requires": { - "@types/cheerio": "^0.22.22", - "lodash": "^4.17.21", - "react-is": "^16.12.0" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "error-stack-parser": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.6.tgz", - "integrity": "sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ==", - "dev": true, - "requires": { - "stackframe": "^1.1.1" - } - }, - "es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", - "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - } - }, - "es-module-lexer": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", - "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", - "dev": true - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "dev": true, - "requires": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - } - } - }, - "eslint": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.7.0.tgz", - "integrity": "sha512-ifHYzkBGrzS2iDU7KjhCAVMGCvF6M3Xfs8X8b37cgrUlDt6bWRTpRh6T/gtSXv1HJ/BUGgmjvNvOEGu85Iif7w==", - "dev": true, - "requires": { - "@eslint/eslintrc": "^1.0.5", - "@humanwhocodes/config-array": "^0.9.2", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.0", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.2.0", - "espree": "^9.3.0", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", - "globals": "^13.6.0", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "eslint-scope": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.0.tgz", - "integrity": "sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "eslint-visitor-keys": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.2.0.tgz", - "integrity": "sha512-IOzT0X126zn7ALX0dwFiUQEdsfzrm4+ISsQS8nukaJXwEyYKRSnEIIDULYg1mCtGp7UUXgfGl7BIolXREQK+XQ==", - "dev": true - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - } - }, - "globals": { - "version": "13.8.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.8.0.tgz", - "integrity": "sha512-rHtdA6+PDBIjeEvA91rpqzEvk/k3/i7EeNQiryiWuJH0Hw9cpyJMAt2jtbAwUaRdhD+573X4vWw6IcjKPasi9Q==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - } - } - }, - "eslint-config-airbnb": { - "version": "19.0.4", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-19.0.4.tgz", - "integrity": "sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==", - "dev": true, - "requires": { - "eslint-config-airbnb-base": "^15.0.0", - "object.assign": "^4.1.2", - "object.entries": "^1.1.5" - } - }, - "eslint-config-airbnb-base": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", - "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", - "dev": true, - "requires": { - "confusing-browser-globals": "^1.0.10", - "object.assign": "^4.1.2", - "object.entries": "^1.1.5", - "semver": "^6.3.0" - } - }, - "eslint-config-prettier": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", - "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", - "dev": true, - "requires": {} - }, - "eslint-config-react-app": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-7.0.1.tgz", - "integrity": "sha512-K6rNzvkIeHaTd8m/QEh1Zko0KI7BACWkkneSs6s9cKZC/J27X3eZR6Upt1jkmZ/4FK+XUOPPxMEN7+lbUXfSlA==", - "dev": true, - "requires": { - "@babel/core": "^7.16.0", - "@babel/eslint-parser": "^7.16.3", - "@rushstack/eslint-patch": "^1.1.0", - "@typescript-eslint/eslint-plugin": "^5.5.0", - "@typescript-eslint/parser": "^5.5.0", - "babel-preset-react-app": "^10.0.1", - "confusing-browser-globals": "^1.0.11", - "eslint-plugin-flowtype": "^8.0.3", - "eslint-plugin-import": "^2.25.3", - "eslint-plugin-jest": "^25.3.0", - "eslint-plugin-jsx-a11y": "^6.5.1", - "eslint-plugin-react": "^7.27.1", - "eslint-plugin-react-hooks": "^4.3.0", - "eslint-plugin-testing-library": "^5.0.1" - } - }, - "eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", - "dev": true, - "requires": { - "debug": "^3.2.7", - "resolve": "^1.20.0" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "eslint-import-resolver-webpack": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.13.2.tgz", - "integrity": "sha512-XodIPyg1OgE2h5BDErz3WJoK7lawxKTJNhgPNafRST6csC/MZC+L5P6kKqsZGRInpbgc02s/WZMrb4uGJzcuRg==", - "dev": true, - "requires": { - "array-find": "^1.0.0", - "debug": "^3.2.7", - "enhanced-resolve": "^0.9.1", - "find-root": "^1.1.0", - "has": "^1.0.3", - "interpret": "^1.4.0", - "is-core-module": "^2.7.0", - "is-regex": "^1.1.4", - "lodash": "^4.17.21", - "resolve": "^1.20.0", - "semver": "^5.7.1" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "eslint-module-utils": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.2.tgz", - "integrity": "sha512-zquepFnWCY2ISMFwD/DqzaM++H+7PDzOpUvotJWm/y1BAFt5R4oeULgdrTejKqLkz7MA/tgstsUMNYc7wNdTrg==", - "dev": true, - "requires": { - "debug": "^3.2.7", - "find-up": "^2.1.0" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - } - } - }, - "eslint-plugin-flowtype": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-8.0.3.tgz", - "integrity": "sha512-dX8l6qUL6O+fYPtpNRideCFSpmWOUVx5QcaGLVqe/vlDiBSe4vYljDWDETwnyFzpl7By/WVIu6rcrniCgH9BqQ==", - "dev": true, - "requires": { - "lodash": "^4.17.21", - "string-natural-compare": "^3.0.1" - } - }, - "eslint-plugin-i18next": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-i18next/-/eslint-plugin-i18next-5.2.1.tgz", - "integrity": "sha512-yXlWOMiyWz9aCGVrLeFijt+LsCXZj9QoddYXmxUeFZrqst4Z2j6vAMBn2iSE2JTNbPDyrdGl3H03UCo+CbdKbQ==", - "dev": true, - "requires": { - "requireindex": "~1.1.0" - } - }, - "eslint-plugin-import": { - "version": "2.25.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz", - "integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==", - "dev": true, - "requires": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.2", - "has": "^1.0.3", - "is-core-module": "^2.8.0", - "is-glob": "^4.0.3", - "minimatch": "^3.0.4", - "object.values": "^1.1.5", - "resolve": "^1.20.0", - "tsconfig-paths": "^3.12.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "eslint-plugin-jest": { - "version": "25.7.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-25.7.0.tgz", - "integrity": "sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==", - "dev": true, - "requires": { - "@typescript-eslint/experimental-utils": "^5.0.0" - } - }, - "eslint-plugin-jsx-a11y": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.5.1.tgz", - "integrity": "sha512-sVCFKX9fllURnXT2JwLN5Qgo24Ug5NF6dxhkmxsMEUZhXRcGg+X3e1JbJ84YePQKBl5E0ZjAH5Q4rkdcGY99+g==", - "dev": true, - "requires": { - "@babel/runtime": "^7.16.3", - "aria-query": "^4.2.2", - "array-includes": "^3.1.4", - "ast-types-flow": "^0.0.7", - "axe-core": "^4.3.5", - "axobject-query": "^2.2.0", - "damerau-levenshtein": "^1.0.7", - "emoji-regex": "^9.2.2", - "has": "^1.0.3", - "jsx-ast-utils": "^3.2.1", - "language-tags": "^1.0.5", - "minimatch": "^3.0.4" - }, - "dependencies": { - "emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - } - } - }, - "eslint-plugin-react": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.28.0.tgz", - "integrity": "sha512-IOlFIRHzWfEQQKcAD4iyYDndHwTQiCMcJVJjxempf203jnNLUnW34AXLrV33+nEXoifJE2ZEGmcjKPL8957eSw==", - "dev": true, - "requires": { - "array-includes": "^3.1.4", - "array.prototype.flatmap": "^1.2.5", - "doctrine": "^2.1.0", - "estraverse": "^5.3.0", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.0.4", - "object.entries": "^1.1.5", - "object.fromentries": "^2.0.5", - "object.hasown": "^1.1.0", - "object.values": "^1.1.5", - "prop-types": "^15.7.2", - "resolve": "^2.0.0-next.3", - "semver": "^6.3.0", - "string.prototype.matchall": "^4.0.6" - }, - "dependencies": { - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "resolve": { - "version": "2.0.0-next.3", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", - "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==", - "dev": true, - "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - } - } - } - }, - "eslint-plugin-react-hooks": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.3.0.tgz", - "integrity": "sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA==", - "dev": true, - "requires": {} - }, - "eslint-plugin-testing-library": { - "version": "5.9.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.9.1.tgz", - "integrity": "sha512-6BQp3tmb79jLLasPHJmy8DnxREe+2Pgf7L+7o09TSWPfdqqtQfRZmZNetr5mOs3yqZk/MRNxpN3RUpJe0wB4LQ==", - "dev": true, - "requires": { - "@typescript-eslint/utils": "^5.13.0" - } - }, - "eslint-rule-composer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", - "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", - "dev": true - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - } - }, - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - }, - "espree": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.0.tgz", - "integrity": "sha512-d/5nCsb0JcqsSEeQzFZ8DH1RmxPcglRWh24EFTlUEmCKoehXGdpsx0RkHDubqUI8LSAIKMQp4r9SzQ3n+sm4HQ==", - "dev": true, - "requires": { - "acorn": "^8.7.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^3.1.0" - }, - "dependencies": { - "acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", - "dev": true - }, - "eslint-visitor-keys": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.2.0.tgz", - "integrity": "sha512-IOzT0X126zn7ALX0dwFiUQEdsfzrm4+ISsQS8nukaJXwEyYKRSnEIIDULYg1mCtGp7UUXgfGl7BIolXREQK+XQ==", - "dev": true - } - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "dev": true - }, - "eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true - }, - "events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true - }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true - }, - "expect": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.4.6.tgz", - "integrity": "sha512-1M/0kAALIaj5LaG66sFJTbRsWTADnylly82cu4bspI0nl+pgP4E6Bh/aqdHlTUjul06K7xQnnrAoqfxVU0+/ag==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "jest-get-type": "^27.4.0", - "jest-matcher-utils": "^27.4.6", - "jest-message-util": "^27.4.6" - }, - "dependencies": { - "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "jest-get-type": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", - "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", - "dev": true, - "requires": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.1", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "dependencies": { - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", - "dev": true - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", - "dev": true - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - }, - "statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true - } - } - }, - "external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", - "dev": true, - "requires": { - "websocket-driver": ">=0.5.1" - } - }, - "fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", - "dev": true, - "requires": { - "bser": "2.1.1" - } - }, - "figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "file-loader": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", - "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", - "dev": true, - "requires": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" - } - }, - "file-selector": { - "version": "0.1.19", - "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.1.19.tgz", - "integrity": "sha512-kCWw3+Aai8Uox+5tHCNgMFaUdgidxvMnLWO6fM5sZ0hA2wlHP5/DHGF0ECe84BiB95qdJbKNEJhWKVDvMN+JDQ==", - "requires": { - "tslib": "^2.0.1" - }, - "dependencies": { - "tslib": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz", - "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==" - } - } - }, - "filelist": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", - "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", - "dev": true, - "requires": { - "minimatch": "^5.0.1" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "minimatch": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", - "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - } - } - }, - "filesize": { - "version": "8.0.7", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", - "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==", - "dev": true - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "dev": true, - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true - } - } - }, - "find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, - "dependencies": { - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - } - } - }, - "find-root": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", - "dev": true - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "find-yarn-workspace-root": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz", - "integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==", - "dev": true, - "requires": { - "micromatch": "^4.0.2" - } - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", - "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", - "dev": true - }, - "focus-trap": { - "version": "6.9.2", - "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-6.9.2.tgz", - "integrity": "sha512-gBEuXOPNOKPrLdZpMFUSTyIo1eT2NSZRrwZ9r/0Jqw5tmT3Yvxfmu8KBHw8xW2XQkw6E/JoG+OlEq7UDtSUNgw==", - "requires": { - "tabbable": "^5.3.2" - } - }, - "follow-redirects": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", - "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==" - }, - "fork-ts-checker-webpack-plugin": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.2.tgz", - "integrity": "sha512-m5cUmF30xkZ7h4tWUgTAcEaKmUW7tfyUyTqNNOz7OxWJ0v1VWKTcOvH8FWHUwSjlW/356Ijc9vi3XfcPstpQKA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.8.3", - "@types/json-schema": "^7.0.5", - "chalk": "^4.1.0", - "chokidar": "^3.4.2", - "cosmiconfig": "^6.0.0", - "deepmerge": "^4.2.2", - "fs-extra": "^9.0.0", - "glob": "^7.1.6", - "memfs": "^3.1.2", - "minimatch": "^3.0.4", - "schema-utils": "2.7.0", - "semver": "^7.3.2", - "tapable": "^1.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "cosmiconfig": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", - "dev": true, - "requires": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.7.2" - } - }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "schema-utils": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", - "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.4", - "ajv": "^6.12.2", - "ajv-keywords": "^3.4.1" - } - }, - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "tapable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", - "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", - "dev": true - } - } - }, - "form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "formik": { - "version": "2.2.9", - "resolved": "https://registry.npmjs.org/formik/-/formik-2.2.9.tgz", - "integrity": "sha512-LQLcISMmf1r5at4/gyJigGn0gOwFbeEAlji+N9InZF6LIMXnFNkO42sCI8Jt84YZggpD4cPWObAZaxpEFtSzNA==", - "requires": { - "deepmerge": "^2.1.1", - "hoist-non-react-statics": "^3.3.0", - "lodash": "^4.17.21", - "lodash-es": "^4.17.21", - "react-fast-compare": "^2.0.1", - "tiny-warning": "^1.0.2", - "tslib": "^1.10.0" - } - }, - "forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "dev": true - }, - "fraction.js": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.2.tgz", - "integrity": "sha512-o2RiJQ6DZaR/5+Si0qJUIy637QMRudSi9kU/FFzx9EZazrIdnBgpU+3sEWCxAVhH2RtxW2Oz+T4p2o8uOPVcgA==", - "dev": true - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "dev": true - }, - "fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "requires": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "fs-monkey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", - "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "function.prototype.name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.4.tgz", - "integrity": "sha512-iqy1pIotY/RmhdFZygSSlW0wko2yxkSCKqsuv4pr8QESohpYyG/Z7B/XXvPRKTJS//960rgguE5mSRUsDdaJrQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", - "functions-have-names": "^1.2.2" - } - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "functions-have-names": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.2.tgz", - "integrity": "sha512-bLgc3asbWdwPbx2mNk2S49kmJCuQeu0nfmaOgbs8WIyzzkw3r4htszdIi9Q9EMezDPTYuJx2wvjZ/EwgAthpnA==", - "dev": true - }, - "fuzzaldrin": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fuzzaldrin/-/fuzzaldrin-2.1.0.tgz", - "integrity": "sha1-kCBMPi/appQbso0WZF1BgGOpDps=", - "dev": true - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "get-own-enumerable-property-symbols": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", - "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", - "dev": true - }, - "get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true - }, - "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true - }, - "global-modules": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", - "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", - "dev": true, - "requires": { - "global-prefix": "^3.0.0" - } - }, - "global-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", - "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", - "dev": true, - "requires": { - "ini": "^1.3.5", - "kind-of": "^6.0.2", - "which": "^1.3.1" - }, - "dependencies": { - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" - }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, - "graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", - "dev": true - }, - "graphlib": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz", - "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==", - "requires": { - "lodash": "^4.17.15" - } - }, - "gzip-size": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", - "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", - "dev": true, - "requires": { - "duplexer": "^0.1.2" - } - }, - "handle-thing": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true - }, - "harmony-reflect": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz", - "integrity": "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-ansi": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-5.0.1.tgz", - "integrity": "sha512-Fp2IsZDnnyoJkKg22ZyQFvD7QRCcMTsLAtloKXyXWJ1joGLtItRU9Bv/k1o0tELL2NF3ZZBcycSKryZUM+Yl3g==", - "requires": { - "ansi-regex": "^6.0.1" - } - }, - "has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true - }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, - "history": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", - "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", - "requires": { - "@babel/runtime": "^7.1.2", - "loose-envify": "^1.2.0", - "resolve-pathname": "^3.0.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0", - "value-equal": "^1.0.1" - } - }, - "hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "requires": { - "react-is": "^16.7.0" - } - }, - "hoopy": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", - "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==", - "dev": true - }, - "hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "html-element-map": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/html-element-map/-/html-element-map-1.3.0.tgz", - "integrity": "sha512-AqCt/m9YaiMwaaAyOPdq4Ga0cM+jdDWWGueUMkdROZcTeClaGpN0AQeyGchZhTegQoABmc6+IqH7oCR/8vhQYg==", - "dev": true, - "requires": { - "array-filter": "^1.0.0", - "call-bind": "^1.0.2" - } - }, - "html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", - "dev": true, - "requires": { - "whatwg-encoding": "^1.0.5" - } - }, - "html-entities": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.2.tgz", - "integrity": "sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==" - }, - "html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", - "dev": true, - "requires": { - "camel-case": "^4.1.2", - "clean-css": "^5.2.2", - "commander": "^8.3.0", - "he": "^1.2.0", - "param-case": "^3.0.4", - "relateurl": "^0.2.7", - "terser": "^5.10.0" - }, - "dependencies": { - "commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "dev": true - } - } - }, - "html-webpack-plugin": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz", - "integrity": "sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw==", - "dev": true, - "requires": { - "@types/html-minifier-terser": "^6.0.0", - "html-minifier-terser": "^6.0.2", - "lodash": "^4.17.21", - "pretty-error": "^4.0.0", - "tapable": "^2.0.0" - }, - "dependencies": { - "tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true - } - } - }, - "htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "dev": true, - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, - "http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", - "dev": true - }, - "http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dev": true, - "requires": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "dependencies": { - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true - }, - "statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true - } - } - }, - "http-parser-js": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.5.tgz", - "integrity": "sha512-x+JVEkO2PoM8qqpbPbOL3cqHPwerep7OwzK7Ay+sMQjKzaKCqWvjoXm5tqMP9tXWWTnTzAjIhXg+J99XYuPhPA==", - "dev": true - }, - "http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dev": true, - "requires": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - } - }, - "http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dev": true, - "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - } - }, - "http-proxy-middleware": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-1.3.1.tgz", - "integrity": "sha512-13eVVDYS4z79w7f1+NPllJtOQFx/FdUW4btIvVRMaRlUY9VGstAbo5MOhLEuUgZFRHn3x50ufn25zkj/boZnEg==", - "dev": true, - "requires": { - "@types/http-proxy": "^1.17.5", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" - } - }, - "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dev": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "icss-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "dev": true, - "requires": {} - }, - "idb": { - "version": "6.1.5", - "resolved": "https://registry.npmjs.org/idb/-/idb-6.1.5.tgz", - "integrity": "sha512-IJtugpKkiVXQn5Y+LteyBCNk1N8xpGV3wWZk9EVtZWH8DYkjBn0bX1XnGP9RkyZF0sAcywa6unHqSWKe7q4LGw==", - "dev": true - }, - "identity-obj-proxy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", - "integrity": "sha1-lNK9qWCERT7zb7xarsN+D3nx/BQ=", - "dev": true, - "requires": { - "harmony-reflect": "^1.4.6" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true - }, - "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true - }, - "immer": { - "version": "9.0.16", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.16.tgz", - "integrity": "sha512-qenGE7CstVm1NrHQbMh8YaSzTZTFNP3zPqr3YU0S0UY441j4bJTg4A2Hh5KAhwgaiU6ZZ1Ar6y/2f4TblnMReQ==", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "dependencies": { - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - } - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "inquirer": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", - "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.19", - "mute-stream": "0.0.8", - "run-async": "^2.4.0", - "rxjs": "^6.6.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, - "internmap": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", - "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==" - }, - "interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true - }, - "ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", - "dev": true - }, - "ipaddr.js": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", - "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==", - "dev": true - }, - "is-alphabetical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", - "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", - "dev": true - }, - "is-alphanumerical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", - "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", - "dev": true, - "requires": { - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0" - } - }, - "is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-bigint": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz", - "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==", - "dev": true - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-boolean-object": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz", - "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "dev": true - }, - "is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-date-object": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.4.tgz", - "integrity": "sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A==", - "dev": true - }, - "is-decimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", - "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", - "dev": true - }, - "is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "dev": true - }, - "is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", - "dev": true - }, - "is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", - "dev": true - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-number-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz", - "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==", - "dev": true - }, - "is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", - "dev": true - }, - "is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "dev": true - }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true - }, - "is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", - "dev": true - }, - "is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", - "dev": true - }, - "is-root": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", - "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==", - "dev": true - }, - "is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", - "dev": true - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-subset": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-subset/-/is-subset-0.1.1.tgz", - "integrity": "sha1-ilkRfZMt4d4A8kX83TnOQ/HpOaY=", - "dev": true - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true - }, - "is-weakref": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz", - "integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.0" - } - }, - "is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "requires": { - "is-docker": "^2.0.0" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", - "dev": true, - "requires": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - } - }, - "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - } - }, - "istanbul-reports": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.3.tgz", - "integrity": "sha512-x9LtDVtfm/t1GFiLl3NffC7hz+I1ragvgX1P/Lg1NlIagifZDKUkuuaAxH/qpwj2IuEfD8G2Bs/UKp+sZ/pKkg==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, - "jake": { - "version": "10.8.5", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", - "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==", - "dev": true, - "requires": { - "async": "^3.2.3", - "chalk": "^4.0.2", - "filelist": "^1.0.1", - "minimatch": "^3.0.4" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "async": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", - "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest": { - "version": "27.4.7", - "resolved": "https://registry.npmjs.org/jest/-/jest-27.4.7.tgz", - "integrity": "sha512-8heYvsx7nV/m8m24Vk26Y87g73Ba6ueUd0MWed/NXMhSZIm62U/llVbS0PJe1SHunbyXjJ/BqG1z9bFjGUIvTg==", - "dev": true, - "requires": { - "@jest/core": "^27.4.7", - "import-local": "^3.0.2", - "jest-cli": "^27.4.7" - } - }, - "jest-changed-files": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.4.2.tgz", - "integrity": "sha512-/9x8MjekuzUQoPjDHbBiXbNEBauhrPU2ct7m8TfCg69ywt1y/N+yYwGh3gCpnqUS3klYWDU/lSNgv+JhoD2k1A==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "execa": "^5.0.0", - "throat": "^6.0.1" - }, - "dependencies": { - "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-circus": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.4.6.tgz", - "integrity": "sha512-UA7AI5HZrW4wRM72Ro80uRR2Fg+7nR0GESbSI/2M+ambbzVuA63mn5T1p3Z/wlhntzGpIG1xx78GP2YIkf6PhQ==", - "dev": true, - "requires": { - "@jest/environment": "^27.4.6", - "@jest/test-result": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "expect": "^27.4.6", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.4.6", - "jest-matcher-utils": "^27.4.6", - "jest-message-util": "^27.4.6", - "jest-runtime": "^27.4.6", - "jest-snapshot": "^27.4.6", - "jest-util": "^27.4.2", - "pretty-format": "^27.4.6", - "slash": "^3.0.0", - "stack-utils": "^2.0.3", - "throat": "^6.0.1" - }, - "dependencies": { - "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "pretty-format": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz", - "integrity": "sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-cli": { - "version": "27.4.7", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.4.7.tgz", - "integrity": "sha512-zREYhvjjqe1KsGV15mdnxjThKNDgza1fhDT+iUsXWLCq3sxe9w5xnvyctcYVT5PcdLSjv7Y5dCwTS3FCF1tiuw==", - "dev": true, - "requires": { - "@jest/core": "^27.4.7", - "@jest/test-result": "^27.4.6", - "@jest/types": "^27.4.2", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "import-local": "^3.0.2", - "jest-config": "^27.4.7", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.6", - "prompts": "^2.0.1", - "yargs": "^16.2.0" - }, - "dependencies": { - "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "jest-get-type": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", - "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", - "dev": true - }, - "jest-validate": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.4.6.tgz", - "integrity": "sha512-872mEmCPVlBqbA5dToC57vA3yJaMRfIdpCoD3cyHWJOMx+SJwLNw0I71EkWs41oza/Er9Zno9XuTkRYCPDUJXQ==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", - "leven": "^3.1.0", - "pretty-format": "^27.4.6" - } - }, - "pretty-format": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz", - "integrity": "sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-config": { - "version": "27.4.7", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.4.7.tgz", - "integrity": "sha512-xz/o/KJJEedHMrIY9v2ParIoYSrSVY6IVeE4z5Z3i101GoA5XgfbJz+1C8EYPsv7u7f39dS8F9v46BHDhn0vlw==", - "dev": true, - "requires": { - "@babel/core": "^7.8.0", - "@jest/test-sequencer": "^27.4.6", - "@jest/types": "^27.4.2", - "babel-jest": "^27.4.6", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.4", - "jest-circus": "^27.4.6", - "jest-environment-jsdom": "^27.4.6", - "jest-environment-node": "^27.4.6", - "jest-get-type": "^27.4.0", - "jest-jasmine2": "^27.4.6", - "jest-regex-util": "^27.4.0", - "jest-resolve": "^27.4.6", - "jest-runner": "^27.4.6", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.6", - "micromatch": "^4.0.4", - "pretty-format": "^27.4.6", - "slash": "^3.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "jest-get-type": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", - "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", - "dev": true - }, - "jest-validate": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.4.6.tgz", - "integrity": "sha512-872mEmCPVlBqbA5dToC57vA3yJaMRfIdpCoD3cyHWJOMx+SJwLNw0I71EkWs41oza/Er9Zno9XuTkRYCPDUJXQ==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", - "leven": "^3.1.0", - "pretty-format": "^27.4.6" - } - }, - "pretty-format": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz", - "integrity": "sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-diff": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.4.6.tgz", - "integrity": "sha512-zjaB0sh0Lb13VyPsd92V7HkqF6yKRH9vm33rwBt7rPYrpQvS1nCvlIy2pICbKta+ZjWngYLNn4cCK4nyZkjS/w==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^27.4.0", - "jest-get-type": "^27.4.0", - "pretty-format": "^27.4.6" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "jest-get-type": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", - "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", - "dev": true - }, - "pretty-format": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz", - "integrity": "sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-docblock": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.4.0.tgz", - "integrity": "sha512-7TBazUdCKGV7svZ+gh7C8esAnweJoG+SvcF6Cjqj4l17zA2q1cMwx2JObSioubk317H+cjcHgP+7fTs60paulg==", - "dev": true, - "requires": { - "detect-newline": "^3.0.0" - } - }, - "jest-each": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.4.6.tgz", - "integrity": "sha512-n6QDq8y2Hsmn22tRkgAk+z6MCX7MeVlAzxmZDshfS2jLcaBlyhpF3tZSJLR+kXmh23GEvS0ojMR8i6ZeRvpQcA==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", - "jest-util": "^27.4.2", - "pretty-format": "^27.4.6" - }, - "dependencies": { - "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "jest-get-type": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", - "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", - "dev": true - }, - "pretty-format": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz", - "integrity": "sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-environment-jsdom": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.4.6.tgz", - "integrity": "sha512-o3dx5p/kHPbUlRvSNjypEcEtgs6LmvESMzgRFQE6c+Prwl2JLA4RZ7qAnxc5VM8kutsGRTB15jXeeSbJsKN9iA==", - "dev": true, - "requires": { - "@jest/environment": "^27.4.6", - "@jest/fake-timers": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/node": "*", - "jest-mock": "^27.4.6", - "jest-util": "^27.4.2", - "jsdom": "^16.6.0" - }, - "dependencies": { - "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-environment-node": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.4.6.tgz", - "integrity": "sha512-yfHlZ9m+kzTKZV0hVfhVu6GuDxKAYeFHrfulmy7Jxwsq4V7+ZK7f+c0XP/tbVDMQW7E4neG2u147hFkuVz0MlQ==", - "dev": true, - "requires": { - "@jest/environment": "^27.4.6", - "@jest/fake-timers": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/node": "*", - "jest-mock": "^27.4.6", - "jest-util": "^27.4.2" - }, - "dependencies": { - "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", - "dev": true - }, - "jest-haste-map": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.4.6.tgz", - "integrity": "sha512-0tNpgxg7BKurZeFkIOvGCkbmOHbLFf4LUQOxrQSMjvrQaQe3l6E8x6jYC1NuWkGo5WDdbr8FEzUxV2+LWNawKQ==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.4", - "jest-regex-util": "^27.4.0", - "jest-serializer": "^27.4.0", - "jest-util": "^27.4.2", - "jest-worker": "^27.4.6", - "micromatch": "^4.0.4", - "walker": "^1.0.7" - }, - "dependencies": { - "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-jasmine2": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.4.6.tgz", - "integrity": "sha512-uAGNXF644I/whzhsf7/qf74gqy9OuhvJ0XYp8SDecX2ooGeaPnmJMjXjKt0mqh1Rl5dtRGxJgNrHlBQIBfS5Nw==", - "dev": true, - "requires": { - "@jest/environment": "^27.4.6", - "@jest/source-map": "^27.4.0", - "@jest/test-result": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^27.4.6", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.4.6", - "jest-matcher-utils": "^27.4.6", - "jest-message-util": "^27.4.6", - "jest-runtime": "^27.4.6", - "jest-snapshot": "^27.4.6", - "jest-util": "^27.4.2", - "pretty-format": "^27.4.6", - "throat": "^6.0.1" - }, - "dependencies": { - "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "pretty-format": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz", - "integrity": "sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-leak-detector": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.4.6.tgz", - "integrity": "sha512-kkaGixDf9R7CjHm2pOzfTxZTQQQ2gHTIWKY/JZSiYTc90bZp8kSZnUMS3uLAfwTZwc0tcMRoEX74e14LG1WapA==", - "dev": true, - "requires": { - "jest-get-type": "^27.4.0", - "pretty-format": "^27.4.6" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - }, - "jest-get-type": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", - "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", - "dev": true - }, - "pretty-format": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz", - "integrity": "sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - } - } - }, - "jest-matcher-utils": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.4.6.tgz", - "integrity": "sha512-XD4PKT3Wn1LQnRAq7ZsTI0VRuEc9OrCPFiO1XL7bftTGmfNF0DcEwMHRgqiu7NGf8ZoZDREpGrCniDkjt79WbA==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^27.4.6", - "jest-get-type": "^27.4.0", - "pretty-format": "^27.4.6" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "jest-get-type": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", - "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", - "dev": true - }, - "pretty-format": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz", - "integrity": "sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-message-util": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.4.6.tgz", - "integrity": "sha512-0p5szriFU0U74czRSFjH6RyS7UYIAkn/ntwMuOwTGWrQIOh5NzXXrq72LOqIkJKKvFbPq+byZKuBz78fjBERBA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.4.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.4", - "pretty-format": "^27.4.6", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "dependencies": { - "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "pretty-format": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz", - "integrity": "sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-mock": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.4.6.tgz", - "integrity": "sha512-kvojdYRkst8iVSZ1EJ+vc1RRD9llueBjKzXzeCytH3dMM7zvPV/ULcfI2nr0v0VUgm3Bjt3hBCQvOeaBz+ZTHw==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "@types/node": "*" - }, - "dependencies": { - "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, - "requires": {} - }, - "jest-regex-util": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.4.0.tgz", - "integrity": "sha512-WeCpMpNnqJYMQoOjm1nTtsgbR4XHAk1u00qDoNBQoykM280+/TmgA5Qh5giC1ecy6a5d4hbSsHzpBtu5yvlbEg==", - "dev": true - }, - "jest-resolve": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.4.6.tgz", - "integrity": "sha512-SFfITVApqtirbITKFAO7jOVN45UgFzcRdQanOFzjnbd+CACDoyeX7206JyU92l4cRr73+Qy/TlW51+4vHGt+zw==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.6", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.6", - "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", - "slash": "^3.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "jest-get-type": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", - "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", - "dev": true - }, - "jest-validate": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.4.6.tgz", - "integrity": "sha512-872mEmCPVlBqbA5dToC57vA3yJaMRfIdpCoD3cyHWJOMx+SJwLNw0I71EkWs41oza/Er9Zno9XuTkRYCPDUJXQ==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", - "leven": "^3.1.0", - "pretty-format": "^27.4.6" - } - }, - "pretty-format": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz", - "integrity": "sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-resolve-dependencies": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.4.6.tgz", - "integrity": "sha512-W85uJZcFXEVZ7+MZqIPCscdjuctruNGXUZ3OHSXOfXR9ITgbUKeHj+uGcies+0SsvI5GtUfTw4dY7u9qjTvQOw==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "jest-regex-util": "^27.4.0", - "jest-snapshot": "^27.4.6" - }, - "dependencies": { - "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-runner": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.4.6.tgz", - "integrity": "sha512-IDeFt2SG4DzqalYBZRgbbPmpwV3X0DcntjezPBERvnhwKGWTW7C5pbbA5lVkmvgteeNfdd/23gwqv3aiilpYPg==", - "dev": true, - "requires": { - "@jest/console": "^27.4.6", - "@jest/environment": "^27.4.6", - "@jest/test-result": "^27.4.6", - "@jest/transform": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.8.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-docblock": "^27.4.0", - "jest-environment-jsdom": "^27.4.6", - "jest-environment-node": "^27.4.6", - "jest-haste-map": "^27.4.6", - "jest-leak-detector": "^27.4.6", - "jest-message-util": "^27.4.6", - "jest-resolve": "^27.4.6", - "jest-runtime": "^27.4.6", - "jest-util": "^27.4.2", - "jest-worker": "^27.4.6", - "source-map-support": "^0.5.6", - "throat": "^6.0.1" - }, - "dependencies": { - "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-runtime": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.4.6.tgz", - "integrity": "sha512-eXYeoR/MbIpVDrjqy5d6cGCFOYBFFDeKaNWqTp0h6E74dK0zLHzASQXJpl5a2/40euBmKnprNLJ0Kh0LCndnWQ==", - "dev": true, - "requires": { - "@jest/environment": "^27.4.6", - "@jest/fake-timers": "^27.4.6", - "@jest/globals": "^27.4.6", - "@jest/source-map": "^27.4.0", - "@jest/test-result": "^27.4.6", - "@jest/transform": "^27.4.6", - "@jest/types": "^27.4.2", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "execa": "^5.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.6", - "jest-message-util": "^27.4.6", - "jest-mock": "^27.4.6", - "jest-regex-util": "^27.4.0", - "jest-resolve": "^27.4.6", - "jest-snapshot": "^27.4.6", - "jest-util": "^27.4.2", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-serializer": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.4.0.tgz", - "integrity": "sha512-RDhpcn5f1JYTX2pvJAGDcnsNTnsV9bjYPU8xcV+xPwOXnUPOQwf4ZEuiU6G9H1UztH+OapMgu/ckEVwO87PwnQ==", - "dev": true, - "requires": { - "@types/node": "*", - "graceful-fs": "^4.2.4" - } - }, - "jest-snapshot": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.4.6.tgz", - "integrity": "sha512-fafUCDLQfzuNP9IRcEqaFAMzEe7u5BF7mude51wyWv7VRex60WznZIC7DfKTgSIlJa8aFzYmXclmN328aqSDmQ==", - "dev": true, - "requires": { - "@babel/core": "^7.7.2", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.0.0", - "@jest/transform": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^27.4.6", - "graceful-fs": "^4.2.4", - "jest-diff": "^27.4.6", - "jest-get-type": "^27.4.0", - "jest-haste-map": "^27.4.6", - "jest-matcher-utils": "^27.4.6", - "jest-message-util": "^27.4.6", - "jest-util": "^27.4.2", - "natural-compare": "^1.4.0", - "pretty-format": "^27.4.6", - "semver": "^7.3.2" - }, - "dependencies": { - "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "jest-get-type": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", - "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", - "dev": true - }, - "pretty-format": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz", - "integrity": "sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-util": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.4.2.tgz", - "integrity": "sha512-YuxxpXU6nlMan9qyLuxHaMMOzXAl5aGZWCSzben5DhLHemYQxCc4YK+4L3ZrCutT8GPQ+ui9k5D8rUJoDioMnA==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.4", - "picomatch": "^2.2.3" - }, - "dependencies": { - "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-validate": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-26.6.2.tgz", - "integrity": "sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "camelcase": "^6.0.0", - "chalk": "^4.0.0", - "jest-get-type": "^26.3.0", - "leven": "^3.1.0", - "pretty-format": "^26.6.2" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", - "dev": true - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-watch-typeahead": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/jest-watch-typeahead/-/jest-watch-typeahead-1.0.0.tgz", - "integrity": "sha512-jxoszalAb394WElmiJTFBMzie/RDCF+W7Q29n5LzOPtcoQoHWfdUtHFkbhgf5NwWe8uMOxvKb/g7ea7CshfkTw==", - "dev": true, - "requires": { - "ansi-escapes": "^4.3.1", - "chalk": "^4.0.0", - "jest-regex-util": "^27.0.0", - "jest-watcher": "^27.0.0", - "slash": "^4.0.0", - "string-length": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "char-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-2.0.0.tgz", - "integrity": "sha512-oGu2QekBMXgyQNWPDRQ001bjvDnZe4/zBTz37TMbiKz1NbNiyiH5hRkobe7npRN6GfbGbxMYFck/vQ1r9c1VMA==", - "dev": true - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", - "dev": true - }, - "string-length": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-5.0.1.tgz", - "integrity": "sha512-9Ep08KAMUn0OadnVaBuRdE2l615CQ508kr0XMadjClfYpdCyvrbFp6Taebo8yyxokQ4viUd/xPPUA4FGgUa0ow==", - "dev": true, - "requires": { - "char-regex": "^2.0.0", - "strip-ansi": "^7.0.1" - } - }, - "strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", - "dev": true, - "requires": { - "ansi-regex": "^6.0.1" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-watcher": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.4.6.tgz", - "integrity": "sha512-yKQ20OMBiCDigbD0quhQKLkBO+ObGN79MO4nT7YaCuQ5SM+dkBNWE8cZX0FjU6czwMvWw6StWbe+Wv4jJPJ+fw==", - "dev": true, - "requires": { - "@jest/test-result": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "jest-util": "^27.4.2", - "string-length": "^4.0.1" - }, - "dependencies": { - "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-websocket-mock": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/jest-websocket-mock/-/jest-websocket-mock-2.2.0.tgz", - "integrity": "sha512-lc3wwXOEyNa4ZpcgJtUG3mmKMAq5FAsKYiZph0p/+PAJrAPuX4JCIfJMdJ/urRsLBG51fwm/wlVPNbR6s2nzNw==", - "dev": true - }, - "jest-worker": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.6.tgz", - "integrity": "sha512-gHWJF/6Xi5CTG5QCvROr6GcmpIqNYpDJyc8A1h/DyXqH1tD6SnRCM0d3U5msV31D2LB/U+E0M+W4oyvKV44oNw==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "requires": { - "argparse": "^2.0.1" - } - }, - "jsdom": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", - "dev": true, - "requires": { - "abab": "^2.0.5", - "acorn": "^8.2.4", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.3.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.1", - "domexception": "^2.0.1", - "escodegen": "^2.0.0", - "form-data": "^3.0.0", - "html-encoding-sniffer": "^2.0.1", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.5.0", - "ws": "^7.4.6", - "xml-name-validator": "^3.0.0" - }, - "dependencies": { - "acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", - "dev": true - } - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "jsonpointer": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.0.tgz", - "integrity": "sha512-PNYZIdMjVIvVgDSYKTT63Y+KZ6IZvGRNNWcxwD+GNnUz1MKPfv30J8ueCjdwcN0nDx2SlshgyB7Oy0epAzVRRg==", - "dev": true - }, - "jsx-ast-utils": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz", - "integrity": "sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA==", - "dev": true, - "requires": { - "array-includes": "^3.1.3", - "object.assign": "^4.1.2" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true - }, - "klona": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", - "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==", - "dev": true - }, - "language-subtag-registry": { - "version": "0.3.21", - "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz", - "integrity": "sha512-L0IqwlIXjilBVVYKFT37X9Ih11Um5NEl9cbJIuU/SwP/zEEAbBPOnEeeuxVMf45ydWQRDQN3Nqc96OgbH1K+Pg==", - "dev": true - }, - "language-tags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", - "integrity": "sha1-0yHbxNowuovzAk4ED6XBRmH5GTo=", - "dev": true, - "requires": { - "language-subtag-registry": "~0.3.2" - } - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "lilconfig": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz", - "integrity": "sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==", - "dev": true - }, - "lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", - "dev": true - }, - "loader-runner": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", - "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", - "dev": true - }, - "loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" - }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", - "dev": true - }, - "lodash.escape": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-4.0.1.tgz", - "integrity": "sha1-yQRGkMIeBClL6qUXcS/e0fqI3pg=", - "dev": true - }, - "lodash.flattendeep": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", - "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", - "dev": true - }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" - }, - "lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" - }, - "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", - "dev": true - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true - }, - "lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", - "dev": true - }, - "log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "lower-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "dev": true, - "requires": { - "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - } - } - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "luxon": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.2.1.tgz", - "integrity": "sha512-QrwPArQCNLAKGO/C+ZIilgIuDnEnKx5QYODdDtbFaxzsbZcc/a7WFq7MhsVYgRlwawLtvOUESTlfJ+hc/USqPg==" - }, - "lz-string": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", - "integrity": "sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=", - "dev": true - }, - "magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", - "dev": true, - "requires": { - "sourcemap-codec": "^1.4.4" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - } - }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "make-plural": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/make-plural/-/make-plural-6.2.2.tgz", - "integrity": "sha512-8iTuFioatnTTmb/YJjywkVIHLjcwkFD9Ms0JpxjEm9Mo8eQYkh1z+55dwv4yc1jQ8ftVBxWQbihvZL1DfzGGWA==" - }, - "makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "requires": { - "tmpl": "1.0.5" - } - }, - "mdn-data": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", - "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", - "dev": true - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "dev": true - }, - "memfs": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.1.tgz", - "integrity": "sha512-1c9VPVvW5P7I85c35zAdEr1TD5+F11IToIHIlrVIcflfnzPkJa0ZoYEoEdYDP8KgPFoSZ/opDrUsAoZWym3mtw==", - "dev": true, - "requires": { - "fs-monkey": "1.0.3" - } - }, - "memory-fs": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.2.0.tgz", - "integrity": "sha1-8rslNovBIeORwlIN6Slpyu4KApA=", - "dev": true - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", - "dev": true - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "messageformat-parser": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/messageformat-parser/-/messageformat-parser-4.1.3.tgz", - "integrity": "sha512-2fU3XDCanRqeOCkn7R5zW5VQHWf+T3hH65SzuqRvjatBK7r4uyFa5mEX+k6F9Bd04LVM5G4/BHBTUJsOdW7uyg==" - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "dev": true - }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true - }, - "mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==" - }, - "mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", - "requires": { - "mime-db": "1.51.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "dev": true - }, - "mini-create-react-context": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz", - "integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==", - "requires": { - "@babel/runtime": "^7.12.1", - "tiny-warning": "^1.0.3" - } - }, - "mini-css-extract-plugin": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.5.2.tgz", - "integrity": "sha512-Lwgq9qLNyBK6yNLgzssXnq4r2+mB9Mz3cJWlM8kseysHIvTicFhDNimFgY94jjqlwhNzLPsq8wv4X+vOHtMdYA==", - "dev": true, - "requires": { - "schema-utils": "^4.0.0" - }, - "dependencies": { - "ajv": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.9.0.tgz", - "integrity": "sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.3" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "schema-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" - } - } - } - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true - }, - "mock-socket": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/mock-socket/-/mock-socket-9.1.3.tgz", - "integrity": "sha512-uz8lx8c5wuJYJ21f5UtovqpV0+KJuVwE7cVOLNhrl2QW/CvmstOLRfjXnLSbfFHZtJtiaSGQu0oCJA8SmRcK6A==", - "dev": true - }, - "moo": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.1.tgz", - "integrity": "sha512-I1mnb5xn4fO80BH9BLcF0yLypy2UKl+Cb01Fu0hJRkJjlCRtxZMWkTdAtDd5ZqCOxtCkhmRwyI57vWT+1iZ67w==", - "dev": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "multicast-dns": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", - "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", - "dev": true, - "requires": { - "dns-packet": "^1.3.1", - "thunky": "^1.0.2" - } - }, - "multicast-dns-service-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", - "dev": true - }, - "mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "nanoid": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", - "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, - "nearley": { - "version": "2.20.1", - "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.20.1.tgz", - "integrity": "sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==", - "dev": true, - "requires": { - "commander": "^2.19.0", - "moo": "^0.5.0", - "railroad-diagrams": "^1.0.0", - "randexp": "0.4.6" - } - }, - "negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true - }, - "neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "no-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", - "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", - "dev": true, - "requires": { - "lower-case": "^2.0.2", - "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - } - } - }, - "node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", - "dev": true - }, - "node-gettext": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/node-gettext/-/node-gettext-3.0.0.tgz", - "integrity": "sha512-/VRYibXmVoN6tnSAY2JWhNRhWYJ8Cd844jrZU/DwLVoI4vBI6ceYbd8i42sYZ9uOgDH3S7vslIKOWV/ZrT2YBA==", - "dev": true, - "requires": { - "lodash.get": "^4.4.2" - } - }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", - "dev": true - }, - "node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", - "dev": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", - "dev": true - }, - "normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", - "dev": true, - "requires": { - "boolbase": "^1.0.0" - } - }, - "nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "object-hash": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", - "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", - "dev": true - }, - "object-inspect": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.1.tgz", - "integrity": "sha512-If7BjFlpkzzBeV1cqgT3OSWT3azyoxDGajR+iGnFBfVV2EWyDyWaZZW2ERDjUaY2QM8i5jI3Sj7mhsM4DDAqWA==", - "dev": true - }, - "object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - } - }, - "object.entries": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", - "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - } - }, - "object.fromentries": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", - "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - } - }, - "object.getownpropertydescriptors": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz", - "integrity": "sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2" - } - }, - "object.hasown": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.0.tgz", - "integrity": "sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - } - }, - "object.values": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", - "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - } - }, - "obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true - }, - "on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dev": true, - "requires": { - "ee-first": "1.1.1" - } - }, - "on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "open": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", - "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", - "dev": true, - "requires": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "ora": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.0.tgz", - "integrity": "sha512-1StwyXQGoU6gdjYkyVcqOLnVlbKj+6yPNNOxJVgpt9t4eksKjiriiHuxktLYkgllwk+D6MbC4ihH84L1udRXPg==", - "dev": true, - "requires": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "requires": { - "aggregate-error": "^3.0.0" - } - }, - "p-retry": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.1.tgz", - "integrity": "sha512-e2xXGNhZOZ0lfgR9kL34iGlU8N/KO0xZnQxVEwdeOvpqNDQfdnxIYizvWtK8RglUa3bGqI8g0R/BdfzLMxRkiA==", - "dev": true, - "requires": { - "@types/retry": "^0.12.0", - "retry": "^0.13.1" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "papaparse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.3.0.tgz", - "integrity": "sha512-Lb7jN/4bTpiuGPrYy4tkKoUS8sTki8zacB5ke1p5zolhcSE4TlWgrlsxjrDTbG/dFVh07ck7X36hUf/b5V68pg==", - "dev": true - }, - "param-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", - "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", - "dev": true, - "requires": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - } - } - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, - "parse5-htmlparser2-tree-adapter": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", - "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", - "dev": true, - "requires": { - "parse5": "^6.0.1" - } - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true - }, - "pascal-case": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", - "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", - "dev": true, - "requires": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - } - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "requires": { - "isarray": "0.0.1" - } - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "picomatch": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz", - "integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==", - "dev": true - }, - "pirates": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.4.tgz", - "integrity": "sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw==", - "dev": true - }, - "pkg-up": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", - "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", - "dev": true, - "requires": { - "find-up": "^3.0.0" - }, - "dependencies": { - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - } - } - }, - "plurals-cldr": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/plurals-cldr/-/plurals-cldr-1.0.4.tgz", - "integrity": "sha512-4nLXqtel7fsCgzi8dvRZvUjfL8SXpP982sKg7b2TgpnR8rDnes06iuQ83trQ/+XdtyMIQkBBbKzX6x97eLfsJQ==", - "dev": true - }, - "pofile": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pofile/-/pofile-1.1.1.tgz", - "integrity": "sha512-RVAzFGo1Mx9+YukVKSgTLut6r4ZVBW8IVrqGHAPfEsVJN93WSp5HRD6+qNa7av1q/joPKDNJd55m5AJl9GBQGA==", - "dev": true - }, - "popper.js": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", - "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==" - }, - "portfinder": { - "version": "1.0.28", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", - "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", - "dev": true, - "requires": { - "async": "^2.6.2", - "debug": "^3.1.1", - "mkdirp": "^0.5.5" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - } - } - }, - "postcss": { - "version": "8.4.5", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", - "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", - "dev": true, - "requires": { - "nanoid": "^3.1.30", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.1" - } - }, - "postcss-attribute-case-insensitive": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.0.tgz", - "integrity": "sha512-b4g9eagFGq9T5SWX4+USfVyjIb3liPnjhHHRMP7FMB2kFVpYyfEscV0wP3eaXhKlcHKUut8lt5BGoeylWA/dBQ==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.2" - } - }, - "postcss-browser-comments": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-browser-comments/-/postcss-browser-comments-4.0.0.tgz", - "integrity": "sha512-X9X9/WN3KIvY9+hNERUqX9gncsgBA25XaeR+jshHz2j8+sYyHktHw1JdKuMjeLpGktXidqDhA7b/qm1mrBDmgg==", - "dev": true, - "requires": {} - }, - "postcss-calc": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.2.tgz", - "integrity": "sha512-B5R0UeB4zLJvxNt1FVCaDZULdzsKLPc6FhjFJ+xwFiq7VG4i9cuaJLxVjNtExNK8ocm3n2o4unXXLiVX1SCqxA==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.0.2" - } - }, - "postcss-color-functional-notation": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.1.tgz", - "integrity": "sha512-62OBIXCjRXpQZcFOYIXwXBlpAVWrYk8ek1rcjvMING4Q2cf0ipyN9qT+BhHA6HmftGSEnFQu2qgKO3gMscl3Rw==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-color-hex-alpha": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-8.0.2.tgz", - "integrity": "sha512-gyx8RgqSmGVK156NAdKcsfkY3KPGHhKqvHTL3hhveFrBBToguKFzhyiuk3cljH6L4fJ0Kv+JENuPXs1Wij27Zw==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-color-rebeccapurple": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-7.0.2.tgz", - "integrity": "sha512-SFc3MaocHaQ6k3oZaFwH8io6MdypkUtEy/eXzXEB1vEQlO3S3oDc/FSZA8AsS04Z25RirQhlDlHLh3dn7XewWw==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-colormin": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.2.3.tgz", - "integrity": "sha512-dra4xoAjub2wha6RUXAgadHEn2lGxbj8drhFcIGLOMn914Eu7DkPUurugDXgstwttCYkJtZ/+PkWRWdp3UHRIA==", - "dev": true, - "requires": { - "browserslist": "^4.16.6", - "caniuse-api": "^3.0.0", - "colord": "^2.9.1", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-convert-values": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.0.2.tgz", - "integrity": "sha512-KQ04E2yadmfa1LqXm7UIDwW1ftxU/QWZmz6NKnHnUvJ3LEYbbcX6i329f/ig+WnEByHegulocXrECaZGLpL8Zg==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.1.0" - } - }, - "postcss-custom-media": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-8.0.0.tgz", - "integrity": "sha512-FvO2GzMUaTN0t1fBULDeIvxr5IvbDXcIatt6pnJghc736nqNgsGao5NT+5+WVLAQiTt6Cb3YUms0jiPaXhL//g==", - "dev": true, - "requires": {} - }, - "postcss-custom-properties": { - "version": "12.1.3", - "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.3.tgz", - "integrity": "sha512-rtu3otIeY532PnEuuBrIIe+N+pcdbX/7JMZfrcL09wc78YayrHw5E8UkDfvnlOhEUrI4ptCuzXQfj+Or6spbGA==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-custom-selectors": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-6.0.0.tgz", - "integrity": "sha512-/1iyBhz/W8jUepjGyu7V1OPcGbc636snN1yXEQCinb6Bwt7KxsiU7/bLQlp8GwAXzCh7cobBU5odNn/2zQWR8Q==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.4" - } - }, - "postcss-dir-pseudo-class": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-6.0.3.tgz", - "integrity": "sha512-qiPm+CNAlgXiMf0J5IbBBEXA9l/Q5HGsNGkL3znIwT2ZFRLGY9U2fTUpa4lqCUXQOxaLimpacHeQC80BD2qbDw==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.8" - } - }, - "postcss-discard-comments": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.0.1.tgz", - "integrity": "sha512-lgZBPTDvWrbAYY1v5GYEv8fEO/WhKOu/hmZqmCYfrpD6eyDWWzAOsl2rF29lpvziKO02Gc5GJQtlpkTmakwOWg==", - "dev": true, - "requires": {} - }, - "postcss-discard-duplicates": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.0.1.tgz", - "integrity": "sha512-svx747PWHKOGpAXXQkCc4k/DsWo+6bc5LsVrAsw+OU+Ibi7klFZCyX54gjYzX4TH+f2uzXjRviLARxkMurA2bA==", - "dev": true, - "requires": {} - }, - "postcss-discard-empty": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.0.1.tgz", - "integrity": "sha512-vfU8CxAQ6YpMxV2SvMcMIyF2LX1ZzWpy0lqHDsOdaKKLQVQGVP1pzhrI9JlsO65s66uQTfkQBKBD/A5gp9STFw==", - "dev": true, - "requires": {} - }, - "postcss-discard-overridden": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.0.2.tgz", - "integrity": "sha512-+56BLP6NSSUuWUXjRgAQuho1p5xs/hU5Sw7+xt9S3JSg+7R6+WMGnJW7Hre/6tTuZ2xiXMB42ObkiZJ2hy/Pew==", - "dev": true, - "requires": {} - }, - "postcss-double-position-gradients": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-3.0.4.tgz", - "integrity": "sha512-qz+s5vhKJlsHw8HjSs+HVk2QGFdRyC68KGRQGX3i+GcnUjhWhXQEmCXW6siOJkZ1giu0ddPwSO6I6JdVVVPoog==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-env-function": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-4.0.4.tgz", - "integrity": "sha512-0ltahRTPtXSIlEZFv7zIvdEib7HN0ZbUQxrxIKn8KbiRyhALo854I/CggU5lyZe6ZBvSTJ6Al2vkZecI2OhneQ==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-flexbugs-fixes": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-5.0.2.tgz", - "integrity": "sha512-18f9voByak7bTktR2QgDveglpn9DTbBWPUzSOe9g0N4WR/2eSt6Vrcbf0hmspvMI6YWGywz6B9f7jzpFNJJgnQ==", - "dev": true, - "requires": {} - }, - "postcss-focus-visible": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-6.0.3.tgz", - "integrity": "sha512-ozOsg+L1U8S+rxSHnJJiET6dNLyADcPHhEarhhtCI9DBLGOPG/2i4ddVoFch9LzrBgb8uDaaRI4nuid2OM82ZA==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.8" - } - }, - "postcss-focus-within": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-5.0.3.tgz", - "integrity": "sha512-fk9y2uFS6/Kpp7/A9Hz9Z4rlFQ8+tzgBcQCXAFSrXFGAbKx+4ZZOmmfHuYjCOMegPWoz0pnC6fNzi8j7Xyqp5Q==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.8" - } - }, - "postcss-font-variant": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", - "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", - "dev": true, - "requires": {} - }, - "postcss-gap-properties": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.2.tgz", - "integrity": "sha512-EaMy/pbxtQnKDsnbEjdqlkCkROTQZzolcLKgIE+3b7EuJfJydH55cZeHfm+MtIezXRqhR80VKgaztO/vHq94Fw==", - "dev": true, - "requires": {} - }, - "postcss-image-set-function": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-4.0.4.tgz", - "integrity": "sha512-BlEo9gSTj66lXjRNByvkMK9dEdEGFXRfGjKRi9fo8s0/P3oEk74cAoonl/utiM50E2OPVb/XSu+lWvdW4KtE/Q==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-initial": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz", - "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==", - "dev": true, - "requires": {} - }, - "postcss-js": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.0.tgz", - "integrity": "sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==", - "dev": true, - "requires": { - "camelcase-css": "^2.0.1" - } - }, - "postcss-lab-function": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-4.0.3.tgz", - "integrity": "sha512-MH4tymWmefdZQ7uVG/4icfLjAQmH6o2NRYyVh2mKoB4RXJp9PjsyhZwhH4ouaCQHvg+qJVj3RzeAR1EQpIlXZA==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-load-config": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.1.tgz", - "integrity": "sha512-c/9XYboIbSEUZpiD1UQD0IKiUe8n9WHYV7YFe7X7J+ZwCsEKkUJSFWjS9hBU1RR9THR7jMXst8sxiqP0jjo2mg==", - "dev": true, - "requires": { - "lilconfig": "^2.0.4", - "yaml": "^1.10.2" - } - }, - "postcss-loader": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz", - "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==", - "dev": true, - "requires": { - "cosmiconfig": "^7.0.0", - "klona": "^2.0.5", - "semver": "^7.3.5" - }, - "dependencies": { - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "postcss-logical": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.3.tgz", - "integrity": "sha512-P5NcHWYrif0vK8rgOy/T87vg0WRIj3HSknrvp1wzDbiBeoDPVmiVRmkown2eSQdpPveat/MC1ess5uhzZFVnqQ==", - "dev": true, - "requires": {} - }, - "postcss-media-minmax": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz", - "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==", - "dev": true, - "requires": {} - }, - "postcss-merge-longhand": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.0.4.tgz", - "integrity": "sha512-2lZrOVD+d81aoYkZDpWu6+3dTAAGkCKbV5DoRhnIR7KOULVrI/R7bcMjhrH9KTRy6iiHKqmtG+n/MMj1WmqHFw==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.1.0", - "stylehacks": "^5.0.1" - } - }, - "postcss-merge-rules": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.0.4.tgz", - "integrity": "sha512-yOj7bW3NxlQxaERBB0lEY1sH5y+RzevjbdH4DBJurjKERNpknRByFNdNe+V72i5pIZL12woM9uGdS5xbSB+kDQ==", - "dev": true, - "requires": { - "browserslist": "^4.16.6", - "caniuse-api": "^3.0.0", - "cssnano-utils": "^3.0.0", - "postcss-selector-parser": "^6.0.5" - } - }, - "postcss-minify-font-values": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.0.2.tgz", - "integrity": "sha512-R6MJZryq28Cw0AmnyhXrM7naqJZZLoa1paBltIzh2wM7yb4D45TLur+eubTQ4jCmZU9SGeZdWsc5KcSoqTMeTg==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-minify-gradients": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.0.4.tgz", - "integrity": "sha512-RVwZA7NC4R4J76u8X0Q0j+J7ItKUWAeBUJ8oEEZWmtv3Xoh19uNJaJwzNpsydQjk6PkuhRrK+YwwMf+c+68EYg==", - "dev": true, - "requires": { - "colord": "^2.9.1", - "cssnano-utils": "^3.0.0", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-minify-params": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.0.3.tgz", - "integrity": "sha512-NY92FUikE+wralaiVexFd5gwb7oJTIDhgTNeIw89i1Ymsgt4RWiPXfz3bg7hDy4NL6gepcThJwOYNtZO/eNi7Q==", - "dev": true, - "requires": { - "alphanum-sort": "^1.0.2", - "browserslist": "^4.16.6", - "cssnano-utils": "^3.0.0", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-minify-selectors": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.1.1.tgz", - "integrity": "sha512-TOzqOPXt91O2luJInaVPiivh90a2SIK5Nf1Ea7yEIM/5w+XA5BGrZGUSW8aEx9pJ/oNj7ZJBhjvigSiBV+bC1Q==", - "dev": true, - "requires": { - "alphanum-sort": "^1.0.2", - "postcss-selector-parser": "^6.0.5" - } - }, - "postcss-modules-extract-imports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", - "dev": true, - "requires": {} - }, - "postcss-modules-local-by-default": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", - "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", - "dev": true, - "requires": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.1.0" - } - }, - "postcss-modules-scope": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", - "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.4" - } - }, - "postcss-modules-values": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", - "dev": true, - "requires": { - "icss-utils": "^5.0.0" - } - }, - "postcss-nested": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.6.tgz", - "integrity": "sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.6" - } - }, - "postcss-nesting": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.1.2.tgz", - "integrity": "sha512-dJGmgmsvpzKoVMtDMQQG/T6FSqs6kDtUDirIfl4KnjMCiY9/ETX8jdKyCd20swSRAbUYkaBKV20pxkzxoOXLqQ==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.8" - } - }, - "postcss-normalize": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize/-/postcss-normalize-10.0.1.tgz", - "integrity": "sha512-+5w18/rDev5mqERcG3W5GZNMJa1eoYYNGo8gB7tEwaos0ajk3ZXAI4mHGcNT47NE+ZnZD1pEpUOFLvltIwmeJA==", - "dev": true, - "requires": { - "@csstools/normalize.css": "*", - "postcss-browser-comments": "^4", - "sanitize.css": "*" - } - }, - "postcss-normalize-charset": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.0.1.tgz", - "integrity": "sha512-6J40l6LNYnBdPSk+BHZ8SF+HAkS4q2twe5jnocgd+xWpz/mx/5Sa32m3W1AA8uE8XaXN+eg8trIlfu8V9x61eg==", - "dev": true, - "requires": {} - }, - "postcss-normalize-display-values": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.0.2.tgz", - "integrity": "sha512-RxXoJPUR0shSjkMMzgEZDjGPrgXUVYyWA/YwQRicb48H15OClPuaDR7tYokLAlGZ2tCSENEN5WxjgxSD5m4cUw==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-positions": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.0.2.tgz", - "integrity": "sha512-tqghWFVDp2btqFg1gYob1etPNxXLNh3uVeWgZE2AQGh6b2F8AK2Gj36v5Vhyh+APwIzNjmt6jwZ9pTBP+/OM8g==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-repeat-style": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.0.2.tgz", - "integrity": "sha512-/rIZn8X9bBzC7KvY4iKUhXUGW3MmbXwfPF23jC9wT9xTi7kAvgj8sEgwxjixBmoL6MVa4WOgxNz2hAR6wTK8tw==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-string": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.0.2.tgz", - "integrity": "sha512-zaI1yzwL+a/FkIzUWMQoH25YwCYxi917J4pYm1nRXtdgiCdnlTkx5eRzqWEC64HtRa06WCJ9TIutpb6GmW4gFw==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-timing-functions": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.0.2.tgz", - "integrity": "sha512-Ao0PP6MoYsRU1LxeVUW740ioknvdIUmfr6uAA3xWlQJ9s69/Tupy8qwhuKG3xWfl+KvLMAP9p2WXF9cwuk/7Bg==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-unicode": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.0.2.tgz", - "integrity": "sha512-3y/V+vjZ19HNcTizeqwrbZSUsE69ZMRHfiiyLAJb7C7hJtYmM4Gsbajy7gKagu97E8q5rlS9k8FhojA8cpGhWw==", - "dev": true, - "requires": { - "browserslist": "^4.16.6", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-url": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.0.4.tgz", - "integrity": "sha512-cNj3RzK2pgQQyNp7dzq0dqpUpQ/wYtdDZM3DepPmFjCmYIfceuD9VIAcOdvrNetjIU65g1B4uwdP/Krf6AFdXg==", - "dev": true, - "requires": { - "normalize-url": "^6.0.1", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-whitespace": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.0.2.tgz", - "integrity": "sha512-CXBx+9fVlzSgbk0IXA/dcZn9lXixnQRndnsPC5ht3HxlQ1bVh77KQDL1GffJx1LTzzfae8ftMulsjYmO2yegxA==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-ordered-values": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.0.3.tgz", - "integrity": "sha512-T9pDS+P9bWeFvqivXd5ACzQmrCmHjv3ZP+djn8E1UZY7iK79pFSm7i3WbKw2VSmFmdbMm8sQ12OPcNpzBo3Z2w==", - "dev": true, - "requires": { - "cssnano-utils": "^3.0.0", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-overflow-shorthand": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.2.tgz", - "integrity": "sha512-odBMVt6PTX7jOE9UNvmnLrFzA9pXS44Jd5shFGGtSHY80QCuJF+14McSy0iavZggRZ9Oj//C9vOKQmexvyEJMg==", - "dev": true, - "requires": {} - }, - "postcss-page-break": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", - "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", - "dev": true, - "requires": {} - }, - "postcss-place": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-7.0.3.tgz", - "integrity": "sha512-tDQ3m+GYoOar+KoQgj+pwPAvGHAp/Sby6vrFiyrELrMKQJ4AejL0NcS0mm296OKKYA2SRg9ism/hlT/OLhBrdQ==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-preset-env": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.2.3.tgz", - "integrity": "sha512-Ok0DhLfwrcNGrBn8sNdy1uZqWRk/9FId0GiQ39W4ILop5GHtjJs8bu1MY9isPwHInpVEPWjb4CEcEaSbBLpfwA==", - "dev": true, - "requires": { - "autoprefixer": "^10.4.2", - "browserslist": "^4.19.1", - "caniuse-lite": "^1.0.30001299", - "css-blank-pseudo": "^3.0.2", - "css-has-pseudo": "^3.0.3", - "css-prefers-color-scheme": "^6.0.2", - "cssdb": "^5.0.0", - "postcss-attribute-case-insensitive": "^5.0.0", - "postcss-color-functional-notation": "^4.2.1", - "postcss-color-hex-alpha": "^8.0.2", - "postcss-color-rebeccapurple": "^7.0.2", - "postcss-custom-media": "^8.0.0", - "postcss-custom-properties": "^12.1.2", - "postcss-custom-selectors": "^6.0.0", - "postcss-dir-pseudo-class": "^6.0.3", - "postcss-double-position-gradients": "^3.0.4", - "postcss-env-function": "^4.0.4", - "postcss-focus-visible": "^6.0.3", - "postcss-focus-within": "^5.0.3", - "postcss-font-variant": "^5.0.0", - "postcss-gap-properties": "^3.0.2", - "postcss-image-set-function": "^4.0.4", - "postcss-initial": "^4.0.1", - "postcss-lab-function": "^4.0.3", - "postcss-logical": "^5.0.3", - "postcss-media-minmax": "^5.0.0", - "postcss-nesting": "^10.1.2", - "postcss-overflow-shorthand": "^3.0.2", - "postcss-page-break": "^3.0.4", - "postcss-place": "^7.0.3", - "postcss-pseudo-class-any-link": "^7.0.2", - "postcss-replace-overflow-wrap": "^4.0.0", - "postcss-selector-not": "^5.0.0" - } - }, - "postcss-pseudo-class-any-link": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.0.2.tgz", - "integrity": "sha512-CG35J1COUH7OOBgpw5O+0koOLUd5N4vUGKUqSAuIe4GiuLHWU96Pqp+UPC8QITTd12zYAFx76pV7qWT/0Aj/TA==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.8" - } - }, - "postcss-reduce-initial": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.0.2.tgz", - "integrity": "sha512-v/kbAAQ+S1V5v9TJvbGkV98V2ERPdU6XvMcKMjqAlYiJ2NtsHGlKYLPjWWcXlaTKNxooId7BGxeraK8qXvzKtw==", - "dev": true, - "requires": { - "browserslist": "^4.16.6", - "caniuse-api": "^3.0.0" - } - }, - "postcss-reduce-transforms": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.0.2.tgz", - "integrity": "sha512-25HeDeFsgiPSUx69jJXZn8I06tMxLQJJNF5h7i9gsUg8iP4KOOJ8EX8fj3seeoLt3SLU2YDD6UPnDYVGUO7DEA==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-replace-overflow-wrap": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", - "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", - "dev": true, - "requires": {} - }, - "postcss-selector-not": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-5.0.0.tgz", - "integrity": "sha512-/2K3A4TCP9orP4TNS7u3tGdRFVKqz/E6pX3aGnriPG0jU78of8wsUcqE4QAhWEU0d+WnMSF93Ah3F//vUtK+iQ==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "postcss-selector-parser": { - "version": "6.0.8", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.8.tgz", - "integrity": "sha512-D5PG53d209Z1Uhcc0qAZ5U3t5HagH3cxu+WLZ22jt3gLUpXM4eXXfiO14jiDWST3NNooX/E8wISfOhZ9eIjGTQ==", - "dev": true, - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - } - }, - "postcss-svgo": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.0.3.tgz", - "integrity": "sha512-41XZUA1wNDAZrQ3XgWREL/M2zSw8LJPvb5ZWivljBsUQAGoEKMYm6okHsTjJxKYI4M75RQEH4KYlEM52VwdXVA==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.1.0", - "svgo": "^2.7.0" - }, - "dependencies": { - "commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true - }, - "css-tree": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", - "dev": true, - "requires": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" - } - }, - "mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", - "dev": true - }, - "svgo": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", - "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", - "dev": true, - "requires": { - "@trysound/sax": "0.2.0", - "commander": "^7.2.0", - "css-select": "^4.1.3", - "css-tree": "^1.1.3", - "csso": "^4.2.0", - "picocolors": "^1.0.0", - "stable": "^0.1.8" - } - } - } - }, - "postcss-unique-selectors": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.0.2.tgz", - "integrity": "sha512-w3zBVlrtZm7loQWRPVC0yjUwwpty7OM6DnEHkxcSQXO1bMS3RJ+JUS5LFMSDZHJcvGsRwhZinCWVqn8Kej4EDA==", - "dev": true, - "requires": { - "alphanum-sort": "^1.0.2", - "postcss-selector-parser": "^6.0.5" - } - }, - "postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "prettier": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.2.tgz", - "integrity": "sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==", - "dev": true - }, - "pretty-bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", - "dev": true - }, - "pretty-error": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", - "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", - "dev": true, - "requires": { - "lodash": "^4.17.20", - "renderkid": "^3.0.0" - } - }, - "pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - } - } - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "promise": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz", - "integrity": "sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==", - "dev": true, - "requires": { - "asap": "~2.0.6" - } - }, - "prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - } - }, - "prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "prop-types-exact": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/prop-types-exact/-/prop-types-exact-1.2.0.tgz", - "integrity": "sha512-K+Tk3Kd9V0odiXFP9fwDHUYRyvK3Nun3GVyPapSIs5OBkITAm15W0CPFD/YKTkMUAbc0b9CUwRQp2ybiBIq+eA==", - "dev": true, - "requires": { - "has": "^1.0.3", - "object.assign": "^4.1.0", - "reflect.ownkeys": "^0.2.0" - } - }, - "prop-types-extra": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz", - "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==", - "requires": { - "react-is": "^16.3.2", - "warning": "^4.0.0" - } - }, - "proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dev": true, - "requires": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "dependencies": { - "ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true - } - } - }, - "pseudolocale": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pseudolocale/-/pseudolocale-1.2.0.tgz", - "integrity": "sha512-k0OQFvIlvpRdzR0dPVrrbWX7eE9EaZ6gpZtTlFSDi1Gf9tMy9wiANCNu7JZ0drcKgUri/39a2mBbH0goiQmrmQ==", - "dev": true, - "requires": { - "commander": "*" - } - }, - "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", - "dev": true - }, - "qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dev": true, - "requires": { - "side-channel": "^1.0.4" - } - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "dev": true - }, - "raf": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", - "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", - "dev": true, - "requires": { - "performance-now": "^2.1.0" - } - }, - "railroad-diagrams": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz", - "integrity": "sha1-635iZ1SN3t+4mcG5Dlc3RVnN234=", - "dev": true - }, - "ramda": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.1.tgz", - "integrity": "sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw==", - "dev": true - }, - "randexp": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz", - "integrity": "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==", - "dev": true, - "requires": { - "discontinuous-range": "1.0.0", - "ret": "~0.1.10" - } - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true - }, - "raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "dev": true, - "requires": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "dependencies": { - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true - } - } - }, - "react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "react-ace": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/react-ace/-/react-ace-10.1.0.tgz", - "integrity": "sha512-VkvUjZNhdYTuKOKQpMIZi7uzZZVgzCjM7cLYu6F64V0mejY8a2XTyPUIMszC6A4trbeMIHbK5fYFcT/wkP/8VA==", - "requires": { - "ace-builds": "^1.4.14", - "diff-match-patch": "^1.0.5", - "lodash.get": "^4.4.2", - "lodash.isequal": "^4.5.0", - "prop-types": "^15.7.2" - } - }, - "react-app-polyfill": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-3.0.0.tgz", - "integrity": "sha512-sZ41cxiU5llIB003yxxQBYrARBqe0repqPTTYBTmMqTz9szeBbE37BehCE891NZsmdZqqP+xWKdT3eo3vOzN8w==", - "dev": true, - "requires": { - "core-js": "^3.19.2", - "object-assign": "^4.1.1", - "promise": "^8.1.0", - "raf": "^3.4.1", - "regenerator-runtime": "^0.13.9", - "whatwg-fetch": "^3.6.2" - }, - "dependencies": { - "core-js": { - "version": "3.20.3", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.20.3.tgz", - "integrity": "sha512-vVl8j8ph6tRS3B8qir40H7yw7voy17xL0piAjlbBUsH7WIfzoedL/ZOr1OV9FyZQLWXsayOJyV4tnRyXR85/ag==", - "dev": true - } - } - }, - "react-dev-utils": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", - "integrity": "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.16.0", - "address": "^1.1.2", - "browserslist": "^4.18.1", - "chalk": "^4.1.2", - "cross-spawn": "^7.0.3", - "detect-port-alt": "^1.1.6", - "escape-string-regexp": "^4.0.0", - "filesize": "^8.0.6", - "find-up": "^5.0.0", - "fork-ts-checker-webpack-plugin": "^6.5.0", - "global-modules": "^2.0.0", - "globby": "^11.0.4", - "gzip-size": "^6.0.0", - "immer": "^9.0.7", - "is-root": "^2.1.0", - "loader-utils": "^3.2.0", - "open": "^8.4.0", - "pkg-up": "^3.1.0", - "prompts": "^2.4.2", - "react-error-overlay": "^6.0.11", - "recursive-readdir": "^2.2.2", - "shell-quote": "^1.7.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "loader-utils": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", - "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", - "dev": true - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "react-dom": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", - "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" - } - }, - "react-dropzone": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-9.0.0.tgz", - "integrity": "sha512-wZ2o9B2qkdE3RumWhfyZT9swgJYJPeU5qHEcMU8weYpmLex1eeWX0CC32/Y0VutB+BBi2D+iePV/YZIiB4kZGw==", - "requires": { - "attr-accept": "^1.1.3", - "file-selector": "^0.1.8", - "prop-types": "^15.6.2", - "prop-types-extra": "^1.1.0" - } - }, - "react-error-boundary": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-3.1.4.tgz", - "integrity": "sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==", - "requires": { - "@babel/runtime": "^7.12.5" - } - }, - "react-error-overlay": { - "version": "6.0.11", - "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", - "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==", - "dev": true - }, - "react-fast-compare": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz", - "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==" - }, - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "react-lifecycles-compat": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", - "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" - }, - "react-refresh": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", - "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==", - "dev": true - }, - "react-router": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.3.tgz", - "integrity": "sha512-mzQGUvS3bM84TnbtMYR8ZjKnuPJ71IjSzR+DE6UkUqvN4czWIqEs17yLL8xkAycv4ev0AiN+IGrWu88vJs/p2w==", - "requires": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "hoist-non-react-statics": "^3.1.0", - "loose-envify": "^1.3.1", - "mini-create-react-context": "^0.4.0", - "path-to-regexp": "^1.7.0", - "prop-types": "^15.6.2", - "react-is": "^16.6.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" - } - }, - "react-router-dom": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.3.tgz", - "integrity": "sha512-Ov0tGPMBgqmbu5CDmN++tv2HQ9HlWDuWIIqn4b88gjlAN5IHI+4ZUZRcpz9Hl0azFIwihbLDYw1OiHGRo7ZIng==", - "requires": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "loose-envify": "^1.3.1", - "prop-types": "^15.6.2", - "react-router": "5.3.3", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" - } - }, - "react-scripts": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", - "integrity": "sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==", - "dev": true, - "requires": { - "@babel/core": "^7.16.0", - "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", - "@svgr/webpack": "^5.5.0", - "babel-jest": "^27.4.2", - "babel-loader": "^8.2.3", - "babel-plugin-named-asset-import": "^0.3.8", - "babel-preset-react-app": "^10.0.1", - "bfj": "^7.0.2", - "browserslist": "^4.18.1", - "camelcase": "^6.2.1", - "case-sensitive-paths-webpack-plugin": "^2.4.0", - "css-loader": "^6.5.1", - "css-minimizer-webpack-plugin": "^3.2.0", - "dotenv": "^10.0.0", - "dotenv-expand": "^5.1.0", - "eslint": "^8.3.0", - "eslint-config-react-app": "^7.0.1", - "eslint-webpack-plugin": "^3.1.1", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "fsevents": "^2.3.2", - "html-webpack-plugin": "^5.5.0", - "identity-obj-proxy": "^3.0.0", - "jest": "^27.4.3", - "jest-resolve": "^27.4.2", - "jest-watch-typeahead": "^1.0.0", - "mini-css-extract-plugin": "^2.4.5", - "postcss": "^8.4.4", - "postcss-flexbugs-fixes": "^5.0.2", - "postcss-loader": "^6.2.1", - "postcss-normalize": "^10.0.1", - "postcss-preset-env": "^7.0.1", - "prompts": "^2.4.2", - "react-app-polyfill": "^3.0.0", - "react-dev-utils": "^12.0.1", - "react-refresh": "^0.11.0", - "resolve": "^1.20.0", - "resolve-url-loader": "^4.0.0", - "sass-loader": "^12.3.0", - "semver": "^7.3.5", - "source-map-loader": "^3.0.0", - "style-loader": "^3.3.1", - "tailwindcss": "^3.0.2", - "terser-webpack-plugin": "^5.2.5", - "webpack": "^5.64.4", - "webpack-dev-server": "^4.6.0", - "webpack-manifest-plugin": "^4.0.2", - "workbox-webpack-plugin": "^6.4.1" - }, - "dependencies": { - "@types/eslint": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.29.0.tgz", - "integrity": "sha512-VNcvioYDH8/FxaeTKkM4/TiTwt6pBV9E3OfGmvaw8tPl0rrHCJ4Ll15HRT+pMiFAf/MLQvAzC+6RzUMEL9Ceng==", - "dev": true, - "requires": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - }, - "eslint-webpack-plugin": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.1.1.tgz", - "integrity": "sha512-xSucskTN9tOkfW7so4EaiFIkulWLXwCB/15H917lR6pTv0Zot6/fetFucmENRb7J5whVSFKIvwnrnsa78SG2yg==", - "dev": true, - "requires": { - "@types/eslint": "^7.28.2", - "jest-worker": "^27.3.1", - "micromatch": "^4.0.4", - "normalize-path": "^3.0.0", - "schema-utils": "^3.1.1" - } - }, - "fs-extra": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", - "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "react-shallow-renderer": { - "version": "16.14.1", - "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.14.1.tgz", - "integrity": "sha512-rkIMcQi01/+kxiTE9D3fdS959U1g7gs+/rborw++42m1O9FAQiNI/UNRZExVUoAOprn4umcXf+pFRou8i4zuBg==", - "dev": true, - "requires": { - "object-assign": "^4.1.1", - "react-is": "^16.12.0 || ^17.0.0" - } - }, - "react-test-renderer": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-17.0.2.tgz", - "integrity": "sha512-yaQ9cB89c17PUb0x6UfWRs7kQCorVdHlutU1boVPEsB8IDZH6n9tHxMacc3y0JoXOJUsZb/t/Mb8FUWMKaM7iQ==", - "dev": true, - "requires": { - "object-assign": "^4.1.1", - "react-is": "^17.0.2", - "react-shallow-renderer": "^16.13.1", - "scheduler": "^0.20.2" - }, - "dependencies": { - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - } - } - }, - "react-virtualized": { - "version": "9.22.3", - "resolved": "https://registry.npmjs.org/react-virtualized/-/react-virtualized-9.22.3.tgz", - "integrity": "sha512-MKovKMxWTcwPSxE1kK1HcheQTWfuCxAuBoSTf2gwyMM21NdX/PXUhnoP8Uc5dRKd+nKm8v41R36OellhdCpkrw==", - "requires": { - "@babel/runtime": "^7.7.2", - "clsx": "^1.0.4", - "dom-helpers": "^5.1.3", - "loose-envify": "^1.4.0", - "prop-types": "^15.7.2", - "react-lifecycles-compat": "^3.0.4" - } - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "readdirp": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", - "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "recursive-readdir": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", - "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", - "dev": true, - "requires": { - "minimatch": "^3.0.5" - } - }, - "redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "dev": true, - "requires": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - } - }, - "reflect.ownkeys": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/reflect.ownkeys/-/reflect.ownkeys-0.2.0.tgz", - "integrity": "sha1-dJrO7H8/34tj+SegSAnpDFwLNGA=", - "dev": true - }, - "regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true - }, - "regenerate-unicode-properties": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz", - "integrity": "sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA==", - "dev": true, - "requires": { - "regenerate": "^1.4.2" - } - }, - "regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" - }, - "regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", - "dev": true, - "requires": { - "@babel/runtime": "^7.8.4" - } - }, - "regex-parser": { - "version": "2.2.11", - "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", - "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==", - "dev": true - }, - "regexp.prototype.flags": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", - "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, - "regexpu-core": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.8.0.tgz", - "integrity": "sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg==", - "dev": true, - "requires": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^9.0.0", - "regjsgen": "^0.5.2", - "regjsparser": "^0.7.0", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.0.0" - } - }, - "regjsgen": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", - "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==", - "dev": true - }, - "regjsparser": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.7.0.tgz", - "integrity": "sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ==", - "dev": true, - "requires": { - "jsesc": "~0.5.0" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true - } - } - }, - "relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", - "dev": true - }, - "renderkid": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", - "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", - "dev": true, - "requires": { - "css-select": "^4.1.3", - "dom-converter": "^0.2.0", - "htmlparser2": "^6.1.0", - "lodash": "^4.17.21", - "strip-ansi": "^6.0.1" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true - }, - "requireindex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.1.0.tgz", - "integrity": "sha1-5UBLgVV+91225JxacgBIk/4D4WI=", - "dev": true - }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", - "dev": true - }, - "resolve": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.21.0.tgz", - "integrity": "sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA==", - "dev": true, - "requires": { - "is-core-module": "^2.8.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "requires": { - "resolve-from": "^5.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "resolve-pathname": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", - "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" - }, - "resolve-url-loader": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-4.0.0.tgz", - "integrity": "sha512-05VEMczVREcbtT7Bz+C+96eUO5HDNvdthIiMB34t7FcF8ehcu4wC0sSgPUubs3XW2Q3CNLJk/BJrCU9wVRymiA==", - "dev": true, - "requires": { - "adjust-sourcemap-loader": "^4.0.0", - "convert-source-map": "^1.7.0", - "loader-utils": "^2.0.0", - "postcss": "^7.0.35", - "source-map": "0.6.1" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dev": true, - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - } - } - }, - "resolve.exports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", - "dev": true - }, - "restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - } - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, - "retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "dev": true - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "robust-predicates": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.1.tgz", - "integrity": "sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g==" - }, - "rollup": { - "version": "2.64.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.64.0.tgz", - "integrity": "sha512-+c+lbw1lexBKSMb1yxGDVfJ+vchJH3qLbmavR+awDinTDA2C5Ug9u7lkOzj62SCu0PKUExsW36tpgW7Fmpn3yQ==", - "dev": true, - "requires": { - "fsevents": "~2.3.2" - } - }, - "rollup-plugin-terser": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", - "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "jest-worker": "^26.2.1", - "serialize-javascript": "^4.0.0", - "terser": "^5.0.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - } - }, - "serialize-javascript": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "rrule": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rrule/-/rrule-2.7.1.tgz", - "integrity": "sha512-4p20u/1U7WqR3Nb1hOUrm0u1nSI7sO93ZUVZEZ5HeF6Gr5OlJuyhwEGRvUHq8ZfrPsq5gfa5b9dqnUs/kPqpIw==", - "requires": { - "tslib": "^2.4.0" - }, - "dependencies": { - "tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" - } - } - }, - "rst-selector-parser": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/rst-selector-parser/-/rst-selector-parser-2.2.3.tgz", - "integrity": "sha1-gbIw6i/MYGbInjRy3nlChdmwPZE=", - "dev": true, - "requires": { - "lodash.flattendeep": "^4.4.0", - "nearley": "^2.7.10" - } - }, - "run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "rw": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=" - }, - "rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "sanitize.css": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-13.0.0.tgz", - "integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==", - "dev": true - }, - "sass-loader": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.4.0.tgz", - "integrity": "sha512-7xN+8khDIzym1oL9XyS6zP6Ges+Bo2B2xbPrjdMHEYyV3AQYhd/wXeru++3ODHF0zMjYmVadblSKrPrjEkL8mg==", - "dev": true, - "requires": { - "klona": "^2.0.4", - "neo-async": "^2.6.2" - } - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "dev": true, - "requires": { - "xmlchars": "^2.2.0" - } - }, - "scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - }, - "select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", - "dev": true - }, - "selfsigned": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.0.0.tgz", - "integrity": "sha512-cUdFiCbKoa1mZ6osuJs2uDHrs0k0oprsKveFiiaBKCNq3SYyb5gs2HxhQyDNLCmL51ZZThqi4YNDpCK6GOP1iQ==", - "dev": true, - "requires": { - "node-forge": "^1.2.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - }, - "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dev": true, - "requires": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - } - } - }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true - } - } - }, - "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", - "dev": true, - "requires": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", - "dev": true, - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true - } - } - }, - "serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "dev": true, - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - } - }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true - }, - "shallowequal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", - "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "shell-quote": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.4.tgz", - "integrity": "sha512-8o/QEhSSRb1a5i7TFR0iM4G16Z0vYB2OQVs4G3aAFXjn3T6yEx8AZxy1PgDF7I00LZHYA3WxaSYIf5e5sAX8Rw==", - "dev": true - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true - }, - "sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "sockjs": { - "version": "0.3.24", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", - "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", - "dev": true, - "requires": { - "faye-websocket": "^0.11.3", - "uuid": "^8.3.2", - "websocket-driver": "^0.7.4" - } - }, - "source-list-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true - }, - "source-map-loader": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-3.0.1.tgz", - "integrity": "sha512-Vp1UsfyPvgujKQzi4pyDiTOnE3E4H+yHvkVRN3c/9PJmQS4CQJExvcDvaX/D+RV+xQben9HJ56jMJS3CgUeWyA==", - "dev": true, - "requires": { - "abab": "^2.0.5", - "iconv-lite": "^0.6.3", - "source-map-js": "^1.0.1" - }, - "dependencies": { - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - } - } - }, - "source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "source-map-url": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", - "dev": true - }, - "sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "dev": true - }, - "spdy": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", - "dev": true, - "requires": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" - } - }, - "spdy-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", - "dev": true, - "requires": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "stable": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", - "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", - "dev": true - }, - "stack-utils": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", - "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", - "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - } - } - }, - "stackframe": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz", - "integrity": "sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA==", - "dev": true - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "dev": true - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "requires": { - "safe-buffer": "~5.2.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - } - } - }, - "string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "requires": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - } - }, - "string-natural-compare": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz", - "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==", - "dev": true - }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "string.prototype.matchall": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz", - "integrity": "sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", - "get-intrinsic": "^1.1.1", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "regexp.prototype.flags": "^1.3.1", - "side-channel": "^1.0.4" - } - }, - "string.prototype.trim": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.4.tgz", - "integrity": "sha512-hWCk/iqf7lp0/AgTF7/ddO1IWtSNPASjlzCicV5irAVdE1grjsneK26YG6xACMBEdCvO8fUST0UzDMh/2Qy+9Q==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2" - } - }, - "string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "stringify-object": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", - "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", - "dev": true, - "requires": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - } - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "strip-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-2.0.1.tgz", - "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==", - "dev": true - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true - }, - "strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dev": true, - "requires": { - "min-indent": "^1.0.0" - } - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "style-loader": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz", - "integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==", - "dev": true, - "requires": {} - }, - "style-mod": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.0.tgz", - "integrity": "sha512-OPhtyEjyyN9x3nhPsu76f52yUGXiZcgvsrFVtvTkyGRQJ0XK+GPc6ov1z+lRpbeabka+MYEQxOYRnt5nF30aMw==" - }, - "styled-components": { - "version": "5.3.6", - "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.6.tgz", - "integrity": "sha512-hGTZquGAaTqhGWldX7hhfzjnIYBZ0IXQXkCYdvF1Sq3DsUaLx6+NTHC5Jj1ooM2F68sBiVz3lvhfwQs/S3l6qg==", - "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/traverse": "^7.4.5", - "@emotion/is-prop-valid": "^1.1.0", - "@emotion/stylis": "^0.8.4", - "@emotion/unitless": "^0.7.4", - "babel-plugin-styled-components": ">= 1.12.0", - "css-to-react-native": "^3.0.0", - "hoist-non-react-statics": "^3.0.0", - "shallowequal": "^1.1.0", - "supports-color": "^5.5.0" - } - }, - "stylehacks": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.0.1.tgz", - "integrity": "sha512-Es0rVnHIqbWzveU1b24kbw92HsebBepxfcqe5iix7t9j0PQqhs0IxXVXv0pY2Bxa08CgMkzD6OWql7kbGOuEdA==", - "dev": true, - "requires": { - "browserslist": "^4.16.0", - "postcss-selector-parser": "^6.0.4" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - }, - "supports-hyperlinks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", - "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", - "dev": true, - "requires": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true - }, - "svg-parser": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", - "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", - "dev": true - }, - "svgo": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", - "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", - "dev": true, - "requires": { - "chalk": "^2.4.1", - "coa": "^2.0.2", - "css-select": "^2.0.0", - "css-select-base-adapter": "^0.1.1", - "css-tree": "1.0.0-alpha.37", - "csso": "^4.0.2", - "js-yaml": "^3.13.1", - "mkdirp": "~0.5.1", - "object.values": "^1.1.0", - "sax": "~1.2.4", - "stable": "^0.1.8", - "unquote": "~1.1.1", - "util.promisify": "~1.0.0" - }, - "dependencies": { - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "css-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", - "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", - "dev": true, - "requires": { - "boolbase": "^1.0.0", - "css-what": "^3.2.1", - "domutils": "^1.7.0", - "nth-check": "^1.0.2" - } - }, - "css-what": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", - "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==", - "dev": true - }, - "dom-serializer": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", - "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", - "dev": true, - "requires": { - "domelementtype": "^2.0.1", - "entities": "^2.0.0" - }, - "dependencies": { - "domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "dev": true - } - } - }, - "domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", - "dev": true - }, - "domutils": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", - "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", - "dev": true, - "requires": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "nth-check": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", - "dev": true, - "requires": { - "boolbase": "~1.0.0" - } - } - } - }, - "symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "tabbable": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-5.3.3.tgz", - "integrity": "sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA==" - }, - "tailwindcss": { - "version": "3.0.15", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.0.15.tgz", - "integrity": "sha512-bT2iy7FtjwgsXik4ZoJnHXR+SRCiGR1W95fVqpLZebr64m4ahwUwRbIAc5w5+2fzr1YF4Ct2eI7dojMRRl8sVQ==", - "dev": true, - "requires": { - "arg": "^5.0.1", - "chalk": "^4.1.2", - "chokidar": "^3.5.2", - "color-name": "^1.1.4", - "cosmiconfig": "^7.0.1", - "detective": "^5.2.0", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.2.7", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "normalize-path": "^3.0.0", - "object-hash": "^2.2.0", - "postcss-js": "^4.0.0", - "postcss-load-config": "^3.1.0", - "postcss-nested": "5.0.6", - "postcss-selector-parser": "^6.0.8", - "postcss-value-parser": "^4.2.0", - "quick-lru": "^5.1.1", - "resolve": "^1.21.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "arg": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.1.tgz", - "integrity": "sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "cosmiconfig": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", - "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", - "dev": true, - "requires": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - } - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "tapable": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.1.10.tgz", - "integrity": "sha1-KcNXB8K3DlDQdIK10gLo7URtr9Q=", - "dev": true - }, - "temp-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", - "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", - "dev": true - }, - "tempy": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.6.0.tgz", - "integrity": "sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==", - "dev": true, - "requires": { - "is-stream": "^2.0.0", - "temp-dir": "^2.0.0", - "type-fest": "^0.16.0", - "unique-string": "^2.0.0" - }, - "dependencies": { - "type-fest": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", - "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", - "dev": true - } - } - }, - "terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - } - }, - "terser": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.0.tgz", - "integrity": "sha512-KjTV81QKStSfwbNiwlBXfcgMcOloyuRdb62/iLFPGBcVNF4EXjhdYBhYHmbJpiBrVxZhDvltE11j+LBQUxEEJg==", - "dev": true, - "requires": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "dependencies": { - "acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", - "dev": true - } - } - }, - "terser-webpack-plugin": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.0.tgz", - "integrity": "sha512-LPIisi3Ol4chwAaPP8toUJ3L4qCM1G0wao7L3qNv57Drezxj6+VEyySpPw4B1HSO2Eg/hDY/MNF5XihCAoqnsQ==", - "dev": true, - "requires": { - "jest-worker": "^27.4.1", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1", - "terser": "^5.7.2" - } - }, - "test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "requires": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "throat": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", - "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", - "dev": true - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true - }, - "timsort": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", - "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", - "dev": true - }, - "tiny-invariant": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz", - "integrity": "sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg==" - }, - "tiny-warning": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", - "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" - }, - "tippy.js": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-5.1.2.tgz", - "integrity": "sha512-Qtrv2wqbRbaKMUb6bWWBQWPayvcDKNrGlvihxtsyowhT7RLGEh1STWuy6EMXC6QLkfKPB2MLnf8W2mzql9VDAw==", - "requires": { - "popper.js": "^1.16.0" - } - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - }, - "tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true - }, - "tough-cookie": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", - "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", - "dev": true, - "requires": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.1.2" - }, - "dependencies": { - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true - } - } - }, - "tr46": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", - "dev": true, - "requires": { - "punycode": "^2.1.1" - } - }, - "tryer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", - "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==", - "dev": true - }, - "ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "dev": true, - "requires": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "dependencies": { - "acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", - "dev": true - }, - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true - } - } - }, - "tsconfig-paths": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz", - "integrity": "sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==", - "dev": true, - "requires": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.0", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - } - } - }, - "tslib": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", - "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==" - }, - "tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true - }, - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dev": true, - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "requires": { - "is-typedarray": "^1.0.0" - } - }, - "typescript": { - "version": "4.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", - "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==", - "dev": true, - "peer": true - }, - "unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - } - }, - "unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", - "dev": true - }, - "unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "dev": true, - "requires": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - } - }, - "unicode-match-property-value-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", - "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", - "dev": true - }, - "unicode-property-aliases-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", - "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", - "dev": true - }, - "unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "dev": true, - "requires": { - "crypto-random-string": "^2.0.0" - } - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true - }, - "unquote": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", - "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", - "dev": true - }, - "upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "dev": true - }, - "update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", - "dev": true, - "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "util.promisify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", - "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.2", - "has-symbols": "^1.0.1", - "object.getownpropertydescriptors": "^2.1.0" - } - }, - "utila": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", - "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", - "dev": true - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "dev": true - }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true - }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "v8-to-istanbul": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", - "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" - }, - "dependencies": { - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true - } - } - }, - "value-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", - "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "dev": true - }, - "w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dev": true, - "requires": { - "browser-process-hrtime": "^1.0.0" - } - }, - "w3c-keyname": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.4.tgz", - "integrity": "sha512-tOhfEwEzFLJzf6d1ZPkYfGj+FWhIpBux9ppoP3rlclw3Z0BZv3N7b7030Z1kYth+6rDuAsXUFr+d0VE6Ed1ikw==" - }, - "w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", - "dev": true, - "requires": { - "xml-name-validator": "^3.0.0" - } - }, - "walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "requires": { - "makeerror": "1.0.12" - } - }, - "warning": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", - "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", - "requires": { - "loose-envify": "^1.0.0" - } - }, - "watchpack": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", - "integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==", - "dev": true, - "requires": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - } - }, - "wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", - "dev": true, - "requires": { - "minimalistic-assert": "^1.0.0" - } - }, - "wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", - "dev": true, - "requires": { - "defaults": "^1.0.3" - } - }, - "webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", - "dev": true - }, - "webpack": { - "version": "5.66.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.66.0.tgz", - "integrity": "sha512-NJNtGT7IKpGzdW7Iwpn/09OXz9inIkeIQ/ibY6B+MdV1x6+uReqz/5z1L89ezWnpPDWpXF0TY5PCYKQdWVn8Vg==", - "dev": true, - "requires": { - "@types/eslint-scope": "^3.7.0", - "@types/estree": "^0.0.50", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.4.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.8.3", - "es-module-lexer": "^0.9.0", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-better-errors": "^1.0.2", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.3.1", - "webpack-sources": "^3.2.2" - }, - "dependencies": { - "acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", - "dev": true - }, - "acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", - "dev": true, - "requires": {} - }, - "enhanced-resolve": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz", - "integrity": "sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - } - }, - "tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true - } - } - }, - "webpack-dev-middleware": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.0.tgz", - "integrity": "sha512-MouJz+rXAm9B1OTOYaJnn6rtD/lWZPy2ufQCH3BPs8Rloh/Du6Jze4p7AeLYHkVi0giJnYLaSGDC7S+GM9arhg==", - "dev": true, - "requires": { - "colorette": "^2.0.10", - "memfs": "^3.2.2", - "mime-types": "^2.1.31", - "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" - }, - "dependencies": { - "ajv": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.9.0.tgz", - "integrity": "sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.3" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "schema-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" - } - } - } - }, - "webpack-dev-server": { - "version": "4.7.3", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.7.3.tgz", - "integrity": "sha512-mlxq2AsIw2ag016nixkzUkdyOE8ST2GTy34uKSABp1c4nhjZvH90D5ZRR+UOLSsG4Z3TFahAi72a3ymRtfRm+Q==", - "dev": true, - "requires": { - "@types/bonjour": "^3.5.9", - "@types/connect-history-api-fallback": "^1.3.5", - "@types/serve-index": "^1.9.1", - "@types/sockjs": "^0.3.33", - "@types/ws": "^8.2.2", - "ansi-html-community": "^0.0.8", - "bonjour": "^3.5.0", - "chokidar": "^3.5.2", - "colorette": "^2.0.10", - "compression": "^1.7.4", - "connect-history-api-fallback": "^1.6.0", - "default-gateway": "^6.0.3", - "del": "^6.0.0", - "express": "^4.17.1", - "graceful-fs": "^4.2.6", - "html-entities": "^2.3.2", - "http-proxy-middleware": "^2.0.0", - "ipaddr.js": "^2.0.1", - "open": "^8.0.9", - "p-retry": "^4.5.0", - "portfinder": "^1.0.28", - "schema-utils": "^4.0.0", - "selfsigned": "^2.0.0", - "serve-index": "^1.9.1", - "sockjs": "^0.3.21", - "spdy": "^4.0.2", - "strip-ansi": "^7.0.0", - "webpack-dev-middleware": "^5.3.0", - "ws": "^8.1.0" - }, - "dependencies": { - "ajv": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.9.0.tgz", - "integrity": "sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.3" - } - }, - "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - } - }, - "http-proxy-middleware": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.1.tgz", - "integrity": "sha512-cfaXRVoZxSed/BmkA7SwBVNI9Kj7HFltaE5rqYOub5kWzWZ+gofV2koVN1j2rMW7pEfSSlCHGJ31xmuyFyfLOg==", - "dev": true, - "requires": { - "@types/http-proxy": "^1.17.5", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "schema-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" - } - }, - "strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", - "dev": true, - "requires": { - "ansi-regex": "^6.0.1" - } - }, - "ws": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.4.2.tgz", - "integrity": "sha512-Kbk4Nxyq7/ZWqr/tarI9yIt/+iNNFOjBXEWgTb4ydaNHBNGgvf2QHbS9fdfsndfjFlFwEd4Al+mw83YkaD10ZA==", - "dev": true, - "requires": {} - } - } - }, - "webpack-manifest-plugin": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-4.1.1.tgz", - "integrity": "sha512-YXUAwxtfKIJIKkhg03MKuiFAD72PlrqCiwdwO4VEXdRO5V0ORCNwaOwAZawPZalCbmH9kBDmXnNeQOw+BIEiow==", - "dev": true, - "requires": { - "tapable": "^2.0.0", - "webpack-sources": "^2.2.0" - }, - "dependencies": { - "tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true - }, - "webpack-sources": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.3.1.tgz", - "integrity": "sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA==", - "dev": true, - "requires": { - "source-list-map": "^2.0.1", - "source-map": "^0.6.1" - } - } - } - }, - "webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "dev": true - }, - "websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", - "dev": true, - "requires": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" - } - }, - "websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", - "dev": true - }, - "whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dev": true, - "requires": { - "iconv-lite": "0.4.24" - } - }, - "whatwg-fetch": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", - "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==", - "dev": true - }, - "whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true - }, - "whatwg-url": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", - "dev": true, - "requires": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "workbox-background-sync": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-6.4.2.tgz", - "integrity": "sha512-P7c8uG5X2k+DMICH9xeSA9eUlCOjHHYoB42Rq+RtUpuwBxUOflAXR1zdsMWj81LopE4gjKXlTw7BFd1BDAHo7g==", - "dev": true, - "requires": { - "idb": "^6.1.4", - "workbox-core": "6.4.2" - } - }, - "workbox-broadcast-update": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-6.4.2.tgz", - "integrity": "sha512-qnBwQyE0+PWFFc/n4ISXINE49m44gbEreJUYt2ldGH3+CNrLmJ1egJOOyUqqu9R4Eb7QrXcmB34ClXG7S37LbA==", - "dev": true, - "requires": { - "workbox-core": "6.4.2" - } - }, - "workbox-build": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-6.4.2.tgz", - "integrity": "sha512-WMdYLhDIsuzViOTXDH+tJ1GijkFp5khSYolnxR/11zmfhNDtuo7jof72xPGFy+KRpsz6tug39RhivCj77qqO0w==", - "dev": true, - "requires": { - "@apideck/better-ajv-errors": "^0.3.1", - "@babel/core": "^7.11.1", - "@babel/preset-env": "^7.11.0", - "@babel/runtime": "^7.11.2", - "@rollup/plugin-babel": "^5.2.0", - "@rollup/plugin-node-resolve": "^11.2.1", - "@rollup/plugin-replace": "^2.4.1", - "@surma/rollup-plugin-off-main-thread": "^2.2.3", - "ajv": "^8.6.0", - "common-tags": "^1.8.0", - "fast-json-stable-stringify": "^2.1.0", - "fs-extra": "^9.0.1", - "glob": "^7.1.6", - "lodash": "^4.17.20", - "pretty-bytes": "^5.3.0", - "rollup": "^2.43.1", - "rollup-plugin-terser": "^7.0.0", - "source-map": "^0.8.0-beta.0", - "source-map-url": "^0.4.0", - "stringify-object": "^3.3.0", - "strip-comments": "^2.0.1", - "tempy": "^0.6.0", - "upath": "^1.2.0", - "workbox-background-sync": "6.4.2", - "workbox-broadcast-update": "6.4.2", - "workbox-cacheable-response": "6.4.2", - "workbox-core": "6.4.2", - "workbox-expiration": "6.4.2", - "workbox-google-analytics": "6.4.2", - "workbox-navigation-preload": "6.4.2", - "workbox-precaching": "6.4.2", - "workbox-range-requests": "6.4.2", - "workbox-recipes": "6.4.2", - "workbox-routing": "6.4.2", - "workbox-strategies": "6.4.2", - "workbox-streams": "6.4.2", - "workbox-sw": "6.4.2", - "workbox-window": "6.4.2" - }, - "dependencies": { - "@apideck/better-ajv-errors": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.2.tgz", - "integrity": "sha512-JdEazx7qiVqTBzzBl5rolRwl5cmhihjfIcpqRzIZjtT6b18liVmDn/VlWpqW4C/qP2hrFFMLRV1wlex8ZVBPTg==", - "dev": true, - "requires": { - "json-schema": "^0.4.0", - "jsonpointer": "^5.0.0", - "leven": "^3.1.0" - } - }, - "ajv": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.9.0.tgz", - "integrity": "sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "source-map": { - "version": "0.8.0-beta.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", - "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", - "dev": true, - "requires": { - "whatwg-url": "^7.0.0" - } - }, - "tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true - }, - "whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "dev": true, - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - } - } - }, - "workbox-cacheable-response": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-6.4.2.tgz", - "integrity": "sha512-9FE1W/cKffk1AJzImxgEN0ceWpyz1tqNjZVtA3/LAvYL3AC5SbIkhc7ZCO82WmO9IjTfu8Vut2X/C7ViMSF7TA==", - "dev": true, - "requires": { - "workbox-core": "6.4.2" - } - }, - "workbox-core": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-6.4.2.tgz", - "integrity": "sha512-1U6cdEYPcajRXiboSlpJx6U7TvhIKbxRRerfepAJu2hniKwJ3DHILjpU/zx3yvzSBCWcNJDoFalf7Vgd7ey/rw==", - "dev": true - }, - "workbox-expiration": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-6.4.2.tgz", - "integrity": "sha512-0hbpBj0tDnW+DZOUmwZqntB/8xrXOgO34i7s00Si/VlFJvvpRKg1leXdHHU8ykoSBd6+F2KDcMP3swoCi5guLw==", - "dev": true, - "requires": { - "idb": "^6.1.4", - "workbox-core": "6.4.2" - } - }, - "workbox-google-analytics": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-6.4.2.tgz", - "integrity": "sha512-u+gxs3jXovPb1oul4CTBOb+T9fS1oZG+ZE6AzS7l40vnyfJV79DaLBvlpEZfXGv3CjMdV1sT/ltdOrKzo7HcGw==", - "dev": true, - "requires": { - "workbox-background-sync": "6.4.2", - "workbox-core": "6.4.2", - "workbox-routing": "6.4.2", - "workbox-strategies": "6.4.2" - } - }, - "workbox-navigation-preload": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-6.4.2.tgz", - "integrity": "sha512-viyejlCtlKsbJCBHwhSBbWc57MwPXvUrc8P7d+87AxBGPU+JuWkT6nvBANgVgFz6FUhCvRC8aYt+B1helo166g==", - "dev": true, - "requires": { - "workbox-core": "6.4.2" - } - }, - "workbox-precaching": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-6.4.2.tgz", - "integrity": "sha512-CZ6uwFN/2wb4noHVlALL7UqPFbLfez/9S2GAzGAb0Sk876ul9ukRKPJJ6gtsxfE2HSTwqwuyNVa6xWyeyJ1XSA==", - "dev": true, - "requires": { - "workbox-core": "6.4.2", - "workbox-routing": "6.4.2", - "workbox-strategies": "6.4.2" - } - }, - "workbox-range-requests": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-6.4.2.tgz", - "integrity": "sha512-SowF3z69hr3Po/w7+xarWfzxJX/3Fo0uSG72Zg4g5FWWnHpq2zPvgbWerBZIa81zpJVUdYpMa3akJJsv+LaO1Q==", - "dev": true, - "requires": { - "workbox-core": "6.4.2" - } - }, - "workbox-recipes": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-6.4.2.tgz", - "integrity": "sha512-/oVxlZFpAjFVbY+3PoGEXe8qyvtmqMrTdWhbOfbwokNFtUZ/JCtanDKgwDv9x3AebqGAoJRvQNSru0F4nG+gWA==", - "dev": true, - "requires": { - "workbox-cacheable-response": "6.4.2", - "workbox-core": "6.4.2", - "workbox-expiration": "6.4.2", - "workbox-precaching": "6.4.2", - "workbox-routing": "6.4.2", - "workbox-strategies": "6.4.2" - } - }, - "workbox-routing": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-6.4.2.tgz", - "integrity": "sha512-0ss/n9PAcHjTy4Ad7l2puuod4WtsnRYu9BrmHcu6Dk4PgWeJo1t5VnGufPxNtcuyPGQ3OdnMdlmhMJ57sSrrSw==", - "dev": true, - "requires": { - "workbox-core": "6.4.2" - } - }, - "workbox-strategies": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-6.4.2.tgz", - "integrity": "sha512-YXh9E9dZGEO1EiPC3jPe2CbztO5WT8Ruj8wiYZM56XqEJp5YlGTtqRjghV+JovWOqkWdR+amJpV31KPWQUvn1Q==", - "dev": true, - "requires": { - "workbox-core": "6.4.2" - } - }, - "workbox-streams": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-6.4.2.tgz", - "integrity": "sha512-ROEGlZHGVEgpa5bOZefiJEVsi5PsFjJG9Xd+wnDbApsCO9xq9rYFopF+IRq9tChyYzhBnyk2hJxbQVWphz3sog==", - "dev": true, - "requires": { - "workbox-core": "6.4.2", - "workbox-routing": "6.4.2" - } - }, - "workbox-sw": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-6.4.2.tgz", - "integrity": "sha512-A2qdu9TLktfIM5NE/8+yYwfWu+JgDaCkbo5ikrky2c7r9v2X6DcJ+zSLphNHHLwM/0eVk5XVf1mC5HGhYpMhhg==", - "dev": true - }, - "workbox-webpack-plugin": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-6.4.2.tgz", - "integrity": "sha512-CiEwM6kaJRkx1cP5xHksn13abTzUqMHiMMlp5Eh/v4wRcedgDTyv6Uo8+Hg9MurRbHDosO5suaPyF9uwVr4/CQ==", - "dev": true, - "requires": { - "fast-json-stable-stringify": "^2.1.0", - "pretty-bytes": "^5.4.1", - "source-map-url": "^0.4.0", - "upath": "^1.2.0", - "webpack-sources": "^1.4.3", - "workbox-build": "6.4.2" - }, - "dependencies": { - "webpack-sources": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", - "dev": true, - "requires": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" - } - } - } - }, - "workbox-window": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-6.4.2.tgz", - "integrity": "sha512-KVyRKmrJg7iB+uym/B/CnEUEFG9CvnTU1Bq5xpXHbtgD9l+ShDekSl1wYpqw/O0JfeeQVOFb8CiNfvnwWwqnWQ==", - "dev": true, - "requires": { - "@types/trusted-types": "^2.0.2", - "workbox-core": "6.4.2" - } - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "ws": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz", - "integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==", - "dev": true, - "requires": {} - }, - "xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, - "xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - }, - "yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true - }, - "yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true - } - } -} diff --git a/awx/ui/package.json b/awx/ui/package.json deleted file mode 100644 index c729e16e7db8..000000000000 --- a/awx/ui/package.json +++ /dev/null @@ -1,121 +0,0 @@ -{ - "name": "ui", - "homepage": ".", - "private": true, - "engines": { - "node": ">=16.13.1" - }, - "dependencies": { - "@lingui/react": "3.14.0", - "@patternfly/patternfly": "4.217.1", - "@patternfly/react-core": "^4.264.0", - "@patternfly/react-icons": "4.92.10", - "@patternfly/react-table": "4.108.0", - "ace-builds": "^1.10.1", - "ansi-to-html": "0.7.2", - "axios": "0.27.2", - "codemirror": "^6.0.1", - "d3": "7.6.1", - "dagre": "^0.8.4", - "dompurify": "2.4.0", - "formik": "2.2.9", - "has-ansi": "5.0.1", - "html-entities": "2.3.2", - "js-yaml": "4.1.0", - "luxon": "^3.1.1", - "prop-types": "^15.8.1", - "react": "17.0.2", - "react-ace": "^10.1.0", - "react-dom": "17.0.2", - "react-error-boundary": "^3.1.4", - "react-router-dom": "^5.3.3", - "react-virtualized": "^9.21.1", - "rrule": "2.7.1", - "styled-components": "5.3.6" - }, - "devDependencies": { - "@babel/core": "^7.16.10", - "@babel/eslint-parser": "^7.16.5", - "@babel/eslint-plugin": "^7.16.5", - "@babel/plugin-syntax-jsx": "7.16.7", - "@babel/polyfill": "^7.8.7", - "@babel/preset-react": "7.16.7", - "@cypress/instrument-cra": "^1.4.0", - "@lingui/cli": "^3.7.1", - "@lingui/loader": "3.15.0", - "@lingui/macro": "^3.7.1", - "@nteract/mockument": "^1.0.4", - "@testing-library/jest-dom": "^5.16.2", - "@testing-library/react": "^12.1.5", - "@testing-library/user-event": "14.4.3", - "@wojtekmaj/enzyme-adapter-react-17": "0.6.5", - "babel-plugin-macros": "3.1.0", - "enzyme": "^3.10.0", - "enzyme-adapter-react-16": "^1.14.0", - "enzyme-to-json": "^3.3.5", - "eslint": "^8.7.0", - "eslint-config-airbnb": "19.0.4", - "eslint-config-prettier": "8.3.0", - "eslint-import-resolver-webpack": "0.13.2", - "eslint-plugin-i18next": "5.2.1", - "eslint-plugin-import": "2.25.4", - "eslint-plugin-jsx-a11y": "6.5.1", - "eslint-plugin-react": "7.28.0", - "eslint-plugin-react-hooks": "4.3.0", - "http-proxy-middleware": "^1.0.3", - "jest-websocket-mock": "^2.0.2", - "mock-socket": "^9.1.3", - "prettier": "2.3.2", - "react-scripts": "5.0.1" - }, - "scripts": { - "prelint": "lingui compile", - "prestart": "lingui compile", - "prestart-instrumented": "lingui compile", - "pretest": "lingui compile", - "pretest-watch": "lingui compile", - "start": "GENERATE_SOURCEMAP=false ESLINT_NO_DEV_ERRORS=true PORT=3001 HTTPS=true DANGEROUSLY_DISABLE_HOST_CHECK=true react-scripts start", - "start-instrumented": "ESLINT_NO_DEV_ERRORS=true DEBUG=instrument-cra PORT=3001 HTTPS=true DANGEROUSLY_DISABLE_HOST_CHECK=true react-scripts -r @cypress/instrument-cra start", - "build": "INLINE_RUNTIME_CHUNK=false react-scripts build", - "test": "TZ='UTC' react-scripts test --watchAll=false", - "test-screens": "TZ='UTC' react-scripts test screens --watchAll=false", - "test-general": "TZ='UTC' react-scripts test --testPathIgnorePatterns='/src/screens/' --watchAll=false", - "test-watch": "TZ='UTC' react-scripts test", - "eject": "react-scripts eject", - "lint": "eslint --ext .js --ext .jsx .", - "extract-strings": "lingui extract", - "extract-template": "lingui extract-template", - "compile-strings": "lingui compile", - "prettier": "prettier --write \"src/**/*.{js,jsx,scss}\"", - "prettier-check": "prettier --check \"src/**/*.{js,jsx,scss}\"" - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - }, - "jest": { - "snapshotSerializers": [ - "enzyme-to-json/serializer" - ], - "collectCoverageFrom": [ - "src/**/*.{js,jsx}", - "testUtils/**/*.{js,jsx}" - ], - "coveragePathIgnorePatterns": [ - "/src/locales", - "index.js" - ], - "transformIgnorePatterns": [ - "/node_modules/(?!d3)/", - "/node_modules/(?!has-ansi)/" - ] - } -} diff --git a/awx/ui/placeholder_index_awx.html b/awx/ui/placeholder_index_awx.html new file mode 100644 index 000000000000..3dabf3711fb7 --- /dev/null +++ b/awx/ui/placeholder_index_awx.html @@ -0,0 +1,9 @@ + + + UI Missing + +
+

Oops... Looks like the UI wasn't properly built

+
+ + diff --git a/awx/ui/public/index.html b/awx/ui/public/index.html deleted file mode 100644 index 2478bd616b47..000000000000 --- a/awx/ui/public/index.html +++ /dev/null @@ -1,49 +0,0 @@ - -<% if (process.env.NODE_ENV === 'production') { %> - {% load static %} -<% } %> - - - - <% if (process.env.NODE_ENV === 'production') { %> - - - - <% } else { %> - - <% } %> - - - - - - - - <% if (process.env.NODE_ENV === 'production') { %> -
- <% } else { %> -
- <% } %> - - diff --git a/awx/ui/public/installing.html b/awx/ui/public/installing.html index c13091e9d6b6..accfbcce6811 100644 --- a/awx/ui/public/installing.html +++ b/awx/ui/public/installing.html @@ -5,7 +5,11 @@ {{ title }} diff --git a/awx/ui/public/static/css/assets/fonts/RedHatDisplay/RedHatDisplay-Medium.woff b/awx/ui/public/static/css/assets/fonts/RedHatDisplay/RedHatDisplay-Medium.woff deleted file mode 100644 index 7a88f9dfec7d..000000000000 Binary files a/awx/ui/public/static/css/assets/fonts/RedHatDisplay/RedHatDisplay-Medium.woff and /dev/null differ diff --git a/awx/ui/public/static/css/assets/fonts/RedHatText/RedHatText-Regular.woff b/awx/ui/public/static/css/assets/fonts/RedHatText/RedHatText-Regular.woff deleted file mode 100644 index b0e94af5eeac..000000000000 Binary files a/awx/ui/public/static/css/assets/fonts/RedHatText/RedHatText-Regular.woff and /dev/null differ diff --git a/awx/ui/public/static/css/patternfly.min.css b/awx/ui/public/static/css/patternfly.min.css deleted file mode 100644 index 67bb72558c29..000000000000 --- a/awx/ui/public/static/css/patternfly.min.css +++ /dev/null @@ -1,2 +0,0 @@ -@charset "UTF-8";.pf-c-accordion,.pf-c-alert,.pf-c-banner.pf-m-info,.pf-c-banner.pf-m-warning,.pf-c-calendar-month,.pf-c-chip,.pf-c-chip-group,.pf-c-context-selector__menu,.pf-c-data-list,.pf-c-form-control,.pf-c-input-group,.pf-c-menu,.pf-c-page__sidebar.pf-m-light,.pf-c-select,.pf-c-table,.pf-t-light{--pf-global--Color--100:var(--pf-global--Color--dark-100);--pf-global--Color--200:var(--pf-global--Color--dark-200);--pf-global--BorderColor--100:var(--pf-global--BorderColor--dark-100);--pf-global--primary-color--100:var(--pf-global--primary-color--dark-100);--pf-global--link--Color:var(--pf-global--link--Color--dark);--pf-global--link--Color--hover:var(--pf-global--link--Color--dark--hover);--pf-global--BackgroundColor--100:var(--pf-global--BackgroundColor--light-100)}.pf-c-about-modal-box,.pf-c-banner,.pf-c-login__footer,.pf-c-login__header,.pf-c-page__header,.pf-c-page__main-section[class*=pf-m-dark-],.pf-c-wizard__header,.pf-t-dark{--pf-global--Color--100:var(--pf-global--Color--light-100);--pf-global--Color--200:var(--pf-global--Color--light-200);--pf-global--BorderColor--100:var(--pf-global--BorderColor--light-100);--pf-global--primary-color--100:var(--pf-global--primary-color--light-100);--pf-global--link--Color:var(--pf-global--link--Color--light);--pf-global--link--Color--hover:var(--pf-global--link--Color--light);--pf-global--BackgroundColor--100:var(--pf-global--BackgroundColor--dark-100)}.pf-c-about-modal-box .pf-c-card,.pf-c-banner .pf-c-card,.pf-c-login__footer .pf-c-card,.pf-c-login__header .pf-c-card,.pf-c-page__header .pf-c-card,.pf-c-page__main-section[class*=pf-m-dark-] .pf-c-card,.pf-c-wizard__header .pf-c-card,.pf-t-dark .pf-c-card{--pf-c-card--BackgroundColor:var(--pf-global--BackgroundColor--dark-transparent-200)}.pf-c-about-modal-box .pf-c-button,.pf-c-banner .pf-c-button,.pf-c-login__footer .pf-c-button,.pf-c-login__header .pf-c-button,.pf-c-page__header .pf-c-button,.pf-c-page__main-section[class*=pf-m-dark-] .pf-c-button,.pf-c-wizard__header .pf-c-button,.pf-t-dark .pf-c-button{--pf-c-button--m-primary--Color:var(--pf-global--primary-color--dark-100);--pf-c-button--m-primary--hover--Color:var(--pf-global--primary-color--dark-100);--pf-c-button--m-primary--focus--Color:var(--pf-global--primary-color--dark-100);--pf-c-button--m-primary--active--Color:var(--pf-global--primary-color--dark-100);--pf-c-button--m-primary--BackgroundColor:var(--pf-global--BackgroundColor--light-100);--pf-c-button--m-primary--hover--BackgroundColor:var(--pf-global--BackgroundColor--light-300);--pf-c-button--m-primary--focus--BackgroundColor:var(--pf-global--BackgroundColor--light-300);--pf-c-button--m-primary--active--BackgroundColor:var(--pf-global--BackgroundColor--light-300);--pf-c-button--m-secondary--Color:var(--pf-global--Color--light-100);--pf-c-button--m-secondary--hover--Color:var(--pf-global--Color--light-100);--pf-c-button--m-secondary--focus--Color:var(--pf-global--Color--light-100);--pf-c-button--m-secondary--active--Color:var(--pf-global--Color--light-100);--pf-c-button--m-secondary--BorderColor:var(--pf-global--Color--light-100);--pf-c-button--m-secondary--hover--BorderColor:var(--pf-global--Color--light-100);--pf-c-button--m-secondary--focus--BorderColor:var(--pf-global--Color--light-100);--pf-c-button--m-secondary--active--BorderColor:var(--pf-global--Color--light-100)}.pf-c-data-list__item-action,.pf-c-page__header-tools-group,.pf-c-page__header-tools-item,.pf-c-table tr>*{--pf-hidden-visible--visible--Visibility:visible;--pf-hidden-visible--hidden--Display:none;--pf-hidden-visible--hidden--Visibility:hidden;--pf-hidden-visible--Display:var(--pf-hidden-visible--visible--Display);--pf-hidden-visible--Visibility:var(--pf-hidden-visible--visible--Visibility);display:var(--pf-hidden-visible--Display);visibility:var(--pf-hidden-visible--Visibility)}.pf-c-table tr>.pf-m-hidden,.pf-m-hidden.pf-c-data-list__item-action,.pf-m-hidden.pf-c-page__header-tools-group,.pf-m-hidden.pf-c-page__header-tools-item{--pf-hidden-visible--Display:var(--pf-hidden-visible--hidden--Display);--pf-hidden-visible--Visibility:var(--pf-hidden-visible--hidden--Visibility)}@media screen and (min-width:576px){.pf-c-table tr>.pf-m-hidden-on-sm,.pf-m-hidden-on-sm.pf-c-data-list__item-action,.pf-m-hidden-on-sm.pf-c-page__header-tools-group,.pf-m-hidden-on-sm.pf-c-page__header-tools-item{--pf-hidden-visible--Display:var(--pf-hidden-visible--hidden--Display);--pf-hidden-visible--Visibility:var(--pf-hidden-visible--hidden--Visibility)}.pf-c-table tr>.pf-m-visible-on-sm,.pf-m-visible-on-sm.pf-c-data-list__item-action,.pf-m-visible-on-sm.pf-c-page__header-tools-group,.pf-m-visible-on-sm.pf-c-page__header-tools-item{--pf-hidden-visible--Display:var(--pf-hidden-visible--visible--Display);--pf-hidden-visible--Visibility:var(--pf-hidden-visible--visible--Visibility)}}@media screen and (min-width:768px){.pf-c-table tr>.pf-m-hidden-on-md,.pf-m-hidden-on-md.pf-c-data-list__item-action,.pf-m-hidden-on-md.pf-c-page__header-tools-group,.pf-m-hidden-on-md.pf-c-page__header-tools-item{--pf-hidden-visible--Display:var(--pf-hidden-visible--hidden--Display);--pf-hidden-visible--Visibility:var(--pf-hidden-visible--hidden--Visibility)}.pf-c-table tr>.pf-m-visible-on-md,.pf-m-visible-on-md.pf-c-data-list__item-action,.pf-m-visible-on-md.pf-c-page__header-tools-group,.pf-m-visible-on-md.pf-c-page__header-tools-item{--pf-hidden-visible--Display:var(--pf-hidden-visible--visible--Display);--pf-hidden-visible--Visibility:var(--pf-hidden-visible--visible--Visibility)}}@media screen and (min-width:992px){.pf-c-table tr>.pf-m-hidden-on-lg,.pf-m-hidden-on-lg.pf-c-data-list__item-action,.pf-m-hidden-on-lg.pf-c-page__header-tools-group,.pf-m-hidden-on-lg.pf-c-page__header-tools-item{--pf-hidden-visible--Display:var(--pf-hidden-visible--hidden--Display);--pf-hidden-visible--Visibility:var(--pf-hidden-visible--hidden--Visibility)}.pf-c-table tr>.pf-m-visible-on-lg,.pf-m-visible-on-lg.pf-c-data-list__item-action,.pf-m-visible-on-lg.pf-c-page__header-tools-group,.pf-m-visible-on-lg.pf-c-page__header-tools-item{--pf-hidden-visible--Display:var(--pf-hidden-visible--visible--Display);--pf-hidden-visible--Visibility:var(--pf-hidden-visible--visible--Visibility)}}@media screen and (min-width:1200px){.pf-c-table tr>.pf-m-hidden-on-xl,.pf-m-hidden-on-xl.pf-c-data-list__item-action,.pf-m-hidden-on-xl.pf-c-page__header-tools-group,.pf-m-hidden-on-xl.pf-c-page__header-tools-item{--pf-hidden-visible--Display:var(--pf-hidden-visible--hidden--Display);--pf-hidden-visible--Visibility:var(--pf-hidden-visible--hidden--Visibility)}.pf-c-table tr>.pf-m-visible-on-xl,.pf-m-visible-on-xl.pf-c-data-list__item-action,.pf-m-visible-on-xl.pf-c-page__header-tools-group,.pf-m-visible-on-xl.pf-c-page__header-tools-item{--pf-hidden-visible--Display:var(--pf-hidden-visible--visible--Display);--pf-hidden-visible--Visibility:var(--pf-hidden-visible--visible--Visibility)}}@media screen and (min-width:1450px){.pf-c-table tr>.pf-m-hidden-on-2xl,.pf-m-hidden-on-2xl.pf-c-data-list__item-action,.pf-m-hidden-on-2xl.pf-c-page__header-tools-group,.pf-m-hidden-on-2xl.pf-c-page__header-tools-item{--pf-hidden-visible--Display:var(--pf-hidden-visible--hidden--Display);--pf-hidden-visible--Visibility:var(--pf-hidden-visible--hidden--Visibility)}.pf-c-table tr>.pf-m-visible-on-2xl,.pf-m-visible-on-2xl.pf-c-data-list__item-action,.pf-m-visible-on-2xl.pf-c-page__header-tools-group,.pf-m-visible-on-2xl.pf-c-page__header-tools-item{--pf-hidden-visible--Display:var(--pf-hidden-visible--visible--Display);--pf-hidden-visible--Visibility:var(--pf-hidden-visible--visible--Visibility)}}:root{--pf-global--palette--black-100:#fafafa;--pf-global--palette--black-150:#f5f5f5;--pf-global--palette--black-200:#f0f0f0;--pf-global--palette--black-300:#d2d2d2;--pf-global--palette--black-400:#b8bbbe;--pf-global--palette--black-500:#8a8d90;--pf-global--palette--black-600:#6a6e73;--pf-global--palette--black-700:#4f5255;--pf-global--palette--black-800:#3c3f42;--pf-global--palette--black-850:#212427;--pf-global--palette--black-900:#151515;--pf-global--palette--black-1000:#030303;--pf-global--palette--blue-50:#e7f1fa;--pf-global--palette--blue-100:#bee1f4;--pf-global--palette--blue-200:#73bcf7;--pf-global--palette--blue-300:#2b9af3;--pf-global--palette--blue-400:#06c;--pf-global--palette--blue-500:#004080;--pf-global--palette--blue-600:#002952;--pf-global--palette--blue-700:#001223;--pf-global--palette--cyan-50:#f2f9f9;--pf-global--palette--cyan-100:#a2d9d9;--pf-global--palette--cyan-200:#73c5c5;--pf-global--palette--cyan-300:#009596;--pf-global--palette--cyan-400:#005f60;--pf-global--palette--cyan-500:#003737;--pf-global--palette--cyan-600:#002323;--pf-global--palette--cyan-700:#000f0f;--pf-global--palette--gold-50:#fdf7e7;--pf-global--palette--gold-100:#f9e0a2;--pf-global--palette--gold-200:#f6d173;--pf-global--palette--gold-300:#f4c145;--pf-global--palette--gold-400:#f0ab00;--pf-global--palette--gold-500:#c58c00;--pf-global--palette--gold-600:#795600;--pf-global--palette--gold-700:#3d2c00;--pf-global--palette--green-50:#f3faf2;--pf-global--palette--green-100:#bde5b8;--pf-global--palette--green-200:#95d58e;--pf-global--palette--green-300:#6ec664;--pf-global--palette--green-400:#5ba352;--pf-global--palette--green-500:#3e8635;--pf-global--palette--green-600:#1e4f18;--pf-global--palette--green-700:#0f280d;--pf-global--palette--light-blue-100:#beedf9;--pf-global--palette--light-blue-200:#7cdbf3;--pf-global--palette--light-blue-300:#35caed;--pf-global--palette--light-blue-400:#00b9e4;--pf-global--palette--light-blue-500:#008bad;--pf-global--palette--light-blue-600:#005c73;--pf-global--palette--light-blue-700:#002d39;--pf-global--palette--light-green-100:#e4f5bc;--pf-global--palette--light-green-200:#c8eb79;--pf-global--palette--light-green-300:#ace12e;--pf-global--palette--light-green-400:#92d400;--pf-global--palette--light-green-500:#6ca100;--pf-global--palette--light-green-600:#486b00;--pf-global--palette--light-green-700:#253600;--pf-global--palette--orange-100:#f4b678;--pf-global--palette--orange-200:#ef9234;--pf-global--palette--orange-300:#ec7a08;--pf-global--palette--orange-400:#c46100;--pf-global--palette--orange-500:#8f4700;--pf-global--palette--orange-600:#773d00;--pf-global--palette--orange-700:#3b1f00;--pf-global--palette--purple-50:#f2f0fc;--pf-global--palette--purple-100:#cbc1ff;--pf-global--palette--purple-200:#b2a3ff;--pf-global--palette--purple-300:#a18fff;--pf-global--palette--purple-400:#8476d1;--pf-global--palette--purple-500:#6753ac;--pf-global--palette--purple-600:#40199a;--pf-global--palette--purple-700:#1f0066;--pf-global--palette--red-50:#faeae8;--pf-global--palette--red-100:#c9190b;--pf-global--palette--red-200:#a30000;--pf-global--palette--red-300:#7d1007;--pf-global--palette--red-400:#470000;--pf-global--palette--red-500:#2c0000;--pf-global--palette--white:#fff;--pf-global--BackgroundColor--100:#fff;--pf-global--BackgroundColor--200:#f0f0f0;--pf-global--BackgroundColor--light-100:#fff;--pf-global--BackgroundColor--light-200:#fafafa;--pf-global--BackgroundColor--light-300:#f0f0f0;--pf-global--BackgroundColor--dark-100:#151515;--pf-global--BackgroundColor--dark-200:#3c3f42;--pf-global--BackgroundColor--dark-300:#212427;--pf-global--BackgroundColor--dark-400:#4f5255;--pf-global--BackgroundColor--dark-transparent-100:rgba(3,3,3,0.62);--pf-global--BackgroundColor--dark-transparent-200:rgba(3,3,3,0.32);--pf-global--Color--100:#151515;--pf-global--Color--200:#6a6e73;--pf-global--Color--300:#3c3f42;--pf-global--Color--400:#8a8d90;--pf-global--Color--light-100:#fff;--pf-global--Color--light-200:#f0f0f0;--pf-global--Color--light-300:#d2d2d2;--pf-global--Color--dark-100:#151515;--pf-global--Color--dark-200:#6a6e73;--pf-global--active-color--100:#06c;--pf-global--active-color--200:#bee1f4;--pf-global--active-color--300:#2b9af3;--pf-global--active-color--400:#73bcf7;--pf-global--disabled-color--100:#6a6e73;--pf-global--disabled-color--200:#d2d2d2;--pf-global--disabled-color--300:#f0f0f0;--pf-global--primary-color--100:#06c;--pf-global--primary-color--200:#004080;--pf-global--primary-color--light-100:#73bcf7;--pf-global--primary-color--dark-100:#06c;--pf-global--secondary-color--100:#6a6e73;--pf-global--default-color--100:#73c5c5;--pf-global--default-color--200:#009596;--pf-global--default-color--300:#003737;--pf-global--success-color--100:#3e8635;--pf-global--success-color--200:#1e4f18;--pf-global--info-color--100:#2b9af3;--pf-global--info-color--200:#002952;--pf-global--warning-color--100:#f0ab00;--pf-global--warning-color--200:#795600;--pf-global--danger-color--100:#c9190b;--pf-global--danger-color--200:#a30000;--pf-global--danger-color--300:#470000;--pf-global--BoxShadow--sm:0 0.0625rem 0.125rem 0 rgba(3,3,3,0.12),0 0 0.125rem 0 rgba(3,3,3,0.06);--pf-global--BoxShadow--sm-top:0 -0.125rem 0.25rem -0.0625rem rgba(3,3,3,0.16);--pf-global--BoxShadow--sm-right:0.125rem 0 0.25rem -0.0625rem rgba(3,3,3,0.16);--pf-global--BoxShadow--sm-bottom:0 0.125rem 0.25rem -0.0625rem rgba(3,3,3,0.16);--pf-global--BoxShadow--sm-left:-0.125rem 0 0.25rem -0.0625rem rgba(3,3,3,0.16);--pf-global--BoxShadow--md:0 0.25rem 0.5rem 0rem rgba(3,3,3,0.12),0 0 0.25rem 0 rgba(3,3,3,0.06);--pf-global--BoxShadow--md-top:0 -0.5rem 0.5rem -0.375rem rgba(3,3,3,0.18);--pf-global--BoxShadow--md-right:0.5rem 0 0.5rem -0.375rem rgba(3,3,3,0.18);--pf-global--BoxShadow--md-bottom:0 0.5rem 0.5rem -0.375rem rgba(3,3,3,0.18);--pf-global--BoxShadow--md-left:-0.5rem 0 0.5rem -0.375rem rgba(3,3,3,0.18);--pf-global--BoxShadow--lg:0 0.5rem 1rem 0 rgba(3,3,3,0.16),0 0 0.375rem 0 rgba(3,3,3,0.08);--pf-global--BoxShadow--lg-top:0 -0.75rem 0.75rem -0.5rem rgba(3,3,3,0.18);--pf-global--BoxShadow--lg-right:0.75rem 0 0.75rem -0.5rem rgba(3,3,3,0.18);--pf-global--BoxShadow--lg-bottom:0 0.75rem 0.75rem -0.5rem rgba(3,3,3,0.18);--pf-global--BoxShadow--lg-left:-0.75rem 0 0.75rem -0.5rem rgba(3,3,3,0.18);--pf-global--BoxShadow--xl:0 1rem 2rem 0 rgba(3,3,3,0.16),0 0 0.5rem 0 rgba(3,3,3,0.1);--pf-global--BoxShadow--xl-top:0 -1rem 1rem -0.5rem rgba(3,3,3,0.2);--pf-global--BoxShadow--xl-right:1rem 0 1rem -0.5rem rgba(3,3,3,0.2);--pf-global--BoxShadow--xl-bottom:0 1rem 1rem -0.5rem rgba(3,3,3,0.2);--pf-global--BoxShadow--xl-left:-1rem 0 1rem -0.5rem rgba(3,3,3,0.2);--pf-global--BoxShadow--inset:inset 0 0 0.625rem 0 rgba(3,3,3,0.25);--pf-global--font-path:"./assets/fonts";--pf-global--fonticon-path:"./assets/pficon";--pf-global--spacer--xs:0.25rem;--pf-global--spacer--sm:0.5rem;--pf-global--spacer--md:1rem;--pf-global--spacer--lg:1.5rem;--pf-global--spacer--xl:2rem;--pf-global--spacer--2xl:3rem;--pf-global--spacer--3xl:4rem;--pf-global--spacer--4xl:5rem;--pf-global--spacer--form-element:0.375rem;--pf-global--gutter:1rem;--pf-global--gutter--md:1.5rem;--pf-global--ZIndex--xs:100;--pf-global--ZIndex--sm:200;--pf-global--ZIndex--md:300;--pf-global--ZIndex--lg:400;--pf-global--ZIndex--xl:500;--pf-global--ZIndex--2xl:600;--pf-global--breakpoint--xs:0;--pf-global--breakpoint--sm:576px;--pf-global--breakpoint--md:768px;--pf-global--breakpoint--lg:992px;--pf-global--breakpoint--xl:1200px;--pf-global--breakpoint--2xl:1450px;--pf-global--link--Color:#06c;--pf-global--link--Color--hover:#004080;--pf-global--link--Color--light:#2b9af3;--pf-global--link--Color--light--hover:#73bcf7;--pf-global--link--Color--dark:#06c;--pf-global--link--Color--dark--hover:#004080;--pf-global--link--TextDecoration:none;--pf-global--link--TextDecoration--hover:underline;--pf-global--BorderWidth--sm:1px;--pf-global--BorderWidth--md:2px;--pf-global--BorderWidth--lg:3px;--pf-global--BorderWidth--xl:4px;--pf-global--BorderColor--100:#d2d2d2;--pf-global--BorderColor--200:#8a8d90;--pf-global--BorderColor--300:#f0f0f0;--pf-global--BorderColor--dark-100:#d2d2d2;--pf-global--BorderColor--light-100:#b8bbbe;--pf-global--BorderRadius--sm:3px;--pf-global--BorderRadius--lg:30em;--pf-global--icon--Color--light:#6a6e73;--pf-global--icon--Color--dark:#151515;--pf-global--icon--FontSize--sm:0.625rem;--pf-global--icon--FontSize--md:1.125rem;--pf-global--icon--FontSize--lg:1.5rem;--pf-global--icon--FontSize--xl:3.375rem;--pf-global--FontFamily--sans-serif:"RedHatText","Overpass",overpass,helvetica,arial,sans-serif;--pf-global--FontFamily--heading--sans-serif:"RedHatDisplay","Overpass",overpass,helvetica,arial,sans-serif;--pf-global--FontFamily--monospace:"Liberation Mono",consolas,"SFMono-Regular",menlo,monaco,"Courier New",monospace;--pf-global--FontFamily--overpass--sans-serif:"overpass",overpass,"open sans",-apple-system,blinkmacsystemfont,"Segoe UI",roboto,"Helvetica Neue",arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--pf-global--FontFamily--overpass--monospace:"overpass-mono",overpass-mono,"SFMono-Regular",menlo,monaco,consolas,"Liberation Mono","Courier New",monospace;--pf-global--FontSize--4xl:2.25rem;--pf-global--FontSize--3xl:1.75rem;--pf-global--FontSize--2xl:1.5rem;--pf-global--FontSize--xl:1.25rem;--pf-global--FontSize--lg:1.125rem;--pf-global--FontSize--md:1rem;--pf-global--FontSize--sm:0.875rem;--pf-global--FontSize--xs:0.75rem;--pf-global--FontWeight--light:300;--pf-global--FontWeight--normal:400;--pf-global--FontWeight--semi-bold:700;--pf-global--FontWeight--overpass--semi-bold:500;--pf-global--FontWeight--bold:700;--pf-global--FontWeight--overpass--bold:600;--pf-global--LineHeight--sm:1.3;--pf-global--LineHeight--md:1.5;--pf-global--ListStyle:disc outside;--pf-global--Transition:all 250ms ease-in-out;--pf-global--TimingFunction:cubic-bezier(0.645,0.045,0.355,1);--pf-global--TransitionDuration:250ms;--pf-global--arrow--width:0.9375rem;--pf-global--arrow--width-lg:1.5625rem;--pf-global--target-size--MinWidth:44px;--pf-global--target-size--MinHeight:44px}.pf-m-overpass-font{--pf-global--FontFamily--sans-serif:var(--pf-global--FontFamily--overpass--sans-serif);--pf-global--FontFamily--heading--sans-serif:var(--pf-global--FontFamily--sans-serif);--pf-global--FontFamily--monospace:var(--pf-global--FontFamily--overpass--monospace);--pf-global--FontWeight--semi-bold:var(--pf-global--FontWeight--overpass--semi-bold);--pf-global--FontWeight--bold:var(--pf-global--FontWeight--overpass--bold)}@font-face{font-family:RedHatDisplay;src:url(assets/fonts/RedHatDisplay/RedHatDisplay-Regular.eot);src:url(assets/fonts/RedHatDisplay/RedHatDisplay-Regular.eot?#iefix) format("embedded-opentype"),url(assets/fonts/RedHatDisplay/RedHatDisplay-Regular.woff) format("woff");font-style:normal;font-weight:300;text-rendering:optimizeLegibility}@font-face{font-family:RedHatDisplay;src:url(assets/fonts/RedHatDisplay/RedHatDisplay-Medium.eot);src:url(assets/fonts/RedHatDisplay/RedHatDisplay-Medium.eot?#iefix) format("embedded-opentype"),url(assets/fonts/RedHatDisplay/RedHatDisplay-Medium.woff) format("woff");font-style:normal;font-weight:400;text-rendering:optimizeLegibility}@font-face{font-family:RedHatDisplay;src:url(assets/fonts/RedHatDisplay/RedHatDisplay-Bold.eot);src:url(assets/fonts/RedHatDisplay/RedHatDisplay-Bold.eot?#iefix) format("embedded-opentype"),url(assets/fonts/RedHatDisplay/RedHatDisplay-Bold.woff) format("woff");font-style:normal;font-weight:700;text-rendering:optimizeLegibility}@font-face{font-family:RedHatText;src:url(assets/fonts/RedHatText/RedHatText-Regular.eot);src:url(assets/fonts/RedHatText/RedHatText-Regular.eot?#iefix) format("embedded-opentype"),url(assets/fonts/RedHatText/RedHatText-Regular.woff) format("woff");font-style:normal;font-weight:400;text-rendering:optimizeLegibility}@font-face{font-family:RedHatText;src:url(assets/fonts/RedHatText/RedHatText-Medium.eot);src:url(assets/fonts/RedHatText/RedHatText-Medium.eot?#iefix) format("embedded-opentype"),url(assets/fonts/RedHatText/RedHatText-Medium.woff) format("woff");font-style:normal;font-weight:700;text-rendering:optimizeLegibility}@font-face{font-family:overpass;font-style:normal;font-weight:200;src:url(assets/fonts/overpass-webfont/overpass-thin.eot);src:url(assets/fonts/overpass-webfont/overpass-thin.eot?#iefix) format("embedded-opentype"),url(assets/fonts/overpass-webfont/overpass-thin.woff2) format("woff2"),url(assets/fonts/overpass-webfont/overpass-thin.woff) format("woff"),url(assets/fonts/overpass-webfont/overpass-thin.ttf) format("truetype")}@font-face{font-family:overpass;font-style:italic;font-weight:200;src:url(assets/fonts/overpass-webfont/overpass-thin-italic.eot);src:url(assets/fonts/overpass-webfont/overpass-thin-italic.eot?#iefix) format("embedded-opentype"),url(assets/fonts/overpass-webfont/overpass-thin-italic.woff2) format("woff2"),url(assets/fonts/overpass-webfont/overpass-thin-italic.woff) format("woff"),url(assets/fonts/overpass-webfont/overpass-thin-italic.ttf) format("truetype")}@font-face{font-family:overpass;font-style:normal;font-weight:300;src:url(assets/fonts/overpass-webfont/overpass-extralight.eot);src:url(assets/fonts/overpass-webfont/overpass-extralight.eot?#iefix) format("embedded-opentype"),url(assets/fonts/overpass-webfont/overpass-extralight.woff2) format("woff2"),url(assets/fonts/overpass-webfont/overpass-extralight.woff) format("woff"),url(assets/fonts/overpass-webfont/overpass-extralight.ttf) format("truetype")}@font-face{font-family:overpass;font-style:italic;font-weight:300;src:url(assets/fonts/overpass-webfont/overpass-extralight-italic.eot);src:url(assets/fonts/overpass-webfont/overpass-extralight-italic.eot?#iefix) format("embedded-opentype"),url(assets/fonts/overpass-webfont/overpass-extralight-italic.woff2) format("woff2"),url(assets/fonts/overpass-webfont/overpass-extralight-italic.woff) format("woff"),url(assets/fonts/overpass-webfont/overpass-extralight-italic.ttf) format("truetype")}@font-face{font-family:overpass;font-style:normal;font-weight:400;src:url(assets/fonts/overpass-webfont/overpass-light.eot);src:url(assets/fonts/overpass-webfont/overpass-light.eot?#iefix) format("embedded-opentype"),url(assets/fonts/overpass-webfont/overpass-light.woff2) format("woff2"),url(assets/fonts/overpass-webfont/overpass-light.woff) format("woff"),url(assets/fonts/overpass-webfont/overpass-light.ttf) format("truetype")}@font-face{font-family:overpass;font-style:italic;font-weight:400;src:url(assets/fonts/overpass-webfont/overpass-light-italic.eot);src:url(assets/fonts/overpass-webfont/overpass-light-italic.eot?#iefix) format("embedded-opentype"),url(assets/fonts/overpass-webfont/overpass-light-italic.woff2) format("woff2"),url(assets/fonts/overpass-webfont/overpass-light-italic.woff) format("woff"),url(assets/fonts/overpass-webfont/overpass-light-italic.ttf) format("truetype")}@font-face{font-family:overpass;font-style:normal;font-weight:500;src:url(assets/fonts/overpass-webfont/overpass-regular.eot);src:url(assets/fonts/overpass-webfont/overpass-regular.eot?#iefix) format("embedded-opentype"),url(assets/fonts/overpass-webfont/overpass-regular.woff2) format("woff2"),url(assets/fonts/overpass-webfont/overpass-regular.woff) format("woff"),url(assets/fonts/overpass-webfont/overpass-regular.ttf) format("truetype")}@font-face{font-family:overpass;font-style:italic;font-weight:500;src:url(assets/fonts/overpass-webfont/overpass-italic.eot);src:url(assets/fonts/overpass-webfont/overpass-italic.eot?#iefix) format("embedded-opentype"),url(assets/fonts/overpass-webfont/overpass-italic.woff2) format("woff2"),url(assets/fonts/overpass-webfont/overpass-italic.woff) format("woff"),url(assets/fonts/overpass-webfont/overpass-italic.ttf) format("truetype")}@font-face{font-family:overpass;font-style:normal;font-weight:600;src:url(assets/fonts/overpass-webfont/overpass-semibold.eot);src:url(assets/fonts/overpass-webfont/overpass-semibold.eot?#iefix) format("embedded-opentype"),url(assets/fonts/overpass-webfont/overpass-semibold.woff2) format("woff2"),url(assets/fonts/overpass-webfont/overpass-semibold.woff) format("woff"),url(assets/fonts/overpass-webfont/overpass-semibold.ttf) format("truetype")}@font-face{font-family:overpass;font-style:italic;font-weight:600;src:url(assets/fonts/overpass-webfont/overpass-semibold-italic.eot);src:url(assets/fonts/overpass-webfont/overpass-semibold-italic.eot?#iefix) format("embedded-opentype"),url(assets/fonts/overpass-webfont/overpass-semibold-italic.woff2) format("woff2"),url(assets/fonts/overpass-webfont/overpass-semibold-italic.woff) format("woff"),url(assets/fonts/overpass-webfont/overpass-semibold-italic.ttf) format("truetype")}@font-face{font-family:overpass;font-style:normal;font-weight:700;src:url(assets/fonts/overpass-webfont/overpass-bold.eot);src:url(assets/fonts/overpass-webfont/overpass-bold.eot?#iefix) format("embedded-opentype"),url(assets/fonts/overpass-webfont/overpass-bold.woff2) format("woff2"),url(assets/fonts/overpass-webfont/overpass-bold.woff) format("woff"),url(assets/fonts/overpass-webfont/overpass-bold.ttf) format("truetype")}@font-face{font-family:overpass;font-style:italic;font-weight:700;src:url(assets/fonts/overpass-webfont/overpass-bold-italic.eot);src:url(assets/fonts/overpass-webfont/overpass-bold-italic.eot?#iefix) format("embedded-opentype"),url(assets/fonts/overpass-webfont/overpass-bold-italic.woff2) format("woff2"),url(assets/fonts/overpass-webfont/overpass-bold-italic.woff) format("woff"),url(assets/fonts/overpass-webfont/overpass-bold-italic.ttf) format("truetype")}@font-face{font-family:overpass;font-style:normal;font-weight:800;src:url(assets/fonts/overpass-webfont/overpass-extrabold.eot);src:url(assets/fonts/overpass-webfont/overpass-extrabold.eot?#iefix) format("embedded-opentype"),url(assets/fonts/overpass-webfont/overpass-extrabold.woff2) format("woff2"),url(assets/fonts/overpass-webfont/overpass-extrabold.woff) format("woff"),url(assets/fonts/overpass-webfont/overpass-extrabold.ttf) format("truetype")}@font-face{font-family:overpass;font-style:italic;font-weight:800;src:url(assets/fonts/overpass-webfont/overpass-extrabold-italic.eot);src:url(assets/fonts/overpass-webfont/overpass-extrabold-italic.eot?#iefix) format("embedded-opentype"),url(assets/fonts/overpass-webfont/overpass-extrabold-italic.woff2) format("woff2"),url(assets/fonts/overpass-webfont/overpass-extrabold-italic.woff) format("woff"),url(assets/fonts/overpass-webfont/overpass-extrabold-italic.ttf) format("truetype")}@font-face{font-family:overpass;font-style:normal;font-weight:900;src:url(assets/fonts/overpass-webfont/overpass-heavy.eot);src:url(assets/fonts/overpass-webfont/overpass-heavy.eot?#iefix) format("embedded-opentype"),url(assets/fonts/overpass-webfont/overpass-heavy.woff2) format("woff2"),url(assets/fonts/overpass-webfont/overpass-heavy.woff) format("woff"),url(assets/fonts/overpass-webfont/overpass-heavy.ttf) format("truetype")}@font-face{font-family:overpass;font-style:italic;font-weight:900;src:url(assets/fonts/overpass-webfont/overpass-heavy-italic.eot);src:url(assets/fonts/overpass-webfont/overpass-heavy-italic.eot?#iefix) format("embedded-opentype"),url(assets/fonts/overpass-webfont/overpass-heavy-italic.woff2) format("woff2"),url(assets/fonts/overpass-webfont/overpass-heavy-italic.woff) format("woff"),url(assets/fonts/overpass-webfont/overpass-heavy-italic.ttf) format("truetype")}@font-face{font-family:overpass-mono;font-style:normal;font-weight:300;src:url(assets/fonts/overpass-mono-webfont/overpass-mono-light.eot);src:url(assets/fonts/overpass-mono-webfont/overpass-mono-light.eot?#iefix) format("embedded-opentype"),url(assets/fonts/overpass-mono-webfont/overpass-mono-light.woff2) format("woff2"),url(assets/fonts/overpass-mono-webfont/overpass-mono-light.woff) format("woff"),url(assets/fonts/overpass-mono-webfont/overpass-mono-light.ttf) format("truetype")}@font-face{font-family:overpass-mono;font-style:normal;font-weight:400;src:url(assets/fonts/overpass-mono-webfont/overpass-mono-regular.eot);src:url(assets/fonts/overpass-mono-webfont/overpass-mono-regular.eot?#iefix) format("embedded-opentype"),url(assets/fonts/overpass-mono-webfont/overpass-mono-regular.woff2) format("woff2"),url(assets/fonts/overpass-mono-webfont/overpass-mono-regular.woff) format("woff"),url(assets/fonts/overpass-mono-webfont/overpass-mono-regular.ttf) format("truetype")}@font-face{font-family:overpass-mono;font-style:normal;font-weight:500;src:url(assets/fonts/overpass-mono-webfont/overpass-mono-semibold.eot);src:url(assets/fonts/overpass-mono-webfont/overpass-mono-semibold.eot?#iefix) format("embedded-opentype"),url(assets/fonts/overpass-mono-webfont/overpass-mono-semibold.woff2) format("woff2"),url(assets/fonts/overpass-mono-webfont/overpass-mono-semibold.woff) format("woff"),url(assets/fonts/overpass-mono-webfont/overpass-mono-semibold.ttf) format("truetype")}@font-face{font-family:overpass-mono;font-style:normal;font-weight:600;src:url(assets/fonts/overpass-mono-webfont/overpass-mono-bold.eot);src:url(assets/fonts/overpass-mono-webfont/overpass-mono-bold.eot?#iefix) format("embedded-opentype"),url(assets/fonts/overpass-mono-webfont/overpass-mono-bold.woff2) format("woff2"),url(assets/fonts/overpass-mono-webfont/overpass-mono-bold.woff) format("woff"),url(assets/fonts/overpass-mono-webfont/overpass-mono-bold.ttf) format("truetype")}[class*=pf-c-],[class*=pf-c-]:after,[class*=pf-c-]:before{padding:0;margin:0;background-color:transparent}html{font-size:unset!important}.pf-screen-reader{position:fixed;top:0;left:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}blockquote,body,dd,dl,dt,fieldset,figure,h1,h2,h3,h4,h5,h6,hr,html,iframe,legend,li,ol,p,pre,textarea,ul{padding:0;margin:0}body,html{height:100%}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:var(--pf-global--FontWeight--normal)}ul{list-style:none}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:100%;line-height:var(--pf-global--LineHeight--md);color:var(--pf-global--Color--100)}audio,embed,iframe,img,object,video{max-width:100%;height:auto}iframe{border:0}table{border-spacing:0;border-collapse:collapse}td,th{padding:0;text-align:left}*,:after,:before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15}body{font-family:var(--pf-global--FontFamily--sans-serif);font-size:var(--pf-global--FontSize--md);font-weight:var(--pf-global--FontWeight--normal);line-height:var(--pf-global--LineHeight--md);text-align:left;background-color:var(--pf-global--BackgroundColor--100)}a{font-weight:var(--pf-global--link--FontWeight);color:var(--pf-global--link--Color);text-decoration:var(--pf-global--link--TextDecoration)}a:hover{--pf-global--link--Color:var(--pf-global--link--Color--hover);--pf-global--link--TextDecoration:var(--pf-global--link--TextDecoration--hover)}a,button{cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}.pf-m-overpass-font a{font-weight:var(--pf-global--FontWeight--semi-bold)}.pf-t-dark.pf-m-transparent{background-color:transparent}.pf-t-dark.pf-m-transparent-100{background-color:rgba(3,3,3,.42)}.pf-t-dark.pf-m-transparent-200{background-color:rgba(3,3,3,.6)}.pf-t-dark.pf-m-opaque-100{background-color:#3c3f42}.pf-t-dark.pf-m-opaque-200{background-color:#151515}.pf-t-light.pf-m-transparent{background-color:transparent}.pf-t-light.pf-m-opaque-100{background-color:#fff}.pf-t-light.pf-m-opaque-200{background-color:#fafafa}.pf-t-light.pf-m-opaque-300{background-color:#f0f0f0}* .fa,* .fab,* .fal,* .far,* .fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}* .fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}* .fa-xs{font-size:.75em}* .fa-sm{font-size:.875em}* .fa-1x{font-size:1em}* .fa-2x{font-size:2em}* .fa-3x{font-size:3em}* .fa-4x{font-size:4em}* .fa-5x{font-size:5em}* .fa-6x{font-size:6em}* .fa-7x{font-size:7em}* .fa-8x{font-size:8em}* .fa-9x{font-size:9em}* .fa-10x{font-size:10em}* .fa-fw{text-align:center;width:1.25em}* .fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}* .fa-ul>li{position:relative}* .fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}* .fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}* .fa-pull-left{float:left}* .fa-pull-right{float:right}* .fa.fa-pull-left,* .fab.fa-pull-left,* .fal.fa-pull-left,* .far.fa-pull-left,* .fas.fa-pull-left{margin-right:.3em}* .fa.fa-pull-right,* .fab.fa-pull-right,* .fal.fa-pull-right,* .far.fa-pull-right,* .fas.fa-pull-right{margin-left:.3em}* .fa-spin{animation:fa-spin 2s linear infinite}* .fa-pulse{animation:fa-spin 1s steps(8) infinite}@keyframes fa-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}* .fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";transform:rotate(90deg)}* .fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";transform:rotate(180deg)}* .fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";transform:rotate(270deg)}* .fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";transform:scaleX(-1)}* .fa-flip-vertical{transform:scaleY(-1)}* .fa-flip-horizontal.fa-flip-vertical,* .fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}* .fa-flip-horizontal.fa-flip-vertical{transform:scale(-1)}* :root .fa-flip-horizontal,* :root .fa-flip-vertical,* :root .fa-rotate-90,* :root .fa-rotate-180,* :root .fa-rotate-270{filter:none}* .fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}* .fa-stack-1x,* .fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}* .fa-stack-1x{line-height:inherit}* .fa-stack-2x{font-size:2em}* .fa-inverse{color:#fff}* .fa-500px:before{content:"\f26e"}* .fa-accessible-icon:before{content:"\f368"}* .fa-accusoft:before{content:"\f369"}* .fa-acquisitions-incorporated:before{content:"\f6af"}* .fa-ad:before{content:"\f641"}* .fa-address-book:before{content:"\f2b9"}* .fa-address-card:before{content:"\f2bb"}* .fa-adjust:before{content:"\f042"}* .fa-adn:before{content:"\f170"}* .fa-adobe:before{content:"\f778"}* .fa-adversal:before{content:"\f36a"}* .fa-affiliatetheme:before{content:"\f36b"}* .fa-air-freshener:before{content:"\f5d0"}* .fa-algolia:before{content:"\f36c"}* .fa-align-center:before{content:"\f037"}* .fa-align-justify:before{content:"\f039"}* .fa-align-left:before{content:"\f036"}* .fa-align-right:before{content:"\f038"}* .fa-alipay:before{content:"\f642"}* .fa-allergies:before{content:"\f461"}* .fa-amazon:before{content:"\f270"}* .fa-amazon-pay:before{content:"\f42c"}* .fa-ambulance:before{content:"\f0f9"}* .fa-american-sign-language-interpreting:before{content:"\f2a3"}* .fa-amilia:before{content:"\f36d"}* .fa-anchor:before{content:"\f13d"}* .fa-android:before{content:"\f17b"}* .fa-angellist:before{content:"\f209"}* .fa-angle-double-down:before{content:"\f103"}* .fa-angle-double-left:before{content:"\f100"}* .fa-angle-double-right:before{content:"\f101"}* .fa-angle-double-up:before{content:"\f102"}* .fa-angle-down:before{content:"\f107"}* .fa-angle-left:before{content:"\f104"}* .fa-angle-right:before{content:"\f105"}* .fa-angle-up:before{content:"\f106"}* .fa-angry:before{content:"\f556"}* .fa-angrycreative:before{content:"\f36e"}* .fa-angular:before{content:"\f420"}* .fa-ankh:before{content:"\f644"}* .fa-app-store:before{content:"\f36f"}* .fa-app-store-ios:before{content:"\f370"}* .fa-apper:before{content:"\f371"}* .fa-apple:before{content:"\f179"}* .fa-apple-alt:before{content:"\f5d1"}* .fa-apple-pay:before{content:"\f415"}* .fa-archive:before{content:"\f187"}* .fa-archway:before{content:"\f557"}* .fa-arrow-alt-circle-down:before{content:"\f358"}* .fa-arrow-alt-circle-left:before{content:"\f359"}* .fa-arrow-alt-circle-right:before{content:"\f35a"}* .fa-arrow-alt-circle-up:before{content:"\f35b"}* .fa-arrow-circle-down:before{content:"\f0ab"}* .fa-arrow-circle-left:before{content:"\f0a8"}* .fa-arrow-circle-right:before{content:"\f0a9"}* .fa-arrow-circle-up:before{content:"\f0aa"}* .fa-arrow-down:before{content:"\f063"}* .fa-arrow-left:before{content:"\f060"}* .fa-arrow-right:before{content:"\f061"}* .fa-arrow-up:before{content:"\f062"}* .fa-arrows-alt:before{content:"\f0b2"}* .fa-arrows-alt-h:before{content:"\f337"}* .fa-arrows-alt-v:before{content:"\f338"}* .fa-artstation:before{content:"\f77a"}* .fa-assistive-listening-systems:before{content:"\f2a2"}* .fa-asterisk:before{content:"\f069"}* .fa-asymmetrik:before{content:"\f372"}* .fa-at:before{content:"\f1fa"}* .fa-atlas:before{content:"\f558"}* .fa-atlassian:before{content:"\f77b"}* .fa-atom:before{content:"\f5d2"}* .fa-audible:before{content:"\f373"}* .fa-audio-description:before{content:"\f29e"}* .fa-autoprefixer:before{content:"\f41c"}* .fa-avianex:before{content:"\f374"}* .fa-aviato:before{content:"\f421"}* .fa-award:before{content:"\f559"}* .fa-aws:before{content:"\f375"}* .fa-baby:before{content:"\f77c"}* .fa-baby-carriage:before{content:"\f77d"}* .fa-backspace:before{content:"\f55a"}* .fa-backward:before{content:"\f04a"}* .fa-balance-scale:before{content:"\f24e"}* .fa-ban:before{content:"\f05e"}* .fa-band-aid:before{content:"\f462"}* .fa-bandcamp:before{content:"\f2d5"}* .fa-barcode:before{content:"\f02a"}* .fa-bars:before{content:"\f0c9"}* .fa-baseball-ball:before{content:"\f433"}* .fa-basketball-ball:before{content:"\f434"}* .fa-bath:before{content:"\f2cd"}* .fa-battery-empty:before{content:"\f244"}* .fa-battery-full:before{content:"\f240"}* .fa-battery-half:before{content:"\f242"}* .fa-battery-quarter:before{content:"\f243"}* .fa-battery-three-quarters:before{content:"\f241"}* .fa-bed:before{content:"\f236"}* .fa-beer:before{content:"\f0fc"}* .fa-behance:before{content:"\f1b4"}* .fa-behance-square:before{content:"\f1b5"}* .fa-bell:before{content:"\f0f3"}* .fa-bell-slash:before{content:"\f1f6"}* .fa-bezier-curve:before{content:"\f55b"}* .fa-bible:before{content:"\f647"}* .fa-bicycle:before{content:"\f206"}* .fa-bimobject:before{content:"\f378"}* .fa-binoculars:before{content:"\f1e5"}* .fa-biohazard:before{content:"\f780"}* .fa-birthday-cake:before{content:"\f1fd"}* .fa-bitbucket:before{content:"\f171"}* .fa-bitcoin:before{content:"\f379"}* .fa-bity:before{content:"\f37a"}* .fa-black-tie:before{content:"\f27e"}* .fa-blackberry:before{content:"\f37b"}* .fa-blender:before{content:"\f517"}* .fa-blender-phone:before{content:"\f6b6"}* .fa-blind:before{content:"\f29d"}* .fa-blog:before{content:"\f781"}* .fa-blogger:before{content:"\f37c"}* .fa-blogger-b:before{content:"\f37d"}* .fa-bluetooth:before{content:"\f293"}* .fa-bluetooth-b:before{content:"\f294"}* .fa-bold:before{content:"\f032"}* .fa-bolt:before{content:"\f0e7"}* .fa-bomb:before{content:"\f1e2"}* .fa-bone:before{content:"\f5d7"}* .fa-bong:before{content:"\f55c"}* .fa-book:before{content:"\f02d"}* .fa-book-dead:before{content:"\f6b7"}* .fa-book-open:before{content:"\f518"}* .fa-book-reader:before{content:"\f5da"}* .fa-bookmark:before{content:"\f02e"}* .fa-bowling-ball:before{content:"\f436"}* .fa-box:before{content:"\f466"}* .fa-box-open:before{content:"\f49e"}* .fa-boxes:before{content:"\f468"}* .fa-braille:before{content:"\f2a1"}* .fa-brain:before{content:"\f5dc"}* .fa-briefcase:before{content:"\f0b1"}* .fa-briefcase-medical:before{content:"\f469"}* .fa-broadcast-tower:before{content:"\f519"}* .fa-broom:before{content:"\f51a"}* .fa-brush:before{content:"\f55d"}* .fa-btc:before{content:"\f15a"}* .fa-bug:before{content:"\f188"}* .fa-building:before{content:"\f1ad"}* .fa-bullhorn:before{content:"\f0a1"}* .fa-bullseye:before{content:"\f140"}* .fa-burn:before{content:"\f46a"}* .fa-buromobelexperte:before{content:"\f37f"}* .fa-bus:before{content:"\f207"}* .fa-bus-alt:before{content:"\f55e"}* .fa-business-time:before{content:"\f64a"}* .fa-buysellads:before{content:"\f20d"}* .fa-calculator:before{content:"\f1ec"}* .fa-calendar:before{content:"\f133"}* .fa-calendar-alt:before{content:"\f073"}* .fa-calendar-check:before{content:"\f274"}* .fa-calendar-day:before{content:"\f783"}* .fa-calendar-minus:before{content:"\f272"}* .fa-calendar-plus:before{content:"\f271"}* .fa-calendar-times:before{content:"\f273"}* .fa-calendar-week:before{content:"\f784"}* .fa-camera:before{content:"\f030"}* .fa-camera-retro:before{content:"\f083"}* .fa-campground:before{content:"\f6bb"}* .fa-canadian-maple-leaf:before{content:"\f785"}* .fa-candy-cane:before{content:"\f786"}* .fa-cannabis:before{content:"\f55f"}* .fa-capsules:before{content:"\f46b"}* .fa-car:before{content:"\f1b9"}* .fa-car-alt:before{content:"\f5de"}* .fa-car-battery:before{content:"\f5df"}* .fa-car-crash:before{content:"\f5e1"}* .fa-car-side:before{content:"\f5e4"}* .fa-caret-down:before{content:"\f0d7"}* .fa-caret-left:before{content:"\f0d9"}* .fa-caret-right:before{content:"\f0da"}* .fa-caret-square-down:before{content:"\f150"}* .fa-caret-square-left:before{content:"\f191"}* .fa-caret-square-right:before{content:"\f152"}* .fa-caret-square-up:before{content:"\f151"}* .fa-caret-up:before{content:"\f0d8"}* .fa-carrot:before{content:"\f787"}* .fa-cart-arrow-down:before{content:"\f218"}* .fa-cart-plus:before{content:"\f217"}* .fa-cash-register:before{content:"\f788"}* .fa-cat:before{content:"\f6be"}* .fa-cc-amazon-pay:before{content:"\f42d"}* .fa-cc-amex:before{content:"\f1f3"}* .fa-cc-apple-pay:before{content:"\f416"}* .fa-cc-diners-club:before{content:"\f24c"}* .fa-cc-discover:before{content:"\f1f2"}* .fa-cc-jcb:before{content:"\f24b"}* .fa-cc-mastercard:before{content:"\f1f1"}* .fa-cc-paypal:before{content:"\f1f4"}* .fa-cc-stripe:before{content:"\f1f5"}* .fa-cc-visa:before{content:"\f1f0"}* .fa-centercode:before{content:"\f380"}* .fa-centos:before{content:"\f789"}* .fa-certificate:before{content:"\f0a3"}* .fa-chair:before{content:"\f6c0"}* .fa-chalkboard:before{content:"\f51b"}* .fa-chalkboard-teacher:before{content:"\f51c"}* .fa-charging-station:before{content:"\f5e7"}* .fa-chart-area:before{content:"\f1fe"}* .fa-chart-bar:before{content:"\f080"}* .fa-chart-line:before{content:"\f201"}* .fa-chart-pie:before{content:"\f200"}* .fa-check:before{content:"\f00c"}* .fa-check-circle:before{content:"\f058"}* .fa-check-double:before{content:"\f560"}* .fa-check-square:before{content:"\f14a"}* .fa-chess:before{content:"\f439"}* .fa-chess-bishop:before{content:"\f43a"}* .fa-chess-board:before{content:"\f43c"}* .fa-chess-king:before{content:"\f43f"}* .fa-chess-knight:before{content:"\f441"}* .fa-chess-pawn:before{content:"\f443"}* .fa-chess-queen:before{content:"\f445"}* .fa-chess-rook:before{content:"\f447"}* .fa-chevron-circle-down:before{content:"\f13a"}* .fa-chevron-circle-left:before{content:"\f137"}* .fa-chevron-circle-right:before{content:"\f138"}* .fa-chevron-circle-up:before{content:"\f139"}* .fa-chevron-down:before{content:"\f078"}* .fa-chevron-left:before{content:"\f053"}* .fa-chevron-right:before{content:"\f054"}* .fa-chevron-up:before{content:"\f077"}* .fa-child:before{content:"\f1ae"}* .fa-chrome:before{content:"\f268"}* .fa-church:before{content:"\f51d"}* .fa-circle:before{content:"\f111"}* .fa-circle-notch:before{content:"\f1ce"}* .fa-city:before{content:"\f64f"}* .fa-clipboard:before{content:"\f328"}* .fa-clipboard-check:before{content:"\f46c"}* .fa-clipboard-list:before{content:"\f46d"}* .fa-clock:before{content:"\f017"}* .fa-clone:before{content:"\f24d"}* .fa-closed-captioning:before{content:"\f20a"}* .fa-cloud:before{content:"\f0c2"}* .fa-cloud-download-alt:before{content:"\f381"}* .fa-cloud-meatball:before{content:"\f73b"}* .fa-cloud-moon:before{content:"\f6c3"}* .fa-cloud-moon-rain:before{content:"\f73c"}* .fa-cloud-rain:before{content:"\f73d"}* .fa-cloud-showers-heavy:before{content:"\f740"}* .fa-cloud-sun:before{content:"\f6c4"}* .fa-cloud-sun-rain:before{content:"\f743"}* .fa-cloud-upload-alt:before{content:"\f382"}* .fa-cloudscale:before{content:"\f383"}* .fa-cloudsmith:before{content:"\f384"}* .fa-cloudversify:before{content:"\f385"}* .fa-cocktail:before{content:"\f561"}* .fa-code:before{content:"\f121"}* .fa-code-branch:before{content:"\f126"}* .fa-codepen:before{content:"\f1cb"}* .fa-codiepie:before{content:"\f284"}* .fa-coffee:before{content:"\f0f4"}* .fa-cog:before{content:"\f013"}* .fa-cogs:before{content:"\f085"}* .fa-coins:before{content:"\f51e"}* .fa-columns:before{content:"\f0db"}* .fa-comment:before{content:"\f075"}* .fa-comment-alt:before{content:"\f27a"}* .fa-comment-dollar:before{content:"\f651"}* .fa-comment-dots:before{content:"\f4ad"}* .fa-comment-slash:before{content:"\f4b3"}* .fa-comments:before{content:"\f086"}* .fa-comments-dollar:before{content:"\f653"}* .fa-compact-disc:before{content:"\f51f"}* .fa-compass:before{content:"\f14e"}* .fa-compress:before{content:"\f066"}* .fa-compress-arrows-alt:before{content:"\f78c"}* .fa-concierge-bell:before{content:"\f562"}* .fa-confluence:before{content:"\f78d"}* .fa-connectdevelop:before{content:"\f20e"}* .fa-contao:before{content:"\f26d"}* .fa-cookie:before{content:"\f563"}* .fa-cookie-bite:before{content:"\f564"}* .fa-copy:before{content:"\f0c5"}* .fa-copyright:before{content:"\f1f9"}* .fa-couch:before{content:"\f4b8"}* .fa-cpanel:before{content:"\f388"}* .fa-creative-commons:before{content:"\f25e"}* .fa-creative-commons-by:before{content:"\f4e7"}* .fa-creative-commons-nc:before{content:"\f4e8"}* .fa-creative-commons-nc-eu:before{content:"\f4e9"}* .fa-creative-commons-nc-jp:before{content:"\f4ea"}* .fa-creative-commons-nd:before{content:"\f4eb"}* .fa-creative-commons-pd:before{content:"\f4ec"}* .fa-creative-commons-pd-alt:before{content:"\f4ed"}* .fa-creative-commons-remix:before{content:"\f4ee"}* .fa-creative-commons-sa:before{content:"\f4ef"}* .fa-creative-commons-sampling:before{content:"\f4f0"}* .fa-creative-commons-sampling-plus:before{content:"\f4f1"}* .fa-creative-commons-share:before{content:"\f4f2"}* .fa-creative-commons-zero:before{content:"\f4f3"}* .fa-credit-card:before{content:"\f09d"}* .fa-critical-role:before{content:"\f6c9"}* .fa-crop:before{content:"\f125"}* .fa-crop-alt:before{content:"\f565"}* .fa-cross:before{content:"\f654"}* .fa-crosshairs:before{content:"\f05b"}* .fa-crow:before{content:"\f520"}* .fa-crown:before{content:"\f521"}* .fa-css3:before{content:"\f13c"}* .fa-css3-alt:before{content:"\f38b"}* .fa-cube:before{content:"\f1b2"}* .fa-cubes:before{content:"\f1b3"}* .fa-cut:before{content:"\f0c4"}* .fa-cuttlefish:before{content:"\f38c"}* .fa-d-and-d:before{content:"\f38d"}* .fa-d-and-d-beyond:before{content:"\f6ca"}* .fa-dashcube:before{content:"\f210"}* .fa-database:before{content:"\f1c0"}* .fa-deaf:before{content:"\f2a4"}* .fa-delicious:before{content:"\f1a5"}* .fa-democrat:before{content:"\f747"}* .fa-deploydog:before{content:"\f38e"}* .fa-deskpro:before{content:"\f38f"}* .fa-desktop:before{content:"\f108"}* .fa-dev:before{content:"\f6cc"}* .fa-deviantart:before{content:"\f1bd"}* .fa-dharmachakra:before{content:"\f655"}* .fa-dhl:before{content:"\f790"}* .fa-diagnoses:before{content:"\f470"}* .fa-diaspora:before{content:"\f791"}* .fa-dice:before{content:"\f522"}* .fa-dice-d20:before{content:"\f6cf"}* .fa-dice-d6:before{content:"\f6d1"}* .fa-dice-five:before{content:"\f523"}* .fa-dice-four:before{content:"\f524"}* .fa-dice-one:before{content:"\f525"}* .fa-dice-six:before{content:"\f526"}* .fa-dice-three:before{content:"\f527"}* .fa-dice-two:before{content:"\f528"}* .fa-digg:before{content:"\f1a6"}* .fa-digital-ocean:before{content:"\f391"}* .fa-digital-tachograph:before{content:"\f566"}* .fa-directions:before{content:"\f5eb"}* .fa-discord:before{content:"\f392"}* .fa-discourse:before{content:"\f393"}* .fa-divide:before{content:"\f529"}* .fa-dizzy:before{content:"\f567"}* .fa-dna:before{content:"\f471"}* .fa-dochub:before{content:"\f394"}* .fa-docker:before{content:"\f395"}* .fa-dog:before{content:"\f6d3"}* .fa-dollar-sign:before{content:"\f155"}* .fa-dolly:before{content:"\f472"}* .fa-dolly-flatbed:before{content:"\f474"}* .fa-donate:before{content:"\f4b9"}* .fa-door-closed:before{content:"\f52a"}* .fa-door-open:before{content:"\f52b"}* .fa-dot-circle:before{content:"\f192"}* .fa-dove:before{content:"\f4ba"}* .fa-download:before{content:"\f019"}* .fa-draft2digital:before{content:"\f396"}* .fa-drafting-compass:before{content:"\f568"}* .fa-dragon:before{content:"\f6d5"}* .fa-draw-polygon:before{content:"\f5ee"}* .fa-dribbble:before{content:"\f17d"}* .fa-dribbble-square:before{content:"\f397"}* .fa-dropbox:before{content:"\f16b"}* .fa-drum:before{content:"\f569"}* .fa-drum-steelpan:before{content:"\f56a"}* .fa-drumstick-bite:before{content:"\f6d7"}* .fa-drupal:before{content:"\f1a9"}* .fa-dumbbell:before{content:"\f44b"}* .fa-dumpster:before{content:"\f793"}* .fa-dumpster-fire:before{content:"\f794"}* .fa-dungeon:before{content:"\f6d9"}* .fa-dyalog:before{content:"\f399"}* .fa-earlybirds:before{content:"\f39a"}* .fa-ebay:before{content:"\f4f4"}* .fa-edge:before{content:"\f282"}* .fa-edit:before{content:"\f044"}* .fa-eject:before{content:"\f052"}* .fa-elementor:before{content:"\f430"}* .fa-ellipsis-h:before{content:"\f141"}* .fa-ellipsis-v:before{content:"\f142"}* .fa-ello:before{content:"\f5f1"}* .fa-ember:before{content:"\f423"}* .fa-empire:before{content:"\f1d1"}* .fa-envelope:before{content:"\f0e0"}* .fa-envelope-open:before{content:"\f2b6"}* .fa-envelope-open-text:before{content:"\f658"}* .fa-envelope-square:before{content:"\f199"}* .fa-envira:before{content:"\f299"}* .fa-equals:before{content:"\f52c"}* .fa-eraser:before{content:"\f12d"}* .fa-erlang:before{content:"\f39d"}* .fa-ethereum:before{content:"\f42e"}* .fa-ethernet:before{content:"\f796"}* .fa-etsy:before{content:"\f2d7"}* .fa-euro-sign:before{content:"\f153"}* .fa-exchange-alt:before{content:"\f362"}* .fa-exclamation:before{content:"\f12a"}* .fa-exclamation-circle:before{content:"\f06a"}* .fa-exclamation-triangle:before{content:"\f071"}* .fa-expand:before{content:"\f065"}* .fa-expand-arrows-alt:before{content:"\f31e"}* .fa-expeditedssl:before{content:"\f23e"}* .fa-external-link-alt:before{content:"\f35d"}* .fa-external-link-square-alt:before{content:"\f360"}* .fa-eye:before{content:"\f06e"}* .fa-eye-dropper:before{content:"\f1fb"}* .fa-eye-slash:before{content:"\f070"}* .fa-facebook:before{content:"\f09a"}* .fa-facebook-f:before{content:"\f39e"}* .fa-facebook-messenger:before{content:"\f39f"}* .fa-facebook-square:before{content:"\f082"}* .fa-fantasy-flight-games:before{content:"\f6dc"}* .fa-fast-backward:before{content:"\f049"}* .fa-fast-forward:before{content:"\f050"}* .fa-fax:before{content:"\f1ac"}* .fa-feather:before{content:"\f52d"}* .fa-feather-alt:before{content:"\f56b"}* .fa-fedex:before{content:"\f797"}* .fa-fedora:before{content:"\f798"}* .fa-female:before{content:"\f182"}* .fa-fighter-jet:before{content:"\f0fb"}* .fa-figma:before{content:"\f799"}* .fa-file:before{content:"\f15b"}* .fa-file-alt:before{content:"\f15c"}* .fa-file-archive:before{content:"\f1c6"}* .fa-file-audio:before{content:"\f1c7"}* .fa-file-code:before{content:"\f1c9"}* .fa-file-contract:before{content:"\f56c"}* .fa-file-csv:before{content:"\f6dd"}* .fa-file-download:before{content:"\f56d"}* .fa-file-excel:before{content:"\f1c3"}* .fa-file-export:before{content:"\f56e"}* .fa-file-image:before{content:"\f1c5"}* .fa-file-import:before{content:"\f56f"}* .fa-file-invoice:before{content:"\f570"}* .fa-file-invoice-dollar:before{content:"\f571"}* .fa-file-medical:before{content:"\f477"}* .fa-file-medical-alt:before{content:"\f478"}* .fa-file-pdf:before{content:"\f1c1"}* .fa-file-powerpoint:before{content:"\f1c4"}* .fa-file-prescription:before{content:"\f572"}* .fa-file-signature:before{content:"\f573"}* .fa-file-upload:before{content:"\f574"}* .fa-file-video:before{content:"\f1c8"}* .fa-file-word:before{content:"\f1c2"}* .fa-fill:before{content:"\f575"}* .fa-fill-drip:before{content:"\f576"}* .fa-film:before{content:"\f008"}* .fa-filter:before{content:"\f0b0"}* .fa-fingerprint:before{content:"\f577"}* .fa-fire:before{content:"\f06d"}* .fa-fire-alt:before{content:"\f7e4"}* .fa-fire-extinguisher:before{content:"\f134"}* .fa-firefox:before{content:"\f269"}* .fa-first-aid:before{content:"\f479"}* .fa-first-order:before{content:"\f2b0"}* .fa-first-order-alt:before{content:"\f50a"}* .fa-firstdraft:before{content:"\f3a1"}* .fa-fish:before{content:"\f578"}* .fa-fist-raised:before{content:"\f6de"}* .fa-flag:before{content:"\f024"}* .fa-flag-checkered:before{content:"\f11e"}* .fa-flag-usa:before{content:"\f74d"}* .fa-flask:before{content:"\f0c3"}* .fa-flickr:before{content:"\f16e"}* .fa-flipboard:before{content:"\f44d"}* .fa-flushed:before{content:"\f579"}* .fa-fly:before{content:"\f417"}* .fa-folder:before{content:"\f07b"}* .fa-folder-minus:before{content:"\f65d"}* .fa-folder-open:before{content:"\f07c"}* .fa-folder-plus:before{content:"\f65e"}* .fa-font:before{content:"\f031"}* .fa-font-awesome:before{content:"\f2b4"}* .fa-font-awesome-alt:before{content:"\f35c"}* .fa-font-awesome-flag:before{content:"\f425"}* .fa-font-awesome-logo-full:before{content:"\f4e6"}* .fa-fonticons:before{content:"\f280"}* .fa-fonticons-fi:before{content:"\f3a2"}* .fa-football-ball:before{content:"\f44e"}* .fa-fort-awesome:before{content:"\f286"}* .fa-fort-awesome-alt:before{content:"\f3a3"}* .fa-forumbee:before{content:"\f211"}* .fa-forward:before{content:"\f04e"}* .fa-foursquare:before{content:"\f180"}* .fa-free-code-camp:before{content:"\f2c5"}* .fa-freebsd:before{content:"\f3a4"}* .fa-frog:before{content:"\f52e"}* .fa-frown:before{content:"\f119"}* .fa-frown-open:before{content:"\f57a"}* .fa-fulcrum:before{content:"\f50b"}* .fa-funnel-dollar:before{content:"\f662"}* .fa-futbol:before{content:"\f1e3"}* .fa-galactic-republic:before{content:"\f50c"}* .fa-galactic-senate:before{content:"\f50d"}* .fa-gamepad:before{content:"\f11b"}* .fa-gas-pump:before{content:"\f52f"}* .fa-gavel:before{content:"\f0e3"}* .fa-gem:before{content:"\f3a5"}* .fa-genderless:before{content:"\f22d"}* .fa-get-pocket:before{content:"\f265"}* .fa-gg:before{content:"\f260"}* .fa-gg-circle:before{content:"\f261"}* .fa-ghost:before{content:"\f6e2"}* .fa-gift:before{content:"\f06b"}* .fa-gifts:before{content:"\f79c"}* .fa-git:before{content:"\f1d3"}* .fa-git-square:before{content:"\f1d2"}* .fa-github:before{content:"\f09b"}* .fa-github-alt:before{content:"\f113"}* .fa-github-square:before{content:"\f092"}* .fa-gitkraken:before{content:"\f3a6"}* .fa-gitlab:before{content:"\f296"}* .fa-gitter:before{content:"\f426"}* .fa-glass-cheers:before{content:"\f79f"}* .fa-glass-martini:before{content:"\f000"}* .fa-glass-martini-alt:before{content:"\f57b"}* .fa-glass-whiskey:before{content:"\f7a0"}* .fa-glasses:before{content:"\f530"}* .fa-glide:before{content:"\f2a5"}* .fa-glide-g:before{content:"\f2a6"}* .fa-globe:before{content:"\f0ac"}* .fa-globe-africa:before{content:"\f57c"}* .fa-globe-americas:before{content:"\f57d"}* .fa-globe-asia:before{content:"\f57e"}* .fa-globe-europe:before{content:"\f7a2"}* .fa-gofore:before{content:"\f3a7"}* .fa-golf-ball:before{content:"\f450"}* .fa-goodreads:before{content:"\f3a8"}* .fa-goodreads-g:before{content:"\f3a9"}* .fa-google:before{content:"\f1a0"}* .fa-google-drive:before{content:"\f3aa"}* .fa-google-play:before{content:"\f3ab"}* .fa-google-plus:before{content:"\f2b3"}* .fa-google-plus-g:before{content:"\f0d5"}* .fa-google-plus-square:before{content:"\f0d4"}* .fa-google-wallet:before{content:"\f1ee"}* .fa-gopuram:before{content:"\f664"}* .fa-graduation-cap:before{content:"\f19d"}* .fa-gratipay:before{content:"\f184"}* .fa-grav:before{content:"\f2d6"}* .fa-greater-than:before{content:"\f531"}* .fa-greater-than-equal:before{content:"\f532"}* .fa-grimace:before{content:"\f57f"}* .fa-grin:before{content:"\f580"}* .fa-grin-alt:before{content:"\f581"}* .fa-grin-beam:before{content:"\f582"}* .fa-grin-beam-sweat:before{content:"\f583"}* .fa-grin-hearts:before{content:"\f584"}* .fa-grin-squint:before{content:"\f585"}* .fa-grin-squint-tears:before{content:"\f586"}* .fa-grin-stars:before{content:"\f587"}* .fa-grin-tears:before{content:"\f588"}* .fa-grin-tongue:before{content:"\f589"}* .fa-grin-tongue-squint:before{content:"\f58a"}* .fa-grin-tongue-wink:before{content:"\f58b"}* .fa-grin-wink:before{content:"\f58c"}* .fa-grip-horizontal:before{content:"\f58d"}* .fa-grip-lines:before{content:"\f7a4"}* .fa-grip-lines-vertical:before{content:"\f7a5"}* .fa-grip-vertical:before{content:"\f58e"}* .fa-gripfire:before{content:"\f3ac"}* .fa-grunt:before{content:"\f3ad"}* .fa-guitar:before{content:"\f7a6"}* .fa-gulp:before{content:"\f3ae"}* .fa-h-square:before{content:"\f0fd"}* .fa-hacker-news:before{content:"\f1d4"}* .fa-hacker-news-square:before{content:"\f3af"}* .fa-hackerrank:before{content:"\f5f7"}* .fa-hammer:before{content:"\f6e3"}* .fa-hamsa:before{content:"\f665"}* .fa-hand-holding:before{content:"\f4bd"}* .fa-hand-holding-heart:before{content:"\f4be"}* .fa-hand-holding-usd:before{content:"\f4c0"}* .fa-hand-lizard:before{content:"\f258"}* .fa-hand-paper:before{content:"\f256"}* .fa-hand-peace:before{content:"\f25b"}* .fa-hand-point-down:before{content:"\f0a7"}* .fa-hand-point-left:before{content:"\f0a5"}* .fa-hand-point-right:before{content:"\f0a4"}* .fa-hand-point-up:before{content:"\f0a6"}* .fa-hand-pointer:before{content:"\f25a"}* .fa-hand-rock:before{content:"\f255"}* .fa-hand-scissors:before{content:"\f257"}* .fa-hand-spock:before{content:"\f259"}* .fa-hands:before{content:"\f4c2"}* .fa-hands-helping:before{content:"\f4c4"}* .fa-handshake:before{content:"\f2b5"}* .fa-hanukiah:before{content:"\f6e6"}* .fa-hashtag:before{content:"\f292"}* .fa-hat-wizard:before{content:"\f6e8"}* .fa-haykal:before{content:"\f666"}* .fa-hdd:before{content:"\f0a0"}* .fa-heading:before{content:"\f1dc"}* .fa-headphones:before{content:"\f025"}* .fa-headphones-alt:before{content:"\f58f"}* .fa-headset:before{content:"\f590"}* .fa-heart:before{content:"\f004"}* .fa-heart-broken:before{content:"\f7a9"}* .fa-heartbeat:before{content:"\f21e"}* .fa-helicopter:before{content:"\f533"}* .fa-highlighter:before{content:"\f591"}* .fa-hiking:before{content:"\f6ec"}* .fa-hippo:before{content:"\f6ed"}* .fa-hips:before{content:"\f452"}* .fa-hire-a-helper:before{content:"\f3b0"}* .fa-history:before{content:"\f1da"}* .fa-hockey-puck:before{content:"\f453"}* .fa-holly-berry:before{content:"\f7aa"}* .fa-home:before{content:"\f015"}* .fa-hooli:before{content:"\f427"}* .fa-hornbill:before{content:"\f592"}* .fa-horse:before{content:"\f6f0"}* .fa-horse-head:before{content:"\f7ab"}* .fa-hospital:before{content:"\f0f8"}* .fa-hospital-alt:before{content:"\f47d"}* .fa-hospital-symbol:before{content:"\f47e"}* .fa-hot-tub:before{content:"\f593"}* .fa-hotel:before{content:"\f594"}* .fa-hotjar:before{content:"\f3b1"}* .fa-hourglass:before{content:"\f254"}* .fa-hourglass-end:before{content:"\f253"}* .fa-hourglass-half:before{content:"\f252"}* .fa-hourglass-start:before{content:"\f251"}* .fa-house-damage:before{content:"\f6f1"}* .fa-houzz:before{content:"\f27c"}* .fa-hryvnia:before{content:"\f6f2"}* .fa-html5:before{content:"\f13b"}* .fa-hubspot:before{content:"\f3b2"}* .fa-i-cursor:before{content:"\f246"}* .fa-icicles:before{content:"\f7ad"}* .fa-id-badge:before{content:"\f2c1"}* .fa-id-card:before{content:"\f2c2"}* .fa-id-card-alt:before{content:"\f47f"}* .fa-igloo:before{content:"\f7ae"}* .fa-image:before{content:"\f03e"}* .fa-images:before{content:"\f302"}* .fa-imdb:before{content:"\f2d8"}* .fa-inbox:before{content:"\f01c"}* .fa-indent:before{content:"\f03c"}* .fa-industry:before{content:"\f275"}* .fa-infinity:before{content:"\f534"}* .fa-info:before{content:"\f129"}* .fa-info-circle:before{content:"\f05a"}* .fa-instagram:before{content:"\f16d"}* .fa-intercom:before{content:"\f7af"}* .fa-internet-explorer:before{content:"\f26b"}* .fa-invision:before{content:"\f7b0"}* .fa-ioxhost:before{content:"\f208"}* .fa-italic:before{content:"\f033"}* .fa-itunes:before{content:"\f3b4"}* .fa-itunes-note:before{content:"\f3b5"}* .fa-java:before{content:"\f4e4"}* .fa-jedi:before{content:"\f669"}* .fa-jedi-order:before{content:"\f50e"}* .fa-jenkins:before{content:"\f3b6"}* .fa-jira:before{content:"\f7b1"}* .fa-joget:before{content:"\f3b7"}* .fa-joint:before{content:"\f595"}* .fa-joomla:before{content:"\f1aa"}* .fa-journal-whills:before{content:"\f66a"}* .fa-js:before{content:"\f3b8"}* .fa-js-square:before{content:"\f3b9"}* .fa-jsfiddle:before{content:"\f1cc"}* .fa-kaaba:before{content:"\f66b"}* .fa-kaggle:before{content:"\f5fa"}* .fa-key:before{content:"\f084"}* .fa-keybase:before{content:"\f4f5"}* .fa-keyboard:before{content:"\f11c"}* .fa-keycdn:before{content:"\f3ba"}* .fa-khanda:before{content:"\f66d"}* .fa-kickstarter:before{content:"\f3bb"}* .fa-kickstarter-k:before{content:"\f3bc"}* .fa-kiss:before{content:"\f596"}* .fa-kiss-beam:before{content:"\f597"}* .fa-kiss-wink-heart:before{content:"\f598"}* .fa-kiwi-bird:before{content:"\f535"}* .fa-korvue:before{content:"\f42f"}* .fa-landmark:before{content:"\f66f"}* .fa-language:before{content:"\f1ab"}* .fa-laptop:before{content:"\f109"}* .fa-laptop-code:before{content:"\f5fc"}* .fa-laravel:before{content:"\f3bd"}* .fa-lastfm:before{content:"\f202"}* .fa-lastfm-square:before{content:"\f203"}* .fa-laugh:before{content:"\f599"}* .fa-laugh-beam:before{content:"\f59a"}* .fa-laugh-squint:before{content:"\f59b"}* .fa-laugh-wink:before{content:"\f59c"}* .fa-layer-group:before{content:"\f5fd"}* .fa-leaf:before{content:"\f06c"}* .fa-leanpub:before{content:"\f212"}* .fa-lemon:before{content:"\f094"}* .fa-less:before{content:"\f41d"}* .fa-less-than:before{content:"\f536"}* .fa-less-than-equal:before{content:"\f537"}* .fa-level-down-alt:before{content:"\f3be"}* .fa-level-up-alt:before{content:"\f3bf"}* .fa-life-ring:before{content:"\f1cd"}* .fa-lightbulb:before{content:"\f0eb"}* .fa-line:before{content:"\f3c0"}* .fa-link:before{content:"\f0c1"}* .fa-linkedin:before{content:"\f08c"}* .fa-linkedin-in:before{content:"\f0e1"}* .fa-linode:before{content:"\f2b8"}* .fa-linux:before{content:"\f17c"}* .fa-lira-sign:before{content:"\f195"}* .fa-list:before{content:"\f03a"}* .fa-list-alt:before{content:"\f022"}* .fa-list-ol:before{content:"\f0cb"}* .fa-list-ul:before{content:"\f0ca"}* .fa-location-arrow:before{content:"\f124"}* .fa-lock:before{content:"\f023"}* .fa-lock-open:before{content:"\f3c1"}* .fa-long-arrow-alt-down:before{content:"\f309"}* .fa-long-arrow-alt-left:before{content:"\f30a"}* .fa-long-arrow-alt-right:before{content:"\f30b"}* .fa-long-arrow-alt-up:before{content:"\f30c"}* .fa-low-vision:before{content:"\f2a8"}* .fa-luggage-cart:before{content:"\f59d"}* .fa-lyft:before{content:"\f3c3"}* .fa-magento:before{content:"\f3c4"}* .fa-magic:before{content:"\f0d0"}* .fa-magnet:before{content:"\f076"}* .fa-mail-bulk:before{content:"\f674"}* .fa-mailchimp:before{content:"\f59e"}* .fa-male:before{content:"\f183"}* .fa-mandalorian:before{content:"\f50f"}* .fa-map:before{content:"\f279"}* .fa-map-marked:before{content:"\f59f"}* .fa-map-marked-alt:before{content:"\f5a0"}* .fa-map-marker:before{content:"\f041"}* .fa-map-marker-alt:before{content:"\f3c5"}* .fa-map-pin:before{content:"\f276"}* .fa-map-signs:before{content:"\f277"}* .fa-markdown:before{content:"\f60f"}* .fa-marker:before{content:"\f5a1"}* .fa-mars:before{content:"\f222"}* .fa-mars-double:before{content:"\f227"}* .fa-mars-stroke:before{content:"\f229"}* .fa-mars-stroke-h:before{content:"\f22b"}* .fa-mars-stroke-v:before{content:"\f22a"}* .fa-mask:before{content:"\f6fa"}* .fa-mastodon:before{content:"\f4f6"}* .fa-maxcdn:before{content:"\f136"}* .fa-medal:before{content:"\f5a2"}* .fa-medapps:before{content:"\f3c6"}* .fa-medium:before{content:"\f23a"}* .fa-medium-m:before{content:"\f3c7"}* .fa-medkit:before{content:"\f0fa"}* .fa-medrt:before{content:"\f3c8"}* .fa-meetup:before{content:"\f2e0"}* .fa-megaport:before{content:"\f5a3"}* .fa-meh:before{content:"\f11a"}* .fa-meh-blank:before{content:"\f5a4"}* .fa-meh-rolling-eyes:before{content:"\f5a5"}* .fa-memory:before{content:"\f538"}* .fa-mendeley:before{content:"\f7b3"}* .fa-menorah:before{content:"\f676"}* .fa-mercury:before{content:"\f223"}* .fa-meteor:before{content:"\f753"}* .fa-microchip:before{content:"\f2db"}* .fa-microphone:before{content:"\f130"}* .fa-microphone-alt:before{content:"\f3c9"}* .fa-microphone-alt-slash:before{content:"\f539"}* .fa-microphone-slash:before{content:"\f131"}* .fa-microscope:before{content:"\f610"}* .fa-microsoft:before{content:"\f3ca"}* .fa-minus:before{content:"\f068"}* .fa-minus-circle:before{content:"\f056"}* .fa-minus-square:before{content:"\f146"}* .fa-mitten:before{content:"\f7b5"}* .fa-mix:before{content:"\f3cb"}* .fa-mixcloud:before{content:"\f289"}* .fa-mizuni:before{content:"\f3cc"}* .fa-mobile:before{content:"\f10b"}* .fa-mobile-alt:before{content:"\f3cd"}* .fa-modx:before{content:"\f285"}* .fa-monero:before{content:"\f3d0"}* .fa-money-bill:before{content:"\f0d6"}* .fa-money-bill-alt:before{content:"\f3d1"}* .fa-money-bill-wave:before{content:"\f53a"}* .fa-money-bill-wave-alt:before{content:"\f53b"}* .fa-money-check:before{content:"\f53c"}* .fa-money-check-alt:before{content:"\f53d"}* .fa-monument:before{content:"\f5a6"}* .fa-moon:before{content:"\f186"}* .fa-mortar-pestle:before{content:"\f5a7"}* .fa-mosque:before{content:"\f678"}* .fa-motorcycle:before{content:"\f21c"}* .fa-mountain:before{content:"\f6fc"}* .fa-mouse-pointer:before{content:"\f245"}* .fa-mug-hot:before{content:"\f7b6"}* .fa-music:before{content:"\f001"}* .fa-napster:before{content:"\f3d2"}* .fa-neos:before{content:"\f612"}* .fa-network-wired:before{content:"\f6ff"}* .fa-neuter:before{content:"\f22c"}* .fa-newspaper:before{content:"\f1ea"}* .fa-nimblr:before{content:"\f5a8"}* .fa-nintendo-switch:before{content:"\f418"}* .fa-node:before{content:"\f419"}* .fa-node-js:before{content:"\f3d3"}* .fa-not-equal:before{content:"\f53e"}* .fa-notes-medical:before{content:"\f481"}* .fa-npm:before{content:"\f3d4"}* .fa-ns8:before{content:"\f3d5"}* .fa-nutritionix:before{content:"\f3d6"}* .fa-object-group:before{content:"\f247"}* .fa-object-ungroup:before{content:"\f248"}* .fa-odnoklassniki:before{content:"\f263"}* .fa-odnoklassniki-square:before{content:"\f264"}* .fa-oil-can:before{content:"\f613"}* .fa-old-republic:before{content:"\f510"}* .fa-om:before{content:"\f679"}* .fa-opencart:before{content:"\f23d"}* .fa-openid:before{content:"\f19b"}* .fa-opera:before{content:"\f26a"}* .fa-optin-monster:before{content:"\f23c"}* .fa-osi:before{content:"\f41a"}* .fa-otter:before{content:"\f700"}* .fa-outdent:before{content:"\f03b"}* .fa-page4:before{content:"\f3d7"}* .fa-pagelines:before{content:"\f18c"}* .fa-paint-brush:before{content:"\f1fc"}* .fa-paint-roller:before{content:"\f5aa"}* .fa-palette:before{content:"\f53f"}* .fa-palfed:before{content:"\f3d8"}* .fa-pallet:before{content:"\f482"}* .fa-paper-plane:before{content:"\f1d8"}* .fa-paperclip:before{content:"\f0c6"}* .fa-parachute-box:before{content:"\f4cd"}* .fa-paragraph:before{content:"\f1dd"}* .fa-parking:before{content:"\f540"}* .fa-passport:before{content:"\f5ab"}* .fa-pastafarianism:before{content:"\f67b"}* .fa-paste:before{content:"\f0ea"}* .fa-patreon:before{content:"\f3d9"}* .fa-pause:before{content:"\f04c"}* .fa-pause-circle:before{content:"\f28b"}* .fa-paw:before{content:"\f1b0"}* .fa-paypal:before{content:"\f1ed"}* .fa-peace:before{content:"\f67c"}* .fa-pen:before{content:"\f304"}* .fa-pen-alt:before{content:"\f305"}* .fa-pen-fancy:before{content:"\f5ac"}* .fa-pen-nib:before{content:"\f5ad"}* .fa-pen-square:before{content:"\f14b"}* .fa-pencil-alt:before{content:"\f303"}* .fa-pencil-ruler:before{content:"\f5ae"}* .fa-penny-arcade:before{content:"\f704"}* .fa-people-carry:before{content:"\f4ce"}* .fa-percent:before{content:"\f295"}* .fa-percentage:before{content:"\f541"}* .fa-periscope:before{content:"\f3da"}* .fa-person-booth:before{content:"\f756"}* .fa-phabricator:before{content:"\f3db"}* .fa-phoenix-framework:before{content:"\f3dc"}* .fa-phoenix-squadron:before{content:"\f511"}* .fa-phone:before{content:"\f095"}* .fa-phone-slash:before{content:"\f3dd"}* .fa-phone-square:before{content:"\f098"}* .fa-phone-volume:before{content:"\f2a0"}* .fa-php:before{content:"\f457"}* .fa-pied-piper:before{content:"\f2ae"}* .fa-pied-piper-alt:before{content:"\f1a8"}* .fa-pied-piper-hat:before{content:"\f4e5"}* .fa-pied-piper-pp:before{content:"\f1a7"}* .fa-piggy-bank:before{content:"\f4d3"}* .fa-pills:before{content:"\f484"}* .fa-pinterest:before{content:"\f0d2"}* .fa-pinterest-p:before{content:"\f231"}* .fa-pinterest-square:before{content:"\f0d3"}* .fa-place-of-worship:before{content:"\f67f"}* .fa-plane:before{content:"\f072"}* .fa-plane-arrival:before{content:"\f5af"}* .fa-plane-departure:before{content:"\f5b0"}* .fa-play:before{content:"\f04b"}* .fa-play-circle:before{content:"\f144"}* .fa-playstation:before{content:"\f3df"}* .fa-plug:before{content:"\f1e6"}* .fa-plus:before{content:"\f067"}* .fa-plus-circle:before{content:"\f055"}* .fa-plus-square:before{content:"\f0fe"}* .fa-podcast:before{content:"\f2ce"}* .fa-poll:before{content:"\f681"}* .fa-poll-h:before{content:"\f682"}* .fa-poo:before{content:"\f2fe"}* .fa-poo-storm:before{content:"\f75a"}* .fa-poop:before{content:"\f619"}* .fa-portrait:before{content:"\f3e0"}* .fa-pound-sign:before{content:"\f154"}* .fa-power-off:before{content:"\f011"}* .fa-pray:before{content:"\f683"}* .fa-praying-hands:before{content:"\f684"}* .fa-prescription:before{content:"\f5b1"}* .fa-prescription-bottle:before{content:"\f485"}* .fa-prescription-bottle-alt:before{content:"\f486"}* .fa-print:before{content:"\f02f"}* .fa-procedures:before{content:"\f487"}* .fa-product-hunt:before{content:"\f288"}* .fa-project-diagram:before{content:"\f542"}* .fa-pushed:before{content:"\f3e1"}* .fa-puzzle-piece:before{content:"\f12e"}* .fa-python:before{content:"\f3e2"}* .fa-qq:before{content:"\f1d6"}* .fa-qrcode:before{content:"\f029"}* .fa-question:before{content:"\f128"}* .fa-question-circle:before{content:"\f059"}* .fa-quidditch:before{content:"\f458"}* .fa-quinscape:before{content:"\f459"}* .fa-quora:before{content:"\f2c4"}* .fa-quote-left:before{content:"\f10d"}* .fa-quote-right:before{content:"\f10e"}* .fa-quran:before{content:"\f687"}* .fa-r-project:before{content:"\f4f7"}* .fa-radiation:before{content:"\f7b9"}* .fa-radiation-alt:before{content:"\f7ba"}* .fa-rainbow:before{content:"\f75b"}* .fa-random:before{content:"\f074"}* .fa-raspberry-pi:before{content:"\f7bb"}* .fa-ravelry:before{content:"\f2d9"}* .fa-react:before{content:"\f41b"}* .fa-reacteurope:before{content:"\f75d"}* .fa-readme:before{content:"\f4d5"}* .fa-rebel:before{content:"\f1d0"}* .fa-receipt:before{content:"\f543"}* .fa-recycle:before{content:"\f1b8"}* .fa-red-river:before{content:"\f3e3"}* .fa-reddit:before{content:"\f1a1"}* .fa-reddit-alien:before{content:"\f281"}* .fa-reddit-square:before{content:"\f1a2"}* .fa-redhat:before{content:"\f7bc"}* .fa-redo:before{content:"\f01e"}* .fa-redo-alt:before{content:"\f2f9"}* .fa-registered:before{content:"\f25d"}* .fa-renren:before{content:"\f18b"}* .fa-reply:before{content:"\f3e5"}* .fa-reply-all:before{content:"\f122"}* .fa-replyd:before{content:"\f3e6"}* .fa-republican:before{content:"\f75e"}* .fa-researchgate:before{content:"\f4f8"}* .fa-resolving:before{content:"\f3e7"}* .fa-restroom:before{content:"\f7bd"}* .fa-retweet:before{content:"\f079"}* .fa-rev:before{content:"\f5b2"}* .fa-ribbon:before{content:"\f4d6"}* .fa-ring:before{content:"\f70b"}* .fa-road:before{content:"\f018"}* .fa-robot:before{content:"\f544"}* .fa-rocket:before{content:"\f135"}* .fa-rocketchat:before{content:"\f3e8"}* .fa-rockrms:before{content:"\f3e9"}* .fa-route:before{content:"\f4d7"}* .fa-rss:before{content:"\f09e"}* .fa-rss-square:before{content:"\f143"}* .fa-ruble-sign:before{content:"\f158"}* .fa-ruler:before{content:"\f545"}* .fa-ruler-combined:before{content:"\f546"}* .fa-ruler-horizontal:before{content:"\f547"}* .fa-ruler-vertical:before{content:"\f548"}* .fa-running:before{content:"\f70c"}* .fa-rupee-sign:before{content:"\f156"}* .fa-sad-cry:before{content:"\f5b3"}* .fa-sad-tear:before{content:"\f5b4"}* .fa-safari:before{content:"\f267"}* .fa-sass:before{content:"\f41e"}* .fa-satellite:before{content:"\f7bf"}* .fa-satellite-dish:before{content:"\f7c0"}* .fa-save:before{content:"\f0c7"}* .fa-schlix:before{content:"\f3ea"}* .fa-school:before{content:"\f549"}* .fa-screwdriver:before{content:"\f54a"}* .fa-scribd:before{content:"\f28a"}* .fa-scroll:before{content:"\f70e"}* .fa-sd-card:before{content:"\f7c2"}* .fa-search:before{content:"\f002"}* .fa-search-dollar:before{content:"\f688"}* .fa-search-location:before{content:"\f689"}* .fa-search-minus:before{content:"\f010"}* .fa-search-plus:before{content:"\f00e"}* .fa-searchengin:before{content:"\f3eb"}* .fa-seedling:before{content:"\f4d8"}* .fa-sellcast:before{content:"\f2da"}* .fa-sellsy:before{content:"\f213"}* .fa-server:before{content:"\f233"}* .fa-servicestack:before{content:"\f3ec"}* .fa-shapes:before{content:"\f61f"}* .fa-share:before{content:"\f064"}* .fa-share-alt:before{content:"\f1e0"}* .fa-share-alt-square:before{content:"\f1e1"}* .fa-share-square:before{content:"\f14d"}* .fa-shekel-sign:before{content:"\f20b"}* .fa-shield-alt:before{content:"\f3ed"}* .fa-ship:before{content:"\f21a"}* .fa-shipping-fast:before{content:"\f48b"}* .fa-shirtsinbulk:before{content:"\f214"}* .fa-shoe-prints:before{content:"\f54b"}* .fa-shopping-bag:before{content:"\f290"}* .fa-shopping-basket:before{content:"\f291"}* .fa-shopping-cart:before{content:"\f07a"}* .fa-shopware:before{content:"\f5b5"}* .fa-shower:before{content:"\f2cc"}* .fa-shuttle-van:before{content:"\f5b6"}* .fa-sign:before{content:"\f4d9"}* .fa-sign-in-alt:before{content:"\f2f6"}* .fa-sign-language:before{content:"\f2a7"}* .fa-sign-out-alt:before{content:"\f2f5"}* .fa-signal:before{content:"\f012"}* .fa-signature:before{content:"\f5b7"}* .fa-sim-card:before{content:"\f7c4"}* .fa-simplybuilt:before{content:"\f215"}* .fa-sistrix:before{content:"\f3ee"}* .fa-sitemap:before{content:"\f0e8"}* .fa-sith:before{content:"\f512"}* .fa-skating:before{content:"\f7c5"}* .fa-sketch:before{content:"\f7c6"}* .fa-skiing:before{content:"\f7c9"}* .fa-skiing-nordic:before{content:"\f7ca"}* .fa-skull:before{content:"\f54c"}* .fa-skull-crossbones:before{content:"\f714"}* .fa-skyatlas:before{content:"\f216"}* .fa-skype:before{content:"\f17e"}* .fa-slack:before{content:"\f198"}* .fa-slack-hash:before{content:"\f3ef"}* .fa-slash:before{content:"\f715"}* .fa-sleigh:before{content:"\f7cc"}* .fa-sliders-h:before{content:"\f1de"}* .fa-slideshare:before{content:"\f1e7"}* .fa-smile:before{content:"\f118"}* .fa-smile-beam:before{content:"\f5b8"}* .fa-smile-wink:before{content:"\f4da"}* .fa-smog:before{content:"\f75f"}* .fa-smoking:before{content:"\f48d"}* .fa-smoking-ban:before{content:"\f54d"}* .fa-sms:before{content:"\f7cd"}* .fa-snapchat:before{content:"\f2ab"}* .fa-snapchat-ghost:before{content:"\f2ac"}* .fa-snapchat-square:before{content:"\f2ad"}* .fa-snowboarding:before{content:"\f7ce"}* .fa-snowflake:before{content:"\f2dc"}* .fa-snowman:before{content:"\f7d0"}* .fa-snowplow:before{content:"\f7d2"}* .fa-socks:before{content:"\f696"}* .fa-solar-panel:before{content:"\f5ba"}* .fa-sort:before{content:"\f0dc"}* .fa-sort-alpha-down:before{content:"\f15d"}* .fa-sort-alpha-up:before{content:"\f15e"}* .fa-sort-amount-down:before{content:"\f160"}* .fa-sort-amount-up:before{content:"\f161"}* .fa-sort-down:before{content:"\f0dd"}* .fa-sort-numeric-down:before{content:"\f162"}* .fa-sort-numeric-up:before{content:"\f163"}* .fa-sort-up:before{content:"\f0de"}* .fa-soundcloud:before{content:"\f1be"}* .fa-sourcetree:before{content:"\f7d3"}* .fa-spa:before{content:"\f5bb"}* .fa-space-shuttle:before{content:"\f197"}* .fa-speakap:before{content:"\f3f3"}* .fa-spider:before{content:"\f717"}* .fa-spinner:before{content:"\f110"}* .fa-splotch:before{content:"\f5bc"}* .fa-spotify:before{content:"\f1bc"}* .fa-spray-can:before{content:"\f5bd"}* .fa-square:before{content:"\f0c8"}* .fa-square-full:before{content:"\f45c"}* .fa-square-root-alt:before{content:"\f698"}* .fa-squarespace:before{content:"\f5be"}* .fa-stack-exchange:before{content:"\f18d"}* .fa-stack-overflow:before{content:"\f16c"}* .fa-stamp:before{content:"\f5bf"}* .fa-star:before{content:"\f005"}* .fa-star-and-crescent:before{content:"\f699"}* .fa-star-half:before{content:"\f089"}* .fa-star-half-alt:before{content:"\f5c0"}* .fa-star-of-david:before{content:"\f69a"}* .fa-star-of-life:before{content:"\f621"}* .fa-staylinked:before{content:"\f3f5"}* .fa-steam:before{content:"\f1b6"}* .fa-steam-square:before{content:"\f1b7"}* .fa-steam-symbol:before{content:"\f3f6"}* .fa-step-backward:before{content:"\f048"}* .fa-step-forward:before{content:"\f051"}* .fa-stethoscope:before{content:"\f0f1"}* .fa-sticker-mule:before{content:"\f3f7"}* .fa-sticky-note:before{content:"\f249"}* .fa-stop:before{content:"\f04d"}* .fa-stop-circle:before{content:"\f28d"}* .fa-stopwatch:before{content:"\f2f2"}* .fa-store:before{content:"\f54e"}* .fa-store-alt:before{content:"\f54f"}* .fa-strava:before{content:"\f428"}* .fa-stream:before{content:"\f550"}* .fa-street-view:before{content:"\f21d"}* .fa-strikethrough:before{content:"\f0cc"}* .fa-stripe:before{content:"\f429"}* .fa-stripe-s:before{content:"\f42a"}* .fa-stroopwafel:before{content:"\f551"}* .fa-studiovinari:before{content:"\f3f8"}* .fa-stumbleupon:before{content:"\f1a4"}* .fa-stumbleupon-circle:before{content:"\f1a3"}* .fa-subscript:before{content:"\f12c"}* .fa-subway:before{content:"\f239"}* .fa-suitcase:before{content:"\f0f2"}* .fa-suitcase-rolling:before{content:"\f5c1"}* .fa-sun:before{content:"\f185"}* .fa-superpowers:before{content:"\f2dd"}* .fa-superscript:before{content:"\f12b"}* .fa-supple:before{content:"\f3f9"}* .fa-surprise:before{content:"\f5c2"}* .fa-suse:before{content:"\f7d6"}* .fa-swatchbook:before{content:"\f5c3"}* .fa-swimmer:before{content:"\f5c4"}* .fa-swimming-pool:before{content:"\f5c5"}* .fa-synagogue:before{content:"\f69b"}* .fa-sync:before{content:"\f021"}* .fa-sync-alt:before{content:"\f2f1"}* .fa-syringe:before{content:"\f48e"}* .fa-table:before{content:"\f0ce"}* .fa-table-tennis:before{content:"\f45d"}* .fa-tablet:before{content:"\f10a"}* .fa-tablet-alt:before{content:"\f3fa"}* .fa-tablets:before{content:"\f490"}* .fa-tachometer-alt:before{content:"\f3fd"}* .fa-tag:before{content:"\f02b"}* .fa-tags:before{content:"\f02c"}* .fa-tape:before{content:"\f4db"}* .fa-tasks:before{content:"\f0ae"}* .fa-taxi:before{content:"\f1ba"}* .fa-teamspeak:before{content:"\f4f9"}* .fa-teeth:before{content:"\f62e"}* .fa-teeth-open:before{content:"\f62f"}* .fa-telegram:before{content:"\f2c6"}* .fa-telegram-plane:before{content:"\f3fe"}* .fa-temperature-high:before{content:"\f769"}* .fa-temperature-low:before{content:"\f76b"}* .fa-tencent-weibo:before{content:"\f1d5"}* .fa-tenge:before{content:"\f7d7"}* .fa-terminal:before{content:"\f120"}* .fa-text-height:before{content:"\f034"}* .fa-text-width:before{content:"\f035"}* .fa-th:before{content:"\f00a"}* .fa-th-large:before{content:"\f009"}* .fa-th-list:before{content:"\f00b"}* .fa-the-red-yeti:before{content:"\f69d"}* .fa-theater-masks:before{content:"\f630"}* .fa-themeco:before{content:"\f5c6"}* .fa-themeisle:before{content:"\f2b2"}* .fa-thermometer:before{content:"\f491"}* .fa-thermometer-empty:before{content:"\f2cb"}* .fa-thermometer-full:before{content:"\f2c7"}* .fa-thermometer-half:before{content:"\f2c9"}* .fa-thermometer-quarter:before{content:"\f2ca"}* .fa-thermometer-three-quarters:before{content:"\f2c8"}* .fa-think-peaks:before{content:"\f731"}* .fa-thumbs-down:before{content:"\f165"}* .fa-thumbs-up:before{content:"\f164"}* .fa-thumbtack:before{content:"\f08d"}* .fa-ticket-alt:before{content:"\f3ff"}* .fa-times:before{content:"\f00d"}* .fa-times-circle:before{content:"\f057"}* .fa-tint:before{content:"\f043"}* .fa-tint-slash:before{content:"\f5c7"}* .fa-tired:before{content:"\f5c8"}* .fa-toggle-off:before{content:"\f204"}* .fa-toggle-on:before{content:"\f205"}* .fa-toilet:before{content:"\f7d8"}* .fa-toilet-paper:before{content:"\f71e"}* .fa-toolbox:before{content:"\f552"}* .fa-tools:before{content:"\f7d9"}* .fa-tooth:before{content:"\f5c9"}* .fa-torah:before{content:"\f6a0"}* .fa-torii-gate:before{content:"\f6a1"}* .fa-tractor:before{content:"\f722"}* .fa-trade-federation:before{content:"\f513"}* .fa-trademark:before{content:"\f25c"}* .fa-traffic-light:before{content:"\f637"}* .fa-train:before{content:"\f238"}* .fa-tram:before{content:"\f7da"}* .fa-transgender:before{content:"\f224"}* .fa-transgender-alt:before{content:"\f225"}* .fa-trash:before{content:"\f1f8"}* .fa-trash-alt:before{content:"\f2ed"}* .fa-tree:before{content:"\f1bb"}* .fa-trello:before{content:"\f181"}* .fa-tripadvisor:before{content:"\f262"}* .fa-trophy:before{content:"\f091"}* .fa-truck:before{content:"\f0d1"}* .fa-truck-loading:before{content:"\f4de"}* .fa-truck-monster:before{content:"\f63b"}* .fa-truck-moving:before{content:"\f4df"}* .fa-truck-pickup:before{content:"\f63c"}* .fa-tshirt:before{content:"\f553"}* .fa-tty:before{content:"\f1e4"}* .fa-tumblr:before{content:"\f173"}* .fa-tumblr-square:before{content:"\f174"}* .fa-tv:before{content:"\f26c"}* .fa-twitch:before{content:"\f1e8"}* .fa-twitter:before{content:"\f099"}* .fa-twitter-square:before{content:"\f081"}* .fa-typo3:before{content:"\f42b"}* .fa-uber:before{content:"\f402"}* .fa-ubuntu:before{content:"\f7df"}* .fa-uikit:before{content:"\f403"}* .fa-umbrella:before{content:"\f0e9"}* .fa-umbrella-beach:before{content:"\f5ca"}* .fa-underline:before{content:"\f0cd"}* .fa-undo:before{content:"\f0e2"}* .fa-undo-alt:before{content:"\f2ea"}* .fa-uniregistry:before{content:"\f404"}* .fa-universal-access:before{content:"\f29a"}* .fa-university:before{content:"\f19c"}* .fa-unlink:before{content:"\f127"}* .fa-unlock:before{content:"\f09c"}* .fa-unlock-alt:before{content:"\f13e"}* .fa-untappd:before{content:"\f405"}* .fa-upload:before{content:"\f093"}* .fa-ups:before{content:"\f7e0"}* .fa-usb:before{content:"\f287"}* .fa-user:before{content:"\f007"}* .fa-user-alt:before{content:"\f406"}* .fa-user-alt-slash:before{content:"\f4fa"}* .fa-user-astronaut:before{content:"\f4fb"}* .fa-user-check:before{content:"\f4fc"}* .fa-user-circle:before{content:"\f2bd"}* .fa-user-clock:before{content:"\f4fd"}* .fa-user-cog:before{content:"\f4fe"}* .fa-user-edit:before{content:"\f4ff"}* .fa-user-friends:before{content:"\f500"}* .fa-user-graduate:before{content:"\f501"}* .fa-user-injured:before{content:"\f728"}* .fa-user-lock:before{content:"\f502"}* .fa-user-md:before{content:"\f0f0"}* .fa-user-minus:before{content:"\f503"}* .fa-user-ninja:before{content:"\f504"}* .fa-user-plus:before{content:"\f234"}* .fa-user-secret:before{content:"\f21b"}* .fa-user-shield:before{content:"\f505"}* .fa-user-slash:before{content:"\f506"}* .fa-user-tag:before{content:"\f507"}* .fa-user-tie:before{content:"\f508"}* .fa-user-times:before{content:"\f235"}* .fa-users:before{content:"\f0c0"}* .fa-users-cog:before{content:"\f509"}* .fa-usps:before{content:"\f7e1"}* .fa-ussunnah:before{content:"\f407"}* .fa-utensil-spoon:before{content:"\f2e5"}* .fa-utensils:before{content:"\f2e7"}* .fa-vaadin:before{content:"\f408"}* .fa-vector-square:before{content:"\f5cb"}* .fa-venus:before{content:"\f221"}* .fa-venus-double:before{content:"\f226"}* .fa-venus-mars:before{content:"\f228"}* .fa-viacoin:before{content:"\f237"}* .fa-viadeo:before{content:"\f2a9"}* .fa-viadeo-square:before{content:"\f2aa"}* .fa-vial:before{content:"\f492"}* .fa-vials:before{content:"\f493"}* .fa-viber:before{content:"\f409"}* .fa-video:before{content:"\f03d"}* .fa-video-slash:before{content:"\f4e2"}* .fa-vihara:before{content:"\f6a7"}* .fa-vimeo:before{content:"\f40a"}* .fa-vimeo-square:before{content:"\f194"}* .fa-vimeo-v:before{content:"\f27d"}* .fa-vine:before{content:"\f1ca"}* .fa-vk:before{content:"\f189"}* .fa-vnv:before{content:"\f40b"}* .fa-volleyball-ball:before{content:"\f45f"}* .fa-volume-down:before{content:"\f027"}* .fa-volume-mute:before{content:"\f6a9"}* .fa-volume-off:before{content:"\f026"}* .fa-volume-up:before{content:"\f028"}* .fa-vote-yea:before{content:"\f772"}* .fa-vr-cardboard:before{content:"\f729"}* .fa-vuejs:before{content:"\f41f"}* .fa-walking:before{content:"\f554"}* .fa-wallet:before{content:"\f555"}* .fa-warehouse:before{content:"\f494"}* .fa-water:before{content:"\f773"}* .fa-weebly:before{content:"\f5cc"}* .fa-weibo:before{content:"\f18a"}* .fa-weight:before{content:"\f496"}* .fa-weight-hanging:before{content:"\f5cd"}* .fa-weixin:before{content:"\f1d7"}* .fa-whatsapp:before{content:"\f232"}* .fa-whatsapp-square:before{content:"\f40c"}* .fa-wheelchair:before{content:"\f193"}* .fa-whmcs:before{content:"\f40d"}* .fa-wifi:before{content:"\f1eb"}* .fa-wikipedia-w:before{content:"\f266"}* .fa-wind:before{content:"\f72e"}* .fa-window-close:before{content:"\f410"}* .fa-window-maximize:before{content:"\f2d0"}* .fa-window-minimize:before{content:"\f2d1"}* .fa-window-restore:before{content:"\f2d2"}* .fa-windows:before{content:"\f17a"}* .fa-wine-bottle:before{content:"\f72f"}* .fa-wine-glass:before{content:"\f4e3"}* .fa-wine-glass-alt:before{content:"\f5ce"}* .fa-wix:before{content:"\f5cf"}* .fa-wizards-of-the-coast:before{content:"\f730"}* .fa-wolf-pack-battalion:before{content:"\f514"}* .fa-won-sign:before{content:"\f159"}* .fa-wordpress:before{content:"\f19a"}* .fa-wordpress-simple:before{content:"\f411"}* .fa-wpbeginner:before{content:"\f297"}* .fa-wpexplorer:before{content:"\f2de"}* .fa-wpforms:before{content:"\f298"}* .fa-wpressr:before{content:"\f3e4"}* .fa-wrench:before{content:"\f0ad"}* .fa-x-ray:before{content:"\f497"}* .fa-xbox:before{content:"\f412"}* .fa-xing:before{content:"\f168"}* .fa-xing-square:before{content:"\f169"}* .fa-y-combinator:before{content:"\f23b"}* .fa-yahoo:before{content:"\f19e"}* .fa-yandex:before{content:"\f413"}* .fa-yandex-international:before{content:"\f414"}* .fa-yarn:before{content:"\f7e3"}* .fa-yelp:before{content:"\f1e9"}* .fa-yen-sign:before{content:"\f157"}* .fa-yin-yang:before{content:"\f6ad"}* .fa-yoast:before{content:"\f2b1"}* .fa-youtube:before{content:"\f167"}* .fa-youtube-square:before{content:"\f431"}* .fa-zhihu:before{content:"\f63f"}* .sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}* .sr-only-focusable:active,* .sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}@font-face{font-family:Font Awesome\ 5 Free;font-style:normal;font-weight:900;src:url(assets/fonts/webfonts/fa-solid-900.eot);src:url(assets/fonts/webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(assets/fonts/webfonts/fa-solid-900.woff2) format("woff2"),url(assets/fonts/webfonts/fa-solid-900.woff) format("woff"),url(assets/fonts/webfonts/fa-solid-900.ttf) format("truetype"),url(assets/fonts/webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.fas{font-family:Font Awesome\ 5 Free;font-weight:900}@font-face{font-family:pficon;src:url(assets/pficon/pficon.eot);src:url(assets/pficon/pficon.eot?#iefix) format("eot"),url(assets/pficon/pficon.woff2) format("woff2"),url(assets/pficon/pficon.woff) format("woff"),url(assets/pficon/pficon.ttf) format("truetype"),url(assets/pficon/pficon.svg#pficon) format("svg")}.pf-icon-aa-circle-o:before,.pf-icon-add-circle-o:before,.pf-icon-ansible-tower:before,.pf-icon-applications:before,.pf-icon-arrow:before,.pf-icon-asleep:before,.pf-icon-attention-bell:before,.pf-icon-automation:before,.pf-icon-bell:before,.pf-icon-blueprint:before,.pf-icon-build:before,.pf-icon-builder-image:before,.pf-icon-bundle:before,.pf-icon-catalog:before,.pf-icon-chat:before,.pf-icon-close:before,.pf-icon-cloud-security:before,.pf-icon-cloud-tenant:before,.pf-icon-cluster:before,.pf-icon-connected:before,.pf-icon-container-node:before,.pf-icon-cpu:before,.pf-icon-degraded:before,.pf-icon-disconnected:before,.pf-icon-domain:before,.pf-icon-edit:before,.pf-icon-enhancement:before,.pf-icon-enterprise:before,.pf-icon-equalizer:before,.pf-icon-error-circle-o:before,.pf-icon-export:before,.pf-icon-filter:before,.pf-icon-flavor:before,.pf-icon-folder-close:before,.pf-icon-folder-open:before,.pf-icon-globe-route:before,.pf-icon-help:before,.pf-icon-history:before,.pf-icon-home:before,.pf-icon-import:before,.pf-icon-in-progress:before,.pf-icon-info:before,.pf-icon-infrastructure:before,.pf-icon-integration:before,.pf-icon-key:before,.pf-icon-locked:before,.pf-icon-maintenance:before,.pf-icon-memory:before,.pf-icon-messages:before,.pf-icon-middleware:before,.pf-icon-migration:before,.pf-icon-module:before,.pf-icon-monitoring:before,.pf-icon-namespaces:before,.pf-icon-network:before,.pf-icon-new-process:before,.pf-icon-not-started:before,.pf-icon-off:before,.pf-icon-ok:before,.pf-icon-on-running:before,.pf-icon-on:before,.pf-icon-openshift:before,.pf-icon-openstack:before,.pf-icon-optimize:before,.pf-icon-orders:before,.pf-icon-os-image:before,.pf-icon-package:before,.pf-icon-paused:before,.pf-icon-pending:before,.pf-icon-pficon-dragdrop:before,.pf-icon-pficon-history:before,.pf-icon-pficon-network-range:before,.pf-icon-pficon-satellite:before,.pf-icon-pficon-sort-common-asc:before,.pf-icon-pficon-sort-common-desc:before,.pf-icon-pficon-template:before,.pf-icon-pficon-vcenter:before,.pf-icon-plugged:before,.pf-icon-port:before,.pf-icon-print:before,.pf-icon-private:before,.pf-icon-process-automation:before,.pf-icon-project:before,.pf-icon-rebalance:before,.pf-icon-rebooting:before,.pf-icon-regions:before,.pf-icon-registry:before,.pf-icon-remove2:before,.pf-icon-replicator:before,.pf-icon-repository:before,.pf-icon-resource-pool:before,.pf-icon-resources-almost-empty:before,.pf-icon-resources-almost-full:before,.pf-icon-resources-empty:before,.pf-icon-resources-full:before,.pf-icon-running:before,.pf-icon-save:before,.pf-icon-screen:before,.pf-icon-security:before,.pf-icon-server-group:before,.pf-icon-server:before,.pf-icon-service-catalog:before,.pf-icon-service:before,.pf-icon-services:before,.pf-icon-spinner2:before,.pf-icon-spinner:before,.pf-icon-storage-domain:before,.pf-icon-tenant:before,.pf-icon-thumb-tack:before,.pf-icon-topology:before,.pf-icon-trend-down:before,.pf-icon-trend-up:before,.pf-icon-unknown:before,.pf-icon-unlocked:before,.pf-icon-unplugged:before,.pf-icon-user:before,.pf-icon-users:before,.pf-icon-virtual-machine:before,.pf-icon-volume:before,.pf-icon-warning-triangle:before,.pf-icon-zone:before{font-family:pficon;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-style:normal;font-variant:normal;font-weight:400;text-decoration:none;text-transform:none}.pf-icon-aa-circle-o:before{content:""}.pf-icon-add-circle-o:before{content:""}.pf-icon-ansible-tower:before{content:""}.pf-icon-applications:before{content:""}.pf-icon-arrow:before{content:""}.pf-icon-asleep:before{content:""}.pf-icon-attention-bell:before{content:""}.pf-icon-automation:before{content:""}.pf-icon-bell:before{content:""}.pf-icon-blueprint:before{content:""}.pf-icon-build:before{content:""}.pf-icon-builder-image:before{content:""}.pf-icon-bundle:before{content:""}.pf-icon-catalog:before{content:""}.pf-icon-chat:before{content:""}.pf-icon-close:before{content:""}.pf-icon-cloud-security:before{content:""}.pf-icon-cloud-tenant:before{content:""}.pf-icon-cluster:before{content:""}.pf-icon-connected:before{content:""}.pf-icon-container-node:before{content:""}.pf-icon-cpu:before{content:""}.pf-icon-degraded:before{content:""}.pf-icon-disconnected:before{content:""}.pf-icon-domain:before{content:""}.pf-icon-edit:before{content:""}.pf-icon-enhancement:before{content:""}.pf-icon-enterprise:before{content:""}.pf-icon-equalizer:before{content:""}.pf-icon-error-circle-o:before{content:""}.pf-icon-export:before{content:""}.pf-icon-filter:before{content:""}.pf-icon-flavor:before{content:""}.pf-icon-folder-close:before{content:""}.pf-icon-folder-open:before{content:""}.pf-icon-globe-route:before{content:""}.pf-icon-help:before{content:""}.pf-icon-history:before{content:""}.pf-icon-home:before{content:""}.pf-icon-import:before{content:""}.pf-icon-in-progress:before{content:""}.pf-icon-info:before{content:""}.pf-icon-infrastructure:before{content:""}.pf-icon-integration:before{content:""}.pf-icon-key:before{content:""}.pf-icon-locked:before{content:""}.pf-icon-maintenance:before{content:""}.pf-icon-memory:before{content:""}.pf-icon-messages:before{content:""}.pf-icon-middleware:before{content:""}.pf-icon-migration:before{content:""}.pf-icon-module:before{content:""}.pf-icon-monitoring:before{content:""}.pf-icon-namespaces:before{content:""}.pf-icon-network:before{content:""}.pf-icon-new-process:before{content:""}.pf-icon-not-started:before{content:""}.pf-icon-off:before{content:""}.pf-icon-ok:before{content:""}.pf-icon-on-running:before{content:""}.pf-icon-on:before{content:""}.pf-icon-openshift:before{content:""}.pf-icon-openstack:before{content:""}.pf-icon-optimize:before{content:""}.pf-icon-orders:before{content:""}.pf-icon-os-image:before{content:""}.pf-icon-package:before{content:""}.pf-icon-paused:before{content:""}.pf-icon-pending:before{content:""}.pf-icon-pficon-dragdrop:before{content:""}.pf-icon-pficon-history:before{content:""}.pf-icon-pficon-network-range:before{content:""}.pf-icon-pficon-satellite:before{content:""}.pf-icon-pficon-sort-common-asc:before{content:""}.pf-icon-pficon-sort-common-desc:before{content:""}.pf-icon-pficon-template:before{content:""}.pf-icon-pficon-vcenter:before{content:""}.pf-icon-plugged:before{content:""}.pf-icon-port:before{content:""}.pf-icon-print:before{content:""}.pf-icon-private:before{content:""}.pf-icon-process-automation:before{content:""}.pf-icon-project:before{content:""}.pf-icon-rebalance:before{content:""}.pf-icon-rebooting:before{content:""}.pf-icon-regions:before{content:""}.pf-icon-registry:before{content:""}.pf-icon-remove2:before{content:""}.pf-icon-replicator:before{content:""}.pf-icon-repository:before{content:""}.pf-icon-resource-pool:before{content:""}.pf-icon-resources-almost-empty:before{content:""}.pf-icon-resources-almost-full:before{content:""}.pf-icon-resources-empty:before{content:""}.pf-icon-resources-full:before{content:""}.pf-icon-running:before{content:""}.pf-icon-save:before{content:""}.pf-icon-screen:before{content:""}.pf-icon-security:before{content:""}.pf-icon-server-group:before{content:""}.pf-icon-server:before{content:""}.pf-icon-service-catalog:before{content:""}.pf-icon-service:before{content:""}.pf-icon-services:before{content:""}.pf-icon-spinner:before{content:""}.pf-icon-spinner2:before{content:""}.pf-icon-storage-domain:before{content:""}.pf-icon-tenant:before{content:""}.pf-icon-thumb-tack:before{content:""}.pf-icon-topology:before{content:""}.pf-icon-trend-down:before{content:""}.pf-icon-trend-up:before{content:""}.pf-icon-unknown:before{content:""}.pf-icon-unlocked:before{content:""}.pf-icon-unplugged:before{content:""}.pf-icon-user:before{content:""}.pf-icon-users:before{content:""}.pf-icon-virtual-machine:before{content:""}.pf-icon-volume:before{content:""}.pf-icon-warning-triangle:before{content:""}.pf-icon-zone:before{content:""}.pf-c-about-modal-box{--pf-c-about-modal-box--BackgroundColor:var(--pf-global--palette--black-1000);--pf-c-about-modal-box--BoxShadow:0 0 100px 0 hsla(0,0%,100%,0.05);--pf-c-about-modal-box--ZIndex:var(--pf-global--ZIndex--xl);--pf-c-about-modal-box--Height:100%;--pf-c-about-modal-box--lg--Height:47.625rem;--pf-c-about-modal-box--lg--MaxHeight:calc(100% - var(--pf-global--spacer--xl));--pf-c-about-modal-box--Width:100vw;--pf-c-about-modal-box--lg--Width:calc(100% - var(--pf-global--spacer--3xl)*2);--pf-c-about-modal-box--lg--MaxWidth:77rem;--pf-c-about-modal-box--PaddingTop:var(--pf-global--spacer--xl);--pf-c-about-modal-box--PaddingRight:var(--pf-global--spacer--xl);--pf-c-about-modal-box--PaddingBottom:var(--pf-global--spacer--xl);--pf-c-about-modal-box--PaddingLeft:var(--pf-global--spacer--xl);--pf-c-about-modal-box--sm--PaddingTop:var(--pf-global--spacer--3xl);--pf-c-about-modal-box--sm--PaddingRight:var(--pf-global--spacer--3xl);--pf-c-about-modal-box--sm--PaddingBottom:var(--pf-global--spacer--3xl);--pf-c-about-modal-box--sm--PaddingLeft:var(--pf-global--spacer--3xl);--pf-c-about-modal-box--sm--grid-template-columns:5fr 1fr;--pf-c-about-modal-box--lg--grid-template-columns:1fr .6fr;--pf-c-about-modal-box__brand--PaddingTop:var(--pf-global--spacer--2xl);--pf-c-about-modal-box__brand--PaddingRight:var(--pf-global--spacer--xl);--pf-c-about-modal-box__brand--PaddingLeft:var(--pf-global--spacer--xl);--pf-c-about-modal-box__brand--PaddingBottom:var(--pf-global--spacer--xl);--pf-c-about-modal-box__brand--sm--PaddingRight:var(--pf-global--spacer--3xl);--pf-c-about-modal-box__brand--sm--PaddingLeft:var(--pf-global--spacer--3xl);--pf-c-about-modal-box__brand--sm--PaddingBottom:var(--pf-global--spacer--3xl);--pf-c-about-modal-box__close--ZIndex:var(--pf-global--ZIndex--2xl);--pf-c-about-modal-box__close--PaddingTop:var(--pf-global--spacer--2xl);--pf-c-about-modal-box__close--PaddingRight:var(--pf-global--spacer--xl);--pf-c-about-modal-box__close--PaddingBottom:var(--pf-global--spacer--xl);--pf-c-about-modal-box__close--sm--PaddingBottom:var(--pf-global--spacer--3xl);--pf-c-about-modal-box__close--sm--PaddingRight:0;--pf-c-about-modal-box__close--lg--PaddingRight:var(--pf-global--spacer--3xl);--pf-c-about-modal-box__close--c-button--Color:var(--pf-global--Color--100);--pf-c-about-modal-box__close--c-button--FontSize:var(--pf-global--FontSize--xl);--pf-c-about-modal-box__close--c-button--BorderRadius:var(--pf-global--BorderRadius--lg);--pf-c-about-modal-box__close--c-button--Width:calc(var(--pf-c-about-modal-box__close--c-button--FontSize)*2);--pf-c-about-modal-box__close--c-button--Height:calc(var(--pf-c-about-modal-box__close--c-button--FontSize)*2);--pf-c-about-modal-box__close--c-button--BackgroundColor:var(--pf-global--palette--black-1000);--pf-c-about-modal-box__close--c-button--hover--BackgroundColor:rgba(3,3,3,0.4);--pf-c-about-modal-box__hero--sm--BackgroundImage:url(assets/images/pfbg_992@2x.jpg);--pf-c-about-modal-box__hero--sm--BackgroundPosition:top left;--pf-c-about-modal-box__hero--sm--BackgroundSize:cover;--pf-c-about-modal-box__brand-image--Height:2.5rem;--pf-c-about-modal-box__header--PaddingRight:var(--pf-global--spacer--xl);--pf-c-about-modal-box__header--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-about-modal-box__header--PaddingLeft:var(--pf-global--spacer--xl);--pf-c-about-modal-box__header--sm--PaddingRight:var(--pf-global--spacer--3xl);--pf-c-about-modal-box__header--sm--PaddingLeft:var(--pf-global--spacer--3xl);--pf-c-about-modal-box__strapline--PaddingTop:var(--pf-global--spacer--xl);--pf-c-about-modal-box__strapline--FontSize:var(--pf-global--FontSize--sm);--pf-c-about-modal-box__strapline--sm--PaddingTop:var(--pf-global--spacer--2xl);--pf-c-about-modal-box__content--MarginTop:var(--pf-global--spacer--xl);--pf-c-about-modal-box__content--MarginRight:var(--pf-global--spacer--xl);--pf-c-about-modal-box__content--MarginBottom:var(--pf-global--spacer--xl);--pf-c-about-modal-box__content--MarginLeft:var(--pf-global--spacer--xl);--pf-c-about-modal-box__content--sm--MarginTop:var(--pf-global--spacer--2xl);--pf-c-about-modal-box__content--sm--MarginRight:var(--pf-global--spacer--3xl);--pf-c-about-modal-box__content--sm--MarginBottom:var(--pf-global--spacer--2xl);--pf-c-about-modal-box__content--sm--MarginLeft:var(--pf-global--spacer--3xl);color:var(--pf-global--Color--100);position:relative;z-index:var(--pf-c-about-modal-box--ZIndex);display:grid;grid-template-rows:max-content max-content auto;grid-template-areas:"brand close" "header header" "content content";width:var(--pf-c-about-modal-box--Width);height:var(--pf-c-about-modal-box--Height);overflow-x:hidden;overflow-y:auto;background-color:var(--pf-c-about-modal-box--BackgroundColor);box-shadow:var(--pf-c-about-modal-box--BoxShadow)}@media screen and (min-width:576px){.pf-c-about-modal-box{--pf-c-about-modal-box--PaddingTop:var(--pf-c-about-modal-box--sm--PaddingTop);--pf-c-about-modal-box--PaddingRight:var(--pf-c-about-modal-box--sm--PaddingRight);--pf-c-about-modal-box--PaddingBottom:var(--pf-c-about-modal-box--sm--PaddingBottom);--pf-c-about-modal-box--PaddingLeft:var(--pf-c-about-modal-box--sm--PaddingLeft);--pf-c-about-modal-box__brand--PaddingRight:var(--pf-c-about-modal-box__brand--sm--PaddingRight);--pf-c-about-modal-box__brand--PaddingLeft:var(--pf-c-about-modal-box__brand--sm--PaddingLeft);--pf-c-about-modal-box__brand--PaddingBottom:var(--pf-c-about-modal-box__brand--sm--PaddingBottom)}}@media only screen and (min-width:576px){.pf-c-about-modal-box{--pf-c-about-modal-box__close--PaddingRight:var(--pf-c-about-modal-box__close--sm--PaddingRight);--pf-c-about-modal-box__close--PaddingBottom:var(--pf-c-about-modal-box__close--sm--PaddingBottom)}}@media only screen and (min-width:992px){.pf-c-about-modal-box{--pf-c-about-modal-box__close--PaddingRight:var(--pf-c-about-modal-box__close--lg--PaddingRight)}}@media only screen and (min-width:576px){.pf-c-about-modal-box{--pf-c-about-modal-box__header--PaddingRight:var(--pf-c-about-modal-box__header--sm--PaddingRight);--pf-c-about-modal-box__header--PaddingLeft:var(--pf-c-about-modal-box__header--sm--PaddingLeft);--pf-c-about-modal-box__strapline--PaddingTop:var(--pf-c-about-modal-box__strapline--sm--PaddingTop);--pf-c-about-modal-box__content--MarginTop:var(--pf-c-about-modal-box__content--sm--MarginTop);--pf-c-about-modal-box__content--MarginRight:var(--pf-c-about-modal-box__content--sm--MarginRight);--pf-c-about-modal-box__content--MarginBottom:var(--pf-c-about-modal-box__content--sm--MarginBottom);--pf-c-about-modal-box__content--MarginLeft:var(--pf-c-about-modal-box__content--sm--MarginLeft);grid-template-columns:var(--pf-c-about-modal-box--sm--grid-template-columns);grid-template-areas:"brand hero" "header hero" "content hero"}}@media only screen and (min-width:992px){.pf-c-about-modal-box{--pf-c-about-modal-box--Height:var(--pf-c-about-modal-box--lg--Height);--pf-c-about-modal-box--Width:var(--pf-c-about-modal-box--lg--Width);grid-template-columns:var(--pf-c-about-modal-box--lg--grid-template-columns);grid-template-rows:max-content max-content auto;max-width:var(--pf-c-about-modal-box--lg--MaxWidth);max-height:var(--pf-c-about-modal-box--lg--MaxHeight)}}.pf-c-about-modal-box__brand{grid-area:brand;display:flex;padding:var(--pf-c-about-modal-box__brand--PaddingTop) var(--pf-c-about-modal-box__brand--PaddingRight) var(--pf-c-about-modal-box__brand--PaddingBottom) var(--pf-c-about-modal-box__brand--PaddingLeft)}.pf-c-about-modal-box__brand-image{height:var(--pf-c-about-modal-box__brand-image--Height)}.pf-c-about-modal-box__header{grid-area:header;display:flex;flex-direction:column;padding-right:var(--pf-c-about-modal-box__header--PaddingRight);padding-bottom:var(--pf-c-about-modal-box__header--PaddingBottom);padding-left:var(--pf-c-about-modal-box__header--PaddingLeft)}.pf-c-about-modal-box__strapline{padding-top:var(--pf-c-about-modal-box__strapline--PaddingTop);margin-top:auto;font-size:var(--pf-c-about-modal-box__strapline--FontSize)}.pf-c-about-modal-box__content{display:flex;flex-direction:column;grid-area:content;margin:var(--pf-c-about-modal-box__content--MarginTop) var(--pf-c-about-modal-box__content--MarginRight) var(--pf-c-about-modal-box__content--MarginBottom) var(--pf-c-about-modal-box__content--MarginLeft);overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;word-break:break-word}@media screen and (min-width:576px){.pf-c-about-modal-box__content{overflow:visible;overscroll-behavior:auto}}.pf-c-about-modal-box__close{grid-area:close;position:sticky;top:0;display:flex;align-items:flex-start;justify-content:flex-end;padding-top:var(--pf-c-about-modal-box__close--PaddingTop);padding-right:var(--pf-c-about-modal-box__close--PaddingRight);padding-bottom:var(--pf-c-about-modal-box__close--PaddingBottom)}@media only screen and (min-width:576px){.pf-c-about-modal-box__close{grid-area:1/2;justify-content:center}}@media only screen and (min-width:992px){.pf-c-about-modal-box__close{justify-content:flex-end}}.pf-c-about-modal-box__close .pf-c-button.pf-m-plain{display:flex;align-items:center;justify-content:center;width:var(--pf-c-about-modal-box__close--c-button--Width);height:var(--pf-c-about-modal-box__close--c-button--Height);font-size:var(--pf-c-about-modal-box__close--c-button--FontSize);color:var(--pf-c-about-modal-box__close--c-button--Color);background-color:var(--pf-c-about-modal-box__close--c-button--BackgroundColor);border-radius:var(--pf-c-about-modal-box__close--c-button--BorderRadius)}.pf-c-about-modal-box__close .pf-c-button.pf-m-plain:hover{--pf-c-about-modal-box__close--c-button--BackgroundColor:var(--pf-c-about-modal-box__close--c-button--hover--BackgroundColor)}.pf-c-about-modal-box__hero{display:none;visibility:hidden}@media only screen and (min-width:576px){.pf-c-about-modal-box__hero{display:block;visibility:visible;background-image:var(--pf-c-about-modal-box__hero--sm--BackgroundImage);background-repeat:no-repeat;background-attachment:fixed;background-position:var(--pf-c-about-modal-box__hero--sm--BackgroundPosition);background-size:var(--pf-c-about-modal-box__hero--sm--BackgroundSize);grid-area:hero}}.pf-c-accordion{--pf-c-accordion--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-accordion__toggle--PaddingTop:var(--pf-global--spacer--sm);--pf-c-accordion__toggle--PaddingRight:var(--pf-global--spacer--md);--pf-c-accordion__toggle--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-accordion__toggle--PaddingLeft:var(--pf-global--spacer--md);--pf-c-accordion__toggle--before--BackgroundColor:transparent;--pf-c-accordion__toggle--hover--BackgroundColor:var(--pf-global--BackgroundColor--200);--pf-c-accordion__toggle--focus--BackgroundColor:var(--pf-global--BackgroundColor--200);--pf-c-accordion__toggle--active--BackgroundColor:var(--pf-global--BackgroundColor--200);--pf-c-accordion__toggle--before--Width:var(--pf-global--BorderWidth--lg);--pf-c-accordion__toggle--m-expanded--before--BackgroundColor:var(--pf-global--primary-color--100);--pf-c-accordion__toggle-text--MaxWidth:calc(100% - var(--pf-global--spacer--lg));--pf-c-accordion__toggle--hover__toggle-text--Color:var(--pf-global--link--Color);--pf-c-accordion__toggle--active__toggle-text--Color:var(--pf-global--link--Color);--pf-c-accordion__toggle--active__toggle-text--FontWeight:var(--pf-global--FontWeight--semi-bold);--pf-c-accordion__toggle--focus__toggle-text--Color:var(--pf-global--link--Color);--pf-c-accordion__toggle--focus__toggle-text--FontWeight:var(--pf-global--FontWeight--semi-bold);--pf-c-accordion__toggle--m-expanded__toggle-text--Color:var(--pf-global--link--Color);--pf-c-accordion__toggle--m-expanded__toggle-text--FontWeight:var(--pf-global--FontWeight--semi-bold);--pf-c-accordion__toggle-icon--Transition:.2s ease-in 0s;--pf-c-accordion__toggle--m-expanded__toggle-icon--Rotate:90deg;--pf-c-accordion__expanded-content-body--PaddingTop:var(--pf-global--spacer--sm);--pf-c-accordion__expanded-content-body--PaddingRight:var(--pf-global--spacer--md);--pf-c-accordion__expanded-content-body--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-accordion__expanded-content-body--PaddingLeft:var(--pf-global--spacer--md);--pf-c-accordion__expanded-content--Color:var(--pf-global--Color--200);--pf-c-accordion__expanded-content--FontSize:var(--pf-global--FontSize--sm);--pf-c-accordion__expanded-content-body--before--BackgroundColor:transparent;--pf-c-accordion__expanded-content-body--before--Width:var(--pf-global--BorderWidth--lg);--pf-c-accordion__expanded-content--m-expanded__expanded-content-body--before--BackgroundColor:var(--pf-global--primary-color--100);--pf-c-accordion__expanded-content--m-fixed--MaxHeight:9.375rem;color:var(--pf-global--Color--100);background-color:var(--pf-c-accordion--BackgroundColor)}.pf-c-accordion__toggle{position:relative;display:flex;align-items:center;justify-content:space-between;width:100%;padding:var(--pf-c-accordion__toggle--PaddingTop) var(--pf-c-accordion__toggle--PaddingRight) var(--pf-c-accordion__toggle--PaddingBottom) var(--pf-c-accordion__toggle--PaddingLeft);border:0}.pf-c-accordion__toggle:before{position:absolute;top:0;bottom:0;left:0;width:var(--pf-c-accordion__toggle--before--Width);content:"";background-color:var(--pf-c-accordion__toggle--before--BackgroundColor)}.pf-c-accordion__toggle.pf-m-expanded{--pf-c-accordion__toggle--before--BackgroundColor:var(--pf-c-accordion__toggle--m-expanded--before--BackgroundColor)}.pf-c-accordion__toggle.pf-m-expanded .pf-c-accordion__toggle-text{font-weight:var(--pf-c-accordion__toggle--m-expanded__toggle-text--FontWeight);color:var(--pf-c-accordion__toggle--m-expanded__toggle-text--Color)}.pf-c-accordion__toggle.pf-m-expanded .pf-c-accordion__toggle-icon{transform:rotate(var(--pf-c-accordion__toggle--m-expanded__toggle-icon--Rotate))}.pf-c-accordion__toggle:hover{background-color:var(--pf-c-accordion__toggle--hover--BackgroundColor)}.pf-c-accordion__toggle:hover .pf-c-accordion__toggle-text{color:var(--pf-c-accordion__toggle--hover__toggle-text--Color)}.pf-c-accordion__toggle:focus{background-color:var(--pf-c-accordion__toggle--focus--BackgroundColor)}.pf-c-accordion__toggle:focus .pf-c-accordion__toggle-text{font-weight:var(--pf-c-accordion__toggle--focus__toggle-text--FontWeight);color:var(--pf-c-accordion__toggle--focus__toggle-text--Color)}.pf-c-accordion__toggle:active{background-color:var(--pf-c-accordion__toggle--active--BackgroundColor)}.pf-c-accordion__toggle:active .pf-c-accordion__toggle-text{font-weight:var(--pf-c-accordion__toggle--active__toggle-text--FontWeight);color:var(--pf-c-accordion__toggle--active__toggle-text--Color)}.pf-c-accordion__toggle-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:var(--pf-c-accordion__toggle-text--MaxWidth)}.pf-c-accordion__toggle-icon{transition:var(--pf-c-accordion__toggle-icon--Transition)}.pf-c-accordion__expanded-content{font-size:var(--pf-c-accordion__expanded-content--FontSize);color:var(--pf-c-accordion__expanded-content--Color)}.pf-c-accordion__expanded-content.pf-m-fixed{max-height:var(--pf-c-accordion__expanded-content--m-fixed--MaxHeight);overflow-y:auto}.pf-c-accordion__expanded-content.pf-m-expanded{--pf-c-accordion__expanded-content-body--before--BackgroundColor:var(--pf-c-accordion__expanded-content--m-expanded__expanded-content-body--before--BackgroundColor)}.pf-c-accordion__expanded-content-body{position:relative;padding:var(--pf-c-accordion__expanded-content-body--PaddingTop) var(--pf-c-accordion__expanded-content-body--PaddingRight) var(--pf-c-accordion__expanded-content-body--PaddingBottom) var(--pf-c-accordion__expanded-content-body--PaddingLeft)}.pf-c-accordion__expanded-content-body:before{position:absolute;top:0;bottom:0;left:0;width:var(--pf-c-accordion__expanded-content-body--before--Width);content:"";background-color:var(--pf-c-accordion__expanded-content-body--before--BackgroundColor)}.pf-c-action-list{--pf-c-action-list--m-icon--spacer:0;--pf-c-action-list--child--spacer-base:var(--pf-global--spacer--md);--pf-c-action-list--group--spacer-base:var(--pf-global--spacer--2xl)}.pf-c-action-list,.pf-c-action-list__group{--pf-c-action-list--child--spacer:var(--pf-c-action-list--child--spacer-base);--pf-c-action-list--group--spacer:var(--pf-c-action-list--group--spacer-base);display:flex;align-items:center}.pf-c-action-list>*+*,.pf-c-action-list__group>*+*{margin-left:var(--pf-c-action-list--child--spacer)}.pf-c-action-list .pf-c-action-list__group+*,.pf-c-action-list>*+.pf-c-action-list__group,.pf-c-action-list__group .pf-c-action-list__group+*,.pf-c-action-list__group>*+.pf-c-action-list__group{margin-left:var(--pf-c-action-list--group--spacer)}.pf-c-action-list.pf-m-icons,.pf-c-action-list__group.pf-m-icons{--pf-c-action-list--child--spacer:var(--pf-c-action-list--m-icon--spacer)}.pf-c-alert{--pf-c-alert--BoxShadow:var(--pf-global--BoxShadow--lg);--pf-c-alert--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-alert--GridTemplateColumns:max-content 1fr max-content;--pf-c-alert--BorderTopWidth:var(--pf-global--BorderWidth--md);--pf-c-alert--BorderTopColor:var(--pf-global--default-color--200);--pf-c-alert--PaddingTop:var(--pf-global--spacer--md);--pf-c-alert--PaddingRight:var(--pf-global--spacer--md);--pf-c-alert--PaddingBottom:var(--pf-global--spacer--md);--pf-c-alert--PaddingLeft:var(--pf-global--spacer--md);--pf-c-alert__FontSize:var(--pf-global--FontSize--sm);--pf-c-alert__icon--Color:var(--pf-global--default-color--200);--pf-c-alert__icon--MarginTop:0.0625rem;--pf-c-alert__icon--MarginRight:var(--pf-global--spacer--sm);--pf-c-alert__icon--FontSize:var(--pf-global--icon--FontSize--md);--pf-c-alert__title--FontWeight:var(--pf-global--FontWeight--bold);--pf-c-alert__title--Color:var(--pf-global--default-color--300);--pf-c-alert__title--max-lines:1;--pf-c-alert__action--MarginTop:calc(var(--pf-global--spacer--form-element)*-1);--pf-c-alert__action--MarginBottom:calc(var(--pf-global--spacer--form-element)*-1);--pf-c-alert__action--TranslateY:0.125rem;--pf-c-alert__action--MarginRight:calc(var(--pf-global--spacer--sm)*-1);--pf-c-alert__description--PaddingTop:var(--pf-global--spacer--xs);--pf-c-alert__action-group--PaddingTop:var(--pf-global--spacer--xs);--pf-c-alert__description--action-group--PaddingTop:var(--pf-global--spacer--md);--pf-c-alert__action-group__c-button--not-last-child--MarginRight:var(--pf-global--spacer--lg);--pf-c-alert--m-success--BorderTopColor:var(--pf-global--success-color--100);--pf-c-alert--m-success__icon--Color:var(--pf-global--success-color--100);--pf-c-alert--m-success__title--Color:var(--pf-global--success-color--200);--pf-c-alert--m-danger--BorderTopColor:var(--pf-global--danger-color--100);--pf-c-alert--m-danger__icon--Color:var(--pf-global--danger-color--100);--pf-c-alert--m-danger__title--Color:var(--pf-global--danger-color--200);--pf-c-alert--m-warning--BorderTopColor:var(--pf-global--warning-color--100);--pf-c-alert--m-warning__icon--Color:var(--pf-global--warning-color--100);--pf-c-alert--m-warning__title--Color:var(--pf-global--warning-color--200);--pf-c-alert--m-info--BorderTopColor:var(--pf-global--info-color--100);--pf-c-alert--m-info__icon--Color:var(--pf-global--info-color--100);--pf-c-alert--m-info__title--Color:var(--pf-global--info-color--200);--pf-c-alert--m-inline--BoxShadow:none;--pf-c-alert--m-inline--BackgroundColor:var(--pf-global--palette--cyan-50);--pf-c-alert--m-inline--m-success--BackgroundColor:var(--pf-global--palette--green-50);--pf-c-alert--m-inline--m-danger--BackgroundColor:var(--pf-global--palette--red-50);--pf-c-alert--m-inline--m-warning--BackgroundColor:var(--pf-global--palette--gold-50);--pf-c-alert--m-inline--m-info--BackgroundColor:var(--pf-global--palette--blue-50);color:var(--pf-global--Color--100);position:relative;display:grid;padding:var(--pf-c-alert--PaddingTop) var(--pf-c-alert--PaddingRight) var(--pf-c-alert--PaddingBottom) var(--pf-c-alert--PaddingLeft);font-size:var(--pf-c-alert__FontSize);background-color:var(--pf-c-alert--BackgroundColor);border-top:var(--pf-c-alert--BorderTopWidth) solid var(--pf-c-alert--BorderTopColor);box-shadow:var(--pf-c-alert--BoxShadow);grid-template-columns:var(--pf-c-alert--GridTemplateColumns);grid-template-areas:"icon title action" ". description description" ". actiongroup actiongroup"}.pf-c-alert.pf-m-success{--pf-c-alert--BorderTopColor:var(--pf-c-alert--m-success--BorderTopColor);--pf-c-alert__icon--Color:var(--pf-c-alert--m-success__icon--Color);--pf-c-alert__title--Color:var(--pf-c-alert--m-success__title--Color);--pf-c-alert--m-inline--BackgroundColor:var(--pf-c-alert--m-inline--m-success--BackgroundColor)}.pf-c-alert.pf-m-danger{--pf-c-alert--BorderTopColor:var(--pf-c-alert--m-danger--BorderTopColor);--pf-c-alert__icon--Color:var(--pf-c-alert--m-danger__icon--Color);--pf-c-alert__title--Color:var(--pf-c-alert--m-danger__title--Color);--pf-c-alert--m-inline--BackgroundColor:var(--pf-c-alert--m-inline--m-danger--BackgroundColor)}.pf-c-alert.pf-m-warning{--pf-c-alert--BorderTopColor:var(--pf-c-alert--m-warning--BorderTopColor);--pf-c-alert__icon--Color:var(--pf-c-alert--m-warning__icon--Color);--pf-c-alert__title--Color:var(--pf-c-alert--m-warning__title--Color);--pf-c-alert--m-inline--BackgroundColor:var(--pf-c-alert--m-inline--m-warning--BackgroundColor)}.pf-c-alert.pf-m-info{--pf-c-alert--BorderTopColor:var(--pf-c-alert--m-info--BorderTopColor);--pf-c-alert__icon--Color:var(--pf-c-alert--m-info__icon--Color);--pf-c-alert__title--Color:var(--pf-c-alert--m-info__title--Color);--pf-c-alert--m-inline--BackgroundColor:var(--pf-c-alert--m-inline--m-info--BackgroundColor)}.pf-c-alert.pf-m-inline{--pf-c-alert--BoxShadow:var(--pf-c-alert--m-inline--BoxShadow);--pf-c-alert--BackgroundColor:var(--pf-c-alert--m-inline--BackgroundColor)}.pf-c-alert__icon{grid-area:icon;display:flex;margin-top:var(--pf-c-alert__icon--MarginTop);margin-right:var(--pf-c-alert__icon--MarginRight);font-size:var(--pf-c-alert__icon--FontSize);color:var(--pf-c-alert__icon--Color)}.pf-c-alert__title{grid-area:title;font-weight:var(--pf-c-alert__title--FontWeight);color:var(--pf-c-alert__title--Color);word-break:break-word}.pf-c-alert__title.pf-m-truncate{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:var(--pf-c-alert__title--max-lines);overflow:hidden}.pf-c-alert__description{grid-area:description;padding-top:var(--pf-c-alert__description--PaddingTop);word-break:break-word}.pf-c-alert__description+.pf-c-alert__action-group{--pf-c-alert__action-group--PaddingTop:var(--pf-c-alert__description--action-group--PaddingTop)}.pf-c-alert__action{grid-area:action;margin-top:var(--pf-c-alert__action--MarginTop);margin-right:var(--pf-c-alert__action--MarginRight);margin-bottom:var(--pf-c-alert__action--MarginBottom);transform:translateY(var(--pf-c-alert__action--TranslateY))}.pf-c-alert__action>.pf-c-button{--pf-c-button--LineHeight:1}.pf-c-alert__action-group{grid-area:actiongroup;padding-top:var(--pf-c-alert__action-group--PaddingTop)}.pf-c-alert__action-group>.pf-c-button{--pf-c-button--m-link--m-inline--hover--TextDecoration:none}.pf-c-alert__action-group>.pf-c-button:not(:last-child){margin-right:var(--pf-c-alert__action-group__c-button--not-last-child--MarginRight)}.pf-m-overpass-font .pf-c-alert__title{--pf-c-alert__title--FontWeight:var(--pf-global--FontWeight--normal)}.pf-c-alert-group{--pf-c-alert-group__item--MarginTop:var(--pf-global--spacer--sm);--pf-c-alert-group--m-toast--Top:var(--pf-global--spacer--2xl);--pf-c-alert-group--m-toast--Right:var(--pf-global--spacer--xl);--pf-c-alert-group--m-toast--MaxWidth:37.5rem;--pf-c-alert-group--m-toast--ZIndex:var(--pf-global--ZIndex--2xl)}.pf-c-alert-group>*+*{margin-top:var(--pf-c-alert-group__item--MarginTop)}.pf-c-alert-group.pf-m-toast{position:fixed;top:var(--pf-c-alert-group--m-toast--Top);right:var(--pf-c-alert-group--m-toast--Right);z-index:var(--pf-c-alert-group--m-toast--ZIndex);width:calc(100% - var(--pf-c-alert-group--m-toast--Right)*2);max-width:var(--pf-c-alert-group--m-toast--MaxWidth)}.pf-c-app-launcher{--pf-c-app-launcher__menu--BackgroundColor:var(--pf-global--BackgroundColor--light-100);--pf-c-app-launcher__menu--BoxShadow:var(--pf-global--BoxShadow--md);--pf-c-app-launcher__menu--PaddingTop:var(--pf-global--spacer--sm);--pf-c-app-launcher__menu--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-app-launcher__menu--Top:calc(100% + var(--pf-global--spacer--xs));--pf-c-app-launcher__menu--ZIndex:var(--pf-global--ZIndex--sm);--pf-c-app-launcher--m-top__menu--Top:0;--pf-c-app-launcher--m-top__menu--TranslateY:calc(-100% - var(--pf-global--spacer--xs));--pf-c-app-launcher__toggle--PaddingTop:var(--pf-global--spacer--form-element);--pf-c-app-launcher__toggle--PaddingRight:var(--pf-global--spacer--md);--pf-c-app-launcher__toggle--PaddingBottom:var(--pf-global--spacer--form-element);--pf-c-app-launcher__toggle--PaddingLeft:var(--pf-global--spacer--md);--pf-c-app-launcher__toggle--Color:var(--pf-global--Color--200);--pf-c-app-launcher__toggle--hover--Color:var(--pf-global--Color--100);--pf-c-app-launcher__toggle--active--Color:var(--pf-global--Color--100);--pf-c-app-launcher__toggle--focus--Color:var(--pf-global--Color--100);--pf-c-app-launcher__toggle--disabled--Color:var(--pf-global--disabled-color--200);--pf-c-app-launcher__toggle--m-expanded--Color:var(--pf-global--Color--100);--pf-c-app-launcher__menu-search--PaddingTop:var(--pf-global--spacer--sm);--pf-c-app-launcher__menu-search--PaddingRight:var(--pf-global--spacer--md);--pf-c-app-launcher__menu-search--PaddingBottom:var(--pf-global--spacer--md);--pf-c-app-launcher__menu-search--PaddingLeft:var(--pf-global--spacer--md);--pf-c-app-launcher__menu-search--BottomBorderColor:var(--pf-global--BorderColor--100);--pf-c-app-launcher__menu-search--BottomBorderWidth:var(--pf-global--BorderWidth--sm);--pf-c-app-launcher__menu-search--MarginBottom:var(--pf-global--spacer--sm);--pf-c-app-launcher__menu-item--PaddingTop:var(--pf-global--spacer--sm);--pf-c-app-launcher__menu-item--PaddingRight:var(--pf-global--spacer--md);--pf-c-app-launcher__menu-item--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-app-launcher__menu-item--PaddingLeft:var(--pf-global--spacer--md);--pf-c-app-launcher__menu-item--Color:var(--pf-global--Color--dark-100);--pf-c-app-launcher__menu-item--FontWeight:var(--pf-global--FontWeight--normal);--pf-c-app-launcher__menu-item--Width:100%;--pf-c-app-launcher__menu-item--disabled--Color:var(--pf-global--Color--dark-200);--pf-c-app-launcher__menu-item--hover--BackgroundColor:var(--pf-global--BackgroundColor--light-300);--pf-c-app-launcher__menu-item--m-link--PaddingRight:0;--pf-c-app-launcher__menu-item--m-link--hover--BackgroundColor:transparent;--pf-c-app-launcher__menu-item--m-action--Color:var(--pf-global--disabled-color--200);--pf-c-app-launcher__menu-item--m-action--Width:auto;--pf-c-app-launcher__menu-item--m-action--FontSize:var(--pf-global--icon--FontSize--sm);--pf-c-app-launcher__menu-item--m-action--hover--BackgroundColor:transparent;--pf-c-app-launcher__menu-item--hover__menu-item--m-action--Color:var(--pf-global--Color--200);--pf-c-app-launcher__menu-item--m-action--hover--Color:var(--pf-global--Color--100);--pf-c-app-launcher__menu-item--m-favorite__menu-item--m-action--Color:var(--pf-global--palette--gold-400);--pf-c-app-launcher__menu-item-icon--MarginRight:var(--pf-global--spacer--sm);--pf-c-app-launcher__menu-item-icon--Width:var(--pf-global--icon--FontSize--lg);--pf-c-app-launcher__menu-item-icon--Height:var(--pf-global--icon--FontSize--lg);--pf-c-app-launcher__menu-item-external-icon--Color:var(--pf-global--link--Color);--pf-c-app-launcher__menu-item-external-icon--PaddingLeft:var(--pf-global--spacer--md);--pf-c-app-launcher__menu-item-external-icon--TranslateY:-0.0625rem;--pf-c-app-launcher__menu-item-external-icon--FontSize:var(--pf-global--icon--FontSize--sm);--pf-c-app-launcher__group--group--PaddingTop:var(--pf-global--spacer--sm);--pf-c-app-launcher__group-title--PaddingTop:var(--pf-global--spacer--sm);--pf-c-app-launcher__group-title--PaddingRight:var(--pf-c-app-launcher__menu-item--PaddingRight);--pf-c-app-launcher__group-title--PaddingBottom:var(--pf-c-app-launcher__menu-item--PaddingBottom);--pf-c-app-launcher__group-title--PaddingLeft:var(--pf-c-app-launcher__menu-item--PaddingLeft);--pf-c-app-launcher__group-title--FontSize:var(--pf-global--FontSize--sm);--pf-c-app-launcher__group-title--FontWeight:var(--pf-global--FontWeight--semi-bold);--pf-c-app-launcher__group-title--Color:var(--pf-global--Color--dark-200);--pf-c-app-launcher--c-divider--MarginTop:var(--pf-global--spacer--sm);--pf-c-app-launcher--c-divider--MarginBottom:var(--pf-global--spacer--sm);position:relative;display:inline-block;max-width:100%}.pf-c-app-launcher.pf-m-expanded>.pf-c-app-launcher__toggle{color:var(--pf-c-app-launcher__toggle--m-expanded--Color)}.pf-c-app-launcher .pf-c-divider{margin-top:var(--pf-c-app-launcher--c-divider--MarginTop);margin-bottom:var(--pf-c-app-launcher--c-divider--MarginBottom)}.pf-c-app-launcher .pf-c-divider:last-child{--pf-c-app-launcher--c-divider--MarginBottom:0}.pf-c-app-launcher__toggle{padding:var(--pf-c-app-launcher__toggle--PaddingTop) var(--pf-c-app-launcher__toggle--PaddingRight) var(--pf-c-app-launcher__toggle--PaddingBottom) var(--pf-c-app-launcher__toggle--PaddingLeft);color:var(--pf-c-app-launcher__toggle--Color);border:none}.pf-c-app-launcher__toggle:hover{--pf-c-app-launcher__toggle--Color:var(--pf-c-app-launcher__toggle--hover--Color)}.pf-c-app-launcher__toggle.pf-m-active,.pf-c-app-launcher__toggle:active{--pf-c-app-launcher__toggle--Color:var(--pf-c-app-launcher__toggle--active--Color)}.pf-c-app-launcher__toggle:focus{--pf-c-app-launcher__toggle--Color:var(--pf-c-app-launcher__toggle--focus--Color)}.pf-c-app-launcher__toggle:disabled{--pf-c-app-launcher__toggle--Color:var(--pf-c-app-launcher__toggle--disabled--Color);pointer-events:none}.pf-c-app-launcher__menu{position:absolute;top:var(--pf-c-app-launcher__menu--Top);z-index:var(--pf-c-app-launcher__menu--ZIndex);min-width:100%;padding-top:var(--pf-c-app-launcher__menu--PaddingTop);padding-bottom:var(--pf-c-app-launcher__menu--PaddingBottom);background-color:var(--pf-c-app-launcher__menu--BackgroundColor);background-clip:padding-box;box-shadow:var(--pf-c-app-launcher__menu--BoxShadow)}.pf-c-app-launcher__menu.pf-m-align-right{right:0}.pf-c-app-launcher.pf-m-top .pf-c-app-launcher__menu{--pf-c-app-launcher__menu--Top:var(--pf-c-app-launcher--m-top__menu--Top);transform:translateY(var(--pf-c-app-launcher--m-top__menu--TranslateY))}.pf-c-app-launcher__menu-search{padding:var(--pf-c-app-launcher__menu-search--PaddingTop) var(--pf-c-app-launcher__menu-search--PaddingRight) var(--pf-c-app-launcher__menu-search--PaddingBottom) var(--pf-c-app-launcher__menu-search--PaddingLeft);margin-bottom:var(--pf-c-app-launcher__menu-search--MarginBottom);border-bottom:var(--pf-c-app-launcher__menu-search--BottomBorderWidth) solid var(--pf-c-app-launcher__menu-search--BottomBorderColor)}.pf-c-app-launcher__menu-wrapper{display:flex}.pf-c-app-launcher__menu-wrapper.pf-m-favorite{--pf-c-app-launcher__menu-item--m-action--Color:var(--pf-c-app-launcher__menu-item--m-favorite__menu-item--m-action--Color)}.pf-c-app-launcher__menu-item{display:flex;align-items:center;width:var(--pf-c-app-launcher__menu-item--Width);padding:var(--pf-c-app-launcher__menu-item--PaddingTop) var(--pf-c-app-launcher__menu-item--PaddingRight) var(--pf-c-app-launcher__menu-item--PaddingBottom) var(--pf-c-app-launcher__menu-item--PaddingLeft);font-weight:var(--pf-c-app-launcher__menu-item--FontWeight);color:var(--pf-c-app-launcher__menu-item--Color);white-space:nowrap;border:0}.pf-c-app-launcher__menu-item:focus,.pf-c-app-launcher__menu-item:hover{--pf-c-app-launcher__menu-item--m-action--Color:var(--pf-c-app-launcher__menu-item--hover__menu-item--m-action--Color);text-decoration:none}.pf-c-app-launcher__menu-item:focus,.pf-c-app-launcher__menu-item:hover,.pf-c-app-launcher__menu-wrapper.pf-m-focus,.pf-c-app-launcher__menu-wrapper:focus-within,.pf-c-app-launcher__menu-wrapper:hover{background-color:var(--pf-c-app-launcher__menu-item--hover--BackgroundColor)}.pf-c-app-launcher__menu-item.pf-m-disabled,.pf-c-app-launcher__menu-item:disabled{--pf-c-app-launcher__menu-item--Color:var(--pf-c-app-launcher__menu-item--disabled--Color);pointer-events:none}.pf-c-app-launcher__menu-item.pf-m-disabled,.pf-c-app-launcher__menu-item:disabled,.pf-c-app-launcher__menu-wrapper.pf-m-disabled,.pf-c-app-launcher__menu-wrapper:disabled{background-color:transparent}.pf-c-app-launcher__menu-item.pf-m-external:focus .pf-c-app-launcher__menu-item-external-icon,.pf-c-app-launcher__menu-item.pf-m-external:hover .pf-c-app-launcher__menu-item-external-icon,.pf-c-app-launcher__menu-wrapper.pf-m-external:focus .pf-c-app-launcher__menu-item-external-icon,.pf-c-app-launcher__menu-wrapper.pf-m-external:hover .pf-c-app-launcher__menu-item-external-icon{opacity:1}.pf-c-app-launcher__menu-item.pf-m-link{--pf-c-app-launcher__menu-item--PaddingRight:var(--pf-c-app-launcher__menu-item--m-link--PaddingRight);--pf-c-app-launcher__menu-item--hover--BackgroundColor:var(--pf-c-app-launcher__menu-item--m-link--hover--BackgroundColor)}.pf-c-app-launcher__menu-item.pf-m-action{--pf-c-app-launcher__menu-item--Color:var(--pf-c-app-launcher__menu-item--m-action--Color);--pf-c-app-launcher__menu-item--Width:var(--pf-c-app-launcher__menu-item--m-action--Width);--pf-c-app-launcher__menu-item--hover--BackgroundColor:var(--pf-c-app-launcher__menu-item--m-action--hover--BackgroundColor);font-size:var(--pf-c-app-launcher__menu-item--m-action--FontSize)}.pf-c-app-launcher__menu-item.pf-m-action:focus,.pf-c-app-launcher__menu-item.pf-m-action:hover{--pf-c-app-launcher__menu-item--m-action--Color:var(--pf-c-app-launcher__menu-item--m-action--hover--Color)}.pf-c-app-launcher__menu-item-icon{display:inline-flex;align-items:center;justify-content:center;width:var(--pf-c-app-launcher__menu-item-icon--Width);height:var(--pf-c-app-launcher__menu-item-icon--Height);margin-right:var(--pf-c-app-launcher__menu-item-icon--MarginRight)}.pf-c-app-launcher__menu-item-icon>*{max-width:100%;max-height:100%}.pf-c-app-launcher__menu-item-external-icon{padding-left:var(--pf-c-app-launcher__menu-item-external-icon--PaddingLeft);margin-left:auto;font-size:var(--pf-c-app-launcher__menu-item-external-icon--FontSize);color:var(--pf-c-app-launcher__menu-item-external-icon--Color);opacity:0;transform:translateY(var(--pf-c-app-launcher__menu-item-external-icon--TranslateY))}.pf-c-app-launcher__group+.pf-c-app-launcher__group{padding-top:var(--pf-c-app-launcher__group--group--PaddingTop)}.pf-c-app-launcher__group-title{padding:var(--pf-c-app-launcher__group-title--PaddingTop) var(--pf-c-app-launcher__group-title--PaddingRight) var(--pf-c-app-launcher__group-title--PaddingBottom) var(--pf-c-app-launcher__group-title--PaddingLeft);font-size:var(--pf-c-app-launcher__group-title--FontSize);font-weight:var(--pf-c-app-launcher__group-title--FontWeight);color:var(--pf-c-app-launcher__group-title--Color)}.pf-c-avatar{--pf-c-avatar--BorderRadius:var(--pf-global--BorderRadius--lg);--pf-c-avatar--Width:2.25rem;--pf-c-avatar--Height:2.25rem;width:var(--pf-c-avatar--Width);height:var(--pf-c-avatar--Height);border-radius:var(--pf-c-avatar--BorderRadius)}.pf-c-backdrop{--pf-c-backdrop--ZIndex:var(--pf-global--ZIndex--lg);--pf-c-backdrop--BackgroundColor:var(--pf-global--BackgroundColor--dark-transparent-100);position:fixed;top:0;left:0;z-index:var(--pf-c-backdrop--ZIndex);width:100%;height:100%;background-color:var(--pf-c-backdrop--BackgroundColor)}.pf-c-backdrop__open{overflow:hidden}.pf-c-background-image{--pf-c-background-image--BackgroundColor:var(--pf-global--BackgroundColor--dark-100);--pf-c-background-image--BackgroundImage:url(assets/images/pfbg_576.jpg);--pf-c-background-image--BackgroundImage-2x:url(assets/images/pfbg_576@2x.jpg);--pf-c-background-image--BackgroundImage--sm:url(assets/images/pfbg_768.jpg);--pf-c-background-image--BackgroundImage--sm-2x:url(assets/images/pfbg_768@2x.jpg);--pf-c-background-image--BackgroundImage--lg:url(assets/images/pfbg_2000.jpg);--pf-c-background-image--Filter:url(#image_overlay)}.pf-c-background-image:before{position:fixed;top:0;left:0;z-index:-1;width:100%;height:100%;content:"";background-color:var(--pf-c-background-image--BackgroundColor);background-image:var(--pf-c-background-image--BackgroundImage);filter:var(--pf-c-background-image--Filter);background-repeat:no-repeat;background-size:cover}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:192dpi){.pf-c-background-image:before{--pf-c-background-image--BackgroundImage:var(--pf-c-background-image--BackgroundImage-2x)}}@media (min-width:576px){.pf-c-background-image:before{--pf-c-background-image--BackgroundImage:var(--pf-c-background-image--BackgroundImage--sm)}}@media (min-width:576px) and (-webkit-min-device-pixel-ratio:2),(min-width:576px) and (min-resolution:192dpi){.pf-c-background-image:before{--pf-c-background-image--BackgroundImage:var(--pf-c-background-image--BackgroundImage--sm-2x)}}@media (min-width:992px){.pf-c-background-image:before{--pf-c-background-image--BackgroundImage:var(--pf-c-background-image--BackgroundImage--lg)}}.pf-c-background-image__filter{display:block}.pf-c-badge{--pf-c-badge--BorderRadius:var(--pf-global--BorderRadius--lg);--pf-c-badge--FontSize:var(--pf-global--FontSize--xs);--pf-c-badge--FontWeight:var(--pf-global--FontWeight--bold);--pf-c-badge--PaddingRight:var(--pf-global--spacer--sm);--pf-c-badge--PaddingLeft:var(--pf-global--spacer--sm);--pf-c-badge--Color:var(--pf-global--Color--dark-100);--pf-c-badge--MinWidth:var(--pf-global--spacer--xl);--pf-c-badge--m-read--BackgroundColor:var(--pf-global--BackgroundColor--200);--pf-c-badge--m-read--Color:var(--pf-global--Color--dark-100);--pf-c-badge--m-unread--BackgroundColor:var(--pf-global--primary-color--100);--pf-c-badge--m-unread--Color:var(--pf-global--Color--light-100);display:inline-block;min-width:var(--pf-c-badge--MinWidth);padding-right:var(--pf-c-badge--PaddingRight);padding-left:var(--pf-c-badge--PaddingLeft);font-size:var(--pf-c-badge--FontSize);font-weight:var(--pf-c-badge--FontWeight);color:var(--pf-c-badge--Color);text-align:center;background-color:var(--pf-c-badge--BackgroundColor);border-radius:var(--pf-c-badge--BorderRadius)}.pf-c-badge.pf-m-read{--pf-c-badge--Color:var(--pf-c-badge--m-read--Color);--pf-c-badge--BackgroundColor:var(--pf-c-badge--m-read--BackgroundColor)}.pf-c-badge.pf-m-unread{--pf-c-badge--Color:var(--pf-c-badge--m-unread--Color);--pf-c-badge--BackgroundColor:var(--pf-c-badge--m-unread--BackgroundColor)}.pf-c-banner{--pf-c-banner--PaddingTop:var(--pf-global--spacer--xs);--pf-c-banner--PaddingRight:var(--pf-global--spacer--md);--pf-c-banner--md--PaddingRight:var(--pf-global--spacer--lg);--pf-c-banner--PaddingBottom:var(--pf-global--spacer--xs);--pf-c-banner--PaddingLeft:var(--pf-global--spacer--md);--pf-c-banner--md--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-banner--FontSize:var(--pf-global--FontSize--sm);--pf-c-banner--Color:var(--pf-global--Color--100);--pf-c-banner--BackgroundColor:var(--pf-global--BackgroundColor--dark-400);--pf-c-banner--m-info--BackgroundColor:var(--pf-global--palette--blue-200);--pf-c-banner--m-danger--BackgroundColor:var(--pf-global--danger-color--100);--pf-c-banner--m-success--BackgroundColor:var(--pf-global--success-color--100);--pf-c-banner--m-warning--BackgroundColor:var(--pf-global--warning-color--100);--pf-c-banner--m-sticky--ZIndex:var(--pf-global--ZIndex--md);--pf-c-banner--m-sticky--BoxShadow:var(--pf-global--BoxShadow--md-bottom);color:var(--pf-global--Color--100);overflow:hidden;text-overflow:ellipsis;padding:var(--pf-c-banner--PaddingTop) var(--pf-c-banner--PaddingRight) var(--pf-c-banner--PaddingBottom) var(--pf-c-banner--PaddingLeft);flex-shrink:0;font-size:var(--pf-c-banner--FontSize);color:var(--pf-c-banner--Color);white-space:nowrap;background-color:var(--pf-c-banner--BackgroundColor)}@media (min-width:768px){.pf-c-banner{--pf-c-banner--PaddingRight:var(--pf-c-banner--md--PaddingRight);--pf-c-banner--PaddingLeft:var(--pf-c-banner--md--PaddingLeft)}}.pf-c-banner.pf-m-info{color:var(--pf-global--Color--100);--pf-c-banner--BackgroundColor:var(--pf-c-banner--m-info--BackgroundColor)}.pf-c-banner.pf-m-danger{--pf-c-banner--BackgroundColor:var(--pf-c-banner--m-danger--BackgroundColor)}.pf-c-banner.pf-m-success{--pf-c-banner--BackgroundColor:var(--pf-c-banner--m-success--BackgroundColor)}.pf-c-banner.pf-m-warning{color:var(--pf-global--Color--100);--pf-c-banner--BackgroundColor:var(--pf-c-banner--m-warning--BackgroundColor)}.pf-c-banner.pf-m-sticky{position:sticky;top:0;z-index:var(--pf-c-banner--m-sticky--ZIndex);box-shadow:var(--pf-c-banner--m-sticky--BoxShadow)}.pf-c-breadcrumb{--pf-c-breadcrumb__item--FontSize:var(--pf-global--FontSize--sm);--pf-c-breadcrumb__item--LineHeight:var(--pf-global--LineHeight--sm);--pf-c-breadcrumb__item--MarginRight:var(--pf-global--spacer--sm);--pf-c-breadcrumb__item-divider--Color:var(--pf-global--BorderColor--200);--pf-c-breadcrumb__item-divider--MarginRight:var(--pf-global--spacer--sm);--pf-c-breadcrumb__item-divider--FontSize:var(--pf-global--FontSize--sm);--pf-c-breadcrumb__link--m-current--Color:var(--pf-global--Color--100);--pf-c-breadcrumb__heading--FontSize:var(--pf-global--FontSize--sm);display:inline-flex}.pf-c-breadcrumb__list{display:flex;flex-wrap:wrap;align-items:center}.pf-c-breadcrumb__item{display:flex;align-items:baseline;font-size:var(--pf-c-breadcrumb__item--FontSize);font-weight:var(--pf-c-breadcrumb__item--FontWeight);line-height:var(--pf-c-breadcrumb__item--LineHeight);white-space:nowrap;list-style:none}.pf-c-breadcrumb__item:not(:last-child){margin-right:var(--pf-c-breadcrumb__item--MarginRight)}.pf-c-breadcrumb__item-divider{margin-right:var(--pf-c-breadcrumb__item-divider--MarginRight);font-size:var(--pf-c-breadcrumb__item-divider--FontSize);line-height:1;color:var(--pf-c-breadcrumb__item-divider--Color)}.pf-c-breadcrumb__link{font-size:inherit;font-weight:var(--pf-c-breadcrumb__link--FontWeight);line-height:inherit;word-break:break-word}.pf-c-breadcrumb__link.pf-m-current{cursor:default}.pf-c-breadcrumb__link.pf-m-current,.pf-c-breadcrumb__link.pf-m-current:hover{color:var(--pf-c-breadcrumb__link--m-current--Color);text-decoration:none}.pf-c-breadcrumb__heading{display:inline;font-size:var(--pf-c-breadcrumb__heading--FontSize)}.pf-c-breadcrumb__heading,.pf-c-breadcrumb__link{white-space:normal}.pf-m-overpass-font .pf-c-breadcrumb__item,.pf-m-overpass-font .pf-c-breadcrumb__link{font-weight:var(--pf-global--FontWeight--semi-bold)}.pf-c-breadcrumb__list>:first-child .pf-c-breadcrumb__item-divider{display:none;visibility:hidden}.pf-c-button{--pf-c-button--PaddingTop:var(--pf-global--spacer--form-element);--pf-c-button--PaddingRight:var(--pf-global--spacer--md);--pf-c-button--PaddingBottom:var(--pf-global--spacer--form-element);--pf-c-button--PaddingLeft:var(--pf-global--spacer--md);--pf-c-button--LineHeight:var(--pf-global--LineHeight--md);--pf-c-button--FontWeight:var(--pf-global--FontWeight--normal);--pf-c-button--FontSize:var(--pf-global--FontSize--md);--pf-c-button--BorderRadius:var(--pf-global--BorderRadius--sm);--pf-c-button--after--BorderRadius:var(--pf-global--BorderRadius--sm);--pf-c-button--after--BorderColor:transparent;--pf-c-button--after--BorderWidth:var(--pf-global--BorderWidth--sm);--pf-c-button--hover--after--BorderWidth:var(--pf-global--BorderWidth--md);--pf-c-button--focus--after--BorderWidth:var(--pf-global--BorderWidth--md);--pf-c-button--active--after--BorderWidth:var(--pf-global--BorderWidth--md);--pf-c-button--disabled--Color:var(--pf-global--disabled-color--100);--pf-c-button--disabled--BackgroundColor:var(--pf-global--disabled-color--200);--pf-c-button--disabled--after--BorderColor:transparent;--pf-c-button--m-primary--BackgroundColor:var(--pf-global--primary-color--100);--pf-c-button--m-primary--Color:var(--pf-global--Color--light-100);--pf-c-button--m-primary--hover--BackgroundColor:var(--pf-global--primary-color--200);--pf-c-button--m-primary--hover--Color:var(--pf-global--Color--light-100);--pf-c-button--m-primary--focus--BackgroundColor:var(--pf-global--primary-color--200);--pf-c-button--m-primary--focus--Color:var(--pf-global--Color--light-100);--pf-c-button--m-primary--active--BackgroundColor:var(--pf-global--primary-color--200);--pf-c-button--m-primary--active--Color:var(--pf-global--Color--light-100);--pf-c-button--m-secondary--BackgroundColor:transparent;--pf-c-button--m-secondary--after--BorderColor:var(--pf-global--primary-color--100);--pf-c-button--m-secondary--Color:var(--pf-global--primary-color--100);--pf-c-button--m-secondary--hover--BackgroundColor:transparent;--pf-c-button--m-secondary--hover--after--BorderColor:var(--pf-global--primary-color--100);--pf-c-button--m-secondary--hover--Color:var(--pf-global--primary-color--100);--pf-c-button--m-secondary--focus--BackgroundColor:transparent;--pf-c-button--m-secondary--focus--after--BorderColor:var(--pf-global--primary-color--100);--pf-c-button--m-secondary--focus--Color:var(--pf-global--primary-color--100);--pf-c-button--m-secondary--active--BackgroundColor:transparent;--pf-c-button--m-secondary--active--after--BorderColor:var(--pf-global--primary-color--100);--pf-c-button--m-secondary--active--Color:var(--pf-global--primary-color--100);--pf-c-button--m-tertiary--BackgroundColor:transparent;--pf-c-button--m-tertiary--after--BorderColor:var(--pf-global--Color--100);--pf-c-button--m-tertiary--Color:var(--pf-global--Color--100);--pf-c-button--m-tertiary--hover--BackgroundColor:transparent;--pf-c-button--m-tertiary--hover--after--BorderColor:var(--pf-global--Color--100);--pf-c-button--m-tertiary--hover--Color:var(--pf-global--Color--100);--pf-c-button--m-tertiary--focus--BackgroundColor:transparent;--pf-c-button--m-tertiary--focus--after--BorderColor:var(--pf-global--Color--100);--pf-c-button--m-tertiary--focus--Color:var(--pf-global--Color--100);--pf-c-button--m-tertiary--active--BackgroundColor:transparent;--pf-c-button--m-tertiary--active--after--BorderColor:var(--pf-global--Color--100);--pf-c-button--m-tertiary--active--Color:var(--pf-global--Color--100);--pf-c-button--m-warning--BackgroundColor:var(--pf-global--warning-color--100);--pf-c-button--m-warning--Color:var(--pf-global--Color--dark-100);--pf-c-button--m-warning--hover--BackgroundColor:var(--pf-global--palette--gold-500);--pf-c-button--m-warning--hover--Color:var(--pf-global--Color--dark-100);--pf-c-button--m-warning--focus--BackgroundColor:var(--pf-global--palette--gold-500);--pf-c-button--m-warning--focus--Color:var(--pf-global--Color--dark-100);--pf-c-button--m-warning--active--BackgroundColor:var(--pf-global--palette--gold-500);--pf-c-button--m-warning--active--Color:var(--pf-global--Color--dark-100);--pf-c-button--m-danger--BackgroundColor:var(--pf-global--danger-color--100);--pf-c-button--m-danger--Color:var(--pf-global--Color--light-100);--pf-c-button--m-danger--hover--BackgroundColor:var(--pf-global--danger-color--200);--pf-c-button--m-danger--hover--Color:var(--pf-global--Color--light-100);--pf-c-button--m-danger--focus--BackgroundColor:var(--pf-global--danger-color--200);--pf-c-button--m-danger--focus--Color:var(--pf-global--Color--light-100);--pf-c-button--m-danger--active--BackgroundColor:var(--pf-global--danger-color--200);--pf-c-button--m-danger--active--Color:var(--pf-global--Color--light-100);--pf-c-button--m-link--BackgroundColor:transparent;--pf-c-button--m-link--Color:var(--pf-global--link--Color);--pf-c-button--m-link--hover--BackgroundColor:transparent;--pf-c-button--m-link--hover--Color:var(--pf-global--link--Color--hover);--pf-c-button--m-link--focus--BackgroundColor:transparent;--pf-c-button--m-link--focus--Color:var(--pf-global--link--Color--hover);--pf-c-button--m-link--active--BackgroundColor:transparent;--pf-c-button--m-link--active--Color:var(--pf-global--link--Color--hover);--pf-c-button--m-link--disabled--BackgroundColor:transparent;--pf-c-button--m-link--m-inline--FontSize:inherit;--pf-c-button--m-link--m-inline--hover--TextDecoration:var(--pf-global--link--TextDecoration--hover);--pf-c-button--m-link--m-inline--hover--Color:var(--pf-global--link--Color--hover);--pf-c-button--m-plain--BackgroundColor:transparent;--pf-c-button--m-plain--Color:var(--pf-global--Color--200);--pf-c-button--m-plain--hover--BackgroundColor:transparent;--pf-c-button--m-plain--hover--Color:var(--pf-global--Color--100);--pf-c-button--m-plain--focus--BackgroundColor:transparent;--pf-c-button--m-plain--focus--Color:var(--pf-global--Color--100);--pf-c-button--m-plain--active--BackgroundColor:transparent;--pf-c-button--m-plain--active--Color:var(--pf-global--Color--100);--pf-c-button--m-plain--disabled--Color:var(--pf-global--disabled-color--200);--pf-c-button--m-plain--disabled--BackgroundColor:transparent;--pf-c-button--m-control--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-button--m-control--Color:var(--pf-global--Color--100);--pf-c-button--m-control--BorderRadius:0;--pf-c-button--m-control--after--BorderWidth:var(--pf-global--BorderWidth--sm);--pf-c-button--m-control--after--BorderTopColor:var(--pf-global--BorderColor--300);--pf-c-button--m-control--after--BorderRightColor:var(--pf-global--BorderColor--300);--pf-c-button--m-control--after--BorderBottomColor:var(--pf-global--BorderColor--200);--pf-c-button--m-control--after--BorderLeftColor:var(--pf-global--BorderColor--300);--pf-c-button--m-control--disabled--BackgroundColor:var(--pf-global--disabled-color--300);--pf-c-button--m-control--hover--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-button--m-control--hover--Color:var(--pf-global--Color--100);--pf-c-button--m-control--hover--after--BorderBottomWidth:var(--pf-global--BorderWidth--md);--pf-c-button--m-control--hover--after--BorderBottomColor:var(--pf-global--active-color--100);--pf-c-button--m-control--active--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-button--m-control--active--Color:var(--pf-global--Color--100);--pf-c-button--m-control--active--after--BorderBottomWidth:var(--pf-global--BorderWidth--md);--pf-c-button--m-control--active--after--BorderBottomColor:var(--pf-global--active-color--100);--pf-c-button--m-control--focus--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-button--m-control--focus--Color:var(--pf-global--Color--100);--pf-c-button--m-control--focus--after--BorderBottomWidth:var(--pf-global--BorderWidth--md);--pf-c-button--m-control--focus--after--BorderBottomColor:var(--pf-global--active-color--100);--pf-c-button--m-control--m-expanded--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-button--m-control--m-expanded--Color:var(--pf-global--Color--100);--pf-c-button--m-control--m-expanded--after--BorderBottomWidth:var(--pf-global--BorderWidth--md);--pf-c-button--m-control--m-expanded--after--BorderBottomColor:var(--pf-global--active-color--100);--pf-c-button--m-small--FontSize:var(--pf-global--FontSize--sm);--pf-c-button--m-display-lg--PaddingTop:var(--pf-global--spacer--md);--pf-c-button--m-display-lg--PaddingRight:var(--pf-global--spacer--xl);--pf-c-button--m-display-lg--PaddingBottom:var(--pf-global--spacer--md);--pf-c-button--m-display-lg--PaddingLeft:var(--pf-global--spacer--xl);--pf-c-button--m-display-lg--FontWeight:var(--pf-global--FontWeight--bold);--pf-c-button--m-link--m-display-lg--FontSize:var(--pf-global--FontSize--lg);--pf-c-button__icon--m-start--MarginRight:var(--pf-global--spacer--xs);--pf-c-button__icon--m-end--MarginLeft:var(--pf-global--spacer--xs);--pf-c-button__progress--width:calc(var(--pf-global--icon--FontSize--md) + var(--pf-global--spacer--sm));--pf-c-button__progress--Opacity:0;--pf-c-button__progress--TranslateY:-50%;--pf-c-button__progress--Top:50%;--pf-c-button__progress--Left:var(--pf-global--spacer--md);--pf-c-button--m-progress--TransitionProperty:padding;--pf-c-button--m-progress--TransitionDuration:var(--pf-global--TransitionDuration);--pf-c-button--m-progress--PaddingRight:calc(var(--pf-global--spacer--md) + var(--pf-c-button__progress--width)/2);--pf-c-button--m-progress--PaddingLeft:calc(var(--pf-global--spacer--md) + var(--pf-c-button__progress--width)/2);--pf-c-button--m-in-progress--PaddingRight:var(--pf-global--spacer--md);--pf-c-button--m-in-progress--PaddingLeft:calc(var(--pf-global--spacer--md) + var(--pf-c-button__progress--width));position:relative;display:inline-block;padding:var(--pf-c-button--PaddingTop) var(--pf-c-button--PaddingRight) var(--pf-c-button--PaddingBottom) var(--pf-c-button--PaddingLeft);font-size:var(--pf-c-button--FontSize);font-weight:var(--pf-c-button--FontWeight);line-height:var(--pf-c-button--LineHeight);text-align:center;white-space:nowrap;user-select:none;border:0;border-radius:var(--pf-c-button--BorderRadius)}.pf-c-button:after{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none;content:"";border:var(--pf-c-button--after--BorderWidth) solid;border-color:var(--pf-c-button--after--BorderColor);border-radius:var(--pf-c-button--after--BorderRadius)}.pf-c-button:hover{--pf-c-button--after--BorderWidth:var(--pf-c-button--hover--after--BorderWidth);text-decoration:none}.pf-c-button:focus{--pf-c-button--after--BorderWidth:var(--pf-c-button--focus--after--BorderWidth)}.pf-c-button.pf-m-active,.pf-c-button:active{--pf-c-button--after--BorderWidth:var(--pf-c-button--active--after--BorderWidth)}.pf-c-button.pf-m-block{display:block;width:100%}.pf-c-button.pf-m-small{--pf-c-button--FontSize:var(--pf-c-button--m-small--FontSize)}.pf-c-button.pf-m-link.pf-m-display-lg,.pf-c-button.pf-m-primary.pf-m-display-lg,.pf-c-button.pf-m-secondary.pf-m-display-lg,.pf-c-button.pf-m-tertiary.pf-m-display-lg{--pf-c-button--PaddingTop:var(--pf-c-button--m-display-lg--PaddingTop);--pf-c-button--PaddingRight:var(--pf-c-button--m-display-lg--PaddingRight);--pf-c-button--PaddingBottom:var(--pf-c-button--m-display-lg--PaddingBottom);--pf-c-button--PaddingLeft:var(--pf-c-button--m-display-lg--PaddingLeft);--pf-c-button--FontWeight:var(--pf-c-button--m-display-lg--FontWeight)}.pf-c-button.pf-m-primary{color:var(--pf-c-button--m-primary--Color);background-color:var(--pf-c-button--m-primary--BackgroundColor)}.pf-c-button.pf-m-primary:hover{--pf-c-button--m-primary--Color:var(--pf-c-button--m-primary--hover--Color);--pf-c-button--m-primary--BackgroundColor:var(--pf-c-button--m-primary--hover--BackgroundColor)}.pf-c-button.pf-m-primary:focus{--pf-c-button--m-primary--Color:var(--pf-c-button--m-primary--focus--Color);--pf-c-button--m-primary--BackgroundColor:var(--pf-c-button--m-primary--focus--BackgroundColor)}.pf-c-button.pf-m-primary.pf-m-active,.pf-c-button.pf-m-primary:active{--pf-c-button--m-primary--Color:var(--pf-c-button--m-primary--active--Color);--pf-c-button--m-primary--BackgroundColor:var(--pf-c-button--m-primary--active--BackgroundColor)}.pf-c-button.pf-m-secondary{--pf-c-button--after--BorderColor:var(--pf-c-button--m-secondary--after--BorderColor);color:var(--pf-c-button--m-secondary--Color);background-color:var(--pf-c-button--m-secondary--BackgroundColor)}.pf-c-button.pf-m-secondary:hover{--pf-c-button--m-secondary--Color:var(--pf-c-button--m-secondary--hover--Color);--pf-c-button--m-secondary--BackgroundColor:var(--pf-c-button--m-secondary--hover--BackgroundColor);--pf-c-button--after--BorderColor:var(--pf-c-button--m-secondary--hover--after--BorderColor)}.pf-c-button.pf-m-secondary:focus{--pf-c-button--m-secondary--Color:var(--pf-c-button--m-secondary--focus--Color);--pf-c-button--m-secondary--BackgroundColor:var(--pf-c-button--m-secondary--focus--BackgroundColor);--pf-c-button--after--BorderColor:var(--pf-c-button--m-secondary--focus--after--BorderColor)}.pf-c-button.pf-m-secondary.pf-m-active,.pf-c-button.pf-m-secondary:active{--pf-c-button--m-secondary--Color:var(--pf-c-button--m-secondary--active--Color);--pf-c-button--m-secondary--BackgroundColor:var(--pf-c-button--m-secondary--active--BackgroundColor);--pf-c-button--after--BorderColor:var(--pf-c-button--m-secondary--active--after--BorderColor)}.pf-c-button.pf-m-tertiary{--pf-c-button--after--BorderColor:var(--pf-c-button--m-tertiary--after--BorderColor);color:var(--pf-c-button--m-tertiary--Color);background-color:var(--pf-c-button--m-tertiary--BackgroundColor)}.pf-c-button.pf-m-tertiary:hover{--pf-c-button--m-tertiary--Color:var(--pf-c-button--m-tertiary--hover--Color);--pf-c-button--m-tertiary--BackgroundColor:var(--pf-c-button--m-tertiary--hover--BackgroundColor);--pf-c-button--after--BorderColor:var(--pf-c-button--m-tertiary--hover--after--BorderColor)}.pf-c-button.pf-m-tertiary:focus{--pf-c-button--m-tertiary--Color:var(--pf-c-button--m-tertiary--focus--Color);--pf-c-button--m-tertiary--BackgroundColor:var(--pf-c-button--m-tertiary--focus--BackgroundColor);--pf-c-button--after--BorderColor:var(--pf-c-button--m-tertiary--focus--after--BorderColor)}.pf-c-button.pf-m-tertiary.pf-m-active,.pf-c-button.pf-m-tertiary:active{--pf-c-button--m-tertiary--Color:var(--pf-c-button--m-tertiary--active--Color);--pf-c-button--m-tertiary--BackgroundColor:var(--pf-c-button--m-tertiary--active--BackgroundColor);--pf-c-button--after--BorderColor:var(--pf-c-button--m-tertiary--active--after--BorderColor)}.pf-c-button.pf-m-danger{color:var(--pf-c-button--m-danger--Color);background-color:var(--pf-c-button--m-danger--BackgroundColor)}.pf-c-button.pf-m-danger:hover{--pf-c-button--m-danger--Color:var(--pf-c-button--m-danger--hover--Color);--pf-c-button--m-danger--BackgroundColor:var(--pf-c-button--m-danger--hover--BackgroundColor)}.pf-c-button.pf-m-danger:focus{--pf-c-button--m-danger--Color:var(--pf-c-button--m-danger--focus--Color);--pf-c-button--m-danger--BackgroundColor:var(--pf-c-button--m-danger--focus--BackgroundColor)}.pf-c-button.pf-m-danger.pf-m-active,.pf-c-button.pf-m-danger:active{--pf-c-button--m-danger--Color:var(--pf-c-button--m-danger--active--Color);--pf-c-button--m-danger--BackgroundColor:var(--pf-c-button--m-danger--active--BackgroundColor)}.pf-c-button.pf-m-warning{color:var(--pf-c-button--m-warning--Color);background-color:var(--pf-c-button--m-warning--BackgroundColor)}.pf-c-button.pf-m-warning:hover{--pf-c-button--m-warning--Color:var(--pf-c-button--m-warning--hover--Color);--pf-c-button--m-warning--BackgroundColor:var(--pf-c-button--m-warning--hover--BackgroundColor)}.pf-c-button.pf-m-warning:focus{--pf-c-button--m-warning--Color:var(--pf-c-button--m-warning--focus--Color);--pf-c-button--m-warning--BackgroundColor:var(--pf-c-button--m-warning--focus--BackgroundColor)}.pf-c-button.pf-m-warning.pf-m-active,.pf-c-button.pf-m-warning:active{--pf-c-button--m-warning--Color:var(--pf-c-button--m-warning--active--Color);--pf-c-button--m-warning--BackgroundColor:var(--pf-c-button--m-warning--active--BackgroundColor)}.pf-c-button.pf-m-link{--pf-c-button--disabled--BackgroundColor:var(--pf-c-button--m-link--disabled--BackgroundColor);color:var(--pf-c-button--m-link--Color);background-color:var(--pf-c-button--m-link--BackgroundColor)}.pf-c-button.pf-m-link:not(.pf-m-inline):hover{--pf-c-button--m-link--Color:var(--pf-c-button--m-link--hover--Color);--pf-c-button--m-link--BackgroundColor:var(--pf-c-button--m-link--hover--BackgroundColor)}.pf-c-button.pf-m-link:not(.pf-m-inline):focus{--pf-c-button--m-link--Color:var(--pf-c-button--m-link--focus--Color);--pf-c-button--m-link--BackgroundColor:var(--pf-c-button--m-link--focus--BackgroundColor)}.pf-c-button.pf-m-link:not(.pf-m-inline).pf-m-active,.pf-c-button.pf-m-link:not(.pf-m-inline):active{--pf-c-button--m-link--Color:var(--pf-c-button--m-link--active--Color);--pf-c-button--m-link--BackgroundColor:var(--pf-c-button--m-link--active--BackgroundColor)}.pf-c-button.pf-m-link.pf-m-inline{--pf-c-button--FontSize:var(--pf-c-button--m-link--m-inline--FontSize);display:inline;padding:0;text-align:left;white-space:normal;cursor:pointer}.pf-c-button.pf-m-link.pf-m-inline:hover{--pf-c-button--m-link--Color:var(--pf-c-button--m-link--m-inline--hover--Color);text-decoration:var(--pf-c-button--m-link--m-inline--hover--TextDecoration)}.pf-c-button.pf-m-link.pf-m-display-lg{--pf-c-button--FontSize:var(--pf-c-button--m-link--m-display-lg--FontSize)}.pf-c-button.pf-m-control{--pf-c-button--BorderRadius:var(--pf-c-button--m-control--BorderRadius);--pf-c-button--disabled--BackgroundColor:var(--pf-c-button--m-control--disabled--BackgroundColor);--pf-c-button--after--BorderWidth:var(--pf-c-button--m-control--after--BorderWidth);--pf-c-button--after--BorderColor:var(--pf-c-button--m-control--after--BorderTopColor) var(--pf-c-button--m-control--after--BorderRightColor) var(--pf-c-button--m-control--after--BorderBottomColor) var(--pf-c-button--m-control--after--BorderLeftColor);color:var(--pf-c-button--m-control--Color);background-color:var(--pf-c-button--m-control--BackgroundColor)}.pf-c-button.pf-m-control:after{border-radius:initial}.pf-c-button.pf-m-control:hover{--pf-c-button--m-control--Color:var(--pf-c-button--m-control--hover--Color);--pf-c-button--m-control--BackgroundColor:var(--pf-c-button--m-control--hover--BackgroundColor);--pf-c-button--m-control--after--BorderBottomColor:var(--pf-c-button--m-control--hover--after--BorderBottomColor)}.pf-c-button.pf-m-control:hover:after{border-bottom-width:var(--pf-c-button--m-control--hover--after--BorderBottomWidth)}.pf-c-button.pf-m-control.pf-m-active,.pf-c-button.pf-m-control:active{--pf-c-button--m-control--Color:var(--pf-c-button--m-control--active--Color);--pf-c-button--m-control--BackgroundColor:var(--pf-c-button--m-control--active--BackgroundColor);--pf-c-button--m-control--after--BorderBottomColor:var(--pf-c-button--m-control--active--after--BorderBottomColor)}.pf-c-button.pf-m-control.pf-m-active:after,.pf-c-button.pf-m-control:active:after{border-bottom-width:var(--pf-c-button--m-control--active--after--BorderBottomWidth)}.pf-c-button.pf-m-control:focus{--pf-c-button--m-control--Color:var(--pf-c-button--m-control--focus--Color);--pf-c-button--m-control--BackgroundColor:var(--pf-c-button--m-control--focus--BackgroundColor);--pf-c-button--m-control--after--BorderBottomColor:var(--pf-c-button--m-control--focus--after--BorderBottomColor)}.pf-c-button.pf-m-control:focus:after{border-bottom-width:var(--pf-c-button--m-control--focus--after--BorderBottomWidth)}.pf-c-button.pf-m-control.pf-m-expanded{--pf-c-button--m-control--Color:var(--pf-c-button--m-control--m-expanded--Color);--pf-c-button--m-control--BackgroundColor:var(--pf-c-button--m-control--m-expanded--BackgroundColor);--pf-c-button--m-control--after--BorderBottomColor:var(--pf-c-button--m-control--m-expanded--after--BorderBottomColor)}.pf-c-button.pf-m-control.pf-m-expanded:after{border-bottom-width:var(--pf-c-button--m-control--m-expanded--after--BorderBottomWidth)}.pf-c-button.pf-m-plain{--pf-c-button--disabled--Color:var(--pf-c-button--m-plain--disabled--Color);--pf-c-button--disabled--BackgroundColor:var(--pf-c-button--m-plain--disabled--BackgroundColor);color:var(--pf-c-button--m-plain--Color);background-color:var(--pf-c-button--m-plain--BackgroundColor)}.pf-c-button.pf-m-plain:hover{--pf-c-button--m-plain--Color:var(--pf-c-button--m-plain--hover--Color);--pf-c-button--m-plain--BackgroundColor:var(--pf-c-button--m-plain--hover--BackgroundColor)}.pf-c-button.pf-m-plain.pf-m-active,.pf-c-button.pf-m-plain:active{--pf-c-button--m-plain--Color:var(--pf-c-button--m-plain--active--Color);--pf-c-button--m-plain--BackgroundColor:var(--pf-c-button--m-plain--active--BackgroundColor)}.pf-c-button.pf-m-plain:focus{--pf-c-button--m-plain--Color:var(--pf-c-button--m-plain--focus--Color);--pf-c-button--m-plain--BackgroundColor:var(--pf-c-button--m-plain--focus--BackgroundColor)}.pf-c-button.pf-m-disabled,.pf-c-button:disabled{pointer-events:none}.pf-c-button.pf-m-aria-disabled,.pf-c-button.pf-m-disabled,.pf-c-button:disabled{--pf-c-button--after--BorderColor:var(--pf-c-button--disabled--after--BorderColor);color:var(--pf-c-button--disabled--Color);background-color:var(--pf-c-button--disabled--BackgroundColor)}.pf-c-button.pf-m-aria-disabled{--pf-c-button--after--BorderWidth:0;--pf-c-button--m-link--m-inline--hover--TextDecoration:none;cursor:default}.pf-c-button.pf-m-progress{--pf-c-button--PaddingRight:var(--pf-c-button--m-progress--PaddingRight);--pf-c-button--PaddingLeft:var(--pf-c-button--m-progress--PaddingLeft);transition:var(--pf-c-button--m-progress--TransitionProperty) var(--pf-c-button--m-progress--TransitionDuration)}.pf-c-button.pf-m-in-progress{--pf-c-button--PaddingRight:var(--pf-c-button--m-in-progress--PaddingRight);--pf-c-button--PaddingLeft:var(--pf-c-button--m-in-progress--PaddingLeft)}.pf-c-button__icon.pf-m-start{margin-right:var(--pf-c-button__icon--m-start--MarginRight)}.pf-c-button__icon.pf-m-end{margin-left:var(--pf-c-button__icon--m-end--MarginLeft)}.pf-c-button__progress{position:absolute;top:var(--pf-c-button__progress--Top);left:var(--pf-c-button__progress--Left);line-height:1;transform:translateY(var(--pf-c-button__progress--TranslateY))}.pf-c-button__progress .pf-c-spinner{--pf-c-spinner--Color:currentColor}.pf-m-overpass-font .pf-c-button{--pf-c-button--FontWeight:var(--pf-global--FontWeight--semi-bold)}.pf-c-calendar-month{--pf-c-calendar-month--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-calendar-month--PaddingTop:var(--pf-global--spacer--lg);--pf-c-calendar-month--PaddingRight:var(--pf-global--spacer--lg);--pf-c-calendar-month--PaddingBottom:var(--pf-global--spacer--md);--pf-c-calendar-month--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-calendar-month--FontSize:var(--pf-global--FontSize--sm);--pf-c-calendar-month__header--MarginBottom:var(--pf-global--spacer--md);--pf-c-calendar-month__header-year--Width:8ch;--pf-c-calendar-month__header-nav-control--MarginRight:0;--pf-c-calendar-month__header-nav-control--MarginLeft:0;--pf-c-calendar-month__header-nav-control--m-prev-month--MarginRight:var(--pf-global--spacer--sm);--pf-c-calendar-month__header-nav-control--m-prev-month--MarginLeft:calc(var(--pf-global--spacer--md)*-1);--pf-c-calendar-month__header-nav-control--m-next-month--MarginRight:calc(var(--pf-global--spacer--md)*-1);--pf-c-calendar-month__header-nav-control--m-next-month--MarginLeft:var(--pf-global--spacer--sm);--pf-c-calendar-month__days--BorderBottomWidth:var(--pf-global--BorderWidth--sm);--pf-c-calendar-month__days--BorderBottomColor:var(--pf-global--BorderColor--100);--pf-c-calendar-month__day--PaddingBottom:var(--pf-global--spacer--md);--pf-c-calendar-month__day--FontWeight:var(--pf-global--FontWeight--normal);--pf-c-calendar-month__dates-cell--PaddingTop:0.125rem;--pf-c-calendar-month__dates-cell--PaddingRight:0.125rem;--pf-c-calendar-month__dates-cell--PaddingBottom:0.125rem;--pf-c-calendar-month__dates-cell--PaddingLeft:0.125rem;--pf-c-calendar-month__dates-row--first-child__dates-cell--PaddingTop:var(--pf-global--spacer--sm);--pf-c-calendar-month__dates-cell--m-current__date--BackgroundColor:var(--pf-global--BackgroundColor--200);--pf-c-calendar-month__dates-cell--m-selected__date--BackgroundColor:var(--pf-global--active-color--100);--pf-c-calendar-month__dates-cell--m-selected__date--hover--BackgroundColor:var(--pf-global--active-color--100);--pf-c-calendar-month__dates-cell--m-selected__date--focus--BackgroundColor:var(--pf-global--primary-color--200);--pf-c-calendar-month__dates-cell--m-selected__date--focus--after--BorderColor:var(--pf-global--primary-color--200);--pf-c-calendar-month__date-cell--m-selected__date--focus--BoxShadow:0 0 0.3125rem var(--pf-global--primary-color--100);--pf-c-calendar-month__dates-cell--m-selected__date--Color:var(--pf-global--Color--light-100);--pf-c-calendar-month__dates-cell--before--BackgroundColor:transparent;--pf-c-calendar-month__dates-cell--before--Top:0;--pf-c-calendar-month__dates-cell--before--Right:0;--pf-c-calendar-month__dates-cell--before--Bottom:var(--pf-c-calendar-month__dates-cell--PaddingBottom);--pf-c-calendar-month__dates-cell--before--Left:0;--pf-c-calendar-month__dates-cell--m-in-range--before--BackgroundColor:var(--pf-global--palette--blue-50);--pf-c-calendar-month__dates-cell--m-in-range--m-start-range--before--Left:50%;--pf-c-calendar-month__dates-cell--m-in-range--m-end-range--before--Right:50%;--pf-c-calendar-month__dates-cell--m-in-range__date--hover--BackgroundColor:var(--pf-global--palette--blue-100);--pf-c-calendar-month__dates-cell--m-in-range__date--focus--BackgroundColor:var(--pf-global--palette--blue-100);--pf-c-calendar-month__dates-cell--m-adjacent-month__date--Color:var(--pf-global--disabled-color--100);--pf-c-calendar-month__date--Width:4ch;--pf-c-calendar-month__date--Height:4ch;--pf-c-calendar-month__date--BorderRadius:var(--pf-global--BorderRadius--lg);--pf-c-calendar-month__date--Color:var(--pf-global--Color--100);--pf-c-calendar-month__date--BackgroundColor:transparent;--pf-c-calendar-month__date--disabled--Color:var(--pf-global--disabled-color--200);--pf-c-calendar-month__date--after--BorderWidth:var(--pf-global--BorderWidth--md);--pf-c-calendar-month__date--after--BorderColor:transparent;--pf-c-calendar-month__date--hover--BackgroundColor:var(--pf-global--palette--blue-50);--pf-c-calendar-month__date--focus--BackgroundColor:var(--pf-global--palette--blue-50);--pf-c-calendar-month__date--focus--after--BorderColor:var(--pf-global--active-color--100);--pf-c-calendar-month__date--focus--BoxShadow:none;color:var(--pf-global--Color--100);display:inline-flex;flex-direction:column;padding:var(--pf-c-calendar-month--PaddingTop) var(--pf-c-calendar-month--PaddingRight) var(--pf-c-calendar-month--PaddingBottom) var(--pf-c-calendar-month--PaddingLeft);font-size:var(--pf-c-calendar-month--FontSize);background-color:var(--pf-c-calendar-month--BackgroundColor)}.pf-c-calendar-month__header{display:flex;margin-bottom:var(--pf-c-calendar-month__header--MarginBottom)}.pf-c-calendar-month__header-nav-control{margin-right:var(--pf-c-calendar-month__header-nav-control--MarginRight);margin-left:var(--pf-c-calendar-month__header-nav-control--MarginLeft)}.pf-c-calendar-month__header-nav-control.pf-m-prev-month{--pf-c-calendar-month__header-nav-control--MarginRight:var(--pf-c-calendar-month__header-nav-control--m-prev-month--MarginRight);--pf-c-calendar-month__header-nav-control--MarginLeft:var(--pf-c-calendar-month__header-nav-control--m-prev-month--MarginLeft)}.pf-c-calendar-month__header-nav-control.pf-m-next-month{--pf-c-calendar-month__header-nav-control--MarginRight:var(--pf-c-calendar-month__header-nav-control--m-next-month--MarginRight);--pf-c-calendar-month__header-nav-control--MarginLeft:var(--pf-c-calendar-month__header-nav-control--m-next-month--MarginLeft)}.pf-c-calendar-month__header-month{flex-grow:1}.pf-c-calendar-month__header-year{width:var(--pf-c-calendar-month__header-year--Width)}.pf-c-calendar-month__calendar{table-layout:fixed}.pf-c-calendar-month__days{border-bottom:var(--pf-c-calendar-month__days--BorderBottomWidth) solid var(--pf-c-calendar-month__days--BorderBottomColor)}.pf-c-calendar-month__day{padding-bottom:var(--pf-c-calendar-month__day--PaddingBottom);font-weight:var(--pf-c-calendar-month__day--FontWeight);text-align:center}.pf-c-calendar-month__dates-row:first-child{--pf-c-calendar-month__dates-cell--PaddingTop:var(--pf-c-calendar-month__dates-row--first-child__dates-cell--PaddingTop)}.pf-c-calendar-month__dates-cell{--pf-c-calendar-month__dates-cell--before--Top:var(--pf-c-calendar-month__dates-cell--PaddingTop);position:relative;padding:var(--pf-c-calendar-month__dates-cell--PaddingTop) var(--pf-c-calendar-month__dates-cell--PaddingRight) var(--pf-c-calendar-month__dates-cell--PaddingBottom) var(--pf-c-calendar-month__dates-cell--PaddingLeft);text-align:center}.pf-c-calendar-month__dates-cell:before{position:absolute;top:var(--pf-c-calendar-month__dates-cell--before--Top);right:var(--pf-c-calendar-month__dates-cell--before--Right);bottom:var(--pf-c-calendar-month__dates-cell--before--Bottom);left:var(--pf-c-calendar-month__dates-cell--before--Left);content:"";background-color:var(--pf-c-calendar-month__dates-cell--before--BackgroundColor)}.pf-c-calendar-month__dates-cell.pf-m-current{--pf-c-calendar-month__date--BackgroundColor:var(--pf-c-calendar-month__dates-cell--m-current__date--BackgroundColor)}.pf-c-calendar-month__dates-cell.pf-m-in-range{--pf-c-calendar-month__dates-cell--before--BackgroundColor:var(--pf-c-calendar-month__dates-cell--m-in-range--before--BackgroundColor);--pf-c-calendar-month__date--hover--BackgroundColor:var(--pf-c-calendar-month__dates-cell--m-in-range__date--hover--BackgroundColor);--pf-c-calendar-month__date--focus--BackgroundColor:var(--pf-c-calendar-month__dates-cell--m-in-range__date--focus--BackgroundColor)}.pf-c-calendar-month__dates-cell.pf-m-start-range{--pf-c-calendar-month__dates-cell--before--Left:var(--pf-c-calendar-month__dates-cell--m-in-range--m-start-range--before--Left)}.pf-c-calendar-month__dates-cell.pf-m-end-range{--pf-c-calendar-month__dates-cell--before--Right:var(--pf-c-calendar-month__dates-cell--m-in-range--m-end-range--before--Right)}.pf-c-calendar-month__dates-cell.pf-m-adjacent-month{--pf-c-calendar-month__date--Color:var(--pf-c-calendar-month__dates-cell--m-adjacent-month__date--Color)}.pf-c-calendar-month__dates-cell.pf-m-selected{--pf-c-calendar-month__date--BackgroundColor:var(--pf-c-calendar-month__dates-cell--m-selected__date--BackgroundColor);--pf-c-calendar-month__date--hover--BackgroundColor:var(--pf-c-calendar-month__dates-cell--m-selected__date--hover--BackgroundColor);--pf-c-calendar-month__date--focus--BackgroundColor:var(--pf-c-calendar-month__dates-cell--m-selected__date--focus--BackgroundColor);--pf-c-calendar-month__date--focus--after--BorderColor:var(--pf-c-calendar-month__dates-cell--m-selected__date--focus--after--BorderColor);--pf-c-calendar-month__date--focus--BoxShadow:var(--pf-c-calendar-month__date-cell--m-selected__date--focus--BoxShadow);--pf-c-calendar-month__date--Color:var(--pf-c-calendar-month__dates-cell--m-selected__date--Color)}.pf-c-calendar-month__dates-cell.pf-m-disabled{--pf-c-calendar-month__dates-cell--before--BackgroundColor:transparent;--pf-c-calendar-month__date--BackgroundColor:transparent}.pf-c-calendar-month__date{position:relative;display:inline-flex;align-items:center;justify-content:center;width:var(--pf-c-calendar-month__date--Width);height:var(--pf-c-calendar-month__date--Height);line-height:1;color:var(--pf-c-calendar-month__date--Color);background-color:var(--pf-c-calendar-month__date--BackgroundColor);border:0}.pf-c-calendar-month__date:after{position:absolute;top:0;right:0;bottom:0;left:0;content:"";border:var(--pf-c-calendar-month__date--after--BorderWidth) solid var(--pf-c-calendar-month__date--after--BorderColor)}.pf-c-calendar-month__date,.pf-c-calendar-month__date:after{border-radius:var(--pf-c-calendar-month__date--BorderRadius)}.pf-c-calendar-month__date.pf-m-hover,.pf-c-calendar-month__date:hover{--pf-c-calendar-month__date--BackgroundColor:var(--pf-c-calendar-month__date--hover--BackgroundColor)}.pf-c-calendar-month__date.pf-m-focus,.pf-c-calendar-month__date:focus{--pf-c-calendar-month__date--BackgroundColor:var(--pf-c-calendar-month__date--focus--BackgroundColor);--pf-c-calendar-month__date--after--BorderColor:var(--pf-c-calendar-month__date--focus--after--BorderColor);outline:0;box-shadow:var(--pf-c-calendar-month__date--focus--BoxShadow)}.pf-c-calendar-month__date:disabled{pointer-events:none;--pf-c-calendar-month__date--Color:var(--pf-c-calendar-month__date--disabled--Color);--pf-c-calendar-month__date--hover--focus--BorderColor:transparent}.pf-c-card{--pf-c-card--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-card--BoxShadow:var(--pf-global--BoxShadow--sm);--pf-c-card--m-hoverable--hover--BoxShadow:var(--pf-global--BoxShadow--lg);--pf-c-card--m-selectable--hover--BoxShadow:var(--pf-global--BoxShadow--lg);--pf-c-card--m-selectable--focus--BoxShadow:var(--pf-global--BoxShadow--lg);--pf-c-card--m-selectable--active--BoxShadow:var(--pf-global--BoxShadow--lg);--pf-c-card--m-selectable--m-selected--BoxShadow:var(--pf-global--BoxShadow--lg);--pf-c-card--m-selectable--m-selected--before--Height:var(--pf-global--BorderWidth--lg);--pf-c-card--m-selectable--m-selected--before--BackgroundColor:var(--pf-global--active-color--100);--pf-c-card--m-compact__body--FontSize:var(--pf-global--FontSize--sm);--pf-c-card--m-compact__footer--FontSize:var(--pf-global--FontSize--sm);--pf-c-card--m-compact--first-child--PaddingTop:var(--pf-global--spacer--md);--pf-c-card--m-compact--child--PaddingRight:var(--pf-global--spacer--md);--pf-c-card--m-compact--child--PaddingBottom:var(--pf-global--spacer--md);--pf-c-card--m-compact--child--PaddingLeft:var(--pf-global--spacer--md);--pf-c-card--m-compact--c-divider--child--PaddingTop:var(--pf-global--spacer--md);--pf-c-card--m-compact__title--not--last-child--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-card--m-flat--BorderWidth:var(--pf-global--BorderWidth--sm);--pf-c-card--m-flat--BorderColor:var(--pf-global--BorderColor--100);--pf-c-card--first-child--PaddingTop:var(--pf-global--spacer--lg);--pf-c-card--child--PaddingRight:var(--pf-global--spacer--lg);--pf-c-card--child--PaddingBottom:var(--pf-global--spacer--lg);--pf-c-card--child--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-card--c-divider--child--PaddingTop:var(--pf-global--spacer--lg);--pf-c-card__header-toggle--MarginTop:calc(var(--pf-global--spacer--form-element)*-1);--pf-c-card__header-toggle--MarginRight:var(--pf-global--spacer--xs);--pf-c-card__header-toggle--MarginBottom:calc(var(--pf-global--spacer--form-element)*-1);--pf-c-card__header-toggle--MarginLeft:calc(var(--pf-global--spacer--md)*-1);--pf-c-card__header-toggle-icon--Transition:var(--pf-global--Transition);--pf-c-card--m-expanded__header-toggle-icon--Rotate:90deg;--pf-c-card__title--FontSize:var(--pf-global--FontSize--md);--pf-c-card__title--FontWeight:var(--pf-global--FontWeight--bold);--pf-c-card__title--not--last-child--PaddingBottom:var(--pf-global--spacer--md);--pf-c-card__body--FontSize:var(--pf-global--FontSize--md);--pf-c-card__footer--FontSize:var(--pf-global--FontSize--md);--pf-c-card__actions--PaddingLeft:var(--pf-global--spacer--md);--pf-c-card__actions--child--MarginLeft:var(--pf-global--spacer--sm);display:flex;flex-direction:column;background-color:var(--pf-c-card--BackgroundColor);box-shadow:var(--pf-c-card--BoxShadow)}.pf-c-card.pf-m-hoverable:hover{box-shadow:var(--pf-c-card--m-hoverable--hover--BoxShadow)}.pf-c-card.pf-m-selectable{position:relative;cursor:pointer}.pf-c-card.pf-m-selectable:hover{box-shadow:var(--pf-c-card--m-selectable--hover--BoxShadow)}.pf-c-card.pf-m-selectable:focus{box-shadow:var(--pf-c-card--m-selectable--focus--BoxShadow)}.pf-c-card.pf-m-selectable:active{box-shadow:var(--pf-c-card--m-selectable--active--BoxShadow)}.pf-c-card.pf-m-selectable.pf-m-selected{box-shadow:var(--pf-c-card--m-selectable--m-selected--BoxShadow)}.pf-c-card.pf-m-selectable.pf-m-selected:before{position:absolute;top:0;right:0;left:0;height:var(--pf-c-card--m-selectable--m-selected--before--Height);content:"";background-color:var(--pf-c-card--m-selectable--m-selected--before--BackgroundColor)}.pf-c-card.pf-m-compact{--pf-c-card__body--FontSize:var(--pf-c-card--m-compact__body--FontSize);--pf-c-card__footer--FontSize:var(--pf-c-card--m-compact__footer--FontSize);--pf-c-card--first-child--PaddingTop:var(--pf-c-card--m-compact--first-child--PaddingTop);--pf-c-card--child--PaddingRight:var(--pf-c-card--m-compact--child--PaddingRight);--pf-c-card--child--PaddingBottom:var(--pf-c-card--m-compact--child--PaddingBottom);--pf-c-card--child--PaddingLeft:var(--pf-c-card--m-compact--child--PaddingLeft);--pf-c-card--c-divider--child--PaddingTop:var(--pf-c-card--m-compact--c-divider--child--PaddingTop);--pf-c-card__title--not--last-child--PaddingBottom:var(--pf-c-card--m-compact__title--not--last-child--PaddingBottom)}.pf-c-card.pf-m-flat{--pf-c-card--BoxShadow:none;border:var(--pf-c-card--m-flat--BorderWidth) solid var(--pf-c-card--m-flat--BorderColor)}.pf-c-card.pf-m-expanded .pf-c-card__header-toggle-icon{transform:rotate(var(--pf-c-card--m-expanded__header-toggle-icon--Rotate))}.pf-c-card>.pf-c-divider+.pf-c-card__body,.pf-c-card>.pf-c-divider+.pf-c-card__footer,.pf-c-card>.pf-c-divider+.pf-c-card__header,.pf-c-card>.pf-c-divider+.pf-c-card__title{padding-top:var(--pf-c-card--c-divider--child--PaddingTop)}.pf-c-card__header{display:flex;flex-direction:row;align-items:center}.pf-c-card__header .pf-c-card__title{padding:0}.pf-c-card__header-toggle{align-self:flex-start;margin:var(--pf-c-card__header-toggle--MarginTop) var(--pf-c-card__header-toggle--MarginRight) var(--pf-c-card__header-toggle--MarginBottom) var(--pf-c-card__header-toggle--MarginLeft)}.pf-c-card__header-toggle-icon{display:inline-block;transition:var(--pf-c-card__header-toggle-icon--Transition)}.pf-c-card__title{font-family:var(--pf-c-card__title--FontFamily);font-weight:var(--pf-c-card__title--FontWeight)}.pf-c-card__actions{display:flex;align-items:center;align-self:flex-start;order:1;padding-left:var(--pf-c-card__actions--PaddingLeft);margin:var(--pf-c-card__header-toggle--MarginTop) var(--pf-c-card__header-toggle--MarginRight) var(--pf-c-card__header-toggle--MarginBottom) auto}.pf-c-card__actions>*+*{margin-left:var(--pf-c-card__actions--child--MarginLeft)}.pf-c-card__actions+.pf-c-card__body,.pf-c-card__actions+.pf-c-card__footer,.pf-c-card__actions+.pf-c-card__title{padding:0}.pf-c-card__body,.pf-c-card__footer,.pf-c-card__header,.pf-c-card__title{padding-right:var(--pf-c-card--child--PaddingRight);padding-bottom:var(--pf-c-card--child--PaddingBottom);padding-left:var(--pf-c-card--child--PaddingLeft)}.pf-c-card__body:first-child,.pf-c-card__footer:first-child,.pf-c-card__header:first-child,.pf-c-card__title:first-child{padding-top:var(--pf-c-card--first-child--PaddingTop)}.pf-c-card__header:not(:last-child),.pf-c-card__title:not(:last-child){padding-bottom:var(--pf-c-card__title--not--last-child--PaddingBottom)}.pf-c-card__expandable-content{--pf-c-card--first-child--PaddingTop:0}.pf-c-card__body:not(.pf-m-no-fill){flex:1 1 auto}.pf-c-card__body{font-size:var(--pf-c-card__body--FontSize)}.pf-c-card__footer{font-size:var(--pf-c-card__footer--FontSize)}.pf-m-overpass-font .pf-c-card .pf-c-card__title{font-weight:var(--pf-global--FontWeight--normal)}.pf-c-check{--pf-c-check--GridGap:var(--pf-global--spacer--xs) var(--pf-global--spacer--sm);--pf-c-check__label--disabled--Color:var(--pf-global--disabled-color--100);--pf-c-check__label--Color:var(--pf-global--Color--100);--pf-c-check__label--FontWeight:var(--pf-global--FontWeight--normal);--pf-c-check__label--FontSize:var(--pf-global--FontSize--md);--pf-c-check__label--LineHeight:var(--pf-global--LineHeight--sm);--pf-c-check__input--MarginTop:-0.1875rem;--pf-c-check__description--FontSize:var(--pf-global--FontSize--sm);--pf-c-check__description--Color:var(--pf-global--Color--200);display:grid;grid-template-columns:auto 1fr;grid-gap:var(--pf-c-check--GridGap);align-items:center;justify-items:start}.pf-c-check__label{font-size:var(--pf-c-check__label--FontSize);font-weight:var(--pf-c-check__label--FontWeight);line-height:var(--pf-c-check__label--LineHeight);color:var(--pf-c-check__label--Color)}.pf-c-check__input{margin-top:var(--pf-c-check__input--MarginTop)}.pf-c-check__description{grid-column:2;font-size:var(--pf-c-check__description--FontSize);color:var(--pf-c-check__description--Color)}.pf-c-check__input,.pf-c-check__label,label.pf-c-check{cursor:pointer}.pf-c-check__input.pf-m-disabled,.pf-c-check__input:disabled,.pf-c-check__label.pf-m-disabled,.pf-c-check__label:disabled{--pf-c-check__label--Color:var(--pf-c-check__label--disabled--Color);cursor:not-allowed}.pf-c-chip{--pf-c-chip--PaddingTop:var(--pf-global--spacer--xs);--pf-c-chip--PaddingRight:var(--pf-global--spacer--sm);--pf-c-chip--PaddingBottom:var(--pf-global--spacer--xs);--pf-c-chip--PaddingLeft:var(--pf-global--spacer--sm);--pf-c-chip--BackgroundColor:var(--pf-global--Color--light-100);--pf-c-chip--BorderRadius:var(--pf-global--BorderRadius--sm);--pf-c-chip--before--BorderColor:var(--pf-global--BorderColor--300);--pf-c-chip--before--BorderWidth:var(--pf-global--BorderWidth--sm);--pf-c-chip--before--BorderRadius:var(--pf-c-chip--BorderRadius);--pf-c-chip--m-overflow__text--Color:var(--pf-global--primary-color--100);--pf-c-chip--m-draggable--BackgroundColor:var(--pf-global--BackgroundColor--200);--pf-c-chip--m-draggable--BoxShadow:var(--pf-global--BoxShadow--sm);--pf-c-chip--m-draggable__icon--FontSize:var(--pf-global--icon--FontSize--sm);--pf-c-chip__text--FontSize:var(--pf-global--FontSize--xs);--pf-c-chip__text--Color:var(--pf-global--Color--100);--pf-c-chip__text--MaxWidth:16ch;--pf-c-chip__c-button--PaddingTop:var(--pf-global--spacer--xs);--pf-c-chip__c-button--PaddingRight:var(--pf-global--spacer--sm);--pf-c-chip__c-button--PaddingBottom:var(--pf-global--spacer--xs);--pf-c-chip__c-button--PaddingLeft:var(--pf-global--spacer--sm);--pf-c-chip__c-button--MarginTop:calc(var(--pf-c-chip--PaddingTop)*-1);--pf-c-chip__c-button--MarginRight:calc(var(--pf-c-chip--PaddingRight)/2*-1);--pf-c-chip__c-button--MarginBottom:calc(var(--pf-c-chip--PaddingBottom)*-1);--pf-c-chip__c-button--FontSize:var(--pf-global--FontSize--xs);--pf-c-chip__c-badge--MarginLeft:var(--pf-global--spacer--xs);--pf-c-chip__icon--MarginLeft:var(--pf-global--spacer--sm);color:var(--pf-global--Color--100);position:relative;display:inline-flex;align-items:center;padding:var(--pf-c-chip--PaddingTop) var(--pf-c-chip--PaddingRight) var(--pf-c-chip--PaddingBottom) var(--pf-c-chip--PaddingLeft);list-style:none;background-color:var(--pf-c-chip--BackgroundColor);border-radius:var(--pf-c-chip--BorderRadius)}.pf-c-chip:before{position:absolute;top:0;right:0;bottom:0;left:0;content:"";border:var(--pf-c-chip--before--BorderWidth) solid var(--pf-c-chip--before--BorderColor);border-radius:var(--pf-c-chip--before--BorderRadius)}.pf-c-chip.pf-m-overflow{border:0}.pf-c-chip.pf-m-overflow .pf-c-chip__text{color:var(--pf-c-chip--m-overflow__text--Color)}.pf-c-chip.pf-m-draggable{--pf-c-chip--BackgroundColor:var(--pf-c-chip--m-draggable--BackgroundColor);box-shadow:var(--pf-c-chip--m-draggable--BoxShadow)}.pf-c-chip.pf-m-draggable .pf-c-chip__icon{font-size:var(--pf-c-chip--m-draggable__icon--FontSize)}.pf-c-chip .pf-c-button{--pf-c-button--PaddingTop:var(--pf-c-chip__c-button--PaddingTop);--pf-c-button--PaddingRight:var(--pf-c-chip__c-button--PaddingRight);--pf-c-button--PaddingBottom:var(--pf-c-chip__c-button--PaddingBottom);--pf-c-button--PaddingLeft:var(--pf-c-chip__c-button--PaddingLeft);--pf-c-button--FontSize:var(--pf-c-chip__c-button--FontSize);margin-top:var(--pf-c-chip__c-button--MarginTop);margin-right:var(--pf-c-chip__c-button--MarginRight);margin-bottom:var(--pf-c-chip__c-button--MarginBottom)}.pf-c-chip .pf-c-badge{margin-left:var(--pf-c-chip__c-badge--MarginLeft)}.pf-c-chip__text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;position:relative;max-width:var(--pf-c-chip__text--MaxWidth);font-size:var(--pf-c-chip__text--FontSize);color:var(--pf-c-chip__text--Color)}.pf-c-chip__icon+.pf-c-chip__text,.pf-c-chip__text+.pf-c-chip__icon{margin-left:var(--pf-c-chip__icon--MarginLeft)}.pf-c-chip-group{color:var(--pf-global--Color--100);--pf-c-chip-group__list--MarginBottom:calc(var(--pf-global--spacer--xs)*-1);--pf-c-chip-group__list--MarginRight:calc(var(--pf-global--spacer--xs)*-1);--pf-c-chip-group--m-category--PaddingTop:var(--pf-global--spacer--xs);--pf-c-chip-group--m-category--PaddingRight:var(--pf-global--spacer--xs);--pf-c-chip-group--m-category--PaddingBottom:var(--pf-global--spacer--xs);--pf-c-chip-group--m-category--PaddingLeft:var(--pf-global--spacer--sm);--pf-c-chip-group--m-category--BorderRadius:var(--pf-global--BorderRadius--sm);--pf-c-chip-group--m-category--BackgroundColor:var(--pf-global--BackgroundColor--200);--pf-c-chip-group__label--MarginRight:var(--pf-global--spacer--sm);--pf-c-chip-group__label--FontSize:var(--pf-global--FontSize--sm);--pf-c-chip-group__label--MaxWidth:18ch;--pf-c-chip-group__close--MarginTop:calc(var(--pf-global--spacer--xs)*-1);--pf-c-chip-group__close--MarginBottom:calc(var(--pf-global--spacer--xs)*-1);--pf-c-chip-group__list-item--MarginRight:var(--pf-global--spacer--xs);--pf-c-chip-group__list-item--MarginBottom:var(--pf-global--spacer--xs)}.pf-c-chip-group.pf-m-category{padding:var(--pf-c-chip-group--m-category--PaddingTop) var(--pf-c-chip-group--m-category--PaddingRight) var(--pf-c-chip-group--m-category--PaddingBottom) var(--pf-c-chip-group--m-category--PaddingLeft);background-color:var(--pf-c-chip-group--m-category--BackgroundColor);border-radius:var(--pf-c-chip-group--m-category--BorderRadius)}.pf-c-chip-group__main{display:flex;flex:1;flex-wrap:wrap;align-items:baseline}.pf-c-chip-group__list{margin-right:var(--pf-c-chip-group__list--MarginRight);margin-bottom:var(--pf-c-chip-group__list--MarginBottom)}.pf-c-chip-group,.pf-c-chip-group__list{display:inline-flex;flex-wrap:wrap;align-items:center}.pf-c-chip-group__list-item{display:inline-flex;margin-right:var(--pf-c-chip-group__list-item--MarginRight);margin-bottom:var(--pf-c-chip-group__list-item--MarginBottom)}.pf-c-chip-group__label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:var(--pf-c-chip-group__label--MaxWidth);margin-right:var(--pf-c-chip-group__label--MarginRight);font-size:var(--pf-c-chip-group__label--FontSize)}.pf-c-chip-group__close{display:flex;align-self:flex-start;margin-top:var(--pf-c-chip-group__close--MarginTop);margin-bottom:var(--pf-c-chip-group__close--MarginBottom)}.pf-c-clipboard-copy{--pf-c-clipboard-copy__toggle-icon--Transition:.2s ease-in 0s;--pf-c-clipboard-copy--m-expanded__toggle-icon--Rotate:90deg;--pf-c-clipboard-copy__expandable-content--PaddingTop:var(--pf-global--spacer--md);--pf-c-clipboard-copy__expandable-content--PaddingRight:var(--pf-global--spacer--md);--pf-c-clipboard-copy__expandable-content--PaddingBottom:var(--pf-global--spacer--md);--pf-c-clipboard-copy__expandable-content--PaddingLeft:var(--pf-global--spacer--md);--pf-c-clipboard-copy__expandable-content--BackgroundColor:var(--pf-global--BackgroundColor--light-100);--pf-c-clipboard-copy__expandable-content--BorderTopWidth:0;--pf-c-clipboard-copy__expandable-content--BorderRightWidth:var(--pf-global--BorderWidth--sm);--pf-c-clipboard-copy__expandable-content--BorderBottomWidth:var(--pf-global--BorderWidth--sm);--pf-c-clipboard-copy__expandable-content--BorderLeftWidth:var(--pf-global--BorderWidth--sm);--pf-c-clipboard-copy__expandable-content--BorderColor:var(--pf-global--BorderColor--100);--pf-c-clipboard-copy__expandable-content--OutlineOffset:calc(-1*var(--pf-global--spacer--xs))}.pf-c-clipboard-copy.pf-m-expanded .pf-c-clipboard-copy__toggle-icon{transform:rotate(var(--pf-c-clipboard-copy--m-expanded__toggle-icon--Rotate))}.pf-c-clipboard-copy__group{display:flex}.pf-c-clipboard-copy__group>*+*{margin-left:-1px}.pf-c-clipboard-copy__toggle-icon{transition:var(--pf-c-clipboard-copy__toggle-icon--Transition)}.pf-c-clipboard-copy__expandable-content{padding:var(--pf-c-clipboard-copy__expandable-content--PaddingTop) var(--pf-c-clipboard-copy__expandable-content--PaddingRight) var(--pf-c-clipboard-copy__expandable-content--PaddingBottom) var(--pf-c-clipboard-copy__expandable-content--PaddingLeft);word-wrap:break-word;background-color:var(--pf-c-clipboard-copy__expandable-content--BackgroundColor);background-clip:padding-box;border:solid var(--pf-c-clipboard-copy__expandable-content--BorderColor);border-width:var(--pf-c-clipboard-copy__expandable-content--BorderTopWidth) var(--pf-c-clipboard-copy__expandable-content--BorderRightWidth) var(--pf-c-clipboard-copy__expandable-content--BorderBottomWidth) var(--pf-c-clipboard-copy__expandable-content--BorderLeftWidth);box-shadow:var(--pf-c-clipboard-copy__expandable-content--BoxShadow)}.pf-c-clipboard-copy__expandable-content pre{white-space:pre-wrap}.pf-c-code-editor{--pf-c-code-editor__controls--c-button--m-control--Color:var(--pf-global--Color--200);--pf-c-code-editor__controls--c-button--m-control--hover--Color:var(--pf-global--Color--100);--pf-c-code-editor__controls--c-button--m-control--focus--Color:var(--pf-global--Color--100);--pf-c-code-editor__controls--c-button--m-control--disabled--after--BorderBottomColor:var(--pf-global--BorderColor--100);--pf-c-code-editor__header--before--BorderBottomWidth:var(--pf-global--BorderWidth--sm);--pf-c-code-editor__header--before--BorderBottomColor:var(--pf-global--BorderColor--100);--pf-c-code-editor__main--BorderColor:var(--pf-global--BorderColor--100);--pf-c-code-editor__main--BorderWidth:var(--pf-global--BorderWidth--sm);--pf-c-code-editor__main--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-code-editor--m-read-only__main--BackgroundColor:var(--pf-global--disabled-color--300);--pf-c-code-editor__main--m-drag-hover--before--BorderWidth:var(--pf-global--BorderWidth--sm);--pf-c-code-editor__main--m-drag-hover--before--BorderColor:var(--pf-global--primary-color--100);--pf-c-code-editor__main--m-drag-hover--after--BackgroundColor:var(--pf-global--primary-color--100);--pf-c-code-editor__main--m-drag-hover--after--Opacity:.1;--pf-c-code-editor__code--PaddingTop:var(--pf-global--spacer--sm);--pf-c-code-editor__code--PaddingRight:var(--pf-global--spacer--sm);--pf-c-code-editor__code--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-code-editor__code--PaddingLeft:var(--pf-global--spacer--sm);--pf-c-code-editor__code-pre--FontSize:var(--pf-global--FontSize--sm);--pf-c-code-editor__code-pre--FontFamily:var(--pf-global--FontFamily--monospace);--pf-c-code-editor__tab--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-code-editor__tab--Color:var(--pf-global--Color--200);--pf-c-code-editor__tab--PaddingTop:var(--pf-global--spacer--form-element);--pf-c-code-editor__tab--PaddingRight:var(--pf-global--spacer--sm);--pf-c-code-editor__tab--PaddingBottom:var(--pf-global--spacer--form-element);--pf-c-code-editor__tab--PaddingLeft:var(--pf-global--spacer--sm);--pf-c-code-editor__tab--BorderTopWidth:var(--pf-global--BorderWidth--sm);--pf-c-code-editor__tab--BorderRightWidth:var(--pf-global--BorderWidth--sm);--pf-c-code-editor__tab--BorderBottomWidth:0;--pf-c-code-editor__tab--BorderLeftWidth:var(--pf-global--BorderWidth--sm);--pf-c-code-editor__tab--BorderColor:var(--pf-global--BorderColor--100);--pf-c-code-editor__tab-icon--text--MarginLeft:var(--pf-global--spacer--sm)}.pf-c-code-editor.pf-m-read-only{--pf-c-code-editor__main--BackgroundColor:var(--pf-c-code-editor--m-read-only__main--BackgroundColor)}.pf-c-code-editor__header{position:relative;display:flex;align-items:flex-end}.pf-c-code-editor__header:before{position:absolute;right:0;bottom:0;left:0;pointer-events:none;content:"";border-bottom:var(--pf-c-code-editor__header--before--BorderBottomWidth) solid var(--pf-c-code-editor__header--before--BorderBottomColor)}.pf-c-code-editor__controls{display:flex}.pf-c-code-editor__controls .pf-c-button.pf-m-control{--pf-c-button--m-control--Color:var(--pf-c-code-editor__controls--c-button--m-control--Color)}.pf-c-code-editor__controls .pf-c-button.pf-m-control:hover{--pf-c-code-editor__controls--c-button--m-control--Color:var(--pf-c-code-editor__controls--c-button--m-control--hover--Color)}.pf-c-code-editor__controls .pf-c-button.pf-m-control:focus{--pf-c-code-editor__controls--c-button--m-control--Color:var(--pf-c-code-editor__controls--c-button--m-control--focus--Color)}.pf-c-code-editor__controls .pf-c-button.pf-m-control:disabled:after{border-bottom-color:var(--pf-c-code-editor__controls--c-button--m-control--disabled--after--BorderBottomColor)}.pf-c-code-editor__main{position:relative;background-color:var(--pf-c-code-editor__main--BackgroundColor);border:var(--pf-c-code-editor__main--BorderWidth) solid;border-color:var(--pf-c-code-editor__main--BorderColor)}.pf-c-code-editor__main.pf-m-drag-hover:after{position:absolute;top:0;right:0;bottom:0;left:0;content:"";background-color:var(--pf-c-code-editor__main--m-drag-hover--after--BackgroundColor);opacity:var(--pf-c-code-editor__main--m-drag-hover--after--Opacity)}.pf-c-code-editor__main.pf-m-drag-hover:before{position:absolute;top:0;right:0;bottom:0;left:0;content:"";border:var(--pf-c-code-editor__main--m-drag-hover--before--BorderWidth) solid var(--pf-c-code-editor__main--m-drag-hover--before--BorderColor)}.pf-c-code-editor__main .monaco-editor{background-color:var(--pf-c-code-editor__main--BackgroundColor)}.pf-c-code-editor__header+.pf-c-code-editor__main{border-top-width:0}.pf-c-code-editor__code{position:relative;padding:var(--pf-c-code-editor__code--PaddingTop) var(--pf-c-code-editor__code--PaddingRight) var(--pf-c-code-editor__code--PaddingBottom) var(--pf-c-code-editor__code--PaddingLeft)}.pf-c-code-editor__code .pf-c-code-editor__code-pre{font-family:var(--pf-c-code-editor__code-pre--FontFamily);font-size:var(--pf-c-code-editor__code-pre--FontSize);white-space:pre-wrap}.pf-c-code-editor__tab{position:relative;display:flex;align-items:center;padding:var(--pf-c-code-editor__tab--PaddingTop) var(--pf-c-code-editor__tab--PaddingRight) var(--pf-c-code-editor__tab--PaddingBottom) var(--pf-c-code-editor__tab--PaddingLeft);margin-left:auto;color:var(--pf-c-code-editor__tab--Color);background-color:var(--pf-c-code-editor__tab--BackgroundColor);border-left:var(--pf-c-code-editor__tab--BorderLeftWidth) solid var(--pf-c-code-editor__tab--BorderColor);border-bottom:var(--pf-c-code-editor__tab--BorderBottomWidth) solid var(--pf-c-code-editor__tab--BorderColor);border-right:var(--pf-c-code-editor__tab--BorderRightWidth) solid var(--pf-c-code-editor__tab--BorderColor);border-top:var(--pf-c-code-editor__tab--BorderTopWidth) solid var(--pf-c-code-editor__tab--BorderColor)}.pf-c-code-editor__tab-icon+.pf-c-code-editor__tab-text{margin-left:var(--pf-c-code-editor__tab-icon--text--MarginLeft)}.pf-c-content{--pf-c-content--MarginBottom:var(--pf-global--spacer--md);--pf-c-content--LineHeight:var(--pf-global--LineHeight--md);--pf-c-content--FontSize:var(--pf-global--FontSize--md);--pf-c-content--FontWeight:var(--pf-global--FontWeight--normal);--pf-c-content--Color:var(--pf-global--Color--100);--pf-c-content--heading--FontFamily:var(--pf-global--FontFamily--heading--sans-serif);--pf-c-content--h1--MarginTop:var(--pf-global--spacer--lg);--pf-c-content--h1--MarginBottom:var(--pf-global--spacer--sm);--pf-c-content--h1--LineHeight:var(--pf-global--LineHeight--sm);--pf-c-content--h1--FontSize:var(--pf-global--FontSize--2xl);--pf-c-content--h1--FontWeight:var(--pf-global--FontWeight--normal);--pf-c-content--h2--MarginTop:var(--pf-global--spacer--lg);--pf-c-content--h2--MarginBottom:var(--pf-global--spacer--sm);--pf-c-content--h2--LineHeight:var(--pf-global--LineHeight--md);--pf-c-content--h2--FontSize:var(--pf-global--FontSize--xl);--pf-c-content--h2--FontWeight:var(--pf-global--FontWeight--normal);--pf-c-content--h3--MarginTop:var(--pf-global--spacer--lg);--pf-c-content--h3--MarginBottom:var(--pf-global--spacer--sm);--pf-c-content--h3--LineHeight:var(--pf-global--LineHeight--md);--pf-c-content--h3--FontSize:var(--pf-global--FontSize--lg);--pf-c-content--h3--FontWeight:var(--pf-global--FontWeight--normal);--pf-c-content--h4--MarginTop:var(--pf-global--spacer--lg);--pf-c-content--h4--MarginBottom:var(--pf-global--spacer--sm);--pf-c-content--h4--LineHeight:var(--pf-global--LineHeight--md);--pf-c-content--h4--FontSize:var(--pf-global--FontSize--md);--pf-c-content--h4--FontWeight:var(--pf-global--FontWeight--normal);--pf-c-content--h5--MarginTop:var(--pf-global--spacer--lg);--pf-c-content--h5--MarginBottom:var(--pf-global--spacer--sm);--pf-c-content--h5--LineHeight:var(--pf-global--LineHeight--md);--pf-c-content--h5--FontSize:var(--pf-global--FontSize--md);--pf-c-content--h5--FontWeight:var(--pf-global--FontWeight--normal);--pf-c-content--h6--MarginTop:var(--pf-global--spacer--lg);--pf-c-content--h6--MarginBottom:var(--pf-global--spacer--sm);--pf-c-content--h6--LineHeight:var(--pf-global--LineHeight--md);--pf-c-content--h6--FontSize:var(--pf-global--FontSize--md);--pf-c-content--h6--FontWeight:var(--pf-global--FontWeight--normal);--pf-c-content--small--MarginBottom:var(--pf-global--spacer--md);--pf-c-content--small--LineHeight:var(--pf-global--LineHeight--md);--pf-c-content--small--FontSize:var(--pf-global--FontSize--sm);--pf-c-content--small--Color:var(--pf-global--Color--200);--pf-c-content--a--Color:var(--pf-global--link--Color);--pf-c-content--a--TextDecoration:var(--pf-global--link--TextDecoration);--pf-c-content--a--hover--Color:var(--pf-global--link--Color--hover);--pf-c-content--a--hover--TextDecoration:var(--pf-global--link--TextDecoration--hover);--pf-c-content--blockquote--PaddingTop:var(--pf-global--spacer--md);--pf-c-content--blockquote--PaddingRight:var(--pf-global--spacer--md);--pf-c-content--blockquote--PaddingBottom:var(--pf-global--spacer--md);--pf-c-content--blockquote--PaddingLeft:var(--pf-global--spacer--md);--pf-c-content--blockquote--Color:var(--pf-global--Color--200);--pf-c-content--blockquote--BorderLeftColor:var(--pf-global--BorderColor--100);--pf-c-content--blockquote--BorderLeftWidth:var(--pf-global--BorderWidth--lg);--pf-c-content--ol--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-content--ol--MarginLeft:var(--pf-global--spacer--lg);--pf-c-content--ol--nested--MarginTop:var(--pf-global--spacer--sm);--pf-c-content--ol--nested--MarginLeft:var(--pf-global--spacer--sm);--pf-c-content--ul--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-content--ul--MarginLeft:var(--pf-global--spacer--lg);--pf-c-content--ul--nested--MarginTop:var(--pf-global--spacer--sm);--pf-c-content--ul--nested--MarginLeft:var(--pf-global--spacer--sm);--pf-c-content--ul--ListStyle:var(--pf-global--ListStyle);--pf-c-content--li--MarginTop:var(--pf-global--spacer--sm);--pf-c-content--dl--ColumnGap:var(--pf-global--spacer--2xl);--pf-c-content--dl--RowGap:var(--pf-global--spacer--md);--pf-c-content--dt--FontWeight:var(--pf-global--FontWeight--semi-bold);--pf-c-content--dt--MarginTop:var(--pf-global--spacer--md);--pf-c-content--dt--sm--MarginTop:0;--pf-c-content--hr--Height:var(--pf-global--BorderWidth--sm);--pf-c-content--hr--BackgroundColor:var(--pf-global--BorderColor--100);font-size:var(--pf-c-content--FontSize);line-height:var(--pf-c-content--LineHeight);color:var(--pf-c-content--Color)}.pf-c-content a{color:var(--pf-c-content--a--Color);text-decoration:var(--pf-c-content--a--TextDecoration)}.pf-c-content a:hover{--pf-c-content--a--Color:var(--pf-c-content--a--hover--Color);--pf-c-content--a--TextDecoration:var(--pf-c-content--a--hover--TextDecoration)}.pf-c-content li+li{margin-top:var(--pf-c-content--li--MarginTop)}.pf-c-content blockquote:not(:last-child),.pf-c-content dl:not(:last-child),.pf-c-content hr:not(:last-child),.pf-c-content ol:not(:last-child),.pf-c-content p:not(:last-child),.pf-c-content pre:not(:last-child),.pf-c-content small:not(:last-child),.pf-c-content table:not(:last-child),.pf-c-content ul:not(:last-child){margin-bottom:var(--pf-c-content--MarginBottom)}.pf-c-content h1,.pf-c-content h2,.pf-c-content h3,.pf-c-content h4,.pf-c-content h5,.pf-c-content h6{margin:0;font-family:var(--pf-c-content--heading--FontFamily)}.pf-c-content h1:first-child,.pf-c-content h2:first-child,.pf-c-content h3:first-child,.pf-c-content h4:first-child,.pf-c-content h5:first-child,.pf-c-content h6:first-child{margin-top:0}.pf-c-content h1:last-child,.pf-c-content h2:last-child,.pf-c-content h3:last-child,.pf-c-content h4:last-child,.pf-c-content h5:last-child,.pf-c-content h6:last-child{margin-bottom:0}.pf-c-content ol,.pf-c-content ul{margin:0}.pf-c-content h1{margin-top:var(--pf-c-content--h1--MarginTop);margin-bottom:var(--pf-c-content--h1--MarginBottom);font-size:var(--pf-c-content--h1--FontSize);font-weight:var(--pf-c-content--h1--FontWeight);line-height:var(--pf-c-content--h1--LineHeight)}.pf-c-content h2{margin-top:var(--pf-c-content--h2--MarginTop);margin-bottom:var(--pf-c-content--h2--MarginBottom);font-size:var(--pf-c-content--h2--FontSize);font-weight:var(--pf-c-content--h2--FontWeight);line-height:var(--pf-c-content--h2--LineHeight)}.pf-c-content h3{margin-top:var(--pf-c-content--h3--MarginTop);margin-bottom:var(--pf-c-content--h3--MarginBottom);font-size:var(--pf-c-content--h3--FontSize);font-weight:var(--pf-c-content--h3--FontWeight);line-height:var(--pf-c-content--h3--LineHeight)}.pf-c-content h4{margin-top:var(--pf-c-content--h4--MarginTop);margin-bottom:var(--pf-c-content--h4--MarginBottom);font-size:var(--pf-c-content--h4--FontSize);font-weight:var(--pf-c-content--h4--FontWeight);line-height:var(--pf-c-content--h4--LineHeight)}.pf-c-content h5{margin-top:var(--pf-c-content--h5--MarginTop);margin-bottom:var(--pf-c-content--h5--MarginBottom);font-size:var(--pf-c-content--h5--FontSize);font-weight:var(--pf-c-content--h5--FontWeight);line-height:var(--pf-c-content--h5--LineHeight)}.pf-c-content h6{margin-top:var(--pf-c-content--h6--MarginTop);margin-bottom:var(--pf-c-content--h6--MarginBottom);font-size:var(--pf-c-content--h6--FontSize);font-weight:var(--pf-c-content--h6--FontWeight);line-height:var(--pf-c-content--h6--LineHeight)}.pf-c-content small{display:block;font-size:var(--pf-c-content--small--FontSize);line-height:var(--pf-c-content--small--LineHeight);color:var(--pf-c-content--small--Color)}.pf-c-content small:not(:last-child){margin-bottom:var(--pf-c-content--small--MarginBottom)}.pf-c-content blockquote{padding:var(--pf-c-content--blockquote--PaddingTop) var(--pf-c-content--blockquote--PaddingRight) var(--pf-c-content--blockquote--PaddingBottom) var(--pf-c-content--blockquote--PaddingLeft);color:var(--pf-c-content--blockquote--Color);border-left:var(--pf-c-content--blockquote--BorderLeftWidth) solid var(--pf-c-content--blockquote--BorderLeftColor)}.pf-c-content hr{height:var(--pf-c-content--hr--Height);background-color:var(--pf-c-content--hr--BackgroundColor);border:none}.pf-c-content ol{padding-left:var(--pf-c-content--ol--PaddingLeft);margin-left:var(--pf-c-content--ol--MarginLeft)}.pf-c-content ol ul{margin-top:var(--pf-c-content--ul--nested--MarginTop);--pf-c-content--ul--MarginLeft:var(--pf-c-content--ul--nested--MarginLeft)}.pf-c-content ol ol{margin-top:var(--pf-c-content--ol--nested--MarginTop);--pf-c-content--ol--MarginLeft:var(--pf-c-content--ol--nested--MarginLeft)}.pf-c-content ul{padding-left:var(--pf-c-content--ul--PaddingLeft);margin-left:var(--pf-c-content--ul--MarginLeft);list-style:var(--pf-c-content--ul--ListStyle)}.pf-c-content ul ul{margin-top:var(--pf-c-content--ul--nested--MarginTop);--pf-c-content--ul--MarginLeft:var(--pf-c-content--ul--nested--MarginLeft)}.pf-c-content ul ol{margin-top:var(--pf-c-content--ol--nested--MarginTop);--pf-c-content--ol--MarginLeft:var(--pf-c-content--ol--nested--MarginLeft)}.pf-c-content dl{display:grid;grid-template-columns:1fr}@media screen and (min-width:576px){.pf-c-content dl{grid-template:auto/auto 1fr;grid-column-gap:var(--pf-c-content--dl--ColumnGap);grid-row-gap:var(--pf-c-content--dl--RowGap)}}.pf-c-content dt{font-weight:var(--pf-c-content--dt--FontWeight)}.pf-c-content dt:not(:first-child){margin-top:var(--pf-c-content--dt--MarginTop)}@media screen and (min-width:576px){.pf-c-content dt:not(:first-child){--pf-c-content--dt--MarginTop:var(--pf-c-content--dt--sm--MarginTop)}}@media screen and (min-width:576px){.pf-c-content dt{grid-column:1}}@media screen and (min-width:576px){.pf-c-content dd{grid-column:2}}.pf-m-overpass-font .pf-c-content{--pf-c-content--h2--LineHeight:var(--pf-global--LineHeight--sm);--pf-c-content--h4--FontWeight:var(--pf-global--FontWeight--semi-bold);--pf-c-content--h5--FontWeight:var(--pf-global--FontWeight--semi-bold);--pf-c-content--h6--FontWeight:var(--pf-global--FontWeight--semi-bold)}.pf-m-overpass-font .pf-c-content blockquote{font-weight:var(--pf-global--FontWeight--light)}.pf-c-context-selector{--pf-c-context-selector--Width:15.625rem;--pf-c-context-selector__toggle--PaddingTop:var(--pf-global--spacer--form-element);--pf-c-context-selector__toggle--PaddingRight:var(--pf-global--spacer--sm);--pf-c-context-selector__toggle--PaddingBottom:var(--pf-global--spacer--form-element);--pf-c-context-selector__toggle--PaddingLeft:var(--pf-global--spacer--sm);--pf-c-context-selector__toggle--BorderWidth:var(--pf-global--BorderWidth--sm);--pf-c-context-selector__toggle--BorderTopColor:var(--pf-global--BorderColor--300);--pf-c-context-selector__toggle--BorderRightColor:var(--pf-global--BorderColor--300);--pf-c-context-selector__toggle--BorderBottomColor:var(--pf-global--BorderColor--200);--pf-c-context-selector__toggle--BorderLeftColor:var(--pf-global--BorderColor--300);--pf-c-context-selector__toggle--Color:var(--pf-global--Color--100);--pf-c-context-selector__toggle--hover--BorderBottomColor:var(--pf-global--active-color--100);--pf-c-context-selector__toggle--active--BorderBottomWidth:var(--pf-global--BorderWidth--md);--pf-c-context-selector__toggle--active--BorderBottomColor:var(--pf-global--active-color--100);--pf-c-context-selector__toggle--expanded--BorderBottomWidth:var(--pf-global--BorderWidth--md);--pf-c-context-selector__toggle--expanded--BorderBottomColor:var(--pf-global--active-color--100);--pf-c-context-selector__toggle-text--FontSize:var(--pf-global--FontSize--md);--pf-c-context-selector__toggle-text--FontWeight:var(--pf-global--FontWeight--normal);--pf-c-context-selector__toggle-text--LineHeight:var(--pf-global--LineHeight--md);--pf-c-context-selector__toggle-icon--MarginRight:var(--pf-global--spacer--sm);--pf-c-context-selector__toggle-icon--MarginLeft:var(--pf-global--spacer--md);--pf-c-context-selector__menu--Top:calc(100% + var(--pf-global--spacer--xs));--pf-c-context-selector__menu--ZIndex:var(--pf-global--ZIndex--sm);--pf-c-context-selector__menu--PaddingTop:var(--pf-global--spacer--sm);--pf-c-context-selector__menu--BackgroundColor:var(--pf-global--BackgroundColor--light-100);--pf-c-context-selector__menu--BoxShadow:var(--pf-global--BoxShadow--md);--pf-c-context-selector__menu-search--PaddingTop:var(--pf-global--spacer--sm);--pf-c-context-selector__menu-search--PaddingRight:var(--pf-global--spacer--md);--pf-c-context-selector__menu-search--PaddingBottom:var(--pf-global--spacer--md);--pf-c-context-selector__menu-search--PaddingLeft:var(--pf-global--spacer--md);--pf-c-context-selector__menu-search--BorderBottomColor:var(--pf-global--BorderColor--100);--pf-c-context-selector__menu-search--BorderBottomWidth:var(--pf-global--BorderWidth--sm);--pf-c-context-selector__menu-footer--BoxShadow:var(--pf-global--BoxShadow--sm-top);--pf-c-context-selector__menu-footer--PaddingTop:var(--pf-global--spacer--md);--pf-c-context-selector__menu-footer--PaddingRight:var(--pf-global--spacer--md);--pf-c-context-selector__menu-footer--PaddingBottom:var(--pf-global--spacer--md);--pf-c-context-selector__menu-footer--PaddingLeft:var(--pf-global--spacer--md);--pf-c-context-selector__menu-list--MaxHeight:12.5rem;--pf-c-context-selector__menu-list-item--PaddingTop:var(--pf-global--spacer--sm);--pf-c-context-selector__menu-list-item--PaddingRight:var(--pf-global--spacer--lg);--pf-c-context-selector__menu-list-item--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-context-selector__menu-list-item--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-context-selector__menu-list-item--hover--BackgroundColor:var(--pf-global--BackgroundColor--light-300);--pf-c-context-selector__menu-list-item--disabled--Color:var(--pf-global--Color--dark-200);position:relative;display:inline-block;width:var(--pf-c-context-selector--Width);max-width:100%}.pf-c-context-selector__toggle{position:relative;display:flex;align-items:center;justify-content:space-between;width:100%;padding:var(--pf-c-context-selector__toggle--PaddingTop) var(--pf-c-context-selector__toggle--PaddingRight) var(--pf-c-context-selector__toggle--PaddingBottom) var(--pf-c-context-selector__toggle--PaddingLeft);color:var(--pf-c-context-selector__toggle--Color);white-space:nowrap;cursor:pointer;border:none}.pf-c-context-selector__toggle:before{position:absolute;top:0;right:0;bottom:0;left:0;content:"";border:var(--pf-c-context-selector__toggle--BorderWidth) solid;border-color:var(--pf-c-context-selector__toggle--BorderTopColor) var(--pf-c-context-selector__toggle--BorderRightColor) var(--pf-c-context-selector__toggle--BorderBottomColor) var(--pf-c-context-selector__toggle--BorderLeftColor)}.pf-c-context-selector__toggle:hover:before{--pf-c-context-selector__toggle--BorderBottomColor:var(--pf-c-context-selector__toggle--hover--BorderBottomColor)}.pf-c-context-selector__toggle.pf-m-active:before,.pf-c-context-selector__toggle:active:before,.pf-c-context-selector__toggle:focus-within:before{--pf-c-context-selector__toggle--BorderBottomColor:var(--pf-c-context-selector__toggle--active--BorderBottomColor);border-bottom-width:var(--pf-c-context-selector__toggle--active--BorderBottomWidth)}.pf-m-expanded>.pf-c-context-selector__toggle:before{--pf-c-context-selector__toggle--BorderBottomColor:var(--pf-c-context-selector__toggle--expanded--BorderBottomColor);border-bottom-width:var(--pf-c-context-selector__toggle--expanded--BorderBottomWidth)}.pf-c-context-selector__toggle .pf-c-context-selector__toggle-icon{margin-right:var(--pf-c-context-selector__toggle-icon--MarginRight);margin-left:var(--pf-c-context-selector__toggle-icon--MarginLeft)}.pf-c-context-selector__toggle .pf-c-context-selector__toggle-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--pf-c-context-selector__toggle-text--FontSize);font-weight:var(--pf-c-context-selector__toggle-text--FontWeight);line-height:var(--pf-c-context-selector__toggle-text--LineHeight)}.pf-c-context-selector__menu{color:var(--pf-global--Color--100);position:absolute;top:var(--pf-c-context-selector__menu--Top);z-index:var(--pf-c-context-selector__menu--ZIndex);min-width:100%;padding-top:var(--pf-c-context-selector__menu--PaddingTop);background-color:var(--pf-c-context-selector__menu--BackgroundColor);background-clip:padding-box;box-shadow:var(--pf-c-context-selector__menu--BoxShadow)}.pf-c-context-selector__menu-search{position:relative;padding:var(--pf-c-context-selector__menu-search--PaddingTop) var(--pf-c-context-selector__menu-search--PaddingRight) var(--pf-c-context-selector__menu-search--PaddingBottom) var(--pf-c-context-selector__menu-search--PaddingLeft);border-bottom:var(--pf-c-context-selector__menu-search--BorderBottomWidth) solid var(--pf-c-context-selector__menu-search--BorderBottomColor)}.pf-c-context-selector__menu-footer{padding:var(--pf-c-context-selector__menu-footer--PaddingTop) var(--pf-c-context-selector__menu-footer--PaddingRight) var(--pf-c-context-selector__menu-footer--PaddingBottom) var(--pf-c-context-selector__menu-footer--PaddingLeft);text-align:right;box-shadow:var(--pf-c-context-selector__menu-footer--BoxShadow)}.pf-c-context-selector__menu-list{max-height:var(--pf-c-context-selector__menu-list--MaxHeight);overflow-y:scroll}.pf-c-context-selector__menu-list-item{display:flex;align-items:center;width:100%;padding:var(--pf-c-context-selector__menu-list-item--PaddingTop) var(--pf-c-context-selector__menu-list-item--PaddingRight) var(--pf-c-context-selector__menu-list-item--PaddingBottom) var(--pf-c-context-selector__menu-list-item--PaddingLeft);white-space:nowrap;border:none}.pf-c-context-selector__menu-list-item:focus,.pf-c-context-selector__menu-list-item:hover{text-decoration:none;background-color:var(--pf-c-context-selector__menu-list-item--hover--BackgroundColor)}.pf-c-context-selector__menu-list-item:disabled{color:var(--pf-c-context-selector__menu-list-item--disabled--Color);pointer-events:none}@media screen and (min-width:768px){.pf-c-data-list:not([class*=pf-m-grid]){--pf-c-data-list__cell--cell--PaddingTop:var(--pf-c-data-list__cell--cell--md--PaddingTop);--pf-c-data-list__cell--PaddingBottom:var(--pf-c-data-list__cell--md--PaddingBottom);--pf-c-data-list__item-control--MarginRight:var(--pf-c-data-list__item-control--md--MarginRight);--pf-c-data-list__item-action--MarginLeft:var(--pf-c-data-list__item-action--md--MarginLeft);--pf-c-data-list__expandable-content-body--PaddingTop:var(--pf-c-data-list__expandable-content-body--md--PaddingTop);--pf-c-data-list__expandable-content-body--PaddingBottom:var(--pf-c-data-list__expandable-content-body--md--PaddingBottom);--pf-c-data-list--m-compact__cell--PaddingBottom:var(--pf-c-data-list--m-compact__cell--md--PaddingBottom);--pf-c-data-list--m-compact__cell-cell--PaddingTop:var(--pf-c-data-list--m-compact__cell-cell--md--PaddingTop)}}@media screen and (min-width:768px) and (min-width:1200px){.pf-c-data-list:not([class*=pf-m-grid]){--pf-c-data-list__item-row--PaddingRight:var(--pf-c-data-list__item-row--xl--PaddingRight);--pf-c-data-list__item-row--PaddingLeft:var(--pf-c-data-list__item-row--xl--PaddingLeft);--pf-c-data-list__expandable-content-body--PaddingRight:var(--pf-c-data-list__expandable-content-body--xl--PaddingRight);--pf-c-data-list__expandable-content-body--PaddingLeft:var(--pf-c-data-list__expandable-content-body--xl--PaddingLeft)}}@media screen and (min-width:768px){.pf-c-data-list:not([class*=pf-m-grid]) .pf-c-data-list__item-content{display:flex;flex-wrap:wrap;flex-grow:1;padding-bottom:var(--pf-c-data-list__item-content--md--PaddingBottom)}.pf-c-data-list:not([class*=pf-m-grid]) .pf-c-data-list__cell:not(:last-child):not(.pf-m-icon){margin-right:var(--pf-c-data-list__cell--MarginRight)}.pf-c-data-list:not([class*=pf-m-grid]) .pf-c-data-list__cell+.pf-c-data-list__cell{flex:1;order:0}.pf-c-data-list:not([class*=pf-m-grid]) .pf-c-data-list__cell.pf-m-align-right{margin-left:auto}.pf-c-data-list:not([class*=pf-m-grid]) .pf-c-data-list__cell.pf-m-no-fill{flex-grow:0}.pf-c-data-list:not([class*=pf-m-grid]) .pf-c-data-list__cell.pf-m-flex-2{flex-grow:2}.pf-c-data-list:not([class*=pf-m-grid]) .pf-c-data-list__cell.pf-m-flex-3{flex-grow:3}.pf-c-data-list:not([class*=pf-m-grid]) .pf-c-data-list__cell.pf-m-flex-4{flex-grow:4}.pf-c-data-list:not([class*=pf-m-grid]) .pf-c-data-list__cell.pf-m-flex-5{flex-grow:5}.pf-c-data-list:not([class*=pf-m-grid]) .pf-c-data-list__expandable-content{max-height:none;overflow-y:visible}}@media screen and (min-width:0){.pf-c-data-list.pf-m-grid-none{--pf-c-data-list__cell--cell--PaddingTop:var(--pf-c-data-list__cell--cell--md--PaddingTop);--pf-c-data-list__cell--PaddingBottom:var(--pf-c-data-list__cell--md--PaddingBottom);--pf-c-data-list__item-control--MarginRight:var(--pf-c-data-list__item-control--md--MarginRight);--pf-c-data-list__item-action--MarginLeft:var(--pf-c-data-list__item-action--md--MarginLeft);--pf-c-data-list__expandable-content-body--PaddingTop:var(--pf-c-data-list__expandable-content-body--md--PaddingTop);--pf-c-data-list__expandable-content-body--PaddingBottom:var(--pf-c-data-list__expandable-content-body--md--PaddingBottom);--pf-c-data-list--m-compact__cell--PaddingBottom:var(--pf-c-data-list--m-compact__cell--md--PaddingBottom);--pf-c-data-list--m-compact__cell-cell--PaddingTop:var(--pf-c-data-list--m-compact__cell-cell--md--PaddingTop)}}@media screen and (min-width:0) and (min-width:1200px){.pf-c-data-list.pf-m-grid-none{--pf-c-data-list__item-row--PaddingRight:var(--pf-c-data-list__item-row--xl--PaddingRight);--pf-c-data-list__item-row--PaddingLeft:var(--pf-c-data-list__item-row--xl--PaddingLeft);--pf-c-data-list__expandable-content-body--PaddingRight:var(--pf-c-data-list__expandable-content-body--xl--PaddingRight);--pf-c-data-list__expandable-content-body--PaddingLeft:var(--pf-c-data-list__expandable-content-body--xl--PaddingLeft)}}@media screen and (min-width:0){.pf-c-data-list.pf-m-grid-none .pf-c-data-list__item-content{display:flex;flex-wrap:wrap;flex-grow:1;padding-bottom:var(--pf-c-data-list__item-content--md--PaddingBottom)}.pf-c-data-list.pf-m-grid-none .pf-c-data-list__cell:not(:last-child):not(.pf-m-icon){margin-right:var(--pf-c-data-list__cell--MarginRight)}.pf-c-data-list.pf-m-grid-none .pf-c-data-list__cell+.pf-c-data-list__cell{flex:1;order:0}.pf-c-data-list.pf-m-grid-none .pf-c-data-list__cell.pf-m-align-right{margin-left:auto}.pf-c-data-list.pf-m-grid-none .pf-c-data-list__cell.pf-m-no-fill{flex-grow:0}.pf-c-data-list.pf-m-grid-none .pf-c-data-list__cell.pf-m-flex-2{flex-grow:2}.pf-c-data-list.pf-m-grid-none .pf-c-data-list__cell.pf-m-flex-3{flex-grow:3}.pf-c-data-list.pf-m-grid-none .pf-c-data-list__cell.pf-m-flex-4{flex-grow:4}.pf-c-data-list.pf-m-grid-none .pf-c-data-list__cell.pf-m-flex-5{flex-grow:5}.pf-c-data-list.pf-m-grid-none .pf-c-data-list__expandable-content{max-height:none;overflow-y:visible}}@media screen and (min-width:576px){.pf-c-data-list.pf-m-grid-sm{--pf-c-data-list__cell--cell--PaddingTop:var(--pf-c-data-list__cell--cell--md--PaddingTop);--pf-c-data-list__cell--PaddingBottom:var(--pf-c-data-list__cell--md--PaddingBottom);--pf-c-data-list__item-control--MarginRight:var(--pf-c-data-list__item-control--md--MarginRight);--pf-c-data-list__item-action--MarginLeft:var(--pf-c-data-list__item-action--md--MarginLeft);--pf-c-data-list__expandable-content-body--PaddingTop:var(--pf-c-data-list__expandable-content-body--md--PaddingTop);--pf-c-data-list__expandable-content-body--PaddingBottom:var(--pf-c-data-list__expandable-content-body--md--PaddingBottom);--pf-c-data-list--m-compact__cell--PaddingBottom:var(--pf-c-data-list--m-compact__cell--md--PaddingBottom);--pf-c-data-list--m-compact__cell-cell--PaddingTop:var(--pf-c-data-list--m-compact__cell-cell--md--PaddingTop)}}@media screen and (min-width:576px) and (min-width:1200px){.pf-c-data-list.pf-m-grid-sm{--pf-c-data-list__item-row--PaddingRight:var(--pf-c-data-list__item-row--xl--PaddingRight);--pf-c-data-list__item-row--PaddingLeft:var(--pf-c-data-list__item-row--xl--PaddingLeft);--pf-c-data-list__expandable-content-body--PaddingRight:var(--pf-c-data-list__expandable-content-body--xl--PaddingRight);--pf-c-data-list__expandable-content-body--PaddingLeft:var(--pf-c-data-list__expandable-content-body--xl--PaddingLeft)}}@media screen and (min-width:576px){.pf-c-data-list.pf-m-grid-sm .pf-c-data-list__item-content{display:flex;flex-wrap:wrap;flex-grow:1;padding-bottom:var(--pf-c-data-list__item-content--md--PaddingBottom)}.pf-c-data-list.pf-m-grid-sm .pf-c-data-list__cell:not(:last-child):not(.pf-m-icon){margin-right:var(--pf-c-data-list__cell--MarginRight)}.pf-c-data-list.pf-m-grid-sm .pf-c-data-list__cell+.pf-c-data-list__cell{flex:1;order:0}.pf-c-data-list.pf-m-grid-sm .pf-c-data-list__cell.pf-m-align-right{margin-left:auto}.pf-c-data-list.pf-m-grid-sm .pf-c-data-list__cell.pf-m-no-fill{flex-grow:0}.pf-c-data-list.pf-m-grid-sm .pf-c-data-list__cell.pf-m-flex-2{flex-grow:2}.pf-c-data-list.pf-m-grid-sm .pf-c-data-list__cell.pf-m-flex-3{flex-grow:3}.pf-c-data-list.pf-m-grid-sm .pf-c-data-list__cell.pf-m-flex-4{flex-grow:4}.pf-c-data-list.pf-m-grid-sm .pf-c-data-list__cell.pf-m-flex-5{flex-grow:5}.pf-c-data-list.pf-m-grid-sm .pf-c-data-list__expandable-content{max-height:none;overflow-y:visible}}@media screen and (min-width:768px){.pf-c-data-list.pf-m-grid-md{--pf-c-data-list__cell--cell--PaddingTop:var(--pf-c-data-list__cell--cell--md--PaddingTop);--pf-c-data-list__cell--PaddingBottom:var(--pf-c-data-list__cell--md--PaddingBottom);--pf-c-data-list__item-control--MarginRight:var(--pf-c-data-list__item-control--md--MarginRight);--pf-c-data-list__item-action--MarginLeft:var(--pf-c-data-list__item-action--md--MarginLeft);--pf-c-data-list__expandable-content-body--PaddingTop:var(--pf-c-data-list__expandable-content-body--md--PaddingTop);--pf-c-data-list__expandable-content-body--PaddingBottom:var(--pf-c-data-list__expandable-content-body--md--PaddingBottom);--pf-c-data-list--m-compact__cell--PaddingBottom:var(--pf-c-data-list--m-compact__cell--md--PaddingBottom);--pf-c-data-list--m-compact__cell-cell--PaddingTop:var(--pf-c-data-list--m-compact__cell-cell--md--PaddingTop)}}@media screen and (min-width:768px) and (min-width:1200px){.pf-c-data-list.pf-m-grid-md{--pf-c-data-list__item-row--PaddingRight:var(--pf-c-data-list__item-row--xl--PaddingRight);--pf-c-data-list__item-row--PaddingLeft:var(--pf-c-data-list__item-row--xl--PaddingLeft);--pf-c-data-list__expandable-content-body--PaddingRight:var(--pf-c-data-list__expandable-content-body--xl--PaddingRight);--pf-c-data-list__expandable-content-body--PaddingLeft:var(--pf-c-data-list__expandable-content-body--xl--PaddingLeft)}}@media screen and (min-width:768px){.pf-c-data-list.pf-m-grid-md .pf-c-data-list__item-content{display:flex;flex-wrap:wrap;flex-grow:1;padding-bottom:var(--pf-c-data-list__item-content--md--PaddingBottom)}.pf-c-data-list.pf-m-grid-md .pf-c-data-list__cell:not(:last-child):not(.pf-m-icon){margin-right:var(--pf-c-data-list__cell--MarginRight)}.pf-c-data-list.pf-m-grid-md .pf-c-data-list__cell+.pf-c-data-list__cell{flex:1;order:0}.pf-c-data-list.pf-m-grid-md .pf-c-data-list__cell.pf-m-align-right{margin-left:auto}.pf-c-data-list.pf-m-grid-md .pf-c-data-list__cell.pf-m-no-fill{flex-grow:0}.pf-c-data-list.pf-m-grid-md .pf-c-data-list__cell.pf-m-flex-2{flex-grow:2}.pf-c-data-list.pf-m-grid-md .pf-c-data-list__cell.pf-m-flex-3{flex-grow:3}.pf-c-data-list.pf-m-grid-md .pf-c-data-list__cell.pf-m-flex-4{flex-grow:4}.pf-c-data-list.pf-m-grid-md .pf-c-data-list__cell.pf-m-flex-5{flex-grow:5}.pf-c-data-list.pf-m-grid-md .pf-c-data-list__expandable-content{max-height:none;overflow-y:visible}}@media screen and (min-width:992px){.pf-c-data-list.pf-m-grid-lg{--pf-c-data-list__cell--cell--PaddingTop:var(--pf-c-data-list__cell--cell--md--PaddingTop);--pf-c-data-list__cell--PaddingBottom:var(--pf-c-data-list__cell--md--PaddingBottom);--pf-c-data-list__item-control--MarginRight:var(--pf-c-data-list__item-control--md--MarginRight);--pf-c-data-list__item-action--MarginLeft:var(--pf-c-data-list__item-action--md--MarginLeft);--pf-c-data-list__expandable-content-body--PaddingTop:var(--pf-c-data-list__expandable-content-body--md--PaddingTop);--pf-c-data-list__expandable-content-body--PaddingBottom:var(--pf-c-data-list__expandable-content-body--md--PaddingBottom);--pf-c-data-list--m-compact__cell--PaddingBottom:var(--pf-c-data-list--m-compact__cell--md--PaddingBottom);--pf-c-data-list--m-compact__cell-cell--PaddingTop:var(--pf-c-data-list--m-compact__cell-cell--md--PaddingTop)}}@media screen and (min-width:992px) and (min-width:1200px){.pf-c-data-list.pf-m-grid-lg{--pf-c-data-list__item-row--PaddingRight:var(--pf-c-data-list__item-row--xl--PaddingRight);--pf-c-data-list__item-row--PaddingLeft:var(--pf-c-data-list__item-row--xl--PaddingLeft);--pf-c-data-list__expandable-content-body--PaddingRight:var(--pf-c-data-list__expandable-content-body--xl--PaddingRight);--pf-c-data-list__expandable-content-body--PaddingLeft:var(--pf-c-data-list__expandable-content-body--xl--PaddingLeft)}}@media screen and (min-width:992px){.pf-c-data-list.pf-m-grid-lg .pf-c-data-list__item-content{display:flex;flex-wrap:wrap;flex-grow:1;padding-bottom:var(--pf-c-data-list__item-content--md--PaddingBottom)}.pf-c-data-list.pf-m-grid-lg .pf-c-data-list__cell:not(:last-child):not(.pf-m-icon){margin-right:var(--pf-c-data-list__cell--MarginRight)}.pf-c-data-list.pf-m-grid-lg .pf-c-data-list__cell+.pf-c-data-list__cell{flex:1;order:0}.pf-c-data-list.pf-m-grid-lg .pf-c-data-list__cell.pf-m-align-right{margin-left:auto}.pf-c-data-list.pf-m-grid-lg .pf-c-data-list__cell.pf-m-no-fill{flex-grow:0}.pf-c-data-list.pf-m-grid-lg .pf-c-data-list__cell.pf-m-flex-2{flex-grow:2}.pf-c-data-list.pf-m-grid-lg .pf-c-data-list__cell.pf-m-flex-3{flex-grow:3}.pf-c-data-list.pf-m-grid-lg .pf-c-data-list__cell.pf-m-flex-4{flex-grow:4}.pf-c-data-list.pf-m-grid-lg .pf-c-data-list__cell.pf-m-flex-5{flex-grow:5}.pf-c-data-list.pf-m-grid-lg .pf-c-data-list__expandable-content{max-height:none;overflow-y:visible}}@media screen and (min-width:1200px){.pf-c-data-list.pf-m-grid-xl{--pf-c-data-list__cell--cell--PaddingTop:var(--pf-c-data-list__cell--cell--md--PaddingTop);--pf-c-data-list__cell--PaddingBottom:var(--pf-c-data-list__cell--md--PaddingBottom);--pf-c-data-list__item-control--MarginRight:var(--pf-c-data-list__item-control--md--MarginRight);--pf-c-data-list__item-action--MarginLeft:var(--pf-c-data-list__item-action--md--MarginLeft);--pf-c-data-list__expandable-content-body--PaddingTop:var(--pf-c-data-list__expandable-content-body--md--PaddingTop);--pf-c-data-list__expandable-content-body--PaddingBottom:var(--pf-c-data-list__expandable-content-body--md--PaddingBottom);--pf-c-data-list--m-compact__cell--PaddingBottom:var(--pf-c-data-list--m-compact__cell--md--PaddingBottom);--pf-c-data-list--m-compact__cell-cell--PaddingTop:var(--pf-c-data-list--m-compact__cell-cell--md--PaddingTop)}}@media screen and (min-width:1200px) and (min-width:1200px){.pf-c-data-list.pf-m-grid-xl{--pf-c-data-list__item-row--PaddingRight:var(--pf-c-data-list__item-row--xl--PaddingRight);--pf-c-data-list__item-row--PaddingLeft:var(--pf-c-data-list__item-row--xl--PaddingLeft);--pf-c-data-list__expandable-content-body--PaddingRight:var(--pf-c-data-list__expandable-content-body--xl--PaddingRight);--pf-c-data-list__expandable-content-body--PaddingLeft:var(--pf-c-data-list__expandable-content-body--xl--PaddingLeft)}}@media screen and (min-width:1200px){.pf-c-data-list.pf-m-grid-xl .pf-c-data-list__item-content{display:flex;flex-wrap:wrap;flex-grow:1;padding-bottom:var(--pf-c-data-list__item-content--md--PaddingBottom)}.pf-c-data-list.pf-m-grid-xl .pf-c-data-list__cell:not(:last-child):not(.pf-m-icon){margin-right:var(--pf-c-data-list__cell--MarginRight)}.pf-c-data-list.pf-m-grid-xl .pf-c-data-list__cell+.pf-c-data-list__cell{flex:1;order:0}.pf-c-data-list.pf-m-grid-xl .pf-c-data-list__cell.pf-m-align-right{margin-left:auto}.pf-c-data-list.pf-m-grid-xl .pf-c-data-list__cell.pf-m-no-fill{flex-grow:0}.pf-c-data-list.pf-m-grid-xl .pf-c-data-list__cell.pf-m-flex-2{flex-grow:2}.pf-c-data-list.pf-m-grid-xl .pf-c-data-list__cell.pf-m-flex-3{flex-grow:3}.pf-c-data-list.pf-m-grid-xl .pf-c-data-list__cell.pf-m-flex-4{flex-grow:4}.pf-c-data-list.pf-m-grid-xl .pf-c-data-list__cell.pf-m-flex-5{flex-grow:5}.pf-c-data-list.pf-m-grid-xl .pf-c-data-list__expandable-content{max-height:none;overflow-y:visible}}@media screen and (min-width:1450px){.pf-c-data-list.pf-m-grid-2xl{--pf-c-data-list__cell--cell--PaddingTop:var(--pf-c-data-list__cell--cell--md--PaddingTop);--pf-c-data-list__cell--PaddingBottom:var(--pf-c-data-list__cell--md--PaddingBottom);--pf-c-data-list__item-control--MarginRight:var(--pf-c-data-list__item-control--md--MarginRight);--pf-c-data-list__item-action--MarginLeft:var(--pf-c-data-list__item-action--md--MarginLeft);--pf-c-data-list__expandable-content-body--PaddingTop:var(--pf-c-data-list__expandable-content-body--md--PaddingTop);--pf-c-data-list__expandable-content-body--PaddingBottom:var(--pf-c-data-list__expandable-content-body--md--PaddingBottom);--pf-c-data-list--m-compact__cell--PaddingBottom:var(--pf-c-data-list--m-compact__cell--md--PaddingBottom);--pf-c-data-list--m-compact__cell-cell--PaddingTop:var(--pf-c-data-list--m-compact__cell-cell--md--PaddingTop)}}@media screen and (min-width:1450px) and (min-width:1200px){.pf-c-data-list.pf-m-grid-2xl{--pf-c-data-list__item-row--PaddingRight:var(--pf-c-data-list__item-row--xl--PaddingRight);--pf-c-data-list__item-row--PaddingLeft:var(--pf-c-data-list__item-row--xl--PaddingLeft);--pf-c-data-list__expandable-content-body--PaddingRight:var(--pf-c-data-list__expandable-content-body--xl--PaddingRight);--pf-c-data-list__expandable-content-body--PaddingLeft:var(--pf-c-data-list__expandable-content-body--xl--PaddingLeft)}}@media screen and (min-width:1450px){.pf-c-data-list.pf-m-grid-2xl .pf-c-data-list__item-content{display:flex;flex-wrap:wrap;flex-grow:1;padding-bottom:var(--pf-c-data-list__item-content--md--PaddingBottom)}.pf-c-data-list.pf-m-grid-2xl .pf-c-data-list__cell:not(:last-child):not(.pf-m-icon){margin-right:var(--pf-c-data-list__cell--MarginRight)}.pf-c-data-list.pf-m-grid-2xl .pf-c-data-list__cell+.pf-c-data-list__cell{flex:1;order:0}.pf-c-data-list.pf-m-grid-2xl .pf-c-data-list__cell.pf-m-align-right{margin-left:auto}.pf-c-data-list.pf-m-grid-2xl .pf-c-data-list__cell.pf-m-no-fill{flex-grow:0}.pf-c-data-list.pf-m-grid-2xl .pf-c-data-list__cell.pf-m-flex-2{flex-grow:2}.pf-c-data-list.pf-m-grid-2xl .pf-c-data-list__cell.pf-m-flex-3{flex-grow:3}.pf-c-data-list.pf-m-grid-2xl .pf-c-data-list__cell.pf-m-flex-4{flex-grow:4}.pf-c-data-list.pf-m-grid-2xl .pf-c-data-list__cell.pf-m-flex-5{flex-grow:5}.pf-c-data-list.pf-m-grid-2xl .pf-c-data-list__expandable-content{max-height:none;overflow-y:visible}}.pf-c-data-list{--pf-c-data-list--BorderTopColor:var(--pf-global--BorderColor--300);--pf-c-data-list--BorderTopWidth:var(--pf-global--spacer--sm);--pf-c-data-list--sm--BorderTopWidth:var(--pf-global--BorderWidth--sm);--pf-c-data-list--sm--BorderTopColor:var(--pf-global--BorderColor--100);--pf-c-data-list__item--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-data-list__item--m-selected--ZIndex:var(--pf-global--ZIndex--xs);--pf-c-data-list__item--m-expanded--before--BackgroundColor:var(--pf-global--active-color--100);--pf-c-data-list__item--m-selected--before--BackgroundColor:var(--pf-global--active-color--100);--pf-c-data-list__item--m-selected--BoxShadow:var(--pf-global--BoxShadow--sm-top),var(--pf-global--BoxShadow--sm-bottom);--pf-c-data-list__item--m-selectable--OutlineOffset:calc(-1*var(--pf-global--spacer--xs));--pf-c-data-list__item--m-selectable--hover--ZIndex:calc(var(--pf-c-data-list__item--m-selected--ZIndex) + 1);--pf-c-data-list__item--m-selectable--hover--BoxShadow:var(--pf-global--BoxShadow--sm-top),var(--pf-global--BoxShadow--sm-bottom);--pf-c-data-list__item--m-selectable--focus--BoxShadow:var(--pf-global--BoxShadow--sm-top),var(--pf-global--BoxShadow--sm-bottom);--pf-c-data-list__item--m-selectable--active--BoxShadow:var(--pf-global--BoxShadow--sm-top),var(--pf-global--BoxShadow--sm-bottom);--pf-c-data-list__item--m-expanded--m-selectable--before--BackgroundColor:var(--pf-global--active-color--300);--pf-c-data-list__item--BorderBottomColor:var(--pf-global--BorderColor--300);--pf-c-data-list__item--BorderBottomWidth:0.5rem;--pf-c-data-list__item--m-selectable--hover--item--BorderTopColor:var(--pf-c-data-list__item--BorderBottomColor);--pf-c-data-list__item--m-selectable--hover--item--BorderTopWidth:var(--pf-c-data-list__item--BorderBottomWidth);--pf-c-data-list__item--sm--BorderBottomWidth:var(--pf-global--BorderWidth--sm);--pf-c-data-list__item--sm--BorderBottomColor:var(--pf-global--BorderColor--100);--pf-c-data-list__item--before--BackgroundColor:transparent;--pf-c-data-list__item--before--Width:var(--pf-global--BorderWidth--lg);--pf-c-data-list__item--before--Transition:var(--pf-global--Transition);--pf-c-data-list__item--before--Top:0;--pf-c-data-list__item--before--sm--Top:calc(var(--pf-c-data-list__item--BorderBottomWidth)*-1);--pf-c-data-list__item-row--PaddingRight:var(--pf-global--spacer--md);--pf-c-data-list__item-row--PaddingLeft:var(--pf-global--spacer--md);--pf-c-data-list__item-row--xl--PaddingRight:var(--pf-global--spacer--lg);--pf-c-data-list__item-row--xl--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-data-list__item-content--md--PaddingBottom:var(--pf-global--spacer--lg);--pf-c-data-list__cell--PaddingTop:var(--pf-global--spacer--lg);--pf-c-data-list__cell--PaddingBottom:var(--pf-global--spacer--lg);--pf-c-data-list__cell--MarginRight:var(--pf-global--spacer--xl);--pf-c-data-list__cell--md--PaddingBottom:0;--pf-c-data-list__cell--m-icon--MarginRight:var(--pf-global--spacer--md);--pf-c-data-list__cell--cell--PaddingTop:0;--pf-c-data-list__cell--cell--md--PaddingTop:var(--pf-global--spacer--lg);--pf-c-data-list__cell--m-icon--cell--PaddingTop:var(--pf-global--spacer--lg);--pf-c-data-list--cell--MinWidth:initial;--pf-c-data-list--cell--Overflow:visible;--pf-c-data-list--cell--TextOverflow:clip;--pf-c-data-list--cell--WhiteSpace:normal;--pf-c-data-list--cell--WordBreak:normal;--pf-c-data-list--cell--m-truncate--MinWidth:5ch;--pf-c-data-list__toggle--MarginLeft:calc(var(--pf-global--spacer--sm)*-1);--pf-c-data-list__toggle--MarginTop:calc(var(--pf-global--spacer--form-element)*-1);--pf-c-data-list__toggle-icon--Transition:.2s ease-in 0s;--pf-c-data-list__item--m-expanded__toggle-icon--Rotate:90deg;--pf-c-data-list__item-draggable-button--PaddingLeft:var(--pf-global--spacer--md);--pf-c-data-list__item-draggable-button--PaddingRight:var(--pf-global--spacer--md);--pf-c-data-list__item-draggable-button--MarginTop:calc(var(--pf-global--spacer--sm)*-1);--pf-c-data-list__item-draggable-button--MarginLeft:calc(var(--pf-global--spacer--md)*-1);--pf-c-data-list__item-draggable-button-icon--Color:var(--pf-global--icon--Color--light);--pf-c-data-list__item-draggable-button--m-disabled__draggable-icon--Color:var(--pf-global--disabled-color--200);--pf-c-data-list__item-draggable-button--hover__draggable-icon--Color:var(--pf-global--icon--Color--dark);--pf-c-data-list__item-draggable-button--focus__draggable-icon--Color:var(--pf-global--icon--Color--dark);--pf-c-data-list__item--m-ghost-row--after--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-data-list__item--m-ghost-row--after--Opacity:.6;--pf-c-data-list__item-control--PaddingTop:var(--pf-global--spacer--lg);--pf-c-data-list__item-control--PaddingBottom:var(--pf-global--spacer--lg);--pf-c-data-list__item-control--MarginRight:var(--pf-global--spacer--md);--pf-c-data-list__item-control--md--MarginRight:var(--pf-global--spacer--xl);--pf-c-data-list__item-control--not-last-child--MarginRight:var(--pf-global--spacer--md);--pf-c-data-list__item-action--Display:flex;--pf-c-data-list__item-action--PaddingTop:var(--pf-global--spacer--lg);--pf-c-data-list__item-action--PaddingBottom:var(--pf-global--spacer--lg);--pf-c-data-list__item-action--MarginLeft:var(--pf-global--spacer--md);--pf-c-data-list__item-action--md--MarginLeft:var(--pf-global--spacer--xl);--pf-c-data-list__item-action--not-last-child--MarginRight:var(--pf-global--spacer--md);--pf-c-data-list__action--MarginTop:calc(var(--pf-global--spacer--form-element)*-1);--pf-c-data-list__expandable-content--BorderTopWidth:var(--pf-global--BorderWidth--sm);--pf-c-data-list__expandable-content--BorderTopColor:var(--pf-global--BorderColor--100);--pf-c-data-list__expandable-content--MarginRight:calc(var(--pf-c-data-list__expandable-content-body--PaddingRight)*-1);--pf-c-data-list__expandable-content--MarginLeft:calc(var(--pf-c-data-list__expandable-content-body--PaddingLeft)*-1);--pf-c-data-list__expandable-content--MaxHeight:37.5rem;--pf-c-data-list__expandable-content--before--Top:calc(var(--pf-c-data-list__item--BorderBottomWidth)*-1);--pf-c-data-list__expandable-content-body--PaddingTop:var(--pf-global--spacer--md);--pf-c-data-list__expandable-content-body--PaddingRight:var(--pf-global--spacer--md);--pf-c-data-list__expandable-content-body--PaddingBottom:var(--pf-global--spacer--md);--pf-c-data-list__expandable-content-body--PaddingLeft:var(--pf-global--spacer--md);--pf-c-data-list__expandable-content-body--md--PaddingTop:var(--pf-global--spacer--lg);--pf-c-data-list__expandable-content-body--xl--PaddingRight:var(--pf-global--spacer--lg);--pf-c-data-list__expandable-content-body--md--PaddingBottom:var(--pf-global--spacer--lg);--pf-c-data-list__expandable-content-body--xl--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-data-list--m-compact--FontSize:var(--pf-global--FontSize--sm);--pf-c-data-list--m-compact__check--FontSize:var(--pf-global--FontSize--md);--pf-c-data-list--m-compact__cell--PaddingTop:var(--pf-global--spacer--sm);--pf-c-data-list--m-compact__cell--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-data-list--m-compact__cell--md--PaddingBottom:0;--pf-c-data-list--m-compact__cell-cell--PaddingTop:0;--pf-c-data-list--m-compact__cell-cell--md--PaddingTop:var(--pf-global--spacer--sm);--pf-c-data-list--m-compact__cell--cell--MarginRight:var(--pf-global--spacer--md);--pf-c-data-list--m-compact__item-control--PaddingTop:var(--pf-global--spacer--sm);--pf-c-data-list--m-compact__item-control--PaddingBottom:0;--pf-c-data-list--m-compact__item-control--MarginRight:var(--pf-global--spacer--md);--pf-c-data-list--m-compact__item-action--PaddingTop:var(--pf-global--spacer--sm);--pf-c-data-list--m-compact__item-action--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-data-list--m-compact__item-action--MarginLeft:var(--pf-global--spacer--md);--pf-c-data-list--m-compact__item-content--PaddingBottom:var(--pf-global--spacer--sm);color:var(--pf-global--Color--100);overflow-wrap:break-word;list-style-type:disc;border-top:var(--pf-c-data-list--BorderTopWidth) solid var(--pf-c-data-list--BorderTopColor)}@media screen and (min-width:576px){.pf-c-data-list{--pf-c-data-list--BorderTopColor:var(--pf-c-data-list--sm--BorderTopColor);--pf-c-data-list--BorderTopWidth:var(--pf-c-data-list--sm--BorderTopWidth);--pf-c-data-list__item--BorderBottomWidth:var(--pf-c-data-list__item--sm--BorderBottomWidth);--pf-c-data-list__item--BorderBottomColor:var(--pf-c-data-list__item--sm--BorderBottomColor)}}@media (min-width:576px){.pf-c-data-list{--pf-c-data-list__item--before--Top:var(--pf-c-data-list__item--before--sm--Top)}}.pf-c-data-list.pf-m-compact{font-size:var(--pf-c-data-list--m-compact--FontSize);--pf-c-data-list__item-action--MarginLeft:var(--pf-c-data-list--m-compact__item-action--MarginLeft);--pf-c-data-list__item-action--PaddingTop:var(--pf-c-data-list--m-compact__item-action--PaddingTop);--pf-c-data-list__item-action--PaddingBottom:var(--pf-c-data-list--m-compact__item-action--PaddingBottom);--pf-c-data-list__item-control--MarginRight:var(--pf-c-data-list--m-compact__item-control--MarginRight);--pf-c-data-list__item-control--PaddingTop:var(--pf-c-data-list--m-compact__item-control--PaddingTop);--pf-c-data-list__item-control--PaddingBottom:var(--pf-c-data-list--m-compact__item-control--PaddingBottom);--pf-c-data-list__item-content--md--PaddingBottom:var(--pf-c-data-list--m-compact__item-content--PaddingBottom)}.pf-c-data-list.pf-m-compact .pf-c-data-list__cell{--pf-c-data-list__cell--PaddingTop:var(--pf-c-data-list--m-compact__cell--PaddingTop);--pf-c-data-list__cell--PaddingBottom:var(--pf-c-data-list--m-compact__cell--PaddingBottom);--pf-c-data-list__cell--MarginRight:var(--pf-c-data-list--m-compact__cell--cell--MarginRight);--pf-c-data-list__cell--cell--PaddingTop:var(--pf-c-data-list--m-compact__cell-cell--PaddingTop)}.pf-c-data-list.pf-m-compact .pf-c-data-list__check{font-size:var(--pf-c-data-list--m-compact__check--FontSize)}.pf-c-data-list.pf-m-drag-over{overflow-anchor:none}.pf-c-data-list.pf-m-truncate,.pf-c-data-list__cell.pf-m-truncate,.pf-c-data-list__item-row.pf-m-truncate,.pf-c-data-list__text.pf-m-truncate{--pf-c-data-list--cell--MinWidth:var(--pf-c-data-list--cell--m-truncate--MinWidth);--pf-c-data-list--cell--Overflow:hidden;--pf-c-data-list--cell--TextOverflow:ellipsis;--pf-c-data-list--cell--WhiteSpace:nowrap}.pf-c-data-list.pf-m-break-word,.pf-c-data-list__cell.pf-m-break-word,.pf-c-data-list__item-row.pf-m-break-word,.pf-c-data-list__text.pf-m-break-word{--pf-c-data-list--cell--WordBreak:break-word}.pf-c-data-list.pf-m-nowrap,.pf-c-data-list__cell.pf-m-nowrap,.pf-c-data-list__item-row.pf-m-nowrap,.pf-c-data-list__text.pf-m-nowrap{--pf-c-data-list--cell--WhiteSpace:nowrap}.pf-c-data-list__item{position:relative;display:flex;flex-direction:column;background-color:var(--pf-c-data-list__item--BackgroundColor);border-bottom:var(--pf-c-data-list__item--BorderBottomWidth) solid var(--pf-c-data-list__item--BorderBottomColor)}.pf-c-data-list__item:before{position:absolute;top:var(--pf-c-data-list__item--before--Top);bottom:0;left:0;width:var(--pf-c-data-list__item--before--Width);content:"";background-color:var(--pf-c-data-list__item--before--BackgroundColor);transition:var(--pf-c-data-list__item--before--Transition)}.pf-c-data-list__item.pf-m-selectable{cursor:pointer;outline-offset:var(--pf-c-data-list__item--m-selectable--OutlineOffset)}.pf-c-data-list__item.pf-m-selectable:focus,.pf-c-data-list__item.pf-m-selectable:hover{position:relative;z-index:var(--pf-c-data-list__item--m-selectable--hover--ZIndex)}.pf-c-data-list__item.pf-m-selectable:focus:not(.pf-m-selected):not(:last-child),.pf-c-data-list__item.pf-m-selectable:hover:not(.pf-m-selected):not(:last-child){--pf-c-data-list__item--BorderBottomWidth:0}.pf-c-data-list__item.pf-m-selectable:focus:not(.pf-m-selected):not(:last-child)+.pf-c-data-list__item,.pf-c-data-list__item.pf-m-selectable:hover:not(.pf-m-selected):not(:last-child)+.pf-c-data-list__item{border-top:var(--pf-c-data-list__item--m-selectable--hover--item--BorderTopWidth) solid var(--pf-c-data-list__item--m-selectable--hover--item--BorderTopColor)}.pf-c-data-list__item.pf-m-selectable:hover{box-shadow:var(--pf-c-data-list__item--m-selectable--hover--BoxShadow)}.pf-c-data-list__item.pf-m-selectable:focus{box-shadow:var(--pf-c-data-list__item--m-selectable--focus--BoxShadow)}.pf-c-data-list__item.pf-m-selectable:active{box-shadow:var(--pf-c-data-list__item--m-selectable--active--BoxShadow)}.pf-c-data-list__item.pf-m-selected{--pf-c-data-list__item--before--BackgroundColor:var(--pf-c-data-list__item--m-selected--before--BackgroundColor);position:relative;z-index:var(--pf-c-data-list__item--m-selected--ZIndex);box-shadow:var(--pf-c-data-list__item--m-selected--BoxShadow)}.pf-c-data-list__item.pf-m-ghost-row:after{position:absolute;top:0;right:0;bottom:0;left:0;content:"";background-color:var(--pf-c-data-list__item--m-ghost-row--after--BackgroundColor);opacity:var(--pf-c-data-list__item--m-ghost-row--after--Opacity)}.pf-c-data-list__item.pf-m-expanded{--pf-c-data-list__item--before--BackgroundColor:var(--pf-c-data-list__item--m-expanded--before--BackgroundColor)}.pf-c-data-list__item.pf-m-expanded.pf-m-selectable:not(.pf-m-selected){--pf-c-data-list__item--before--BackgroundColor:var(--pf-c-data-list__item--m-expanded--m-selectable--before--BackgroundColor)}.pf-c-data-list__item-row{display:flex;flex-wrap:nowrap;padding-right:var(--pf-c-data-list__item-row--PaddingRight);padding-left:var(--pf-c-data-list__item-row--PaddingLeft)}.pf-c-data-list__item-control{display:flex;flex-wrap:nowrap;padding-top:var(--pf-c-data-list__item-control--PaddingTop);padding-bottom:var(--pf-c-data-list__item-control--PaddingBottom);margin-right:var(--pf-c-data-list__item-control--MarginRight)}.pf-c-data-list__item-control>:not(:last-child){margin-right:var(--pf-c-data-list__item-control--not-last-child--MarginRight)}.pf-c-data-list__item-draggable-button{padding-right:var(--pf-c-data-list__item-draggable-button--PaddingRight);padding-left:var(--pf-c-data-list__item-draggable-button--PaddingLeft);margin-top:var(--pf-c-data-list__item-draggable-button--MarginTop);margin-left:var(--pf-c-data-list__item-draggable-button--MarginLeft);border:0}.pf-c-data-list__item-draggable-button:hover{--pf-c-data-list__item-draggable-button-icon--Color:var(--pf-c-data-list__item-draggable-button--hover__draggable-icon--Color);cursor:grab}.pf-c-data-list__item-draggable-button:focus{--pf-c-data-list__item-draggable-button-icon--Color:var(--pf-c-data-list__item-draggable-button--focus__draggable-icon--Color)}.pf-c-data-list__item-draggable-button:active{cursor:grabbing}.pf-c-data-list__item-draggable-button.pf-m-disabled{--pf-c-data-list__item-draggable-button-icon--Color:var(--pf-c-data-list__item-draggable-button--m-disabled__draggable-icon--Color);pointer-events:none;cursor:none}.pf-c-data-list__item-draggable-button .pf-c-data-list__item-draggable-icon{color:var(--pf-c-data-list__item-draggable-button-icon--Color)}.pf-c-data-list__item-action{--pf-hidden-visible--visible--Display:var(--pf-c-data-list__item-action--Display);align-items:flex-start;align-content:flex-start;padding-top:var(--pf-c-data-list__item-action--PaddingTop);padding-bottom:var(--pf-c-data-list__item-action--PaddingBottom);margin-left:var(--pf-c-data-list__item-action--MarginLeft)}.pf-c-data-list__item-action>:not(:last-child){margin-right:var(--pf-c-data-list__item-action--not-last-child--MarginRight)}.pf-c-data-list__item-action .pf-c-data-list__action{margin-top:var(--pf-c-data-list__action--MarginTop)}.pf-c-data-list__toggle{margin-top:var(--pf-c-data-list__toggle--MarginTop);margin-left:var(--pf-c-data-list__toggle--MarginLeft)}.pf-c-data-list__toggle-icon{pointer-events:none;transition:var(--pf-c-data-list__toggle-icon--Transition)}.pf-c-data-list__item.pf-m-expanded .pf-c-data-list__toggle-icon{transform:rotate(var(--pf-c-data-list__item--m-expanded__toggle-icon--Rotate))}.pf-c-data-list__item-content{display:grid;width:100%;grid-template-columns:auto 1fr}.pf-c-data-list__cell{flex:1;grid-column:1/-1;padding-top:var(--pf-c-data-list__cell--PaddingTop);padding-bottom:var(--pf-c-data-list__cell--PaddingBottom)}.pf-c-data-list__cell+.pf-c-data-list__cell{flex:1 0 100%;order:1;padding-top:var(--pf-c-data-list__cell--cell--PaddingTop)}.pf-c-data-list__cell.pf-m-icon{flex-grow:0;margin-right:var(--pf-c-data-list__cell--m-icon--MarginRight);grid-column:1/2}.pf-c-data-list__cell.pf-m-icon+.pf-c-data-list__cell{grid-column:2/3;padding-top:var(--pf-c-data-list__cell--m-icon--cell--PaddingTop)}.pf-c-data-list__cell.pf-m-align-right{margin-left:0}.pf-c-data-list__text{display:inline-block}.pf-c-data-list__cell,.pf-c-data-list__text{min-width:var(--pf-c-data-list--cell--MinWidth);max-width:100%;overflow:var(--pf-c-data-list--cell--Overflow);text-overflow:var(--pf-c-data-list--cell--TextOverflow);word-break:var(--pf-c-data-list--cell--WordBreak);white-space:var(--pf-c-data-list--cell--WhiteSpace)}.pf-c-data-list__expandable-content{max-height:var(--pf-c-data-list__expandable-content--MaxHeight);overflow-y:auto;border-top:var(--pf-c-data-list__expandable-content--BorderTopWidth) solid var(--pf-c-data-list__expandable-content--BorderTopColor)}.pf-c-data-list__expandable-content .pf-c-data-list__expandable-content-body{padding:var(--pf-c-data-list__expandable-content-body--PaddingTop) var(--pf-c-data-list__expandable-content-body--PaddingRight) var(--pf-c-data-list__expandable-content-body--PaddingBottom) var(--pf-c-data-list__expandable-content-body--PaddingLeft)}.pf-c-data-list__expandable-content .pf-c-data-list__expandable-content-body.pf-m-no-padding{padding:0}.pf-c-description-list{--pf-c-description-list--RowGap:var(--pf-global--gutter--md);--pf-c-description-list--ColumnGap:var(--pf-global--spacer--lg);--pf-c-description-list--GridTemplateColumns--count:1;--pf-c-description-list--GridTemplateColumns--width:1fr;--pf-c-description-list--GridTemplateColumns:repeat(var(--pf-c-description-list--GridTemplateColumns--count),var(--pf-c-description-list--GridTemplateColumns--width));--pf-c-description-list__group--RowGap:var(--pf-global--spacer--sm);--pf-c-description-list__group--ColumnGap:var(--pf-global--spacer--md);--pf-c-description-list__group--GridTemplateColumns:auto;--pf-c-description-list__group--GridColumn:auto;--pf-c-description-list__term--FontWeight:var(--pf-global--FontWeight--bold);--pf-c-description-list__term--FontSize:var(--pf-global--FontSize--sm);--pf-c-description-list--m-horizontal__term--width:12ch;--pf-c-description-list--m-horizontal__description--width:minmax(10ch,auto);--pf-c-description-list--m-horizontal__group--GridTemplateColumns:var(--pf-c-description-list__term--width) var(--pf-c-description-list--m-horizontal__description--width);--pf-c-description-list--m-1-col--GridTemplateColumns--count:1;--pf-c-description-list--m-auto-fit--GridTemplateColumns--min:15.625rem;--pf-c-description-list--m-auto-fit--GridTemplateColumns--minmax--min:var(--pf-c-description-list--m-auto-fit--GridTemplateColumns--min);display:grid;align-items:baseline;row-gap:var(--pf-c-description-list--RowGap);column-gap:var(--pf-c-description-list--ColumnGap);grid-template-columns:var(--pf-c-description-list--GridTemplateColumns)}@media screen and (min-width:768px){.pf-c-description-list{--pf-c-description-list--m-2-col--GridTemplateColumns--count:2;--pf-c-description-list--m-3-col--GridTemplateColumns--count:3}}.pf-c-description-list.pf-m-horizontal{--pf-c-description-list__group--GridTemplateColumns:var(--pf-c-description-list--m-horizontal__group--GridTemplateColumns);--pf-c-description-list__term--width:var(--pf-c-description-list--m-horizontal__term--width)}@media (min-width:768px){.pf-c-description-list.pf-m-horizontal{--pf-c-description-list__term--width:var(--pf-c-description-list--m-horizontal__term--width-on-md,var(--pf-c-description-list--m-horizontal__term--width))}}@media (min-width:992px){.pf-c-description-list.pf-m-horizontal{--pf-c-description-list__term--width:var(--pf-c-description-list--m-horizontal__term--width-on-lg,var(--pf-c-description-list--m-horizontal__term--width-on-md,var(--pf-c-description-list--m-horizontal__term--width)))}}@media (min-width:1200px){.pf-c-description-list.pf-m-horizontal{--pf-c-description-list__term--width:var(--pf-c-description-list--m-horizontal__term--width-on-xl,var(--pf-c-description-list--m-horizontal__term--width-on-lg,var(--pf-c-description-list--m-horizontal__term--width-on-md,var(--pf-c-description-list--m-horizontal__term--width))))}}@media (min-width:1450px){.pf-c-description-list.pf-m-horizontal{--pf-c-description-list__term--width:var(--pf-c-description-list--m-horizontal__term--width-on-2xl,var(--pf-c-description-list--m-horizontal__term--width-on-xl,var(--pf-c-description-list--m-horizontal__term--width-on-lg,var(--pf-c-description-list--m-horizontal__term--width-on-md,var(--pf-c-description-list--m-horizontal__term--width)))))}}.pf-c-description-list.pf-m-inline-grid{display:inline-grid}.pf-c-description-list.pf-m-auto-column-widths{--pf-c-description-list--GridTemplateColumns--width:minmax(8ch,max-content)}.pf-c-description-list.pf-m-auto-fit{grid-template-columns:repeat(auto-fit,minmax(var(--pf-c-description-list--m-auto-fit--GridTemplateColumns--minmax--min),1fr));--pf-c-description-list--GridTemplateColumns--minmax--min:var(--pf-c-description-list--GridTemplateColumns--min)}@media (min-width:768px){.pf-c-description-list.pf-m-auto-fit{--pf-c-description-list--GridTemplateColumns--minmax--min:var(--pf-c-description-list--GridTemplateColumns--min-on-md,var(--pf-c-description-list--GridTemplateColumns--min))}}@media (min-width:992px){.pf-c-description-list.pf-m-auto-fit{--pf-c-description-list--GridTemplateColumns--minmax--min:var(--pf-c-description-list--GridTemplateColumns--min-on-lg,var(--pf-c-description-list--GridTemplateColumns--min-on-md,var(--pf-c-description-list--GridTemplateColumns--min)))}}@media (min-width:1200px){.pf-c-description-list.pf-m-auto-fit{--pf-c-description-list--GridTemplateColumns--minmax--min:var(--pf-c-description-list--GridTemplateColumns--min-on-xl,var(--pf-c-description-list--GridTemplateColumns--min-on-lg,var(--pf-c-description-list--GridTemplateColumns--min-on-md,var(--pf-c-description-list--GridTemplateColumns--min))))}}@media (min-width:1450px){.pf-c-description-list.pf-m-auto-fit{--pf-c-description-list--GridTemplateColumns--minmax--min:var(--pf-c-description-list--GridTemplateColumns--min-on-2xl,var(--pf-c-description-list--GridTemplateColumns--min-on-xl,var(--pf-c-description-list--GridTemplateColumns--min-on-lg,var(--pf-c-description-list--GridTemplateColumns--min-on-md,var(--pf-c-description-list--GridTemplateColumns--min)))))}}.pf-c-description-list__group{display:grid;grid-column:var(--pf-c-description-list__group--GridColumn);row-gap:var(--pf-c-description-list__group--RowGap);column-gap:var(--pf-c-description-list__group--ColumnGap);grid-template-columns:var(--pf-c-description-list__group--GridTemplateColumns);align-items:baseline}.pf-c-description-list__description,.pf-c-description-list__term{text-align:left}.pf-c-description-list__term{font-size:var(--pf-c-description-list__term--FontSize);font-weight:var(--pf-c-description-list__term--FontWeight)}.pf-c-description-list__term .pf-c-description-list__text{display:inline}.pf-c-description-list.pf-m-1-col{--pf-c-description-list--GridTemplateColumns--count:var(--pf-c-description-list--m-1-col--GridTemplateColumns--count)}.pf-c-description-list.pf-m-2-col{--pf-c-description-list--GridTemplateColumns--count:var(--pf-c-description-list--m-2-col--GridTemplateColumns--count)}.pf-c-description-list.pf-m-3-col{--pf-c-description-list--GridTemplateColumns--count:var(--pf-c-description-list--m-3-col--GridTemplateColumns--count)}@media (min-width:768px){.pf-c-description-list.pf-m-1-col-on-md{--pf-c-description-list--GridTemplateColumns--count:var(--pf-c-description-list--m-1-col--GridTemplateColumns--count)}.pf-c-description-list.pf-m-2-col-on-md{--pf-c-description-list--GridTemplateColumns--count:var(--pf-c-description-list--m-2-col--GridTemplateColumns--count)}.pf-c-description-list.pf-m-3-col-on-md{--pf-c-description-list--GridTemplateColumns--count:var(--pf-c-description-list--m-3-col--GridTemplateColumns--count)}}@media (min-width:992px){.pf-c-description-list.pf-m-1-col-on-lg{--pf-c-description-list--GridTemplateColumns--count:var(--pf-c-description-list--m-1-col--GridTemplateColumns--count)}.pf-c-description-list.pf-m-2-col-on-lg{--pf-c-description-list--GridTemplateColumns--count:var(--pf-c-description-list--m-2-col--GridTemplateColumns--count)}.pf-c-description-list.pf-m-3-col-on-lg{--pf-c-description-list--GridTemplateColumns--count:var(--pf-c-description-list--m-3-col--GridTemplateColumns--count)}}@media (min-width:1200px){.pf-c-description-list.pf-m-1-col-on-xl{--pf-c-description-list--GridTemplateColumns--count:var(--pf-c-description-list--m-1-col--GridTemplateColumns--count)}.pf-c-description-list.pf-m-2-col-on-xl{--pf-c-description-list--GridTemplateColumns--count:var(--pf-c-description-list--m-2-col--GridTemplateColumns--count)}.pf-c-description-list.pf-m-3-col-on-xl{--pf-c-description-list--GridTemplateColumns--count:var(--pf-c-description-list--m-3-col--GridTemplateColumns--count)}}@media (min-width:1450px){.pf-c-description-list.pf-m-1-col-on-2xl{--pf-c-description-list--GridTemplateColumns--count:var(--pf-c-description-list--m-1-col--GridTemplateColumns--count)}.pf-c-description-list.pf-m-2-col-on-2xl{--pf-c-description-list--GridTemplateColumns--count:var(--pf-c-description-list--m-2-col--GridTemplateColumns--count)}.pf-c-description-list.pf-m-3-col-on-2xl{--pf-c-description-list--GridTemplateColumns--count:var(--pf-c-description-list--m-3-col--GridTemplateColumns--count)}}.pf-c-dual-list-selector{--pf-c-dual-list-selector__header--GridArea:pane-header;--pf-c-dual-list-selector__tools--GridArea:pane-tools;--pf-c-dual-list-selector__status--GridArea:pane-status;--pf-c-dual-list-selector__menu--GridArea:pane-menu;--pf-c-dual-list-selector__controls--GridArea:controls;--pf-c-dual-list-selector--m-chosen__header--GridArea:pane-header-c;--pf-c-dual-list-selector--m-chosen__tools--GridArea:pane-tools-c;--pf-c-dual-list-selector--m-chosen__status--GridArea:pane-status-c;--pf-c-dual-list-selector--m-chosen__menu--GridArea:pane-menu-c;--pf-c-dual-list-selector--GridTemplateColumns--pane--MinMax--min:12.5rem;--pf-c-dual-list-selector--GridTemplateColumns--pane--MinMax--max:28.125rem;--pf-c-dual-list-selector__header--MarginBottom:var(--pf-global--spacer--sm);--pf-c-dual-list-selector__title-text--FontWeight:var(--pf-global--FontWeight--bold);--pf-c-dual-list-selector__tools--MarginBottom:var(--pf-global--spacer--md);--pf-c-dual-list-selector__tools-filter--tools-actions--MarginLeft:var(--pf-global--spacer--sm);--pf-c-dual-list-selector__menu--BorderWidth:var(--pf-global--BorderWidth--sm);--pf-c-dual-list-selector__menu--BorderColor:var(--pf-global--BorderColor--100);--pf-c-dual-list-selector__menu--MinHeight:12.5rem;--pf-c-dual-list-selector__menu--MaxHeight:20rem;--pf-c-dual-list-selector__item--PaddingTop:var(--pf-global--spacer--sm);--pf-c-dual-list-selector__item--PaddingRight:var(--pf-global--spacer--md);--pf-c-dual-list-selector__item--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-dual-list-selector__item--PaddingLeft:var(--pf-global--spacer--md);--pf-c-dual-list-selector__item--FontSize:var(--pf-global--FontSize--sm);--pf-c-dual-list-selector__item--BackgroundColor:transparent;--pf-c-dual-list-selector__item--hover--BackgroundColor:var(--pf-global--BackgroundColor--light-300);--pf-c-dual-list-selector__item--focus-within--BackgroundColor:var(--pf-global--BackgroundColor--light-300);--pf-c-dual-list-selector__item--m-selected--BackgroundColor:var(--pf-global--BackgroundColor--light-300);--pf-c-dual-list-selector__item--m-expandable--PaddingLeft:0;--pf-c-dual-list-selector__item--indent--base:calc(var(--pf-global--spacer--md) + var(--pf-global--spacer--sm) + var(--pf-c-dual-list-selector__item--FontSize));--pf-c-dual-list-selector__item--nested-indent--base:calc(var(--pf-c-dual-list-selector__item--indent--base) - var(--pf-global--spacer--md));--pf-c-dual-list-selector__item-text--Color:var(--pf-global--Color--100);--pf-c-dual-list-selector__item--m-selected__text--Color:var(--pf-global--active-color--100);--pf-c-dual-list-selector__item--m-selected__text--FontWeight:var(--pf-global--FontWeight--bold);--pf-c-dual-list-selector__status--MarginBottom:var(--pf-global--spacer--sm);--pf-c-dual-list-selector__status-text--FontSize:var(--pf-global--FontSize--sm);--pf-c-dual-list-selector__status-text--Color:var(--pf-global--Color--200);--pf-c-dual-list-selector__controls--PaddingRight:var(--pf-global--spacer--md);--pf-c-dual-list-selector__controls--PaddingLeft:var(--pf-global--spacer--md);--pf-c-dual-list-selector__item-toggle--PaddingTop:var(--pf-global--spacer--sm);--pf-c-dual-list-selector__item-toggle--PaddingRight:var(--pf-global--spacer--sm);--pf-c-dual-list-selector__item-toggle--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-dual-list-selector__item-toggle--PaddingLeft:var(--pf-global--spacer--md);--pf-c-dual-list-selector__item-toggle--MarginTop:calc(var(--pf-global--spacer--sm)*-1);--pf-c-dual-list-selector__item-toggle--MarginBottom:calc(var(--pf-global--spacer--sm)*-1);--pf-c-dual-list-selector__list__list__item-toggle--Left:0;--pf-c-dual-list-selector__list__list__item-toggle--TranslateX:-100%;--pf-c-dual-list-selector__item-check--MarginRight:var(--pf-global--spacer--sm);--pf-c-dual-list-selector__item-count--Marginleft:var(--pf-global--spacer--sm);--pf-c-dual-list-selector__item--c-badge--m-read--BackgroundColor:var(--pf-global--disabled-color--200);--pf-c-dual-list-selector__item-toggle-icon--Rotate:0;--pf-c-dual-list-selector__list-item--m-expanded__item-toggle-icon--Rotate:90deg;--pf-c-dual-list-selector__item-toggle-icon--Transition:var(--pf-global--Transition);--pf-c-dual-list-selector__item-toggle-icon--MinWidth:var(--pf-c-dual-list-selector__item--FontSize);display:grid;grid-template-areas:"pane-header . pane-header-c" "pane-tools . pane-tools-c" "pane-status . pane-status-c" "pane-menu controls pane-menu-c";grid-template-columns:minmax(var(--pf-c-dual-list-selector--GridTemplateColumns--pane--MinMax--min),var(--pf-c-dual-list-selector--GridTemplateColumns--pane--MinMax--max)) min-content minmax(var(--pf-c-dual-list-selector--GridTemplateColumns--pane--MinMax--min),var(--pf-c-dual-list-selector--GridTemplateColumns--pane--MinMax--max));grid-template-rows:repeat(3,auto) auto}.pf-c-dual-list-selector__pane{display:contents}.pf-c-dual-list-selector__pane.pf-m-chosen{--pf-c-dual-list-selector__header--GridArea:var(--pf-c-dual-list-selector--m-chosen__header--GridArea);--pf-c-dual-list-selector__tools--GridArea:var(--pf-c-dual-list-selector--m-chosen__tools--GridArea);--pf-c-dual-list-selector__status--GridArea:var(--pf-c-dual-list-selector--m-chosen__status--GridArea);--pf-c-dual-list-selector__menu--GridArea:var(--pf-c-dual-list-selector--m-chosen__menu--GridArea)}.pf-c-dual-list-selector__header{grid-area:var(--pf-c-dual-list-selector__header--GridArea);margin-bottom:var(--pf-c-dual-list-selector__header--MarginBottom)}.pf-c-dual-list-selector__title-text{font-weight:var(--pf-c-dual-list-selector__title-text--FontWeight)}.pf-c-dual-list-selector__tools{display:flex;grid-area:var(--pf-c-dual-list-selector__tools--GridArea);margin-bottom:var(--pf-c-dual-list-selector__tools--MarginBottom)}.pf-c-dual-list-selector__tools-filter{flex-grow:1}.pf-c-dual-list-selector__tools-actions{display:flex}.pf-c-dual-list-selector__tools-filter~.pf-c-dual-list-selector__tools-actions{margin-left:var(--pf-c-dual-list-selector__tools-filter--tools-actions--MarginLeft)}.pf-c-dual-list-selector__status{display:flex;grid-area:var(--pf-c-dual-list-selector__status--GridArea);margin-bottom:var(--pf-c-dual-list-selector__status--MarginBottom)}.pf-c-dual-list-selector__status-text{flex-grow:1;font-size:var(--pf-c-dual-list-selector__status-text--FontSize);color:var(--pf-c-dual-list-selector__status-text--Color)}.pf-c-dual-list-selector__menu{grid-area:var(--pf-c-dual-list-selector__menu--GridArea);min-height:var(--pf-c-dual-list-selector__menu--MinHeight);max-height:var(--pf-c-dual-list-selector__menu--MaxHeight);overflow:auto;border:var(--pf-c-dual-list-selector__menu--BorderWidth) solid var(--pf-c-dual-list-selector__menu--BorderColor)}.pf-c-dual-list-selector__list{display:flex;flex-direction:column}.pf-c-dual-list-selector__list .pf-c-dual-list-selector__list{--pf-c-dual-list-selector__item-toggle--MarginTop:0;--pf-c-dual-list-selector__item-toggle--MarginBottom:0}.pf-c-dual-list-selector__list .pf-c-dual-list-selector__list .pf-c-dual-list-selector__item-toggle{position:absolute;top:0;left:var(--pf-c-dual-list-selector__list__list__item-toggle--Left);transform:translateX(var(--pf-c-dual-list-selector__list__list__item-toggle--TranslateX))}.pf-c-dual-list-selector__list-item.pf-m-expandable{--pf-c-dual-list-selector__item--PaddingLeft:var(--pf-c-dual-list-selector__item--m-expandable--PaddingLeft)}.pf-c-dual-list-selector__list-item.pf-m-expanded>.pf-c-dual-list-selector__item{--pf-c-dual-list-selector__item-toggle-icon--Rotate:var(--pf-c-dual-list-selector__list-item--m-expanded__item-toggle-icon--Rotate)}.pf-c-dual-list-selector__item,.pf-c-dual-list-selector__main{display:flex}.pf-c-dual-list-selector__item,.pf-c-dual-list-selector__item-main{flex-basis:100%}.pf-c-dual-list-selector__item{position:relative;width:100%;padding:var(--pf-c-dual-list-selector__item--PaddingTop) var(--pf-c-dual-list-selector__item--PaddingRight) var(--pf-c-dual-list-selector__item--PaddingBottom) var(--pf-c-dual-list-selector__item--PaddingLeft);font-size:var(--pf-c-dual-list-selector__item--FontSize);text-align:left;cursor:pointer;background-color:var(--pf-c-dual-list-selector__item--BackgroundColor);border:0}.pf-c-dual-list-selector__item:hover{--pf-c-dual-list-selector__item--BackgroundColor:var(--pf-c-dual-list-selector__item--hover--BackgroundColor)}.pf-c-dual-list-selector__item:focus-within{--pf-c-dual-list-selector__item--BackgroundColor:var(--pf-c-dual-list-selector__item--focus-within--BackgroundColor)}.pf-c-dual-list-selector__item.pf-m-selected{--pf-c-dual-list-selector__item--BackgroundColor:var(--pf-c-dual-list-selector__item--m-selected--BackgroundColor)}.pf-c-dual-list-selector__item.pf-m-selected .pf-c-dual-list-selector__item-text{--pf-c-dual-list-selector__item-text--Color:var(--pf-c-dual-list-selector__item--m-selected__text--Color);font-weight:var(--pf-c-dual-list-selector__item--m-selected__text--FontWeight)}.pf-c-dual-list-selector__item.pf-m-check{--pf-c-dual-list-selector__item--m-selected--BackgroundColor:transparent}.pf-c-dual-list-selector__item .pf-c-dual-list-selector__item-count{margin-left:var(--pf-c-dual-list-selector__item-count--Marginleft)}.pf-c-dual-list-selector__item .pf-c-dual-list-selector__item-count .pf-c-badge.pf-m-read{--pf-c-badge--m-read--BackgroundColor:var(--pf-c-dual-list-selector__item--c-badge--m-read--BackgroundColor)}.pf-c-dual-list-selector__item-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-grow:1;color:var(--pf-c-dual-list-selector__item-text--Color)}.pf-c-dual-list-selector__controls{grid-area:var(--pf-c-dual-list-selector__controls--GridArea);align-self:center;padding-right:var(--pf-c-dual-list-selector__controls--PaddingRight);padding-left:var(--pf-c-dual-list-selector__controls--PaddingLeft)}.pf-c-dual-list-selector__item-main{display:flex;min-width:0}.pf-c-dual-list-selector__item-toggle{padding:var(--pf-c-dual-list-selector__item-toggle--PaddingTop) var(--pf-c-dual-list-selector__item-toggle--PaddingRight) var(--pf-c-dual-list-selector__item-toggle--PaddingBottom) var(--pf-c-dual-list-selector__item-toggle--PaddingLeft);margin-top:var(--pf-c-dual-list-selector__item-toggle--MarginTop);margin-bottom:var(--pf-c-dual-list-selector__item-toggle--MarginBottom)}.pf-c-dual-list-selector__item-check{display:flex;align-items:center;margin-right:var(--pf-c-dual-list-selector__item-check--MarginRight)}.pf-c-dual-list-selector__item-toggle-icon{display:inline-block;min-width:var(--pf-c-dual-list-selector__item-toggle-icon--MinWidth);text-align:center;transition:var(--pf-c-dual-list-selector__item-toggle-icon--Transition);transform:rotate(var(--pf-c-dual-list-selector__item-toggle-icon--Rotate))}.pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item{--pf-c-dual-list-selector__item--PaddingLeft:calc(var(--pf-c-dual-list-selector__item--nested-indent--base)*1 + var(--pf-c-dual-list-selector__item--indent--base));--pf-c-dual-list-selector__list__list__item-toggle--Left:var(--pf-c-dual-list-selector__item--PaddingLeft)}.pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item{--pf-c-dual-list-selector__item--PaddingLeft:calc(var(--pf-c-dual-list-selector__item--nested-indent--base)*2 + var(--pf-c-dual-list-selector__item--indent--base));--pf-c-dual-list-selector__list__list__item-toggle--Left:var(--pf-c-dual-list-selector__item--PaddingLeft)}.pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item{--pf-c-dual-list-selector__item--PaddingLeft:calc(var(--pf-c-dual-list-selector__item--nested-indent--base)*3 + var(--pf-c-dual-list-selector__item--indent--base));--pf-c-dual-list-selector__list__list__item-toggle--Left:var(--pf-c-dual-list-selector__item--PaddingLeft)}.pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item{--pf-c-dual-list-selector__item--PaddingLeft:calc(var(--pf-c-dual-list-selector__item--nested-indent--base)*4 + var(--pf-c-dual-list-selector__item--indent--base));--pf-c-dual-list-selector__list__list__item-toggle--Left:var(--pf-c-dual-list-selector__item--PaddingLeft)}.pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item{--pf-c-dual-list-selector__item--PaddingLeft:calc(var(--pf-c-dual-list-selector__item--nested-indent--base)*5 + var(--pf-c-dual-list-selector__item--indent--base));--pf-c-dual-list-selector__list__list__item-toggle--Left:var(--pf-c-dual-list-selector__item--PaddingLeft)}.pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item{--pf-c-dual-list-selector__item--PaddingLeft:calc(var(--pf-c-dual-list-selector__item--nested-indent--base)*6 + var(--pf-c-dual-list-selector__item--indent--base));--pf-c-dual-list-selector__list__list__item-toggle--Left:var(--pf-c-dual-list-selector__item--PaddingLeft)}.pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item{--pf-c-dual-list-selector__item--PaddingLeft:calc(var(--pf-c-dual-list-selector__item--nested-indent--base)*7 + var(--pf-c-dual-list-selector__item--indent--base));--pf-c-dual-list-selector__list__list__item-toggle--Left:var(--pf-c-dual-list-selector__item--PaddingLeft)}.pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item{--pf-c-dual-list-selector__item--PaddingLeft:calc(var(--pf-c-dual-list-selector__item--nested-indent--base)*8 + var(--pf-c-dual-list-selector__item--indent--base));--pf-c-dual-list-selector__list__list__item-toggle--Left:var(--pf-c-dual-list-selector__item--PaddingLeft)}.pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item{--pf-c-dual-list-selector__item--PaddingLeft:calc(var(--pf-c-dual-list-selector__item--nested-indent--base)*9 + var(--pf-c-dual-list-selector__item--indent--base));--pf-c-dual-list-selector__list__list__item-toggle--Left:var(--pf-c-dual-list-selector__item--PaddingLeft)}.pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item{--pf-c-dual-list-selector__item--PaddingLeft:calc(var(--pf-c-dual-list-selector__item--nested-indent--base)*10 + var(--pf-c-dual-list-selector__item--indent--base));--pf-c-dual-list-selector__list__list__item-toggle--Left:var(--pf-c-dual-list-selector__item--PaddingLeft)}.pf-c-toolbar{--pf-c-toolbar--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-toolbar--RowGap:var(--pf-global--spacer--lg);--pf-c-toolbar--PaddingTop:var(--pf-global--spacer--md);--pf-c-toolbar--PaddingBottom:var(--pf-global--spacer--md);--pf-c-toolbar__content--PaddingRight:var(--pf-global--spacer--md);--pf-c-toolbar__content--PaddingLeft:var(--pf-global--spacer--md);--pf-c-toolbar--m-page-insets--inset:var(--pf-global--spacer--md);--pf-c-toolbar--m-page-insets--xl--inset:var(--pf-global--spacer--lg);--pf-c-toolbar__expandable-content--PaddingTop:var(--pf-c-toolbar--RowGap);--pf-c-toolbar__expandable-content--PaddingRight:var(--pf-c-toolbar__content--PaddingRight);--pf-c-toolbar__expandable-content--PaddingBottom:var(--pf-global--spacer--md);--pf-c-toolbar__expandable-content--PaddingLeft:var(--pf-c-toolbar__content--PaddingLeft);--pf-c-toolbar__expandable-content--lg--PaddingRight:0;--pf-c-toolbar__expandable-content--lg--PaddingBottom:0;--pf-c-toolbar__expandable-content--lg--PaddingLeft:0;--pf-c-toolbar__expandable-content--ZIndex:var(--pf-global--ZIndex--xs);--pf-c-toolbar__expandable-content--BoxShadow:var(--pf-global--BoxShadow--md-bottom);--pf-c-toolbar__expandable-content--BackgroundColor:var(--pf-c-toolbar--BackgroundColor);--pf-c-toolbar__expandable-content--m-expanded--GridRowGap:var(--pf-global--gutter--md);--pf-c-toolbar__group--m-chip-container--MarginTop:calc(var(--pf-global--spacer--md)*-1);--pf-c-toolbar__group--m-chip-container__item--MarginTop:var(--pf-global--spacer--md);--pf-c-toolbar--spacer--base:var(--pf-global--spacer--md);--pf-c-toolbar__item--spacer:var(--pf-c-toolbar--spacer--base);--pf-c-toolbar__group--spacer:var(--pf-c-toolbar--spacer--base);--pf-c-toolbar__group--m-toggle-group--spacer:var(--pf-global--spacer--sm);--pf-c-toolbar__group--m-toggle-group--m-show--spacer:var(--pf-c-toolbar__group--spacer);--pf-c-toolbar__group--m-icon-button-group--spacer:var(--pf-c-toolbar__group--spacer);--pf-c-toolbar__group--m-icon-button-group--space-items:0;--pf-c-toolbar__group--m-button-group--spacer:var(--pf-c-toolbar__group--spacer);--pf-c-toolbar__group--m-button-group--space-items:var(--pf-global--spacer--sm);--pf-c-toolbar__group--m-filter-group--spacer:var(--pf-c-toolbar__group--spacer);--pf-c-toolbar__group--m-filter-group--space-items:0;--pf-c-toolbar__item--m-overflow-menu--spacer:var(--pf-c-toolbar__item--spacer);--pf-c-toolbar__item--m-bulk-select--spacer:var(--pf-global--spacer--lg);--pf-c-toolbar__expand-all-icon--Rotate:0;--pf-c-toolbar__expand-all-icon--Transition:var(--pf-global--Transition);--pf-c-toolbar__item--m-expand-all--m-expanded__expand-all-icon--Rotate:90deg;--pf-c-toolbar__item--m-search-filter--spacer:var(--pf-global--spacer--sm);--pf-c-toolbar__item--m-chip-group--spacer:var(--pf-global--spacer--sm);--pf-c-toolbar__item--m-label--spacer:var(--pf-c-toolbar__item--spacer);--pf-c-toolbar__item--m-label--FontWeight:var(--pf-global--FontWeight--bold);--pf-c-toolbar__toggle--m-expanded__c-button--m-plain--Color:var(--pf-global--Color--100);--pf-c-toolbar--c-divider--m-vertical--spacer:var(--pf-c-toolbar--spacer--base);position:relative;row-gap:var(--pf-c-toolbar--RowGap);display:grid;padding-top:var(--pf-c-toolbar--PaddingTop);padding-bottom:var(--pf-c-toolbar--PaddingBottom);background-color:var(--pf-c-toolbar--BackgroundColor)}@media screen and (min-width:992px){.pf-c-toolbar{--pf-c-toolbar__expandable-content--PaddingRight:var(--pf-c-toolbar__expandable-content--lg--PaddingRight);--pf-c-toolbar__expandable-content--PaddingBottom:var(--pf-c-toolbar__expandable-content--lg--PaddingBottom);--pf-c-toolbar__expandable-content--PaddingLeft:var(--pf-c-toolbar__expandable-content--lg--PaddingLeft)}}@media screen and (min-width:1200px){.pf-c-toolbar{--pf-c-toolbar--m-page-insets--inset:var(--pf-c-toolbar--m-page-insets--xl--inset)}}.pf-c-toolbar.pf-m-page-insets{--pf-c-toolbar__content--PaddingRight:var(--pf-c-toolbar--m-page-insets--inset);--pf-c-toolbar__content--PaddingLeft:var(--pf-c-toolbar--m-page-insets--inset)}.pf-c-toolbar__content-section>.pf-c-divider,.pf-c-toolbar__group>.pf-c-divider{--pf-c-toolbar--spacer:var(--pf-c-toolbar--c-divider--m-vertical--spacer)}.pf-c-toolbar__content-section>.pf-c-divider.pf-m-vertical,.pf-c-toolbar__group>.pf-c-divider.pf-m-vertical{margin-right:var(--pf-c-toolbar--spacer)}.pf-c-toolbar__content-section>.pf-c-divider.pf-m-vertical:last-child,.pf-c-toolbar__group>.pf-c-divider.pf-m-vertical:last-child{--pf-c-toolbar--spacer:0}.pf-c-toolbar__group{--pf-c-toolbar--spacer:var(--pf-c-toolbar__group--spacer);display:flex;align-items:center;margin-right:var(--pf-c-toolbar--spacer)}.pf-c-toolbar__group.pf-m-button-group{--pf-c-toolbar--spacer:var(--pf-c-toolbar__group--m-button-group--spacer)}.pf-c-toolbar__group.pf-m-button-group>*{--pf-c-toolbar--spacer:var(--pf-c-toolbar__group--m-button-group--space-items)}.pf-c-toolbar__group.pf-m-icon-button-group{--pf-c-toolbar--spacer:var(--pf-c-toolbar__group--m-icon-button-group--spacer)}.pf-c-toolbar__group.pf-m-icon-button-group>*{--pf-c-toolbar--spacer:var(--pf-c-toolbar__group--m-icon-button-group--space-items)}.pf-c-toolbar__group.pf-m-filter-group{--pf-c-toolbar--spacer:var(--pf-c-toolbar__group--m-filter-group--spacer)}.pf-c-toolbar__group.pf-m-filter-group>*{--pf-c-toolbar--spacer:var(--pf-c-toolbar__group--m-filter-group--space-items)}.pf-c-toolbar__group.pf-m-filter-group>*+*{margin-left:-1px}.pf-c-toolbar__group.pf-m-toggle-group{--pf-c-toolbar--spacer:var(--pf-c-toolbar__group--m-toggle-group--spacer)}.pf-c-toolbar__group.pf-m-toggle-group .pf-c-toolbar__group,.pf-c-toolbar__group.pf-m-toggle-group .pf-c-toolbar__item{display:none;visibility:hidden}.pf-c-toolbar__group.pf-m-toggle-group .pf-c-toolbar__toggle{display:inline-block;visibility:visible}.pf-c-toolbar__group:last-child{--pf-c-toolbar--spacer:0}.pf-c-toolbar__item{--pf-c-toolbar--spacer:var(--pf-c-toolbar__item--spacer);margin-right:var(--pf-c-toolbar--spacer)}.pf-c-toolbar__item.pf-m-overflow-menu{--pf-c-toolbar--spacer:var(--pf-c-toolbar__item--m-overflow-menu--spacer)}.pf-c-toolbar__item.pf-m-bulk-select{--pf-c-toolbar--spacer:var(--pf-c-toolbar__item--m-bulk-select--spacer)}.pf-c-toolbar__item.pf-m-expand-all.pf-m-expanded{--pf-c-toolbar__expand-all-icon--Rotate:var(--pf-c-toolbar__item--m-expand-all--m-expanded__expand-all-icon--Rotate)}.pf-c-toolbar__item.pf-m-search-filter{--pf-c-toolbar--spacer:var(--pf-c-toolbar__item--m-search-filter--spacer)}.pf-c-toolbar__item.pf-m-chip-group{--pf-c-toolbar--spacer:var(--pf-c-toolbar__item--m-chip-group--spacer)}.pf-c-toolbar__item.pf-m-label{--pf-c-toolbar--spacer:var(--pf-c-toolbar__item--m-label--spacer);font-weight:var(--pf-c-toolbar__item--m-label--FontWeight)}.pf-c-toolbar__item.pf-m-pagination{margin-left:auto}.pf-c-toolbar__item.pf-m-pagination .pf-c-pagination{flex-wrap:nowrap}.pf-c-toolbar__item:last-child{--pf-c-toolbar--spacer:0}.pf-c-toolbar__expand-all-icon{display:inline-block;transition:var(--pf-c-toolbar__expand-all-icon--Transition);transform:rotate(var(--pf-c-toolbar__expand-all-icon--Rotate))}.pf-c-toolbar__content,.pf-c-toolbar__content-section{display:flex;flex-wrap:wrap;align-items:center}.pf-c-toolbar__content{position:relative;padding-right:var(--pf-c-toolbar__content--PaddingRight);padding-left:var(--pf-c-toolbar__content--PaddingLeft)}.pf-c-toolbar__content-section{width:100%}.pf-c-toolbar__expandable-content{position:absolute;top:100%;right:0;left:0;z-index:var(--pf-c-toolbar__expandable-content--ZIndex);display:none;width:100%;padding:var(--pf-c-toolbar__expandable-content--PaddingTop) var(--pf-c-toolbar__expandable-content--PaddingRight) var(--pf-c-toolbar__expandable-content--PaddingBottom) var(--pf-c-toolbar__expandable-content--PaddingLeft);visibility:hidden;background-color:var(--pf-c-toolbar__expandable-content--BackgroundColor);box-shadow:var(--pf-c-toolbar__expandable-content--BoxShadow)}@media screen and (min-width:992px){.pf-c-toolbar__expandable-content{position:static;box-shadow:none}}.pf-c-toolbar__expandable-content.pf-m-expanded{display:grid;grid-row-gap:var(--pf-c-toolbar__expandable-content--m-expanded--GridRowGap);visibility:visible}.pf-c-toolbar__expandable-content .pf-c-toolbar__group,.pf-c-toolbar__expandable-content .pf-c-toolbar__item{--pf-c-toolbar--spacer:0}.pf-c-toolbar__expandable-content .pf-c-toolbar__group{display:grid;grid-row-gap:var(--pf-c-toolbar__expandable-content--m-expanded--GridRowGap)}.pf-c-toolbar__expandable-content .pf-m-label{display:none;visibility:hidden}.pf-c-toolbar__content.pf-m-chip-container,.pf-c-toolbar__group.pf-m-chip-container{display:flex;flex-wrap:wrap;align-items:baseline;margin-top:var(--pf-c-toolbar__group--m-chip-container--MarginTop);grid-row-gap:0}.pf-c-toolbar__content.pf-m-chip-container .pf-c-toolbar__item,.pf-c-toolbar__group.pf-m-chip-container .pf-c-toolbar__item{--pf-c-toolbar--spacer:var(--pf-c-toolbar__item--spacer);margin-top:var(--pf-c-toolbar__group--m-chip-container__item--MarginTop)}.pf-c-toolbar__content.pf-m-chip-container .pf-c-toolbar__group,.pf-c-toolbar__group.pf-m-chip-container .pf-c-toolbar__group{--pf-c-toolbar--spacer:var(--pf-c-toolbar__group--spacer);display:flex;flex-wrap:wrap;grid-row-gap:0}.pf-c-toolbar__content.pf-m-chip-container .pf-c-toolbar__group:last-child,.pf-c-toolbar__content.pf-m-chip-container .pf-c-toolbar__item:last-child,.pf-c-toolbar__group.pf-m-chip-container .pf-c-toolbar__group:last-child,.pf-c-toolbar__group.pf-m-chip-container .pf-c-toolbar__item:last-child{--pf-c-toolbar--spacer:0}.pf-c-toolbar .pf-c-chip-group:last-child{--pf-c-chip-group--MarginRight:0}.pf-c-toolbar .pf-c-chip-group li:last-child{--pf-c-chip-group__li--m-toolbar--MarginRight:0}.pf-c-toolbar__toggle.pf-m-expanded .pf-c-button.pf-m-plain{color:var(--pf-c-toolbar__toggle--m-expanded__c-button--m-plain--Color)}.pf-m-toggle-group.pf-m-show{--pf-c-toolbar--spacer:var(--pf-c-toolbar__group--m-toggle-group--m-show--spacer)}.pf-m-toggle-group.pf-m-show .pf-c-toolbar__group,.pf-m-toggle-group.pf-m-show .pf-c-toolbar__item{display:flex;flex:0 1 auto;visibility:visible}.pf-m-toggle-group.pf-m-show .pf-c-toolbar__toggle{display:none;visibility:hidden}@media (min-width:576px){.pf-m-toggle-group.pf-m-show-on-sm{--pf-c-toolbar--spacer:var(--pf-c-toolbar__group--m-toggle-group--m-show--spacer)}.pf-m-toggle-group.pf-m-show-on-sm .pf-c-toolbar__group,.pf-m-toggle-group.pf-m-show-on-sm .pf-c-toolbar__item{display:flex;flex:0 1 auto;visibility:visible}.pf-m-toggle-group.pf-m-show-on-sm .pf-c-toolbar__toggle{display:none;visibility:hidden}}@media (min-width:768px){.pf-m-toggle-group.pf-m-show-on-md{--pf-c-toolbar--spacer:var(--pf-c-toolbar__group--m-toggle-group--m-show--spacer)}.pf-m-toggle-group.pf-m-show-on-md .pf-c-toolbar__group,.pf-m-toggle-group.pf-m-show-on-md .pf-c-toolbar__item{display:flex;flex:0 1 auto;visibility:visible}.pf-m-toggle-group.pf-m-show-on-md .pf-c-toolbar__toggle{display:none;visibility:hidden}}@media (min-width:992px){.pf-m-toggle-group.pf-m-show-on-lg{--pf-c-toolbar--spacer:var(--pf-c-toolbar__group--m-toggle-group--m-show--spacer)}.pf-m-toggle-group.pf-m-show-on-lg .pf-c-toolbar__group,.pf-m-toggle-group.pf-m-show-on-lg .pf-c-toolbar__item{display:flex;flex:0 1 auto;visibility:visible}.pf-m-toggle-group.pf-m-show-on-lg .pf-c-toolbar__toggle{display:none;visibility:hidden}}@media (min-width:1200px){.pf-m-toggle-group.pf-m-show-on-xl{--pf-c-toolbar--spacer:var(--pf-c-toolbar__group--m-toggle-group--m-show--spacer)}.pf-m-toggle-group.pf-m-show-on-xl .pf-c-toolbar__group,.pf-m-toggle-group.pf-m-show-on-xl .pf-c-toolbar__item{display:flex;flex:0 1 auto;visibility:visible}.pf-m-toggle-group.pf-m-show-on-xl .pf-c-toolbar__toggle{display:none;visibility:hidden}}@media (min-width:1450px){.pf-m-toggle-group.pf-m-show-on-2xl{--pf-c-toolbar--spacer:var(--pf-c-toolbar__group--m-toggle-group--m-show--spacer)}.pf-m-toggle-group.pf-m-show-on-2xl .pf-c-toolbar__group,.pf-m-toggle-group.pf-m-show-on-2xl .pf-c-toolbar__item{display:flex;flex:0 1 auto;visibility:visible}.pf-m-toggle-group.pf-m-show-on-2xl .pf-c-toolbar__toggle{display:none;visibility:hidden}}.pf-c-toolbar .pf-c-toolbar__group.pf-m-align-right,.pf-c-toolbar .pf-c-toolbar__item.pf-m-align-right{margin-left:auto}.pf-c-toolbar .pf-c-toolbar__group.pf-m-align-left,.pf-c-toolbar .pf-c-toolbar__group.pf-m-align-right~.pf-m-pagination,.pf-c-toolbar .pf-c-toolbar__item.pf-m-align-left,.pf-c-toolbar .pf-c-toolbar__item.pf-m-align-right~.pf-m-pagination{margin-left:0}.pf-c-toolbar .pf-c-toolbar__group.pf-m-align-left~.pf-m-pagination,.pf-c-toolbar .pf-c-toolbar__item.pf-m-align-left~.pf-m-pagination{margin-left:auto}.pf-c-toolbar .pf-m-hidden{display:none;visibility:hidden}.pf-c-toolbar .pf-m-visible{display:flex;visibility:visible}.pf-c-toolbar .pf-c-toolbar__content-section.pf-m-nowrap,.pf-c-toolbar .pf-c-toolbar__group.pf-m-nowrap{flex-wrap:nowrap}.pf-c-toolbar .pf-c-toolbar__content-section.pf-m-wrap,.pf-c-toolbar .pf-c-toolbar__group.pf-m-wrap{flex-wrap:wrap}@media (min-width:576px){.pf-c-toolbar .pf-c-toolbar__group.pf-m-align-right-on-sm,.pf-c-toolbar .pf-c-toolbar__item.pf-m-align-right-on-sm{margin-left:auto}.pf-c-toolbar .pf-c-toolbar__group.pf-m-align-left-on-sm,.pf-c-toolbar .pf-c-toolbar__group.pf-m-align-right-on-sm~.pf-m-pagination,.pf-c-toolbar .pf-c-toolbar__item.pf-m-align-left-on-sm,.pf-c-toolbar .pf-c-toolbar__item.pf-m-align-right-on-sm~.pf-m-pagination{margin-left:0}.pf-c-toolbar .pf-c-toolbar__group.pf-m-align-left-on-sm~.pf-m-pagination,.pf-c-toolbar .pf-c-toolbar__item.pf-m-align-left-on-sm~.pf-m-pagination{margin-left:auto}.pf-c-toolbar .pf-m-hidden-on-sm{display:none;visibility:hidden}.pf-c-toolbar .pf-m-visible-on-sm{display:flex;visibility:visible}.pf-c-toolbar .pf-c-toolbar__content-section.pf-m-nowrap-on-sm,.pf-c-toolbar .pf-c-toolbar__group.pf-m-nowrap-on-sm{flex-wrap:nowrap}.pf-c-toolbar .pf-c-toolbar__content-section.pf-m-wrap-on-sm,.pf-c-toolbar .pf-c-toolbar__group.pf-m-wrap-on-sm{flex-wrap:wrap}}@media (min-width:768px){.pf-c-toolbar .pf-c-toolbar__group.pf-m-align-right-on-md,.pf-c-toolbar .pf-c-toolbar__item.pf-m-align-right-on-md{margin-left:auto}.pf-c-toolbar .pf-c-toolbar__group.pf-m-align-left-on-md,.pf-c-toolbar .pf-c-toolbar__group.pf-m-align-right-on-md~.pf-m-pagination,.pf-c-toolbar .pf-c-toolbar__item.pf-m-align-left-on-md,.pf-c-toolbar .pf-c-toolbar__item.pf-m-align-right-on-md~.pf-m-pagination{margin-left:0}.pf-c-toolbar .pf-c-toolbar__group.pf-m-align-left-on-md~.pf-m-pagination,.pf-c-toolbar .pf-c-toolbar__item.pf-m-align-left-on-md~.pf-m-pagination{margin-left:auto}.pf-c-toolbar .pf-m-hidden-on-md{display:none;visibility:hidden}.pf-c-toolbar .pf-m-visible-on-md{display:flex;visibility:visible}.pf-c-toolbar .pf-c-toolbar__content-section.pf-m-nowrap-on-md,.pf-c-toolbar .pf-c-toolbar__group.pf-m-nowrap-on-md{flex-wrap:nowrap}.pf-c-toolbar .pf-c-toolbar__content-section.pf-m-wrap-on-md,.pf-c-toolbar .pf-c-toolbar__group.pf-m-wrap-on-md{flex-wrap:wrap}}@media (min-width:992px){.pf-c-toolbar .pf-c-toolbar__group.pf-m-align-right-on-lg,.pf-c-toolbar .pf-c-toolbar__item.pf-m-align-right-on-lg{margin-left:auto}.pf-c-toolbar .pf-c-toolbar__group.pf-m-align-left-on-lg,.pf-c-toolbar .pf-c-toolbar__group.pf-m-align-right-on-lg~.pf-m-pagination,.pf-c-toolbar .pf-c-toolbar__item.pf-m-align-left-on-lg,.pf-c-toolbar .pf-c-toolbar__item.pf-m-align-right-on-lg~.pf-m-pagination{margin-left:0}.pf-c-toolbar .pf-c-toolbar__group.pf-m-align-left-on-lg~.pf-m-pagination,.pf-c-toolbar .pf-c-toolbar__item.pf-m-align-left-on-lg~.pf-m-pagination{margin-left:auto}.pf-c-toolbar .pf-m-hidden-on-lg{display:none;visibility:hidden}.pf-c-toolbar .pf-m-visible-on-lg{display:flex;visibility:visible}.pf-c-toolbar .pf-c-toolbar__content-section.pf-m-nowrap-on-lg,.pf-c-toolbar .pf-c-toolbar__group.pf-m-nowrap-on-lg{flex-wrap:nowrap}.pf-c-toolbar .pf-c-toolbar__content-section.pf-m-wrap-on-lg,.pf-c-toolbar .pf-c-toolbar__group.pf-m-wrap-on-lg{flex-wrap:wrap}}@media (min-width:1200px){.pf-c-toolbar .pf-c-toolbar__group.pf-m-align-right-on-xl,.pf-c-toolbar .pf-c-toolbar__item.pf-m-align-right-on-xl{margin-left:auto}.pf-c-toolbar .pf-c-toolbar__group.pf-m-align-left-on-xl,.pf-c-toolbar .pf-c-toolbar__group.pf-m-align-right-on-xl~.pf-m-pagination,.pf-c-toolbar .pf-c-toolbar__item.pf-m-align-left-on-xl,.pf-c-toolbar .pf-c-toolbar__item.pf-m-align-right-on-xl~.pf-m-pagination{margin-left:0}.pf-c-toolbar .pf-c-toolbar__group.pf-m-align-left-on-xl~.pf-m-pagination,.pf-c-toolbar .pf-c-toolbar__item.pf-m-align-left-on-xl~.pf-m-pagination{margin-left:auto}.pf-c-toolbar .pf-m-hidden-on-xl{display:none;visibility:hidden}.pf-c-toolbar .pf-m-visible-on-xl{display:flex;visibility:visible}.pf-c-toolbar .pf-c-toolbar__content-section.pf-m-nowrap-on-xl,.pf-c-toolbar .pf-c-toolbar__group.pf-m-nowrap-on-xl{flex-wrap:nowrap}.pf-c-toolbar .pf-c-toolbar__content-section.pf-m-wrap-on-xl,.pf-c-toolbar .pf-c-toolbar__group.pf-m-wrap-on-xl{flex-wrap:wrap}}@media (min-width:1450px){.pf-c-toolbar .pf-c-toolbar__group.pf-m-align-right-on-2xl,.pf-c-toolbar .pf-c-toolbar__item.pf-m-align-right-on-2xl{margin-left:auto}.pf-c-toolbar .pf-c-toolbar__group.pf-m-align-left-on-2xl,.pf-c-toolbar .pf-c-toolbar__group.pf-m-align-right-on-2xl~.pf-m-pagination,.pf-c-toolbar .pf-c-toolbar__item.pf-m-align-left-on-2xl,.pf-c-toolbar .pf-c-toolbar__item.pf-m-align-right-on-2xl~.pf-m-pagination{margin-left:0}.pf-c-toolbar .pf-c-toolbar__group.pf-m-align-left-on-2xl~.pf-m-pagination,.pf-c-toolbar .pf-c-toolbar__item.pf-m-align-left-on-2xl~.pf-m-pagination{margin-left:auto}.pf-c-toolbar .pf-m-hidden-on-2xl{display:none;visibility:hidden}.pf-c-toolbar .pf-m-visible-on-2xl{display:flex;visibility:visible}.pf-c-toolbar .pf-c-toolbar__content-section.pf-m-nowrap-on-2xl,.pf-c-toolbar .pf-c-toolbar__group.pf-m-nowrap-on-2xl{flex-wrap:nowrap}.pf-c-toolbar .pf-c-toolbar__content-section.pf-m-wrap-on-2xl,.pf-c-toolbar .pf-c-toolbar__group.pf-m-wrap-on-2xl{flex-wrap:wrap}}.pf-c-toolbar .pf-m-space-items-none>*,.pf-c-toolbar .pf-m-space-items-none>:last-child{--pf-c-toolbar--spacer:0}.pf-c-toolbar .pf-m-space-items-sm>*{--pf-c-toolbar--spacer:var(--pf-global--spacer--sm)}.pf-c-toolbar .pf-m-space-items-sm>:last-child{--pf-c-toolbar--spacer:0}.pf-c-toolbar .pf-m-space-items-md>*{--pf-c-toolbar--spacer:var(--pf-global--spacer--md)}.pf-c-toolbar .pf-m-space-items-md>:last-child{--pf-c-toolbar--spacer:0}.pf-c-toolbar .pf-m-space-items-lg>*{--pf-c-toolbar--spacer:var(--pf-global--spacer--lg)}.pf-c-toolbar .pf-m-space-items-lg>:last-child{--pf-c-toolbar--spacer:0}@media (min-width:576px){.pf-c-toolbar .pf-m-space-items-none-on-sm>*,.pf-c-toolbar .pf-m-space-items-none-on-sm>:last-child{--pf-c-toolbar--spacer:0}.pf-c-toolbar .pf-m-space-items-sm-on-sm>*{--pf-c-toolbar--spacer:var(--pf-global--spacer--sm)}.pf-c-toolbar .pf-m-space-items-sm-on-sm>:last-child{--pf-c-toolbar--spacer:0}.pf-c-toolbar .pf-m-space-items-md-on-sm>*{--pf-c-toolbar--spacer:var(--pf-global--spacer--md)}.pf-c-toolbar .pf-m-space-items-md-on-sm>:last-child{--pf-c-toolbar--spacer:0}.pf-c-toolbar .pf-m-space-items-lg-on-sm>*{--pf-c-toolbar--spacer:var(--pf-global--spacer--lg)}.pf-c-toolbar .pf-m-space-items-lg-on-sm>:last-child{--pf-c-toolbar--spacer:0}}@media (min-width:768px){.pf-c-toolbar .pf-m-space-items-none-on-md>*,.pf-c-toolbar .pf-m-space-items-none-on-md>:last-child{--pf-c-toolbar--spacer:0}.pf-c-toolbar .pf-m-space-items-sm-on-md>*{--pf-c-toolbar--spacer:var(--pf-global--spacer--sm)}.pf-c-toolbar .pf-m-space-items-sm-on-md>:last-child{--pf-c-toolbar--spacer:0}.pf-c-toolbar .pf-m-space-items-md-on-md>*{--pf-c-toolbar--spacer:var(--pf-global--spacer--md)}.pf-c-toolbar .pf-m-space-items-md-on-md>:last-child{--pf-c-toolbar--spacer:0}.pf-c-toolbar .pf-m-space-items-lg-on-md>*{--pf-c-toolbar--spacer:var(--pf-global--spacer--lg)}.pf-c-toolbar .pf-m-space-items-lg-on-md>:last-child{--pf-c-toolbar--spacer:0}}@media (min-width:992px){.pf-c-toolbar .pf-m-space-items-none-on-lg>*,.pf-c-toolbar .pf-m-space-items-none-on-lg>:last-child{--pf-c-toolbar--spacer:0}.pf-c-toolbar .pf-m-space-items-sm-on-lg>*{--pf-c-toolbar--spacer:var(--pf-global--spacer--sm)}.pf-c-toolbar .pf-m-space-items-sm-on-lg>:last-child{--pf-c-toolbar--spacer:0}.pf-c-toolbar .pf-m-space-items-md-on-lg>*{--pf-c-toolbar--spacer:var(--pf-global--spacer--md)}.pf-c-toolbar .pf-m-space-items-md-on-lg>:last-child{--pf-c-toolbar--spacer:0}.pf-c-toolbar .pf-m-space-items-lg-on-lg>*{--pf-c-toolbar--spacer:var(--pf-global--spacer--lg)}.pf-c-toolbar .pf-m-space-items-lg-on-lg>:last-child{--pf-c-toolbar--spacer:0}}@media (min-width:1200px){.pf-c-toolbar .pf-m-space-items-none-on-xl>*,.pf-c-toolbar .pf-m-space-items-none-on-xl>:last-child{--pf-c-toolbar--spacer:0}.pf-c-toolbar .pf-m-space-items-sm-on-xl>*{--pf-c-toolbar--spacer:var(--pf-global--spacer--sm)}.pf-c-toolbar .pf-m-space-items-sm-on-xl>:last-child{--pf-c-toolbar--spacer:0}.pf-c-toolbar .pf-m-space-items-md-on-xl>*{--pf-c-toolbar--spacer:var(--pf-global--spacer--md)}.pf-c-toolbar .pf-m-space-items-md-on-xl>:last-child{--pf-c-toolbar--spacer:0}.pf-c-toolbar .pf-m-space-items-lg-on-xl>*{--pf-c-toolbar--spacer:var(--pf-global--spacer--lg)}.pf-c-toolbar .pf-m-space-items-lg-on-xl>:last-child{--pf-c-toolbar--spacer:0}}@media (min-width:1450px){.pf-c-toolbar .pf-m-space-items-none-on-2xl>*,.pf-c-toolbar .pf-m-space-items-none-on-2xl>:last-child{--pf-c-toolbar--spacer:0}.pf-c-toolbar .pf-m-space-items-sm-on-2xl>*{--pf-c-toolbar--spacer:var(--pf-global--spacer--sm)}.pf-c-toolbar .pf-m-space-items-sm-on-2xl>:last-child{--pf-c-toolbar--spacer:0}.pf-c-toolbar .pf-m-space-items-md-on-2xl>*{--pf-c-toolbar--spacer:var(--pf-global--spacer--md)}.pf-c-toolbar .pf-m-space-items-md-on-2xl>:last-child{--pf-c-toolbar--spacer:0}.pf-c-toolbar .pf-m-space-items-lg-on-2xl>*{--pf-c-toolbar--spacer:var(--pf-global--spacer--lg)}.pf-c-toolbar .pf-m-space-items-lg-on-2xl>:last-child{--pf-c-toolbar--spacer:0}}.pf-c-toolbar .pf-m-spacer-none,.pf-c-toolbar .pf-m-spacer-none:last-child{--pf-c-toolbar--spacer:0}.pf-c-toolbar .pf-m-spacer-sm,.pf-c-toolbar .pf-m-spacer-sm:last-child{--pf-c-toolbar--spacer:var(--pf-global--spacer--sm)}.pf-c-toolbar .pf-m-spacer-md,.pf-c-toolbar .pf-m-spacer-md:last-child{--pf-c-toolbar--spacer:var(--pf-global--spacer--md)}.pf-c-toolbar .pf-m-spacer-lg,.pf-c-toolbar .pf-m-spacer-lg:last-child{--pf-c-toolbar--spacer:var(--pf-global--spacer--lg)}@media (min-width:576px){.pf-c-toolbar .pf-m-spacer-none-on-sm,.pf-c-toolbar .pf-m-spacer-none-on-sm:last-child{--pf-c-toolbar--spacer:0}.pf-c-toolbar .pf-m-spacer-sm-on-sm,.pf-c-toolbar .pf-m-spacer-sm-on-sm:last-child{--pf-c-toolbar--spacer:var(--pf-global--spacer--sm)}.pf-c-toolbar .pf-m-spacer-md-on-sm,.pf-c-toolbar .pf-m-spacer-md-on-sm:last-child{--pf-c-toolbar--spacer:var(--pf-global--spacer--md)}.pf-c-toolbar .pf-m-spacer-lg-on-sm,.pf-c-toolbar .pf-m-spacer-lg-on-sm:last-child{--pf-c-toolbar--spacer:var(--pf-global--spacer--lg)}}@media (min-width:768px){.pf-c-toolbar .pf-m-spacer-none-on-md,.pf-c-toolbar .pf-m-spacer-none-on-md:last-child{--pf-c-toolbar--spacer:0}.pf-c-toolbar .pf-m-spacer-sm-on-md,.pf-c-toolbar .pf-m-spacer-sm-on-md:last-child{--pf-c-toolbar--spacer:var(--pf-global--spacer--sm)}.pf-c-toolbar .pf-m-spacer-md-on-md,.pf-c-toolbar .pf-m-spacer-md-on-md:last-child{--pf-c-toolbar--spacer:var(--pf-global--spacer--md)}.pf-c-toolbar .pf-m-spacer-lg-on-md,.pf-c-toolbar .pf-m-spacer-lg-on-md:last-child{--pf-c-toolbar--spacer:var(--pf-global--spacer--lg)}}@media (min-width:992px){.pf-c-toolbar .pf-m-spacer-none-on-lg,.pf-c-toolbar .pf-m-spacer-none-on-lg:last-child{--pf-c-toolbar--spacer:0}.pf-c-toolbar .pf-m-spacer-sm-on-lg,.pf-c-toolbar .pf-m-spacer-sm-on-lg:last-child{--pf-c-toolbar--spacer:var(--pf-global--spacer--sm)}.pf-c-toolbar .pf-m-spacer-md-on-lg,.pf-c-toolbar .pf-m-spacer-md-on-lg:last-child{--pf-c-toolbar--spacer:var(--pf-global--spacer--md)}.pf-c-toolbar .pf-m-spacer-lg-on-lg,.pf-c-toolbar .pf-m-spacer-lg-on-lg:last-child{--pf-c-toolbar--spacer:var(--pf-global--spacer--lg)}}@media (min-width:1200px){.pf-c-toolbar .pf-m-spacer-none-on-xl,.pf-c-toolbar .pf-m-spacer-none-on-xl:last-child{--pf-c-toolbar--spacer:0}.pf-c-toolbar .pf-m-spacer-sm-on-xl,.pf-c-toolbar .pf-m-spacer-sm-on-xl:last-child{--pf-c-toolbar--spacer:var(--pf-global--spacer--sm)}.pf-c-toolbar .pf-m-spacer-md-on-xl,.pf-c-toolbar .pf-m-spacer-md-on-xl:last-child{--pf-c-toolbar--spacer:var(--pf-global--spacer--md)}.pf-c-toolbar .pf-m-spacer-lg-on-xl,.pf-c-toolbar .pf-m-spacer-lg-on-xl:last-child{--pf-c-toolbar--spacer:var(--pf-global--spacer--lg)}}@media (min-width:1450px){.pf-c-toolbar .pf-m-spacer-none-on-2xl,.pf-c-toolbar .pf-m-spacer-none-on-2xl:last-child{--pf-c-toolbar--spacer:0}.pf-c-toolbar .pf-m-spacer-sm-on-2xl,.pf-c-toolbar .pf-m-spacer-sm-on-2xl:last-child{--pf-c-toolbar--spacer:var(--pf-global--spacer--sm)}.pf-c-toolbar .pf-m-spacer-md-on-2xl,.pf-c-toolbar .pf-m-spacer-md-on-2xl:last-child{--pf-c-toolbar--spacer:var(--pf-global--spacer--md)}.pf-c-toolbar .pf-m-spacer-lg-on-2xl,.pf-c-toolbar .pf-m-spacer-lg-on-2xl:last-child{--pf-c-toolbar--spacer:var(--pf-global--spacer--lg)}}.pf-c-toolbar.pf-m-inset-none{--pf-c-toolbar--inset:0}.pf-c-toolbar.pf-m-inset-none,.pf-c-toolbar.pf-m-inset-sm{--pf-c-toolbar__content--PaddingRight:var(--pf-c-toolbar--inset);--pf-c-toolbar__content--PaddingLeft:var(--pf-c-toolbar--inset)}.pf-c-toolbar.pf-m-inset-sm{--pf-c-toolbar--inset:var(--pf-global--spacer--sm)}.pf-c-toolbar.pf-m-inset-md{--pf-c-toolbar--inset:var(--pf-global--spacer--md)}.pf-c-toolbar.pf-m-inset-lg,.pf-c-toolbar.pf-m-inset-md{--pf-c-toolbar__content--PaddingRight:var(--pf-c-toolbar--inset);--pf-c-toolbar__content--PaddingLeft:var(--pf-c-toolbar--inset)}.pf-c-toolbar.pf-m-inset-lg{--pf-c-toolbar--inset:var(--pf-global--spacer--lg)}.pf-c-toolbar.pf-m-inset-xl{--pf-c-toolbar--inset:var(--pf-global--spacer--xl)}.pf-c-toolbar.pf-m-inset-2xl,.pf-c-toolbar.pf-m-inset-xl{--pf-c-toolbar__content--PaddingRight:var(--pf-c-toolbar--inset);--pf-c-toolbar__content--PaddingLeft:var(--pf-c-toolbar--inset)}.pf-c-toolbar.pf-m-inset-2xl{--pf-c-toolbar--inset:var(--pf-global--spacer--2xl)}@media (min-width:576px){.pf-c-toolbar.pf-m-inset-none-on-sm{--pf-c-toolbar--inset:0}.pf-c-toolbar.pf-m-inset-none-on-sm,.pf-c-toolbar.pf-m-inset-sm-on-sm{--pf-c-toolbar__content--PaddingRight:var(--pf-c-toolbar--inset);--pf-c-toolbar__content--PaddingLeft:var(--pf-c-toolbar--inset)}.pf-c-toolbar.pf-m-inset-sm-on-sm{--pf-c-toolbar--inset:var(--pf-global--spacer--sm)}.pf-c-toolbar.pf-m-inset-md-on-sm{--pf-c-toolbar--inset:var(--pf-global--spacer--md)}.pf-c-toolbar.pf-m-inset-lg-on-sm,.pf-c-toolbar.pf-m-inset-md-on-sm{--pf-c-toolbar__content--PaddingRight:var(--pf-c-toolbar--inset);--pf-c-toolbar__content--PaddingLeft:var(--pf-c-toolbar--inset)}.pf-c-toolbar.pf-m-inset-lg-on-sm{--pf-c-toolbar--inset:var(--pf-global--spacer--lg)}.pf-c-toolbar.pf-m-inset-xl-on-sm{--pf-c-toolbar--inset:var(--pf-global--spacer--xl)}.pf-c-toolbar.pf-m-inset-2xl-on-sm,.pf-c-toolbar.pf-m-inset-xl-on-sm{--pf-c-toolbar__content--PaddingRight:var(--pf-c-toolbar--inset);--pf-c-toolbar__content--PaddingLeft:var(--pf-c-toolbar--inset)}.pf-c-toolbar.pf-m-inset-2xl-on-sm{--pf-c-toolbar--inset:var(--pf-global--spacer--2xl)}}@media (min-width:768px){.pf-c-toolbar.pf-m-inset-none-on-md{--pf-c-toolbar--inset:0}.pf-c-toolbar.pf-m-inset-none-on-md,.pf-c-toolbar.pf-m-inset-sm-on-md{--pf-c-toolbar__content--PaddingRight:var(--pf-c-toolbar--inset);--pf-c-toolbar__content--PaddingLeft:var(--pf-c-toolbar--inset)}.pf-c-toolbar.pf-m-inset-sm-on-md{--pf-c-toolbar--inset:var(--pf-global--spacer--sm)}.pf-c-toolbar.pf-m-inset-md-on-md{--pf-c-toolbar--inset:var(--pf-global--spacer--md)}.pf-c-toolbar.pf-m-inset-lg-on-md,.pf-c-toolbar.pf-m-inset-md-on-md{--pf-c-toolbar__content--PaddingRight:var(--pf-c-toolbar--inset);--pf-c-toolbar__content--PaddingLeft:var(--pf-c-toolbar--inset)}.pf-c-toolbar.pf-m-inset-lg-on-md{--pf-c-toolbar--inset:var(--pf-global--spacer--lg)}.pf-c-toolbar.pf-m-inset-xl-on-md{--pf-c-toolbar--inset:var(--pf-global--spacer--xl)}.pf-c-toolbar.pf-m-inset-2xl-on-md,.pf-c-toolbar.pf-m-inset-xl-on-md{--pf-c-toolbar__content--PaddingRight:var(--pf-c-toolbar--inset);--pf-c-toolbar__content--PaddingLeft:var(--pf-c-toolbar--inset)}.pf-c-toolbar.pf-m-inset-2xl-on-md{--pf-c-toolbar--inset:var(--pf-global--spacer--2xl)}}@media (min-width:992px){.pf-c-toolbar.pf-m-inset-none-on-lg{--pf-c-toolbar--inset:0}.pf-c-toolbar.pf-m-inset-none-on-lg,.pf-c-toolbar.pf-m-inset-sm-on-lg{--pf-c-toolbar__content--PaddingRight:var(--pf-c-toolbar--inset);--pf-c-toolbar__content--PaddingLeft:var(--pf-c-toolbar--inset)}.pf-c-toolbar.pf-m-inset-sm-on-lg{--pf-c-toolbar--inset:var(--pf-global--spacer--sm)}.pf-c-toolbar.pf-m-inset-md-on-lg{--pf-c-toolbar--inset:var(--pf-global--spacer--md)}.pf-c-toolbar.pf-m-inset-lg-on-lg,.pf-c-toolbar.pf-m-inset-md-on-lg{--pf-c-toolbar__content--PaddingRight:var(--pf-c-toolbar--inset);--pf-c-toolbar__content--PaddingLeft:var(--pf-c-toolbar--inset)}.pf-c-toolbar.pf-m-inset-lg-on-lg{--pf-c-toolbar--inset:var(--pf-global--spacer--lg)}.pf-c-toolbar.pf-m-inset-xl-on-lg{--pf-c-toolbar--inset:var(--pf-global--spacer--xl)}.pf-c-toolbar.pf-m-inset-2xl-on-lg,.pf-c-toolbar.pf-m-inset-xl-on-lg{--pf-c-toolbar__content--PaddingRight:var(--pf-c-toolbar--inset);--pf-c-toolbar__content--PaddingLeft:var(--pf-c-toolbar--inset)}.pf-c-toolbar.pf-m-inset-2xl-on-lg{--pf-c-toolbar--inset:var(--pf-global--spacer--2xl)}}@media (min-width:1200px){.pf-c-toolbar.pf-m-inset-none-on-xl{--pf-c-toolbar--inset:0}.pf-c-toolbar.pf-m-inset-none-on-xl,.pf-c-toolbar.pf-m-inset-sm-on-xl{--pf-c-toolbar__content--PaddingRight:var(--pf-c-toolbar--inset);--pf-c-toolbar__content--PaddingLeft:var(--pf-c-toolbar--inset)}.pf-c-toolbar.pf-m-inset-sm-on-xl{--pf-c-toolbar--inset:var(--pf-global--spacer--sm)}.pf-c-toolbar.pf-m-inset-md-on-xl{--pf-c-toolbar--inset:var(--pf-global--spacer--md)}.pf-c-toolbar.pf-m-inset-lg-on-xl,.pf-c-toolbar.pf-m-inset-md-on-xl{--pf-c-toolbar__content--PaddingRight:var(--pf-c-toolbar--inset);--pf-c-toolbar__content--PaddingLeft:var(--pf-c-toolbar--inset)}.pf-c-toolbar.pf-m-inset-lg-on-xl{--pf-c-toolbar--inset:var(--pf-global--spacer--lg)}.pf-c-toolbar.pf-m-inset-xl-on-xl{--pf-c-toolbar--inset:var(--pf-global--spacer--xl)}.pf-c-toolbar.pf-m-inset-2xl-on-xl,.pf-c-toolbar.pf-m-inset-xl-on-xl{--pf-c-toolbar__content--PaddingRight:var(--pf-c-toolbar--inset);--pf-c-toolbar__content--PaddingLeft:var(--pf-c-toolbar--inset)}.pf-c-toolbar.pf-m-inset-2xl-on-xl{--pf-c-toolbar--inset:var(--pf-global--spacer--2xl)}}@media (min-width:1450px){.pf-c-toolbar.pf-m-inset-none-on-2xl{--pf-c-toolbar--inset:0}.pf-c-toolbar.pf-m-inset-none-on-2xl,.pf-c-toolbar.pf-m-inset-sm-on-2xl{--pf-c-toolbar__content--PaddingRight:var(--pf-c-toolbar--inset);--pf-c-toolbar__content--PaddingLeft:var(--pf-c-toolbar--inset)}.pf-c-toolbar.pf-m-inset-sm-on-2xl{--pf-c-toolbar--inset:var(--pf-global--spacer--sm)}.pf-c-toolbar.pf-m-inset-md-on-2xl{--pf-c-toolbar--inset:var(--pf-global--spacer--md)}.pf-c-toolbar.pf-m-inset-lg-on-2xl,.pf-c-toolbar.pf-m-inset-md-on-2xl{--pf-c-toolbar__content--PaddingRight:var(--pf-c-toolbar--inset);--pf-c-toolbar__content--PaddingLeft:var(--pf-c-toolbar--inset)}.pf-c-toolbar.pf-m-inset-lg-on-2xl{--pf-c-toolbar--inset:var(--pf-global--spacer--lg)}.pf-c-toolbar.pf-m-inset-xl-on-2xl{--pf-c-toolbar--inset:var(--pf-global--spacer--xl)}.pf-c-toolbar.pf-m-inset-2xl-on-2xl,.pf-c-toolbar.pf-m-inset-xl-on-2xl{--pf-c-toolbar__content--PaddingRight:var(--pf-c-toolbar--inset);--pf-c-toolbar__content--PaddingLeft:var(--pf-c-toolbar--inset)}.pf-c-toolbar.pf-m-inset-2xl-on-2xl{--pf-c-toolbar--inset:var(--pf-global--spacer--2xl)}}.pf-c-toolbar__content-section>:last-child{--pf-c-toolbar--spacer:0}.pf-c-date-picker{--pf-c-date-picker--m-top__calendar--Top:0;--pf-c-date-picker--m-top__calendar--TranslateY:calc(-100% - var(--pf-global--spacer--xs));--pf-c-date-picker__helper-text--MarginTop:var(--pf-global--spacer--xs);--pf-c-date-picker__helper-text--FontSize:var(--pf-global--FontSize--sm);--pf-c-date-picker__helper-text--Color:var(--pf-global--Color--100);--pf-c-date-picker__helper-text--m-error--Color:var(--pf-global--danger-color--100);--pf-c-date-picker__input--c-form-control--Width:calc(var(--pf-c-date-picker__input--c-form-control--width-chars)*1ch + var(--pf-c-date-picker__input--c-form-control--width-base));--pf-c-date-picker__input--c-form-control--width-base:calc(var(--pf-global--spacer--xl) + var(--pf-global--spacer--sm));--pf-c-date-picker__input--c-form-control--width-chars:10;--pf-c-date-picker__calendar--BackgroundColor:var(--pf-global--BackgroundColor--light-100);--pf-c-date-picker__calendar--BoxShadow:var(--pf-global--BoxShadow--md);--pf-c-date-picker__calendar--ZIndex:var(--pf-global--ZIndex--sm);--pf-c-date-picker__calendar--Top:calc(100% + var(--pf-global--spacer--xs));--pf-c-date-picker__calendar--Right:auto;--pf-c-date-picker__calendar--Left:0;--pf-c-date-picker__calendar--m-align-right--Right:0;--pf-c-date-picker__calendar--m-align-right--Left:auto;position:relative;display:inline-block}.pf-c-date-picker__helper-text{margin-top:var(--pf-c-date-picker__helper-text--MarginTop);font-size:var(--pf-c-date-picker__helper-text--FontSize);color:var(--pf-c-date-picker__helper-text--Color)}.pf-c-date-picker__helper-text.pf-m-error{--pf-c-date-picker__helper-text--Color:var(--pf-c-date-picker__helper-text--m-error--Color)}.pf-c-date-picker__input .pf-c-form-control{width:var(--pf-c-date-picker__input--c-form-control--Width)}.pf-c-date-picker__calendar{position:absolute;top:var(--pf-c-date-picker__calendar--Top);right:var(--pf-c-date-picker__calendar--Right);left:var(--pf-c-date-picker__calendar--Left);z-index:var(--pf-c-date-picker__calendar--ZIndex);background-color:var(--pf-c-date-picker__calendar--BackgroundColor);box-shadow:var(--pf-c-date-picker__calendar--BoxShadow)}.pf-c-date-picker__calendar.pf-m-align-right{--pf-c-date-picker__calendar--Right:var(--pf-c-date-picker__calendar--m-align-right--Right);--pf-c-date-picker__calendar--Left:var(--pf-c-date-picker__calendar--m-align-right--Left)}.pf-c-date-picker.pf-m-top .pf-c-date-picker__calendar{--pf-c-date-picker__calendar--Top:var(--pf-c-date-picker--m-top__calendar--Top);transform:translateY(var(--pf-c-date-picker--m-top__calendar--TranslateY))}.pf-c-divider{--pf-c-divider--Height:var(--pf-global--BorderWidth--sm);--pf-c-divider--BackgroundColor:var(--pf-global--BorderColor--100);--pf-c-divider--after--Height:var(--pf-c-divider--Height);--pf-c-divider--after--BackgroundColor:var(--pf-c-divider--BackgroundColor);--pf-c-divider--after--FlexBasis:100%;--pf-c-divider--after--Inset:0%;--pf-c-divider--m-vertical--after--FlexBasis:100%;--pf-c-divider--m-vertical--after--Width:var(--pf-global--BorderWidth--sm);display:flex;align-items:center;align-self:stretch;justify-content:center;width:100%;border:0}.pf-c-divider:after{flex-basis:calc(var(--pf-c-divider--after--FlexBasis) - var(--pf-c-divider--after--Inset)*2);align-self:stretch;height:var(--pf-c-divider--after--Height);content:"";background-color:var(--pf-c-divider--after--BackgroundColor);justify-self:center}.pf-c-divider.pf-m-vertical{display:inline-flex;flex-direction:column;width:auto;height:inherit;min-height:100%;max-height:100%}.pf-c-divider.pf-m-vertical:after{flex-basis:calc(var(--pf-c-divider--m-vertical--after--FlexBasis) - var(--pf-c-divider--after--Inset));width:var(--pf-c-divider--m-vertical--after--Width)}.pf-c-divider.pf-m-inset-none{--pf-c-divider--after--Inset:0%}.pf-c-divider.pf-m-inset-xs{--pf-c-divider--after--Inset:var(--pf-global--spacer--xs)}.pf-c-divider.pf-m-inset-sm{--pf-c-divider--after--Inset:var(--pf-global--spacer--sm)}.pf-c-divider.pf-m-inset-md{--pf-c-divider--after--Inset:var(--pf-global--spacer--md)}.pf-c-divider.pf-m-inset-lg{--pf-c-divider--after--Inset:var(--pf-global--spacer--lg)}.pf-c-divider.pf-m-inset-xl{--pf-c-divider--after--Inset:var(--pf-global--spacer--xl)}.pf-c-divider.pf-m-inset-2xl{--pf-c-divider--after--Inset:var(--pf-global--spacer--2xl)}.pf-c-divider.pf-m-inset-3xl{--pf-c-divider--after--Inset:var(--pf-global--spacer--3xl)}@media (min-width:576px){.pf-c-divider.pf-m-inset-none-on-sm{--pf-c-divider--after--Inset:0%}.pf-c-divider.pf-m-inset-xs-on-sm{--pf-c-divider--after--Inset:var(--pf-global--spacer--xs)}.pf-c-divider.pf-m-inset-sm-on-sm{--pf-c-divider--after--Inset:var(--pf-global--spacer--sm)}.pf-c-divider.pf-m-inset-md-on-sm{--pf-c-divider--after--Inset:var(--pf-global--spacer--md)}.pf-c-divider.pf-m-inset-lg-on-sm{--pf-c-divider--after--Inset:var(--pf-global--spacer--lg)}.pf-c-divider.pf-m-inset-xl-on-sm{--pf-c-divider--after--Inset:var(--pf-global--spacer--xl)}.pf-c-divider.pf-m-inset-2xl-on-sm{--pf-c-divider--after--Inset:var(--pf-global--spacer--2xl)}.pf-c-divider.pf-m-inset-3xl-on-sm{--pf-c-divider--after--Inset:var(--pf-global--spacer--3xl)}}@media (min-width:768px){.pf-c-divider.pf-m-inset-none-on-md{--pf-c-divider--after--Inset:0%}.pf-c-divider.pf-m-inset-xs-on-md{--pf-c-divider--after--Inset:var(--pf-global--spacer--xs)}.pf-c-divider.pf-m-inset-sm-on-md{--pf-c-divider--after--Inset:var(--pf-global--spacer--sm)}.pf-c-divider.pf-m-inset-md-on-md{--pf-c-divider--after--Inset:var(--pf-global--spacer--md)}.pf-c-divider.pf-m-inset-lg-on-md{--pf-c-divider--after--Inset:var(--pf-global--spacer--lg)}.pf-c-divider.pf-m-inset-xl-on-md{--pf-c-divider--after--Inset:var(--pf-global--spacer--xl)}.pf-c-divider.pf-m-inset-2xl-on-md{--pf-c-divider--after--Inset:var(--pf-global--spacer--2xl)}.pf-c-divider.pf-m-inset-3xl-on-md{--pf-c-divider--after--Inset:var(--pf-global--spacer--3xl)}}@media (min-width:992px){.pf-c-divider.pf-m-inset-none-on-lg{--pf-c-divider--after--Inset:0%}.pf-c-divider.pf-m-inset-xs-on-lg{--pf-c-divider--after--Inset:var(--pf-global--spacer--xs)}.pf-c-divider.pf-m-inset-sm-on-lg{--pf-c-divider--after--Inset:var(--pf-global--spacer--sm)}.pf-c-divider.pf-m-inset-md-on-lg{--pf-c-divider--after--Inset:var(--pf-global--spacer--md)}.pf-c-divider.pf-m-inset-lg-on-lg{--pf-c-divider--after--Inset:var(--pf-global--spacer--lg)}.pf-c-divider.pf-m-inset-xl-on-lg{--pf-c-divider--after--Inset:var(--pf-global--spacer--xl)}.pf-c-divider.pf-m-inset-2xl-on-lg{--pf-c-divider--after--Inset:var(--pf-global--spacer--2xl)}.pf-c-divider.pf-m-inset-3xl-on-lg{--pf-c-divider--after--Inset:var(--pf-global--spacer--3xl)}}@media (min-width:1200px){.pf-c-divider.pf-m-inset-none-on-xl{--pf-c-divider--after--Inset:0%}.pf-c-divider.pf-m-inset-xs-on-xl{--pf-c-divider--after--Inset:var(--pf-global--spacer--xs)}.pf-c-divider.pf-m-inset-sm-on-xl{--pf-c-divider--after--Inset:var(--pf-global--spacer--sm)}.pf-c-divider.pf-m-inset-md-on-xl{--pf-c-divider--after--Inset:var(--pf-global--spacer--md)}.pf-c-divider.pf-m-inset-lg-on-xl{--pf-c-divider--after--Inset:var(--pf-global--spacer--lg)}.pf-c-divider.pf-m-inset-xl-on-xl{--pf-c-divider--after--Inset:var(--pf-global--spacer--xl)}.pf-c-divider.pf-m-inset-2xl-on-xl{--pf-c-divider--after--Inset:var(--pf-global--spacer--2xl)}.pf-c-divider.pf-m-inset-3xl-on-xl{--pf-c-divider--after--Inset:var(--pf-global--spacer--3xl)}}@media (min-width:1450px){.pf-c-divider.pf-m-inset-none-on-2xl{--pf-c-divider--after--Inset:0%}.pf-c-divider.pf-m-inset-xs-on-2xl{--pf-c-divider--after--Inset:var(--pf-global--spacer--xs)}.pf-c-divider.pf-m-inset-sm-on-2xl{--pf-c-divider--after--Inset:var(--pf-global--spacer--sm)}.pf-c-divider.pf-m-inset-md-on-2xl{--pf-c-divider--after--Inset:var(--pf-global--spacer--md)}.pf-c-divider.pf-m-inset-lg-on-2xl{--pf-c-divider--after--Inset:var(--pf-global--spacer--lg)}.pf-c-divider.pf-m-inset-xl-on-2xl{--pf-c-divider--after--Inset:var(--pf-global--spacer--xl)}.pf-c-divider.pf-m-inset-2xl-on-2xl{--pf-c-divider--after--Inset:var(--pf-global--spacer--2xl)}.pf-c-divider.pf-m-inset-3xl-on-2xl{--pf-c-divider--after--Inset:var(--pf-global--spacer--3xl)}}.pf-c-drawer{--pf-c-drawer__section--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-drawer__content--FlexBasis:100%;--pf-c-drawer__content--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-drawer__content--ZIndex:var(--pf-global--ZIndex--xs);--pf-c-drawer__panel--FlexBasis:100%;--pf-c-drawer__panel--md--FlexBasis:50%;--pf-c-drawer__panel--MinWidth:50%;--pf-c-drawer__panel--MaxHeight:auto;--pf-c-drawer--m-panel-bottom__panel--md--MinHeight:50%;--pf-c-drawer__panel--xl--MinWidth:28.125rem;--pf-c-drawer__panel--xl--FlexBasis:28.125rem;--pf-c-drawer--m-panel-bottom__panel--xl--MinHeight:18.75rem;--pf-c-drawer--m-panel-bottom__panel--xl--FlexBasis:18.75rem;--pf-c-drawer__panel--ZIndex:var(--pf-global--ZIndex--sm);--pf-c-drawer__panel--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-drawer__panel--TransitionDuration:var(--pf-global--TransitionDuration);--pf-c-drawer__panel--TransitionProperty:margin,transform,box-shadow,flex-basis;--pf-c-drawer__panel--m-resizable--PaddingLeft:var(--pf-c-drawer__splitter--m-vertical--Width);--pf-c-drawer--m-panel-left__panel--m-resizable--PaddingRight:var(--pf-c-drawer__splitter--m-vertical--Width);--pf-c-drawer--m-panel-bottom__panel--m-resizable--PaddingTop:var(--pf-c-drawer__splitter--Height);--pf-c-drawer--child--PaddingTop:var(--pf-global--spacer--md);--pf-c-drawer--child--PaddingRight:var(--pf-global--spacer--md);--pf-c-drawer--child--PaddingBottom:var(--pf-global--spacer--md);--pf-c-drawer--child--PaddingLeft:var(--pf-global--spacer--md);--pf-c-drawer--child--md--PaddingTop:var(--pf-global--spacer--lg);--pf-c-drawer--child--md--PaddingRight:var(--pf-global--spacer--lg);--pf-c-drawer--child--md--PaddingBottom:var(--pf-global--spacer--lg);--pf-c-drawer--child--md--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-drawer--child--m-padding--PaddingTop:var(--pf-global--spacer--md);--pf-c-drawer--child--m-padding--PaddingRight:var(--pf-global--spacer--md);--pf-c-drawer--child--m-padding--PaddingBottom:var(--pf-global--spacer--md);--pf-c-drawer--child--m-padding--PaddingLeft:var(--pf-global--spacer--md);--pf-c-drawer--child--m-padding--md--PaddingTop:var(--pf-global--spacer--lg);--pf-c-drawer--child--m-padding--md--PaddingRight:var(--pf-global--spacer--lg);--pf-c-drawer--child--m-padding--md--PaddingBottom:var(--pf-global--spacer--lg);--pf-c-drawer--child--m-padding--md--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-drawer__content--child--PaddingTop:0;--pf-c-drawer__content--child--PaddingRight:0;--pf-c-drawer__content--child--PaddingBottom:0;--pf-c-drawer__content--child--PaddingLeft:0;--pf-c-drawer__splitter--Top:0;--pf-c-drawer__splitter--Right:auto;--pf-c-drawer__splitter--Bottom:0;--pf-c-drawer__splitter--Left:0;--pf-c-drawer__splitter--Height:0.5625rem;--pf-c-drawer__splitter--Width:100%;--pf-c-drawer__splitter--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-drawer__splitter--Cursor:row-resize;--pf-c-drawer__splitter--m-vertical--Height:100%;--pf-c-drawer__splitter--m-vertical--Width:0.5625rem;--pf-c-drawer__splitter--m-vertical--Cursor:col-resize;--pf-c-drawer--m-inline__splitter--focus--OutlineOffset:-0.0625rem;--pf-c-drawer__splitter--after--BorderColor:var(--pf-global--BorderColor--100);--pf-c-drawer__splitter--after--border-width--base:var(--pf-global--BorderWidth--sm);--pf-c-drawer__splitter--after--BorderTopWidth:0;--pf-c-drawer__splitter--after--BorderRightWidth:var(--pf-c-drawer__splitter--after--border-width--base);--pf-c-drawer__splitter--after--BorderBottomWidth:0;--pf-c-drawer__splitter--after--BorderLeftWidth:0;--pf-c-drawer--m-panel-left__splitter--after--BorderLeftWidth:var(--pf-c-drawer__splitter--after--border-width--base);--pf-c-drawer--m-panel-bottom__splitter--after--BorderBottomWidth:var(--pf-c-drawer__splitter--after--border-width--base);--pf-c-drawer--m-inline__splitter--m-vertical--Width:0.625rem;--pf-c-drawer--m-inline__splitter-handle--Left:50%;--pf-c-drawer--m-inline__splitter--after--BorderRightWidth:var(--pf-c-drawer__splitter--after--border-width--base);--pf-c-drawer--m-inline__splitter--after--BorderLeftWidth:var(--pf-c-drawer__splitter--after--border-width--base);--pf-c-drawer--m-inline--m-panel-bottom__splitter--Height:0.625rem;--pf-c-drawer--m-inline--m-panel-bottom__splitter-handle--Top:50%;--pf-c-drawer--m-inline--m-panel-bottom__splitter--after--BorderTopWidth:var(--pf-c-drawer__splitter--after--border-width--base);--pf-c-drawer__splitter-handle--Top:50%;--pf-c-drawer__splitter-handle--Left:calc(50% - var(--pf-c-drawer__splitter--after--border-width--base));--pf-c-drawer--m-panel-left__splitter-handle--Left:50%;--pf-c-drawer--m-panel-bottom__splitter-handle--Top:calc(50% - var(--pf-c-drawer__splitter--after--border-width--base));--pf-c-drawer__splitter-handle--after--BorderColor:var(--pf-global--Color--200);--pf-c-drawer__splitter-handle--after--BorderTopWidth:var(--pf-global--BorderWidth--sm);--pf-c-drawer__splitter-handle--after--BorderRightWidth:0;--pf-c-drawer__splitter-handle--after--BorderBottomWidth:var(--pf-global--BorderWidth--sm);--pf-c-drawer__splitter-handle--after--BorderLeftWidth:0;--pf-c-drawer__splitter--hover__splitter-handle--after--BorderColor:var(--pf-global--Color--100);--pf-c-drawer__splitter--focus__splitter-handle--after--BorderColor:var(--pf-global--Color--100);--pf-c-drawer__splitter--m-vertical__splitter-handle--after--BorderTopWidth:0;--pf-c-drawer__splitter--m-vertical__splitter-handle--after--BorderRightWidth:var(--pf-global--BorderWidth--sm);--pf-c-drawer__splitter--m-vertical__splitter-handle--after--BorderBottomWidth:0;--pf-c-drawer__splitter--m-vertical__splitter-handle--after--BorderLeftWidth:var(--pf-global--BorderWidth--sm);--pf-c-drawer__splitter-handle--after--Width:0.75rem;--pf-c-drawer__splitter-handle--after--Height:0.25rem;--pf-c-drawer__splitter--m-vertical__splitter-handle--after--Width:0.25rem;--pf-c-drawer__splitter--m-vertical__splitter-handle--after--Height:0.75rem;--pf-c-drawer__actions--MarginTop:calc(var(pf-global--spacer--form-element)*-1);--pf-c-drawer__actions--MarginRight:calc(var(pf-global--spacer--form-element)*-1);--pf-c-drawer__panel--BoxShadow:none;--pf-c-drawer--m-expanded__panel--BoxShadow:var(--pf-global--BoxShadow--lg-left);--pf-c-drawer--m-expanded--m-panel-left__panel--BoxShadow:var(--pf-global--BoxShadow--lg-right);--pf-c-drawer--m-expanded--m-panel-bottom__panel--BoxShadow:var(--pf-global--BoxShadow--lg-top);--pf-c-drawer__panel--after--Width:var(--pf-global--BorderWidth--sm);--pf-c-drawer--m-panel-bottom__panel--after--Height:var(--pf-global--BorderWidth--sm);--pf-c-drawer__panel--after--BackgroundColor:transparent;--pf-c-drawer--m-inline--m-expanded__panel--after--BackgroundColor:var(--pf-global--BorderColor--100);--pf-c-drawer--m-inline__panel--PaddingLeft:var(--pf-c-drawer__panel--after--Width);--pf-c-drawer--m-panel-left--m-inline__panel--PaddingRight:var(--pf-c-drawer__panel--after--Width);--pf-c-drawer--m-panel-bottom--m-inline__panel--PaddingTop:var(--pf-c-drawer__panel--after--Width);display:flex;flex-direction:column;height:100%;overflow-x:hidden}@media screen and (min-width:768px){.pf-c-drawer{--pf-c-drawer__panel--FlexBasis:var(--pf-c-drawer__panel--md--FlexBasis);--pf-c-drawer--child--PaddingTop:var(--pf-c-drawer--child--md--PaddingTop);--pf-c-drawer--child--PaddingRight:var(--pf-c-drawer--child--md--PaddingRight);--pf-c-drawer--child--PaddingBottom:var(--pf-c-drawer--child--md--PaddingBottom);--pf-c-drawer--child--PaddingLeft:var(--pf-c-drawer--child--md--PaddingLeft);--pf-c-drawer--child--m-padding--PaddingTop:var(--pf-c-drawer--child--m-padding--md--PaddingTop);--pf-c-drawer--child--m-padding--PaddingRight:var(--pf-c-drawer--child--m-padding--md--PaddingRight);--pf-c-drawer--child--m-padding--PaddingBottom:var(--pf-c-drawer--child--m-padding--md--PaddingBottom);--pf-c-drawer--child--m-padding--PaddingLeft:var(--pf-c-drawer--child--m-padding--md--PaddingLeft)}}@media screen and (min-width:1200px){.pf-c-drawer{--pf-c-drawer__panel--FlexBasis:var(--pf-c-drawer__panel--xl--FlexBasis);--pf-c-drawer__panel--MinWidth:var(--pf-c-drawer__panel--xl--MinWidth)}.pf-c-drawer.pf-m-panel-bottom{--pf-c-drawer__panel--MinWidth:auto;--pf-c-drawer__panel--FlexBasis:var(--pf-c-drawer--m-panel-bottom__panel--xl--FlexBasis);--pf-c-drawer__panel--MinHeight:var(--pf-c-drawer--m-panel-bottom__panel--xl--MinHeight)}}.pf-c-drawer.pf-m-inline>.pf-c-drawer__main>.pf-c-drawer__panel,.pf-c-drawer.pf-m-static>.pf-c-drawer__main>.pf-c-drawer__panel{padding-left:var(--pf-c-drawer--m-inline__panel--PaddingLeft)}.pf-c-drawer.pf-m-panel-left>.pf-c-drawer__main>.pf-c-drawer__panel{order:0;margin-right:calc(var(--pf-c-drawer__panel--FlexBasis)*-1);transform:translateX(-100%)}.pf-c-drawer.pf-m-panel-left>.pf-c-drawer__main>.pf-c-drawer__content{order:1}.pf-c-drawer.pf-m-panel-bottom>.pf-c-drawer__main{flex-direction:column}.pf-c-drawer.pf-m-expanded>.pf-c-drawer__main>.pf-c-drawer__panel{transform:translateX(-100%)}.pf-c-drawer.pf-m-expanded.pf-m-panel-left>.pf-c-drawer__main>.pf-c-drawer__panel{transform:translateX(0)}.pf-c-drawer.pf-m-expanded.pf-m-panel-bottom>.pf-c-drawer__main>.pf-c-drawer__panel{transform:translateY(-100%)}.pf-c-drawer__section{flex-grow:0;background-color:var(--pf-c-drawer__section--BackgroundColor)}.pf-c-drawer__section.pf-m-no-background{background-color:transparent}.pf-c-drawer__main{display:flex;flex-grow:1;overflow:hidden}.pf-c-drawer__content,.pf-c-drawer__panel{display:flex;flex-direction:column;flex-shrink:0;overflow:auto}.pf-c-drawer__content{z-index:var(--pf-c-drawer__content--ZIndex);flex-basis:var(--pf-c-drawer__content--FlexBasis);order:0;background-color:var(--pf-c-drawer__content--BackgroundColor)}.pf-c-drawer__content>.pf-c-drawer__body{padding:var(--pf-c-drawer__content--child--PaddingTop) var(--pf-c-drawer__content--child--PaddingRight) var(--pf-c-drawer__content--child--PaddingBottom) var(--pf-c-drawer__content--child--PaddingLeft)}.pf-c-drawer__content.pf-m-no-background{background-color:transparent}.pf-c-drawer__panel{position:relative;z-index:var(--pf-c-drawer__panel--ZIndex);flex-basis:var(--pf-c-drawer__panel--FlexBasis);order:1;max-height:var(--pf-c-drawer__panel--MaxHeight);overflow:auto;background-color:var(--pf-c-drawer__panel--BackgroundColor);box-shadow:var(--pf-c-drawer__panel--BoxShadow);transition-duration:var(--pf-c-drawer__panel--TransitionDuration);transition-property:var(--pf-c-drawer__panel--TransitionProperty);-webkit-overflow-scrolling:touch}.pf-c-drawer__panel:after{position:absolute;top:0;left:0;width:var(--pf-c-drawer__panel--after--Width);height:100%;content:"";background-color:var(--pf-c-drawer__panel--after--BackgroundColor)}.pf-c-drawer__panel.pf-m-no-background{background-color:transparent}@keyframes pf-remove-tab-focus{to{visibility:hidden}}.pf-c-drawer__panel[hidden]{animation-name:pf-remove-tab-focus;animation-delay:var(--pf-c-drawer__panel--TransitionDuration);animation-fill-mode:forwards}.pf-c-drawer__head{display:grid;grid-template-columns:auto;grid-auto-columns:max-content}.pf-c-drawer__head>*{grid-column:1}.pf-c-drawer__actions{grid-column:2;grid-row:1;display:flex;align-self:baseline;margin-top:var(--pf-c-drawer__actions--MarginTop);margin-right:var(--pf-c-drawer__actions--MarginRight)}.pf-c-drawer__body{min-height:0;padding:var(--pf-c-drawer--child--PaddingTop) var(--pf-c-drawer--child--PaddingRight) var(--pf-c-drawer--child--PaddingBottom) var(--pf-c-drawer--child--PaddingLeft)}.pf-c-drawer__body.pf-m-no-padding{padding:0}.pf-c-drawer__body.pf-m-no-padding>.pf-c-drawer__actions,.pf-c-drawer__body.pf-m-no-padding>.pf-c-drawer__head>.pf-c-drawer__actions{margin-top:0;margin-right:0}.pf-c-drawer__body.pf-m-padding{padding:var(--pf-c-drawer--child--m-padding--PaddingTop) var(--pf-c-drawer--child--m-padding--PaddingRight) var(--pf-c-drawer--child--m-padding--PaddingBottom) var(--pf-c-drawer--child--m-padding--PaddingLeft)}.pf-c-drawer__body:not(.pf-m-no-padding)+*{padding-top:0}.pf-c-drawer__body:last-child{flex:1 1}.pf-c-drawer__body>.pf-c-page__main{min-height:100%}.pf-c-drawer__splitter{position:absolute;top:var(--pf-c-drawer__splitter--Top);right:var(--pf-c-drawer__splitter--Right);bottom:var(--pf-c-drawer__splitter--Bottom);left:var(--pf-c-drawer__splitter--Left);display:none;width:var(--pf-c-drawer__splitter--Width);height:var(--pf-c-drawer__splitter--Height);cursor:var(--pf-c-drawer__splitter--Cursor);visibility:hidden;background-color:var(--pf-c-drawer__splitter--BackgroundColor)}.pf-c-drawer__splitter.pf-m-vertical{--pf-c-drawer__splitter--Height:var(--pf-c-drawer__splitter--m-vertical--Height);--pf-c-drawer__splitter--Width:var(--pf-c-drawer__splitter--m-vertical--Width);--pf-c-drawer__splitter--Cursor:var(--pf-c-drawer__splitter--m-vertical--Cursor);--pf-c-drawer__splitter-handle--after--Width:var(--pf-c-drawer__splitter--m-vertical__splitter-handle--after--Width);--pf-c-drawer__splitter-handle--after--Height:var(--pf-c-drawer__splitter--m-vertical__splitter-handle--after--Height);--pf-c-drawer__splitter-handle--after--BorderTopWidth:var(--pf-c-drawer__splitter--m-vertical__splitter-handle--after--BorderTopWidth);--pf-c-drawer__splitter-handle--after--BorderRightWidth:var(--pf-c-drawer__splitter--m-vertical__splitter-handle--after--BorderRightWidth);--pf-c-drawer__splitter-handle--after--BorderBottomWidth:var(--pf-c-drawer__splitter--m-vertical__splitter-handle--after--BorderBottomWidth);--pf-c-drawer__splitter-handle--after--BorderLeftWidth:var(--pf-c-drawer__splitter--m-vertical__splitter-handle--after--BorderLeftWidth)}.pf-c-drawer__splitter:hover{--pf-c-drawer__splitter-handle--after--BorderColor:var(--pf-c-drawer__splitter--hover__splitter-handle--after--BorderColor)}.pf-c-drawer__splitter:focus{--pf-c-drawer__splitter-handle--after--BorderColor:var(--pf-c-drawer__splitter--focus__splitter-handle--after--BorderColor)}.pf-c-drawer__splitter:after{position:absolute;top:0;right:0;bottom:0;left:0;content:"";border:solid var(--pf-c-drawer__splitter--after--BorderColor);border-width:var(--pf-c-drawer__splitter--after--BorderTopWidth) var(--pf-c-drawer__splitter--after--BorderRightWidth) var(--pf-c-drawer__splitter--after--BorderBottomWidth) var(--pf-c-drawer__splitter--after--BorderLeftWidth)}.pf-c-drawer__splitter-handle{position:absolute;top:var(--pf-c-drawer__splitter-handle--Top);left:var(--pf-c-drawer__splitter-handle--Left);transform:translate(-50%,-50%)}.pf-c-drawer__splitter-handle:after{display:block;width:var(--pf-c-drawer__splitter-handle--after--Width);height:var(--pf-c-drawer__splitter-handle--after--Height);content:"";border-left:var(--pf-c-drawer__splitter-handle--after--BorderLeftWidth) solid var(--pf-c-drawer__splitter-handle--after--BorderColor);border-bottom:var(--pf-c-drawer__splitter-handle--after--BorderBottomWidth) solid var(--pf-c-drawer__splitter-handle--after--BorderColor);border-right:var(--pf-c-drawer__splitter-handle--after--BorderRightWidth) solid var(--pf-c-drawer__splitter-handle--after--BorderColor);border-top:var(--pf-c-drawer__splitter-handle--after--BorderTopWidth) solid var(--pf-c-drawer__splitter-handle--after--BorderColor)}@media screen and (min-width:768px){.pf-c-drawer{min-width:var(--pf-c-drawer__panel--MinWidth)}.pf-c-drawer.pf-m-expanded>.pf-c-drawer__main>.pf-c-drawer__panel{box-shadow:var(--pf-c-drawer--m-expanded__panel--BoxShadow)}.pf-c-drawer>.pf-c-drawer__main>.pf-c-drawer__panel.pf-m-resizable{padding-left:var(--pf-c-drawer__panel--m-resizable--PaddingLeft)}.pf-c-drawer>.pf-c-drawer__main>.pf-c-drawer__panel.pf-m-resizable:after{width:0;height:0}.pf-c-drawer.pf-m-panel-left{--pf-c-drawer--m-expanded__panel--BoxShadow:var(--pf-c-drawer--m-expanded--m-panel-left__panel--BoxShadow)}.pf-c-drawer.pf-m-panel-left.pf-m-inline>.pf-c-drawer__main>.pf-c-drawer__panel,.pf-c-drawer.pf-m-panel-left.pf-m-static>.pf-c-drawer__main>.pf-c-drawer__panel{padding-right:var(--pf-c-drawer--m-panel-left--m-inline__panel--PaddingRight);padding-left:0}.pf-c-drawer.pf-m-panel-left.pf-m-expanded>.pf-c-drawer__main>.pf-c-drawer__panel{transform:translateX(0)}.pf-c-drawer.pf-m-panel-left>.pf-c-drawer__main>.pf-c-drawer__panel:after{right:0;left:auto}.pf-c-drawer.pf-m-panel-left>.pf-c-drawer__main>.pf-c-drawer__panel.pf-m-resizable{padding-right:var(--pf-c-drawer--m-panel-left__panel--m-resizable--PaddingRight);padding-left:0}.pf-c-drawer.pf-m-panel-left>.pf-c-drawer__main>.pf-c-drawer__panel.pf-m-resizable>.pf-c-drawer__splitter{--pf-c-drawer__splitter--Right:0;--pf-c-drawer__splitter--Left:auto;--pf-c-drawer__splitter-handle--Left:var(--pf-c-drawer--m-panel-left__splitter-handle--Left);--pf-c-drawer__splitter--after--BorderRightWidth:0;--pf-c-drawer__splitter--after--BorderLeftWidth:var(--pf-c-drawer--m-panel-left__splitter--after--BorderLeftWidth)}.pf-c-drawer.pf-m-panel-bottom{--pf-c-drawer--m-expanded__panel--BoxShadow:var(--pf-c-drawer--m-expanded--m-panel-bottom__panel--BoxShadow);--pf-c-drawer__panel--MaxHeight:100%;min-width:auto;min-height:var(--pf-c-drawer--m-panel-bottom__panel--md--MinHeight)}.pf-c-drawer.pf-m-panel-bottom.pf-m-inline>.pf-c-drawer__main>.pf-c-drawer__panel,.pf-c-drawer.pf-m-panel-bottom.pf-m-static>.pf-c-drawer__main>.pf-c-drawer__panel{padding-top:var(--pf-c-drawer--m-panel-bottom--m-inline__panel--PaddingTop);padding-left:0}.pf-c-drawer.pf-m-panel-bottom>.pf-c-drawer__main>.pf-c-drawer__panel:after{top:0;left:auto;width:100%;height:var(--pf-c-drawer--m-panel-bottom__panel--after--Height)}.pf-c-drawer.pf-m-panel-bottom>.pf-c-drawer__main>.pf-c-drawer__panel.pf-m-resizable{padding-top:var(--pf-c-drawer--m-panel-bottom__panel--m-resizable--PaddingTop);padding-left:0}.pf-c-drawer.pf-m-panel-bottom>.pf-c-drawer__main>.pf-c-drawer__panel.pf-m-resizable>.pf-c-drawer__splitter{--pf-c-drawer__splitter--Top:0;--pf-c-drawer__splitter--Right:0;--pf-c-drawer__splitter--Bottom:auto;--pf-c-drawer__splitter-handle--Top:var(--pf-c-drawer--m-panel-bottom__splitter-handle--Top);--pf-c-drawer__splitter--after--BorderRightWidth:0;--pf-c-drawer__splitter--after--BorderBottomWidth:var(--pf-c-drawer--m-panel-bottom__splitter--after--BorderBottomWidth)}.pf-c-drawer.pf-m-inline>.pf-c-drawer__main>.pf-c-drawer__panel.pf-m-resizable>.pf-c-drawer__splitter{--pf-c-drawer__splitter--m-vertical--Width:var(--pf-c-drawer--m-inline__splitter--m-vertical--Width);--pf-c-drawer__splitter-handle--Left:var(--pf-c-drawer--m-inline__splitter-handle--Left);--pf-c-drawer__splitter--after--BorderRightWidth:var(--pf-c-drawer--m-inline__splitter--after--BorderRightWidth);--pf-c-drawer__splitter--after--BorderLeftWidth:var(--pf-c-drawer--m-inline__splitter--after--BorderLeftWidth);outline-offset:var(--pf-c-drawer--m-inline__splitter--focus--OutlineOffset)}.pf-c-drawer.pf-m-inline.pf-m-panel-bottom>.pf-c-drawer__main>.pf-c-drawer__panel.pf-m-resizable>.pf-c-drawer__splitter{--pf-c-drawer__splitter--Height:var(--pf-c-drawer--m-inline--m-panel-bottom__splitter--Height);--pf-c-drawer__splitter-handle--Top:var(--pf-c-drawer--m-inline--m-panel-bottom__splitter-handle--Top);--pf-c-drawer__splitter--after--BorderTopWidth:var(--pf-c-drawer--m-inline--m-panel-bottom__splitter--after--BorderTopWidth);--pf-c-drawer__splitter--after--BorderRightWidth:0;--pf-c-drawer__splitter--after--BorderLeftWidth:0}.pf-c-drawer.pf-m-panel-left>.pf-c-drawer__main>.pf-c-drawer__panel.pf-m-no-border,.pf-c-drawer>.pf-c-drawer__main>.pf-c-drawer__panel.pf-m-no-border{--pf-c-drawer--m-expanded__panel--BoxShadow:none}.pf-c-drawer__splitter{display:block;visibility:visible}}@media (min-width:768px){.pf-c-drawer__panel.pf-m-width-25{--pf-c-drawer__panel--FlexBasis:25%}.pf-c-drawer__panel.pf-m-width-33{--pf-c-drawer__panel--FlexBasis:33%}.pf-c-drawer__panel.pf-m-width-50{--pf-c-drawer__panel--FlexBasis:50%}.pf-c-drawer__panel.pf-m-width-66{--pf-c-drawer__panel--FlexBasis:66%}.pf-c-drawer__panel.pf-m-width-75{--pf-c-drawer__panel--FlexBasis:75%}.pf-c-drawer__panel.pf-m-width-100{--pf-c-drawer__panel--FlexBasis:100%}}@media (min-width:992px){.pf-c-drawer__panel.pf-m-width-25-on-lg{--pf-c-drawer__panel--FlexBasis:25%}.pf-c-drawer__panel.pf-m-width-33-on-lg{--pf-c-drawer__panel--FlexBasis:33%}.pf-c-drawer__panel.pf-m-width-50-on-lg{--pf-c-drawer__panel--FlexBasis:50%}.pf-c-drawer__panel.pf-m-width-66-on-lg{--pf-c-drawer__panel--FlexBasis:66%}.pf-c-drawer__panel.pf-m-width-75-on-lg{--pf-c-drawer__panel--FlexBasis:75%}.pf-c-drawer__panel.pf-m-width-100-on-lg{--pf-c-drawer__panel--FlexBasis:100%}}@media (min-width:1200px){.pf-c-drawer__panel.pf-m-width-25-on-xl{--pf-c-drawer__panel--FlexBasis:25%}.pf-c-drawer__panel.pf-m-width-33-on-xl{--pf-c-drawer__panel--FlexBasis:33%}.pf-c-drawer__panel.pf-m-width-50-on-xl{--pf-c-drawer__panel--FlexBasis:50%}.pf-c-drawer__panel.pf-m-width-66-on-xl{--pf-c-drawer__panel--FlexBasis:66%}.pf-c-drawer__panel.pf-m-width-75-on-xl{--pf-c-drawer__panel--FlexBasis:75%}.pf-c-drawer__panel.pf-m-width-100-on-xl{--pf-c-drawer__panel--FlexBasis:100%}}@media (min-width:1450px){.pf-c-drawer__panel.pf-m-width-25-on-2xl{--pf-c-drawer__panel--FlexBasis:25%}.pf-c-drawer__panel.pf-m-width-33-on-2xl{--pf-c-drawer__panel--FlexBasis:33%}.pf-c-drawer__panel.pf-m-width-50-on-2xl{--pf-c-drawer__panel--FlexBasis:50%}.pf-c-drawer__panel.pf-m-width-66-on-2xl{--pf-c-drawer__panel--FlexBasis:66%}.pf-c-drawer__panel.pf-m-width-75-on-2xl{--pf-c-drawer__panel--FlexBasis:75%}.pf-c-drawer__panel.pf-m-width-100-on-2xl{--pf-c-drawer__panel--FlexBasis:100%}}@media (min-width:768px){.pf-c-drawer.pf-m-inline>.pf-c-drawer__main>.pf-c-drawer__content,.pf-c-drawer.pf-m-static>.pf-c-drawer__main>.pf-c-drawer__content{flex-shrink:1}.pf-c-drawer.pf-m-inline>.pf-c-drawer__main>.pf-c-drawer__panel,.pf-c-drawer.pf-m-static>.pf-c-drawer__main>.pf-c-drawer__panel{--pf-c-drawer--m-expanded__panel--BoxShadow:none}.pf-c-drawer.pf-m-inline>.pf-c-drawer__main>.pf-c-drawer__panel:not(.pf-m-no-border):after,.pf-c-drawer.pf-m-static>.pf-c-drawer__main>.pf-c-drawer__panel:not(.pf-m-no-border):after{background-color:var(--pf-c-drawer--m-inline--m-expanded__panel--after--BackgroundColor)}.pf-c-drawer.pf-m-inline>.pf-c-drawer__main>.pf-c-drawer__content{overflow-x:auto}.pf-c-drawer.pf-m-inline>.pf-c-drawer__main>.pf-c-drawer__panel{margin-left:calc(var(--pf-c-drawer__panel--FlexBasis)*-1);transform:translateX(100%)}.pf-c-drawer.pf-m-inline.pf-m-expanded>.pf-c-drawer__main>.pf-c-drawer__panel{margin-left:0;transform:translateX(0)}.pf-c-drawer.pf-m-inline>.pf-c-drawer__main>.pf-c-drawer__panel>.pf-c-drawer__body>.pf-c-drawer__head .pf-c-drawer__close{display:unset;visibility:visible}.pf-c-drawer.pf-m-inline.pf-m-panel-left>.pf-c-drawer__main>.pf-c-drawer__panel{margin-right:calc(var(--pf-c-drawer__panel--FlexBasis)*-1);margin-left:0;transform:translateX(-100%)}.pf-c-drawer.pf-m-inline.pf-m-panel-left.pf-m-expanded>.pf-c-drawer__main>.pf-c-drawer__panel{margin-right:0;transform:translateX(0)}.pf-c-drawer.pf-m-inline.pf-m-panel-left>.pf-c-drawer__main>.pf-c-drawer__panel>.pf-c-drawer__body>.pf-c-drawer__head .pf-c-drawer__close{display:unset;visibility:visible}.pf-c-drawer.pf-m-static>.pf-c-drawer__main>.pf-c-drawer__panel{transform:translateX(0)}.pf-c-drawer.pf-m-static.pf-m-panel-left>.pf-c-drawer__main>.pf-c-drawer__panel{margin-right:0;transform:translateX(0)}.pf-c-drawer.pf-m-static.pf-m-panel-bottom>.pf-c-drawer__main>.pf-c-drawer__panel{transform:translateX(0)}.pf-c-drawer.pf-m-static>.pf-c-drawer__main>.pf-c-drawer__panel>.pf-c-drawer__body>.pf-c-drawer__head .pf-c-drawer__close{display:none;visibility:hidden}}@media (min-width:992px){.pf-c-drawer.pf-m-inline-on-lg>.pf-c-drawer__main>.pf-c-drawer__content,.pf-c-drawer.pf-m-static-on-lg>.pf-c-drawer__main>.pf-c-drawer__content{flex-shrink:1}.pf-c-drawer.pf-m-inline-on-lg>.pf-c-drawer__main>.pf-c-drawer__panel,.pf-c-drawer.pf-m-static-on-lg>.pf-c-drawer__main>.pf-c-drawer__panel{--pf-c-drawer--m-expanded__panel--BoxShadow:none}.pf-c-drawer.pf-m-inline-on-lg>.pf-c-drawer__main>.pf-c-drawer__panel:not(.pf-m-no-border):after,.pf-c-drawer.pf-m-static-on-lg>.pf-c-drawer__main>.pf-c-drawer__panel:not(.pf-m-no-border):after{background-color:var(--pf-c-drawer--m-inline--m-expanded__panel--after--BackgroundColor)}.pf-c-drawer.pf-m-inline-on-lg>.pf-c-drawer__main>.pf-c-drawer__content{overflow-x:auto}.pf-c-drawer.pf-m-inline-on-lg>.pf-c-drawer__main>.pf-c-drawer__panel{margin-left:calc(var(--pf-c-drawer__panel--FlexBasis)*-1);transform:translateX(100%)}.pf-c-drawer.pf-m-inline-on-lg.pf-m-expanded>.pf-c-drawer__main>.pf-c-drawer__panel{margin-left:0;transform:translateX(0)}.pf-c-drawer.pf-m-inline-on-lg>.pf-c-drawer__main>.pf-c-drawer__panel>.pf-c-drawer__body>.pf-c-drawer__head .pf-c-drawer__close{display:unset;visibility:visible}.pf-c-drawer.pf-m-inline-on-lg.pf-m-panel-left>.pf-c-drawer__main>.pf-c-drawer__panel{margin-right:calc(var(--pf-c-drawer__panel--FlexBasis)*-1);margin-left:0;transform:translateX(-100%)}.pf-c-drawer.pf-m-inline-on-lg.pf-m-panel-left.pf-m-expanded>.pf-c-drawer__main>.pf-c-drawer__panel{margin-right:0;transform:translateX(0)}.pf-c-drawer.pf-m-inline-on-lg.pf-m-panel-left>.pf-c-drawer__main>.pf-c-drawer__panel>.pf-c-drawer__body>.pf-c-drawer__head .pf-c-drawer__close{display:unset;visibility:visible}.pf-c-drawer.pf-m-static-on-lg>.pf-c-drawer__main>.pf-c-drawer__panel{transform:translateX(0)}.pf-c-drawer.pf-m-static-on-lg.pf-m-panel-left>.pf-c-drawer__main>.pf-c-drawer__panel{margin-right:0;transform:translateX(0)}.pf-c-drawer.pf-m-static-on-lg.pf-m-panel-bottom>.pf-c-drawer__main>.pf-c-drawer__panel{transform:translateX(0)}.pf-c-drawer.pf-m-static-on-lg>.pf-c-drawer__main>.pf-c-drawer__panel>.pf-c-drawer__body>.pf-c-drawer__head .pf-c-drawer__close{display:none;visibility:hidden}}@media (min-width:1200px){.pf-c-drawer.pf-m-inline-on-xl>.pf-c-drawer__main>.pf-c-drawer__content,.pf-c-drawer.pf-m-static-on-xl>.pf-c-drawer__main>.pf-c-drawer__content{flex-shrink:1}.pf-c-drawer.pf-m-inline-on-xl>.pf-c-drawer__main>.pf-c-drawer__panel,.pf-c-drawer.pf-m-static-on-xl>.pf-c-drawer__main>.pf-c-drawer__panel{--pf-c-drawer--m-expanded__panel--BoxShadow:none}.pf-c-drawer.pf-m-inline-on-xl>.pf-c-drawer__main>.pf-c-drawer__panel:not(.pf-m-no-border):after,.pf-c-drawer.pf-m-static-on-xl>.pf-c-drawer__main>.pf-c-drawer__panel:not(.pf-m-no-border):after{background-color:var(--pf-c-drawer--m-inline--m-expanded__panel--after--BackgroundColor)}.pf-c-drawer.pf-m-inline-on-xl>.pf-c-drawer__main>.pf-c-drawer__content{overflow-x:auto}.pf-c-drawer.pf-m-inline-on-xl>.pf-c-drawer__main>.pf-c-drawer__panel{margin-left:calc(var(--pf-c-drawer__panel--FlexBasis)*-1);transform:translateX(100%)}.pf-c-drawer.pf-m-inline-on-xl.pf-m-expanded>.pf-c-drawer__main>.pf-c-drawer__panel{margin-left:0;transform:translateX(0)}.pf-c-drawer.pf-m-inline-on-xl>.pf-c-drawer__main>.pf-c-drawer__panel>.pf-c-drawer__body>.pf-c-drawer__head .pf-c-drawer__close{display:unset;visibility:visible}.pf-c-drawer.pf-m-inline-on-xl.pf-m-panel-left>.pf-c-drawer__main>.pf-c-drawer__panel{margin-right:calc(var(--pf-c-drawer__panel--FlexBasis)*-1);margin-left:0;transform:translateX(-100%)}.pf-c-drawer.pf-m-inline-on-xl.pf-m-panel-left.pf-m-expanded>.pf-c-drawer__main>.pf-c-drawer__panel{margin-right:0;transform:translateX(0)}.pf-c-drawer.pf-m-inline-on-xl.pf-m-panel-left>.pf-c-drawer__main>.pf-c-drawer__panel>.pf-c-drawer__body>.pf-c-drawer__head .pf-c-drawer__close{display:unset;visibility:visible}.pf-c-drawer.pf-m-static-on-xl>.pf-c-drawer__main>.pf-c-drawer__panel{transform:translateX(0)}.pf-c-drawer.pf-m-static-on-xl.pf-m-panel-left>.pf-c-drawer__main>.pf-c-drawer__panel{margin-right:0;transform:translateX(0)}.pf-c-drawer.pf-m-static-on-xl.pf-m-panel-bottom>.pf-c-drawer__main>.pf-c-drawer__panel{transform:translateX(0)}.pf-c-drawer.pf-m-static-on-xl>.pf-c-drawer__main>.pf-c-drawer__panel>.pf-c-drawer__body>.pf-c-drawer__head .pf-c-drawer__close{display:none;visibility:hidden}}@media (min-width:1450px){.pf-c-drawer.pf-m-inline-on-2xl>.pf-c-drawer__main>.pf-c-drawer__content,.pf-c-drawer.pf-m-static-on-2xl>.pf-c-drawer__main>.pf-c-drawer__content{flex-shrink:1}.pf-c-drawer.pf-m-inline-on-2xl>.pf-c-drawer__main>.pf-c-drawer__panel,.pf-c-drawer.pf-m-static-on-2xl>.pf-c-drawer__main>.pf-c-drawer__panel{--pf-c-drawer--m-expanded__panel--BoxShadow:none}.pf-c-drawer.pf-m-inline-on-2xl>.pf-c-drawer__main>.pf-c-drawer__panel:not(.pf-m-no-border):after,.pf-c-drawer.pf-m-static-on-2xl>.pf-c-drawer__main>.pf-c-drawer__panel:not(.pf-m-no-border):after{background-color:var(--pf-c-drawer--m-inline--m-expanded__panel--after--BackgroundColor)}.pf-c-drawer.pf-m-inline-on-2xl>.pf-c-drawer__main>.pf-c-drawer__content{overflow-x:auto}.pf-c-drawer.pf-m-inline-on-2xl>.pf-c-drawer__main>.pf-c-drawer__panel{margin-left:calc(var(--pf-c-drawer__panel--FlexBasis)*-1);transform:translateX(100%)}.pf-c-drawer.pf-m-inline-on-2xl.pf-m-expanded>.pf-c-drawer__main>.pf-c-drawer__panel{margin-left:0;transform:translateX(0)}.pf-c-drawer.pf-m-inline-on-2xl>.pf-c-drawer__main>.pf-c-drawer__panel>.pf-c-drawer__body>.pf-c-drawer__head .pf-c-drawer__close{display:unset;visibility:visible}.pf-c-drawer.pf-m-inline-on-2xl.pf-m-panel-left>.pf-c-drawer__main>.pf-c-drawer__panel{margin-right:calc(var(--pf-c-drawer__panel--FlexBasis)*-1);margin-left:0;transform:translateX(-100%)}.pf-c-drawer.pf-m-inline-on-2xl.pf-m-panel-left.pf-m-expanded>.pf-c-drawer__main>.pf-c-drawer__panel{margin-right:0;transform:translateX(0)}.pf-c-drawer.pf-m-inline-on-2xl.pf-m-panel-left>.pf-c-drawer__main>.pf-c-drawer__panel>.pf-c-drawer__body>.pf-c-drawer__head .pf-c-drawer__close{display:unset;visibility:visible}.pf-c-drawer.pf-m-static-on-2xl>.pf-c-drawer__main>.pf-c-drawer__panel{transform:translateX(0)}.pf-c-drawer.pf-m-static-on-2xl.pf-m-panel-left>.pf-c-drawer__main>.pf-c-drawer__panel{margin-right:0;transform:translateX(0)}.pf-c-drawer.pf-m-static-on-2xl.pf-m-panel-bottom>.pf-c-drawer__main>.pf-c-drawer__panel{transform:translateX(0)}.pf-c-drawer.pf-m-static-on-2xl>.pf-c-drawer__main>.pf-c-drawer__panel>.pf-c-drawer__body>.pf-c-drawer__head .pf-c-drawer__close{display:none;visibility:hidden}}.pf-c-dropdown{--pf-c-dropdown__toggle--PaddingTop:var(--pf-global--spacer--form-element);--pf-c-dropdown__toggle--PaddingRight:var(--pf-global--spacer--sm);--pf-c-dropdown__toggle--PaddingBottom:var(--pf-global--spacer--form-element);--pf-c-dropdown__toggle--PaddingLeft:var(--pf-global--spacer--sm);--pf-c-dropdown__toggle--MinWidth:var(--pf-global--target-size--MinWidth);--pf-c-dropdown__toggle--FontSize:var(--pf-global--FontSize--md);--pf-c-dropdown__toggle--FontWeight:var(--pf-global--FontWeight--normal);--pf-c-dropdown__toggle--Color:var(--pf-global--Color--100);--pf-c-dropdown__toggle--LineHeight:var(--pf-global--LineHeight--md);--pf-c-dropdown__toggle--BackgroundColor:transparent;--pf-c-dropdown__toggle--before--BorderWidth:var(--pf-global--BorderWidth--sm);--pf-c-dropdown__toggle--before--BorderTopColor:var(--pf-global--BorderColor--300);--pf-c-dropdown__toggle--before--BorderRightColor:var(--pf-global--BorderColor--300);--pf-c-dropdown__toggle--before--BorderBottomColor:var(--pf-global--BorderColor--200);--pf-c-dropdown__toggle--before--BorderLeftColor:var(--pf-global--BorderColor--300);--pf-c-dropdown__toggle--hover--before--BorderBottomColor:var(--pf-global--active-color--100);--pf-c-dropdown__toggle--active--before--BorderBottomWidth:var(--pf-global--BorderWidth--md);--pf-c-dropdown__toggle--active--before--BorderBottomColor:var(--pf-global--active-color--100);--pf-c-dropdown__toggle--focus--before--BorderBottomWidth:var(--pf-global--BorderWidth--md);--pf-c-dropdown__toggle--focus--before--BorderBottomColor:var(--pf-global--active-color--100);--pf-c-dropdown--m-expanded__toggle--before--BorderBottomWidth:var(--pf-global--BorderWidth--md);--pf-c-dropdown--m-expanded__toggle--before--BorderBottomColor:var(--pf-global--active-color--100);--pf-c-dropdown__toggle--disabled--BackgroundColor:var(--pf-global--disabled-color--300);--pf-c-dropdown__toggle--m-plain--Color:var(--pf-global--Color--200);--pf-c-dropdown__toggle--m-plain--hover--Color:var(--pf-global--Color--100);--pf-c-dropdown__toggle--m-plain--disabled--Color:var(--pf-global--disabled-color--200);--pf-c-dropdown__toggle--m-plain--child--LineHeight:normal;--pf-c-dropdown__toggle--m-primary--Color:var(--pf-global--Color--light-100);--pf-c-dropdown__toggle--m-primary--BorderRadius:var(--pf-global--BorderRadius--sm);--pf-c-dropdown__toggle--m-primary--BackgroundColor:var(--pf-global--primary-color--100);--pf-c-dropdown__toggle--m-primary--hover--BackgroundColor:var(--pf-global--primary-color--200);--pf-c-dropdown__toggle--m-primary--active--BackgroundColor:var(--pf-global--primary-color--200);--pf-c-dropdown__toggle--m-primary--focus--BackgroundColor:var(--pf-global--primary-color--200);--pf-c-dropdown--m-expanded__toggle--m-primary--BackgroundColor:var(--pf-global--primary-color--200);--pf-c-dropdown__toggle-button--Color:var(--pf-global--Color--100);--pf-c-dropdown__toggle--m-split-button--child--PaddingTop:var(--pf-global--spacer--form-element);--pf-c-dropdown__toggle--m-split-button--child--PaddingRight:var(--pf-global--spacer--xs);--pf-c-dropdown__toggle--m-split-button--child--PaddingBottom:var(--pf-global--spacer--form-element);--pf-c-dropdown__toggle--m-split-button--child--PaddingLeft:var(--pf-global--spacer--xs);--pf-c-dropdown__toggle--m-split-button--child--BackgroundColor:transparent;--pf-c-dropdown__toggle--m-split-button--first-child--PaddingLeft:var(--pf-global--spacer--sm);--pf-c-dropdown__toggle--m-split-button--last-child--PaddingRight:var(--pf-global--spacer--sm);--pf-c-dropdown__toggle--m-split-button--m-action--child--PaddingLeft:var(--pf-global--spacer--sm);--pf-c-dropdown__toggle--m-split-button--m-action--child--PaddingRight:var(--pf-global--spacer--sm);--pf-c-dropdown__toggle--m-split-button--m-action__toggle-button--MarginRight:calc(-1*var(--pf-global--BorderWidth--sm));--pf-c-dropdown__toggle--m-split-button__toggle-check__input--TranslateY:-0.0625rem;--pf-c-dropdown__toggle--m-split-button__toggle-text--MarginLeft:var(--pf-global--spacer--sm);--pf-c-dropdown__toggle-icon--LineHeight:var(--pf-global--LineHeight--md);--pf-c-dropdown__toggle-icon--MarginRight:var(--pf-global--spacer--sm);--pf-c-dropdown__toggle-icon--MarginLeft:var(--pf-global--spacer--md);--pf-c-dropdown--m-top--m-expanded__toggle-icon--Rotate:180deg;--pf-c-dropdown__menu--BackgroundColor:var(--pf-global--BackgroundColor--light-100);--pf-c-dropdown__menu--BoxShadow:var(--pf-global--BoxShadow--md);--pf-c-dropdown__menu--PaddingTop:var(--pf-global--spacer--sm);--pf-c-dropdown__menu--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-dropdown__menu--Top:calc(100% + var(--pf-global--spacer--xs));--pf-c-dropdown__menu--ZIndex:var(--pf-global--ZIndex--sm);--pf-c-dropdown--m-top__menu--Top:0;--pf-c-dropdown--m-top__menu--TranslateY:calc(-100% - var(--pf-global--spacer--xs));--pf-c-dropdown__menu-item--BackgroundColor:transparent;--pf-c-dropdown__menu-item--PaddingTop:var(--pf-global--spacer--sm);--pf-c-dropdown__menu-item--PaddingRight:var(--pf-global--spacer--md);--pf-c-dropdown__menu-item--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-dropdown__menu-item--PaddingLeft:var(--pf-global--spacer--md);--pf-c-dropdown__menu-item--FontSize:var(--pf-global--FontSize--md);--pf-c-dropdown__menu-item--FontWeight:var(--pf-global--FontWeight--normal);--pf-c-dropdown__menu-item--LineHeight:var(--pf-global--LineHeight--md);--pf-c-dropdown__menu-item--Color:var(--pf-global--Color--dark-100);--pf-c-dropdown__menu-item--hover--Color:var(--pf-global--Color--dark-100);--pf-c-dropdown__menu-item--disabled--Color:var(--pf-global--Color--dark-200);--pf-c-dropdown__menu-item--hover--BackgroundColor:var(--pf-global--BackgroundColor--light-300);--pf-c-dropdown__menu-item--disabled--BackgroundColor:transparent;--pf-c-dropdown__menu-item--m-text--Color:var(--pf-global--Color--dark-200);--pf-c-dropdown__menu-item-icon--MarginRight:var(--pf-global--spacer--sm);--pf-c-dropdown__menu-item-icon--Width:var(--pf-global--icon--FontSize--lg);--pf-c-dropdown__menu-item-icon--Height:var(--pf-global--icon--FontSize--lg);--pf-c-dropdown__menu-item-description--FontSize:var(--pf-global--FontSize--xs);--pf-c-dropdown__menu-item-description--Color:var(--pf-global--Color--dark-200);--pf-c-dropdown__group--group--PaddingTop:var(--pf-global--spacer--sm);--pf-c-dropdown__group-title--PaddingTop:var(--pf-global--spacer--sm);--pf-c-dropdown__group-title--PaddingRight:var(--pf-c-dropdown__menu-item--PaddingRight);--pf-c-dropdown__group-title--PaddingBottom:var(--pf-c-dropdown__menu-item--PaddingBottom);--pf-c-dropdown__group-title--PaddingLeft:var(--pf-c-dropdown__menu-item--PaddingLeft);--pf-c-dropdown__group-title--FontSize:var(--pf-global--FontSize--sm);--pf-c-dropdown__group-title--FontWeight:var(--pf-global--FontWeight--semi-bold);--pf-c-dropdown__group-title--Color:var(--pf-global--Color--dark-200);--pf-c-dropdown__toggle-image--MarginTop:var(--pf-global--spacer--xs);--pf-c-dropdown__toggle-image--MarginBottom:var(--pf-global--spacer--xs);--pf-c-dropdown__toggle-image--MarginRight:var(--pf-global--spacer--sm);--pf-c-dropdown--c-divider--MarginTop:var(--pf-global--spacer--sm);--pf-c-dropdown--c-divider--MarginBottom:var(--pf-global--spacer--sm);position:relative;display:inline-block;max-width:100%}.pf-c-dropdown .pf-c-divider{margin-top:var(--pf-c-dropdown--c-divider--MarginTop);margin-bottom:var(--pf-c-dropdown--c-divider--MarginBottom)}.pf-c-dropdown .pf-c-divider:last-child{--pf-c-dropdown--c-divider--MarginBottom:0}.pf-c-dropdown__toggle{position:relative;display:flex;align-items:center;justify-content:space-between;min-width:var(--pf-c-dropdown__toggle--MinWidth);max-width:100%;padding:var(--pf-c-dropdown__toggle--PaddingTop) var(--pf-c-dropdown__toggle--PaddingRight) var(--pf-c-dropdown__toggle--PaddingBottom) var(--pf-c-dropdown__toggle--PaddingLeft);font-size:var(--pf-c-dropdown__toggle--FontSize);font-weight:var(--pf-c-dropdown__toggle--FontWeight);line-height:var(--pf-c-dropdown__toggle--LineHeight);color:var(--pf-c-dropdown__toggle--Color);background-color:var(--pf-c-dropdown__toggle--BackgroundColor);border:none}.pf-c-dropdown__toggle.pf-m-action .pf-c-dropdown__toggle-button:before,.pf-c-dropdown__toggle:before{position:absolute;top:0;right:0;bottom:0;left:0;content:"";border:var(--pf-c-dropdown__toggle--before--BorderWidth) solid;border-color:var(--pf-c-dropdown__toggle--before--BorderTopColor) var(--pf-c-dropdown__toggle--before--BorderRightColor) var(--pf-c-dropdown__toggle--before--BorderBottomColor) var(--pf-c-dropdown__toggle--before--BorderLeftColor)}.pf-c-dropdown__toggle.pf-m-disabled,.pf-c-dropdown__toggle:disabled{pointer-events:none}.pf-c-dropdown__toggle.pf-m-disabled:not(.pf-m-plain),.pf-c-dropdown__toggle:disabled:not(.pf-m-plain){--pf-c-dropdown__toggle--BackgroundColor:var(--pf-c-dropdown__toggle--disabled--BackgroundColor)}.pf-c-dropdown__toggle.pf-m-disabled:not(.pf-m-plain):before,.pf-c-dropdown__toggle:disabled:not(.pf-m-plain):before{border:0}.pf-c-dropdown__toggle.pf-m-split-button{padding:0}.pf-c-dropdown__toggle.pf-m-split-button>*{position:relative;padding:var(--pf-c-dropdown__toggle--m-split-button--child--PaddingTop) var(--pf-c-dropdown__toggle--m-split-button--child--PaddingRight) var(--pf-c-dropdown__toggle--m-split-button--child--PaddingBottom) var(--pf-c-dropdown__toggle--m-split-button--child--PaddingLeft);background-color:var(--pf-c-dropdown__toggle--m-split-button--child--BackgroundColor)}.pf-c-dropdown__toggle.pf-m-split-button>:first-child{--pf-c-dropdown__toggle--m-split-button--child--PaddingLeft:var(--pf-c-dropdown__toggle--m-split-button--first-child--PaddingLeft)}.pf-c-dropdown__toggle.pf-m-split-button>:last-child{--pf-c-dropdown__toggle--m-split-button--child--PaddingRight:var(--pf-c-dropdown__toggle--m-split-button--last-child--PaddingRight)}.pf-c-dropdown__toggle.pf-m-split-button.pf-m-action{--pf-c-dropdown__toggle--m-split-button--child--PaddingRight:var(--pf-c-dropdown__toggle--m-split-button--m-action--child--PaddingRight);--pf-c-dropdown__toggle--m-split-button--child--PaddingLeft:var(--pf-c-dropdown__toggle--m-split-button--m-action--child--PaddingLeft)}.pf-c-dropdown__toggle.pf-m-split-button.pf-m-action .pf-c-dropdown__toggle-button{margin-right:var(--pf-c-dropdown__toggle--m-split-button--m-action__toggle-button--MarginRight)}.pf-c-dropdown__toggle.pf-m-split-button.pf-m-action .pf-c-dropdown__toggle-button:before{border-left:0}.pf-c-dropdown__toggle.pf-m-split-button.pf-m-action .pf-c-dropdown__toggle-button:last-child{--pf-c-dropdown__toggle--m-split-button--m-action__toggle-button--MarginRight:0}.pf-c-dropdown__toggle.pf-m-split-button .pf-c-dropdown__toggle-check{display:flex;align-items:center;cursor:pointer}.pf-c-dropdown__toggle.pf-m-split-button .pf-c-dropdown__toggle-check input{transform:translateY(var(--pf-c-dropdown__toggle--m-split-button__toggle-check__input--TranslateY))}.pf-c-dropdown__toggle.pf-m-split-button .pf-c-dropdown__toggle-button{color:var(--pf-c-dropdown__toggle-button--Color);border:0}.pf-c-dropdown__toggle.pf-m-split-button .pf-c-dropdown__toggle-text{margin-left:var(--pf-c-dropdown__toggle--m-split-button__toggle-text--MarginLeft)}.pf-c-dropdown__toggle.pf-m-action .pf-c-dropdown__toggle-button:hover:before,.pf-c-dropdown__toggle:not(.pf-m-action):hover:before{--pf-c-dropdown__toggle--before--BorderBottomColor:var(--pf-c-dropdown__toggle--hover--before--BorderBottomColor)}.pf-c-dropdown__toggle.pf-m-action .pf-c-dropdown__toggle-button:active:before,.pf-c-dropdown__toggle:not(.pf-m-action).pf-m-active:before,.pf-c-dropdown__toggle:not(.pf-m-action):active:before{--pf-c-dropdown__toggle--before--BorderBottomColor:var(--pf-c-dropdown__toggle--active--before--BorderBottomColor);border-bottom-width:var(--pf-c-dropdown__toggle--active--before--BorderBottomWidth)}.pf-c-dropdown__toggle.pf-m-action .pf-c-dropdown__toggle-button:focus:before,.pf-c-dropdown__toggle:not(.pf-m-action):focus:before{--pf-c-dropdown__toggle--before--BorderBottomColor:var(--pf-c-dropdown__toggle--focus--before--BorderBottomColor);border-bottom-width:var(--pf-c-dropdown__toggle--focus--before--BorderBottomWidth)}.pf-m-expanded>.pf-c-dropdown__toggle.pf-m-action .pf-c-dropdown__toggle-button:before,.pf-m-expanded>.pf-c-dropdown__toggle:not(.pf-m-action):before{--pf-c-dropdown__toggle--before--BorderBottomColor:var(--pf-c-dropdown--m-expanded__toggle--before--BorderBottomColor);border-bottom-width:var(--pf-c-dropdown--m-expanded__toggle--before--BorderBottomWidth)}.pf-c-dropdown__toggle.pf-m-plain{display:inline-block;color:var(--pf-c-dropdown__toggle--m-plain--Color)}.pf-c-dropdown__toggle.pf-m-plain>*{line-height:var(--pf-c-dropdown__toggle--m-plain--child--LineHeight)}.pf-c-dropdown__toggle.pf-m-plain:before{border:0}.pf-c-dropdown__toggle.pf-m-plain.pf-m-active,.pf-c-dropdown__toggle.pf-m-plain:active,.pf-c-dropdown__toggle.pf-m-plain:focus,.pf-c-dropdown__toggle.pf-m-plain:hover,.pf-m-expanded>.pf-c-dropdown__toggle.pf-m-plain{--pf-c-dropdown__toggle--m-plain--Color:var(--pf-c-dropdown__toggle--m-plain--hover--Color)}.pf-c-dropdown__toggle.pf-m-plain.pf-m-disabled,.pf-c-dropdown__toggle.pf-m-plain:disabled{--pf-c-dropdown__toggle--m-plain--Color:var(--pf-c-dropdown__toggle--m-plain--disabled--Color)}.pf-c-dropdown__toggle.pf-m-primary{--pf-c-dropdown__toggle--Color:var(--pf-c-dropdown__toggle--m-primary--Color);--pf-c-dropdown__toggle--BackgroundColor:var(--pf-c-dropdown__toggle--m-primary--BackgroundColor);border-radius:var(--pf-c-dropdown__toggle--m-primary--BorderRadius)}.pf-c-dropdown__toggle.pf-m-primary:before{border:0}.pf-c-dropdown__toggle.pf-m-primary:hover{--pf-c-dropdown__toggle--BackgroundColor:var(--pf-c-dropdown__toggle--m-primary--hover--BackgroundColor)}.pf-c-dropdown__toggle.pf-m-primary.pf-m-active,.pf-c-dropdown__toggle.pf-m-primary:active{--pf-c-dropdown__toggle--BackgroundColor:var(--pf-c-dropdown__toggle--m-primary--active--BackgroundColor)}.pf-c-dropdown__toggle.pf-m-primary:focus{--pf-c-dropdown__toggle--BackgroundColor:var(--pf-c-dropdown__toggle--m-primary--focus--BackgroundColor)}.pf-m-expanded>.pf-c-dropdown__toggle.pf-m-primary{--pf-c-dropdown__toggle--BackgroundColor:var(--pf-c-dropdown--m-expanded__toggle--m-primary--BackgroundColor)}.pf-c-dropdown__toggle .pf-c-dropdown__toggle-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pf-c-dropdown__toggle-icon{margin-right:var(--pf-c-dropdown__toggle-icon--MarginRight);margin-left:var(--pf-c-dropdown__toggle-icon--MarginLeft);line-height:var(--pf-c-dropdown__toggle-icon--LineHeight)}.pf-c-dropdown.pf-m-top.pf-m-expanded .pf-c-dropdown__toggle-icon{transform:rotate(var(--pf-c-dropdown--m-top--m-expanded__toggle-icon--Rotate))}.pf-c-dropdown__toggle-image{display:inline-flex;margin-top:var(--pf-c-dropdown__toggle-image--MarginTop);margin-right:var(--pf-c-dropdown__toggle-image--MarginRight);margin-bottom:var(--pf-c-dropdown__toggle-image--MarginBottom)}.pf-c-dropdown__toggle-image:last-child{--pf-c-dropdown__toggle-image--MarginRight:0}.pf-c-dropdown__menu{position:absolute;top:var(--pf-c-dropdown__menu--Top);z-index:var(--pf-c-dropdown__menu--ZIndex);min-width:100%;padding-top:var(--pf-c-dropdown__menu--PaddingTop);padding-bottom:var(--pf-c-dropdown__menu--PaddingBottom);background:var(--pf-c-dropdown__menu--BackgroundColor);background-clip:padding-box;box-shadow:var(--pf-c-dropdown__menu--BoxShadow)}.pf-c-dropdown__menu.pf-m-align-right{right:0}.pf-c-dropdown.pf-m-top .pf-c-dropdown__menu{--pf-c-dropdown__menu--Top:var(--pf-c-dropdown--m-top__menu--Top);transform:translateY(var(--pf-c-dropdown--m-top__menu--TranslateY))}.pf-c-dropdown__menu-item{display:block;width:100%;padding:var(--pf-c-dropdown__menu-item--PaddingTop) var(--pf-c-dropdown__menu-item--PaddingRight) var(--pf-c-dropdown__menu-item--PaddingBottom) var(--pf-c-dropdown__menu-item--PaddingLeft);font-size:var(--pf-c-dropdown__menu-item--FontSize);font-weight:var(--pf-c-dropdown__menu-item--FontWeight);line-height:var(--pf-c-dropdown__menu-item--LineHeight);color:var(--pf-c-dropdown__menu-item--Color);text-align:left;white-space:nowrap;background-color:var(--pf-c-dropdown__menu-item--BackgroundColor);border:none}.pf-c-dropdown__menu-item:focus,.pf-c-dropdown__menu-item:hover{--pf-c-dropdown__menu-item--Color:var(--pf-c-dropdown__menu-item--hover--Color);--pf-c-dropdown__menu-item--BackgroundColor:var(--pf-c-dropdown__menu-item--hover--BackgroundColor);text-decoration:none}.pf-c-dropdown__menu-item.pf-m-disabled,.pf-c-dropdown__menu-item:disabled{--pf-c-dropdown__menu-item--Color:var(--pf-c-dropdown__menu-item--disabled--Color);--pf-c-dropdown__menu-item--BackgroundColor:var(--pf-c-dropdown__menu-item--disabled--BackgroundColor);pointer-events:none}.pf-c-dropdown__menu-item.pf-m-icon{display:flex;align-items:center}.pf-c-dropdown__menu-item.pf-m-icon.pf-m-description{flex-direction:column;align-items:start}.pf-c-dropdown__menu-item.pf-m-icon .pf-c-dropdown__menu-item-main{display:flex;align-items:center}.pf-c-dropdown__menu-item.pf-m-text{--pf-c-dropdown__menu-item--Color:var(--pf-c-dropdown__menu-item--m-text--Color)}.pf-c-dropdown__menu-item.pf-m-text:focus,.pf-c-dropdown__menu-item.pf-m-text:hover{--pf-c-dropdown__menu-item--BackgroundColor:transparent}.pf-c-dropdown__menu-item-icon{display:inline-flex;align-items:center;justify-content:center;width:var(--pf-c-dropdown__menu-item-icon--Width);height:var(--pf-c-dropdown__menu-item-icon--Height);margin-right:var(--pf-c-dropdown__menu-item-icon--MarginRight)}.pf-c-dropdown__menu-item-icon>*{max-width:100%;max-height:100%}.pf-c-dropdown__menu-item-description{font-size:var(--pf-c-dropdown__menu-item-description--FontSize);color:var(--pf-c-dropdown__menu-item-description--Color)}.pf-c-dropdown__group+.pf-c-dropdown__group{padding-top:var(--pf-c-dropdown__group--group--PaddingTop)}.pf-c-dropdown__group-title{padding:var(--pf-c-dropdown__group-title--PaddingTop) var(--pf-c-dropdown__group-title--PaddingRight) var(--pf-c-dropdown__group-title--PaddingBottom) var(--pf-c-dropdown__group-title--PaddingLeft);font-size:var(--pf-c-dropdown__group-title--FontSize);font-weight:var(--pf-c-dropdown__group-title--FontWeight);color:var(--pf-c-dropdown__group-title--Color)}.pf-c-empty-state{--pf-c-empty-state--PaddingTop:var(--pf-global--spacer--xl);--pf-c-empty-state--PaddingRight:var(--pf-global--spacer--xl);--pf-c-empty-state--PaddingBottom:var(--pf-global--spacer--xl);--pf-c-empty-state--PaddingLeft:var(--pf-global--spacer--xl);--pf-c-empty-state__content--MaxWidth:none;--pf-c-empty-state__icon--MarginBottom:var(--pf-global--spacer--lg);--pf-c-empty-state__icon--FontSize:var(--pf-global--icon--FontSize--xl);--pf-c-empty-state__icon--Color:var(--pf-global--icon--Color--light);--pf-c-empty-state__content--c-title--m-lg--FontSize:var(--pf-global--FontSize--xl);--pf-c-empty-state__body--MarginTop:var(--pf-global--spacer--md);--pf-c-empty-state__body--Color:var(--pf-global--Color--200);--pf-c-empty-state__primary--MarginTop:var(--pf-global--spacer--xl);--pf-c-empty-state__primary--secondary--MarginTop:var(--pf-global--spacer--sm);--pf-c-empty-state__secondary--MarginTop:var(--pf-global--spacer--xl);--pf-c-empty-state__secondary--MarginBottom:calc(var(--pf-global--spacer--xs)*-1);--pf-c-empty-state__secondary--child--MarginRight:calc(var(--pf-global--spacer--xs)/2);--pf-c-empty-state__secondary--child--MarginBottom:var(--pf-global--spacer--xs);--pf-c-empty-state__secondary--child--MarginLeft:calc(var(--pf-global--spacer--xs)/2);--pf-c-empty-state--m-xs__content--MaxWidth:21.875rem;--pf-c-empty-state--m-xs__body--FontSize:var(--pf-global--FontSize--sm);--pf-c-empty-state--m-xs--button--FontSize:var(--pf-global--FontSize--sm);--pf-c-empty-state--m-xs--PaddingTop:var(--pf-global--spacer--md);--pf-c-empty-state--m-xs--PaddingRight:var(--pf-global--spacer--md);--pf-c-empty-state--m-xs--PaddingBottom:var(--pf-global--spacer--md);--pf-c-empty-state--m-xs--PaddingLeft:var(--pf-global--spacer--md);--pf-c-empty-state--m-xs__icon--MarginBottom:var(--pf-global--spacer--md);--pf-c-empty-state--m-xs__body--MarginTop:var(--pf-global--spacer--md);--pf-c-empty-state--m-xs__primary--MarginTop:var(--pf-global--spacer--md);--pf-c-empty-state--m-xs__secondary--MarginTop:var(--pf-global--spacer--md);--pf-c-empty-state--m-sm__content--MaxWidth:25rem;--pf-c-empty-state--m-lg__content--MaxWidth:37.5rem;--pf-c-empty-state--m-xl__body--FontSize:var(--pf-global--FontSize--xl);--pf-c-empty-state--m-xl__body--MarginTop:var(--pf-global--spacer--lg);--pf-c-empty-state--m-xl__icon--MarginBottom:var(--pf-global--spacer--xl);--pf-c-empty-state--m-xl__icon--FontSize:6.25rem;--pf-c-empty-state--m-xl--c-button__secondary--MarginTop:var(--pf-global--spacer--md);display:flex;align-items:center;justify-content:center;padding:var(--pf-c-empty-state--PaddingTop) var(--pf-c-empty-state--PaddingRight) var(--pf-c-empty-state--PaddingBottom) var(--pf-c-empty-state--PaddingLeft);text-align:center}.pf-c-empty-state.pf-m-xs{--pf-c-empty-state--PaddingTop:var(--pf-c-empty-state--m-xs--PaddingTop);--pf-c-empty-state--PaddingRight:var(--pf-c-empty-state--m-xs--PaddingRight);--pf-c-empty-state--PaddingBottom:var(--pf-c-empty-state--m-xs--PaddingBottom);--pf-c-empty-state--PaddingLeft:var(--pf-c-empty-state--m-xs--PaddingLeft);--pf-c-empty-state__content--MaxWidth:var(--pf-c-empty-state--m-xs__content--MaxWidth);--pf-c-empty-state__icon--MarginBottom:var(--pf-c-empty-state--m-xs__icon--MarginBottom);--pf-c-empty-state__body--MarginTop:var(--pf-c-empty-state--m-xs__body--MarginTop);--pf-c-empty-state__primary--MarginTop:var(--pf-c-empty-state--m-xs__primary--MarginTop);--pf-c-empty-state__secondary--MarginTop:var(--pf-c-empty-state--m-xs__secondary--MarginTop)}.pf-c-empty-state.pf-m-xs .pf-c-empty-state__body{font-size:var(--pf-c-empty-state--m-xs__body--FontSize)}.pf-c-empty-state.pf-m-xs .pf-c-button{--pf-c-button--FontSize:var(--pf-c-empty-state--m-xs--button--FontSize)}.pf-c-empty-state.pf-m-sm{--pf-c-empty-state__content--MaxWidth:var(--pf-c-empty-state--m-sm__content--MaxWidth)}.pf-c-empty-state.pf-m-lg{--pf-c-empty-state__content--MaxWidth:var(--pf-c-empty-state--m-lg__content--MaxWidth)}.pf-c-empty-state.pf-m-xl{--pf-c-empty-state__body--MarginTop:var(--pf-c-empty-state--m-xl__body--MarginTop);--pf-c-empty-state__icon--MarginBottom:var(--pf-c-empty-state--m-xl__icon--MarginBottom);--pf-c-empty-state__icon--FontSize:var(--pf-c-empty-state--m-xl__icon--FontSize);--pf-c-empty-state--c-button__secondary--MarginTop:var(--pf-c-empty-state--m-xl--c-button__secondary--MarginTop)}.pf-c-empty-state.pf-m-xl .pf-c-empty-state__body{font-size:var(--pf-c-empty-state--m-xl__body--FontSize)}.pf-c-empty-state.pf-m-full-height{height:100%}.pf-c-empty-state__content{max-width:var(--pf-c-empty-state__content--MaxWidth)}.pf-c-empty-state__content>.pf-c-title.pf-m-lg{font-size:var(--pf-c-empty-state__content--c-title--m-lg--FontSize)}.pf-c-empty-state__icon{margin-bottom:var(--pf-c-empty-state__icon--MarginBottom);font-size:var(--pf-c-empty-state__icon--FontSize);color:var(--pf-c-empty-state__icon--Color)}.pf-c-empty-state__body{margin-top:var(--pf-c-empty-state__body--MarginTop);color:var(--pf-c-empty-state__body--Color)}.pf-c-empty-state__content>.pf-c-button.pf-m-primary,.pf-c-empty-state__primary{margin-top:var(--pf-c-empty-state__primary--MarginTop)}.pf-c-empty-state__content>.pf-c-button.pf-m-primary+.pf-c-empty-state__secondary,.pf-c-empty-state__primary+.pf-c-empty-state__secondary{margin-top:var(--pf-c-empty-state__primary--secondary--MarginTop)}.pf-c-empty-state__secondary{display:flex;flex-wrap:wrap;justify-content:center;margin-top:var(--pf-c-empty-state__secondary--MarginTop);margin-bottom:var(--pf-c-empty-state__secondary--MarginBottom)}.pf-c-empty-state__secondary>*{margin-right:var(--pf-c-empty-state__secondary--child--MarginRight);margin-bottom:var(--pf-c-empty-state__secondary--child--MarginBottom);margin-left:var(--pf-c-empty-state__secondary--child--MarginLeft)}.pf-m-overpass-font .pf-c-empty-state .pf-c-empty-state__content>.pf-c-title.pf-m-lg{font-size:var(--pf-global--FontSize--lg)}.pf-c-expandable-section{--pf-c-expandable-section__toggle--PaddingTop:var(--pf-global--spacer--form-element);--pf-c-expandable-section__toggle--PaddingRight:var(--pf-global--spacer--md);--pf-c-expandable-section__toggle--PaddingBottom:var(--pf-global--spacer--form-element);--pf-c-expandable-section__toggle--PaddingLeft:0;--pf-c-expandable-section__toggle--Color:var(--pf-global--link--Color);--pf-c-expandable-section__toggle--hover--Color:var(--pf-global--link--Color--hover);--pf-c-expandable-section__toggle--active--Color:var(--pf-global--link--Color--hover);--pf-c-expandable-section__toggle--focus--Color:var(--pf-global--link--Color--hover);--pf-c-expandable-section__toggle--m-expanded--Color:var(--pf-global--link--Color--hover);--pf-c-expandable-section__toggle-icon--Color:var(--pf-global--Color--100);--pf-c-expandable-section__toggle-icon--Transition:.2s ease-in 0s;--pf-c-expandable-section__toggle-icon--Rotate:0;--pf-c-expandable-section--m-expanded__toggle-icon--Rotate:90deg;--pf-c-expandable-section__toggle-text--MarginLeft:calc(var(--pf-global--spacer--xs) + var(--pf-global--spacer--sm));--pf-c-expandable-section__content--MarginTop:var(--pf-global--spacer--md)}.pf-c-expandable-section.pf-m-expanded{--pf-c-expandable-section__toggle--Color:var(--pf-c-expandable-section__toggle--m-expanded--Color);--pf-c-expandable-section__toggle-icon--Rotate:var(--pf-c-expandable-section--m-expanded__toggle-icon--Rotate)}.pf-c-expandable-section__toggle{display:flex;padding:var(--pf-c-expandable-section__toggle--PaddingTop) var(--pf-c-expandable-section__toggle--PaddingRight) var(--pf-c-expandable-section__toggle--PaddingBottom) var(--pf-c-expandable-section__toggle--PaddingLeft);color:var(--pf-c-expandable-section__toggle--Color);border:none}.pf-c-expandable-section__toggle:hover{--pf-c-expandable-section__toggle--Color:var(--pf-c-expandable-section__toggle--hover--Color)}.pf-c-expandable-section__toggle.pf-m-active,.pf-c-expandable-section__toggle:active{--pf-c-expandable-section__toggle--Color:var(--pf-c-expandable-section__toggle--active--Color)}.pf-c-expandable-section__toggle:focus{--pf-c-expandable-section__toggle--Color:var(--pf-c-expandable-section__toggle--focus--Color)}.pf-c-expandable-section__toggle-icon{color:var(--pf-c-expandable-section__toggle-icon--Color);transition:var(--pf-c-expandable-section__toggle-icon--Transition);transform:rotate(var(--pf-c-expandable-section__toggle-icon--Rotate))}.pf-c-expandable-section__toggle-text{margin-left:var(--pf-c-expandable-section__toggle-text--MarginLeft)}.pf-c-expandable-section__content{margin-top:var(--pf-c-expandable-section__content--MarginTop)}.pf-m-overpass-font .pf-c-expandable-section__toggle{font-weight:var(--pf-global--FontWeight--semi-bold)}.pf-c-file-upload{--pf-c-file-upload--m-loading__file-details--before--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-file-upload--m-loading__file-details--before--Left:var(--pf-global--BorderWidth--sm);--pf-c-file-upload--m-loading__file-details--before--Right:var(--pf-global--BorderWidth--sm);--pf-c-file-upload--m-loading__file-details--before--Bottom:var(--pf-global--BorderWidth--sm);--pf-c-file-upload--m-drag-hover--before--BorderWidth:var(--pf-global--BorderWidth--sm);--pf-c-file-upload--m-drag-hover--before--BorderColor:var(--pf-global--primary-color--100);--pf-c-file-upload--m-drag-hover--before--ZIndex:var(--pf-global--ZIndex--xs);--pf-c-file-upload--m-drag-hover--after--BackgroundColor:var(--pf-global--primary-color--100);--pf-c-file-upload--m-drag-hover--after--Opacity:.1;--pf-c-file-upload__file-details__c-form-control--MinHeight:calc(var(--pf-global--spacer--3xl)*2);--pf-c-file-upload__file-select__c-button--m-control--OutlineOffset:calc(-1*var(--pf-global--spacer--xs));position:relative;display:flex;flex-direction:column}.pf-c-file-upload.pf-m-drag-hover:before{position:absolute;top:0;right:0;bottom:0;left:0;z-index:var(--pf-c-file-upload--m-drag-hover--before--ZIndex);content:"";border:var(--pf-c-file-upload--m-drag-hover--before--BorderWidth) solid var(--pf-c-file-upload--m-drag-hover--before--BorderColor)}.pf-c-file-upload.pf-m-drag-hover:after{position:absolute;top:0;right:0;bottom:0;left:0;content:"";background-color:var(--pf-c-file-upload--m-drag-hover--after--BackgroundColor);opacity:var(--pf-c-file-upload--m-drag-hover--after--Opacity)}.pf-c-file-upload.pf-m-loading .pf-c-file-upload__file-details{position:relative}.pf-c-file-upload.pf-m-loading .pf-c-file-upload__file-details:before{position:absolute;top:0;right:var(--pf-c-file-upload--m-loading__file-details--before--Left);bottom:var(--pf-c-file-upload--m-loading__file-details--before--Left);left:var(--pf-c-file-upload--m-loading__file-details--before--Left);content:"";background-color:var(--pf-c-file-upload--m-loading__file-details--before--BackgroundColor)}.pf-c-file-upload__file-select .pf-c-button.pf-m-control{outline-offset:var(--pf-c-file-upload__file-select__c-button--m-control--OutlineOffset)}.pf-c-file-upload__file-details{position:relative;display:flex}.pf-c-file-upload__file-details .pf-c-form-control{flex:1 1 auto;min-height:var(--pf-c-file-upload__file-details__c-form-control--MinHeight);border-top:0}.pf-c-file-upload__file-details-spinner{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.pf-c-form{--pf-c-form--GridGap:var(--pf-global--gutter--md);--pf-c-form__group--m-action--MarginTop:var(--pf-global--spacer--xl);--pf-c-form--m-horizontal__group-label--md--GridColumnWidth:9.375rem;--pf-c-form--m-horizontal__group-label--md--GridColumnGap:var(--pf-global--spacer--md);--pf-c-form--m-horizontal__group-control--md--GridColumnWidth:1fr;--pf-c-form--m-limit-width--MaxWidth:31.25rem;--pf-c-form--m-horizontal__group-label--md--PaddingTop:var(--pf-global--spacer--sm);--pf-c-form__group-label--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-form__label--FontSize:var(--pf-global--FontSize--sm);--pf-c-form__label--LineHeight:var(--pf-global--LineHeight--sm);--pf-c-form__label--m-disabled--Color:var(--pf-global--disabled-color--100);--pf-c-form__label-text--FontWeight:var(--pf-global--FontWeight--bold);--pf-c-form__label-required--MarginLeft:var(--pf-global--spacer--xs);--pf-c-form__label-required--FontSize:var(--pf-global--FontSize--sm);--pf-c-form__label-required--Color:var(--pf-global--danger-color--100);--pf-c-form__group-label-help--PaddingTop:var(--pf-global--spacer--xs);--pf-c-form__group-label-help--PaddingRight:var(--pf-global--spacer--xs);--pf-c-form__group-label-help--PaddingBottom:var(--pf-global--spacer--xs);--pf-c-form__group-label-help--PaddingLeft:var(--pf-global--spacer--xs);--pf-c-form__group-label-help--MarginTop:calc(var(--pf-c-form__group-label-help--PaddingTop)*-1);--pf-c-form__group-label-help--MarginRight:calc(var(--pf-c-form__group-label-help--PaddingRight)*-1);--pf-c-form__group-label-help--MarginBottom:calc(var(--pf-c-form__group-label-help--PaddingBottom)*-1);--pf-c-form__group-label-help--MarginLeft:calc(var(--pf-c-form__group-label-help--PaddingLeft)*-1 + var(--pf-global--spacer--xs));--pf-c-form__group-label-help--FontSize:var(--pf-global--FontSize--sm);--pf-c-form__group-label-help--TranslateY:0.125rem;--pf-c-form__group-control--m-inline--child--MarginRight:var(--pf-global--spacer--lg);--pf-c-form__group-control__helper-text--MarginBottom:var(--pf-global--spacer--xs);--pf-c-form__actions--child--MarginTop:var(--pf-global--spacer--sm);--pf-c-form__actions--child--MarginRight:var(--pf-global--spacer--sm);--pf-c-form__actions--child--MarginBottom:var(--pf-global--spacer--sm);--pf-c-form__actions--child--MarginLeft:var(--pf-global--spacer--sm);--pf-c-form__actions--MarginTop:calc(var(--pf-c-form__actions--child--MarginTop)*-1);--pf-c-form__actions--MarginRight:calc(var(--pf-c-form__actions--child--MarginRight)*-1);--pf-c-form__actions--MarginBottom:calc(var(--pf-c-form__actions--child--MarginBottom)*-1);--pf-c-form__actions--MarginLeft:calc(var(--pf-c-form__actions--child--MarginLeft)*-1);--pf-c-form__helper-text--MarginTop:var(--pf-global--spacer--xs);--pf-c-form__helper-text--FontSize:var(--pf-global--FontSize--sm);--pf-c-form__helper-text--Color:var(--pf-global--Color--100);--pf-c-form__helper-text-icon--FontSize:var(--pf-global--FontSize--md);--pf-c-form__helper-text-icon--MarginRight:var(--pf-global--spacer--xs);--pf-c-form__helper-text--m-success--Color:var(--pf-global--success-color--200);--pf-c-form__helper-text--m-warning--Color:var(--pf-global--warning-color--200);--pf-c-form__helper-text--m-error--Color:var(--pf-global--danger-color--100);--pf-c-form__section--MarginTop:var(--pf-global--spacer--xl);--pf-c-form__section--Gap:var(--pf-global--gutter--md);--pf-c-form__field-group--border-width-base:var(--pf-global--BorderWidth--sm);--pf-c-form__field-group--BorderTopWidth:var(--pf-c-form__field-group--border-width-base);--pf-c-form__field-group--BorderTopColor:var(--pf-global--BorderColor--100);--pf-c-form__field-group--BorderBottomWidth:var(--pf-c-form__field-group--border-width-base);--pf-c-form__field-group--BorderBottomColor:var(--pf-global--BorderColor--100);--pf-c-form__field-group--field-group--MarginTop:calc(var(--pf-c-form--GridGap)*-1);--pf-c-form__field-group--GridTemplateColumns--toggle:calc(var(--pf-global--spacer--md)*2 + var(--pf-c-form__field-group-toggle-icon--MinWidth) + var(--pf-global--spacer--xs));--pf-c-form__field-group-toggle--PaddingTop:var(--pf-global--spacer--md);--pf-c-form__field-group-toggle--PaddingRight:var(--pf-global--spacer--xs);--pf-c-form__field-group__field-group__field-group-toggle--PaddingTop:var(--pf-global--spacer--lg);--pf-c-form__field-group-header-toggle--BorderWidth--base:var(--pf-global--BorderWidth--sm);--pf-c-form__field-group__field-group--field-group__field-group-toggle--after--BorderTopWidth:var(--pf-c-form__field-group-header-toggle--BorderWidth--base);--pf-c-form__field-group-toggle-button--MarginTop:calc(var(--pf-global--spacer--form-element)*-1);--pf-c-form__field-group-toggle-button--MarginBottom:calc(var(--pf-global--spacer--form-element)*-1);--pf-c-form__field-group-toggle-icon--Transition:var(--pf-global--Transition);--pf-c-form__field-group-toggle-icon--MinWidth:var(--pf-global--FontSize--md);--pf-c-form__field-group-toggle-icon--Rotate:0;--pf-c-form__field-group--m-expanded__toggle-icon--Rotate:90deg;--pf-c-form__field-group-header--PaddingTop:var(--pf-global--spacer--md);--pf-c-form__field-group-header--PaddingBottom:var(--pf-global--spacer--md);--pf-c-form__field-group-header--GridColumn:1/3;--pf-c-form__field-group__field-group__field-group-header--PaddingTop:var(--pf-global--spacer--lg);--pf-c-form__field-group__field-group__field-group-header--PaddingBottom:var(--pf-global--spacer--lg);--pf-c-form__field-group-toggle--field-group-header--GridColumn:2/3;--pf-c-form__field-group__field-group--field-group__field-group-header--after--BorderTopWidth:var(--pf-c-form__field-group-header-toggle--BorderWidth--base);--pf-c-form__field-group-header-description--MarginTop:var(--pf-global--spacer--xs);--pf-c-form__field-group-header-description--Color:var(--pf-global--Color--200);--pf-c-form__field-group-header-actions--MarginTop:calc(var(--pf-global--spacer--form-element)*-1);--pf-c-form__field-group-header-actions--MarginBottom:calc(var(--pf-global--spacer--form-element)*-1);--pf-c-form__field-group-header-actions--MarginLeft:var(--pf-global--spacer--sm);--pf-c-form__field-group-body--PaddingTop:var(--pf-global--spacer--lg);--pf-c-form__field-group-body--PaddingBottom:var(--pf-global--spacer--lg);--pf-c-form__field-group-body--Gap:var(--pf-c-form--GridGap);--pf-c-form__field-group-body--GridColumn:2/3;--pf-c-form__field-group__field-group__field-group-body--GridColumn:1/3;--pf-c-form__field-group__field-group__field-group-toggle--field-group-body--GridColumn:2/3;--pf-c-form__field-group__field-group--not--m-expandable__field-group--not-m-expandable__field-group-header--GridColumn:2/3;--pf-c-form__field-group__field-group--not--m-expandable__field-group--not-m-expandable__field-group-body--GridColumn:2/3;--pf-c-form__field-group-body__field-group--last-child--MarginBottom:calc(var(--pf-c-form__field-group-body--PaddingBottom)*-1);display:grid;grid-gap:var(--pf-c-form--GridGap)}.pf-c-form.pf-m-horizontal{--pf-c-form__group-label--PaddingBottom:0}.pf-c-form.pf-m-horizontal.pf-m-align-right .pf-c-form__label{text-align:right}@media (min-width:768px){.pf-c-form.pf-m-horizontal .pf-c-form__group{display:grid;grid-column-gap:var(--pf-c-form--m-horizontal__group-label--md--GridColumnGap);grid-template-columns:var(--pf-c-form--m-horizontal__group-label--md--GridColumnWidth) var(--pf-c-form--m-horizontal__group-control--md--GridColumnWidth)}.pf-c-form.pf-m-horizontal .pf-c-form__group-label{padding-top:var(--pf-c-form--m-horizontal__group-label--md--PaddingTop)}.pf-c-form.pf-m-horizontal .pf-c-form__group-label.pf-m-no-padding-top{--pf-c-form--m-horizontal__group-label--md--PaddingTop:0}.pf-c-form.pf-m-horizontal .pf-c-form__group-control{grid-column:2}}.pf-c-form.pf-m-limit-width{max-width:var(--pf-c-form--m-limit-width--MaxWidth)}.pf-c-form__group.pf-m-action{margin-top:var(--pf-c-form__group--m-action--MarginTop);overflow:hidden}.pf-c-form__section{display:grid;gap:var(--pf-c-form__section--Gap)}.pf-c-form__section+.pf-c-form__group:not(.pf-m-action),.pf-c-form__section:not(:first-child){margin-top:var(--pf-c-form__section--MarginTop)}.pf-c-form__group-label{--pf-c-form__helper-text--MarginTop:0;padding-bottom:var(--pf-c-form__group-label--PaddingBottom)}.pf-c-form__label{font-size:var(--pf-c-form__label--FontSize);line-height:var(--pf-c-form__label--LineHeight)}.pf-c-form__label::selection{background-color:none}.pf-c-form__label:not(.pf-m-disabled):hover{cursor:pointer}.pf-c-form__label.pf-m-disabled{color:var(--pf-c-form__label--m-disabled--Color)}.pf-c-form__label.pf-m-disabled:hover{cursor:not-allowed}.pf-c-form__label-text{font-weight:var(--pf-c-form__label-text--FontWeight)}.pf-c-form__label-required{margin-left:var(--pf-c-form__label-required--MarginLeft);font-size:var(--pf-c-form__label-required--FontSize);color:var(--pf-c-form__label-required--Color)}.pf-c-form__group-label-help{padding:var(--pf-c-form__group-label-help--PaddingTop) var(--pf-c-form__group-label-help--PaddingRight) var(--pf-c-form__group-label-help--PaddingBottom) var(--pf-c-form__group-label-help--PaddingLeft);margin:var(--pf-c-form__group-label-help--MarginTop) var(--pf-c-form__group-label-help--MarginRight) var(--pf-c-form__group-label-help--MarginBottom) var(--pf-c-form__group-label-help--MarginLeft);font-size:var(--pf-c-form__group-label-help--FontSize);line-height:1;border:0;transform:translateY(var(--pf-c-form__group-label-help--TranslateY))}.pf-c-form__group-control.pf-m-inline{display:flex;flex-flow:row wrap}.pf-c-form__group-control.pf-m-inline>*{margin-right:var(--pf-c-form__group-control--m-inline--child--MarginRight)}.pf-c-form__group-control .pf-c-form__helper-text:first-child{--pf-c-form__helper-text--MarginTop:0;margin-bottom:var(--pf-c-form__group-control__helper-text--MarginBottom)}.pf-c-form__helper-text{margin-top:var(--pf-c-form__helper-text--MarginTop);font-size:var(--pf-c-form__helper-text--FontSize);color:var(--pf-c-form__helper-text--Color)}.pf-c-form__helper-text.pf-m-error{--pf-c-form__helper-text--Color:var(--pf-c-form__helper-text--m-error--Color)}.pf-c-form__helper-text.pf-m-success{--pf-c-form__helper-text--Color:var(--pf-c-form__helper-text--m-success--Color)}.pf-c-form__helper-text.pf-m-warning{--pf-c-form__helper-text--Color:var(--pf-c-form__helper-text--m-warning--Color)}.pf-c-form__helper-text.pf-m-inactive{display:none;visibility:hidden}.pf-c-form__helper-text.pf-m-hidden{visibility:hidden;opacity:0}.pf-c-form__helper-text-icon{margin-right:var(--pf-c-form__helper-text-icon--MarginRight);font-size:var(--pf-c-form__helper-text-icon--FontSize)}.pf-c-form__fieldset{border:0}.pf-c-form__actions{display:flex;flex-wrap:wrap;margin:var(--pf-c-form__actions--MarginTop) var(--pf-c-form__actions--MarginRight) var(--pf-c-form__actions--MarginBottom) var(--pf-c-form__actions--MarginLeft)}.pf-c-form__actions>*{margin:var(--pf-c-form__actions--child--MarginTop) var(--pf-c-form__actions--child--MarginRight) var(--pf-c-form__actions--child--MarginBottom) var(--pf-c-form__actions--child--MarginLeft)}.pf-c-form__field-group{--pf-c-form__field-group--BorderTopWidth:var(--pf-c-form__field-group--border-width-base);display:grid;grid-template-columns:minmax(var(--pf-c-form__field-group--GridTemplateColumns--toggle),max-content) 1fr;border-top:var(--pf-c-form__field-group--BorderTopWidth) solid var(--pf-c-form__field-group--BorderTopColor);border-bottom:var(--pf-c-form__field-group--BorderBottomWidth) solid var(--pf-c-form__field-group--BorderBottomColor)}.pf-c-form__field-group:last-child{--pf-c-form__field-group--BorderBottomWidth:0}.pf-c-form__field-group+.pf-c-form__field-group,.pf-c-form__field-group:first-child{--pf-c-form__field-group--BorderTopWidth:0}.pf-c-form__field-group+.pf-c-form__field-group{margin-top:var(--pf-c-form__field-group--field-group--MarginTop)}.pf-c-form__field-group .pf-c-form__field-group{--pf-c-form__field-group-body--GridColumn:var(--pf-c-form__field-group__field-group__field-group-body--GridColumn);--pf-c-form__field-group-toggle--PaddingTop:var(--pf-c-form__field-group__field-group__field-group-toggle--PaddingTop);--pf-c-form__field-group-header--PaddingTop:var(--pf-c-form__field-group__field-group__field-group-header--PaddingTop);--pf-c-form__field-group-header--PaddingBottom:var(--pf-c-form__field-group__field-group__field-group-header--PaddingBottom);--pf-c-form__field-group-body--PaddingTop:0}.pf-c-form__field-group .pf-c-form__field-group .pf-c-form__field-group-toggle~.pf-c-form__field-group-body{--pf-c-form__field-group-body--GridColumn:var(--pf-c-form__field-group__field-group__field-group-toggle--field-group-body--GridColumn)}.pf-c-form__field-group.pf-m-expanded>.pf-c-form__field-group-toggle{--pf-c-form__field-group-toggle-icon--Rotate:var(--pf-c-form__field-group--m-expanded__toggle-icon--Rotate)}.pf-c-form__field-group-toggle{grid-column:1/2;grid-row:1/2;padding-top:var(--pf-c-form__field-group-toggle--PaddingTop);padding-right:var(--pf-c-form__field-group-toggle--PaddingRight)}.pf-c-form__field-group-toggle+.pf-c-form__field-group-header{--pf-c-form__field-group-header--GridColumn:var(--pf-c-form__field-group-toggle--field-group-header--GridColumn)}.pf-c-form__field-group-toggle-button{margin-top:var(--pf-c-form__field-group-toggle-button--MarginTop);margin-bottom:var(--pf-c-form__field-group-toggle-button--MarginBottom)}.pf-c-form__field-group-toggle-icon{display:inline-block;min-width:var(--pf-c-form__field-group-toggle-icon--MinWidth);text-align:center;transition:var(--pf-c-form__field-group-toggle-icon--Transition);transform:rotate(var(--pf-c-form__field-group-toggle-icon--Rotate))}.pf-c-form__field-group-header{grid-column:var(--pf-c-form__field-group-header--GridColumn);grid-row:1/2;display:flex;align-items:flex-start;padding-top:var(--pf-c-form__field-group-header--PaddingTop);padding-bottom:var(--pf-c-form__field-group-header--PaddingBottom)}.pf-c-form__field-group-header-main{display:flex;flex-direction:column;flex-grow:1}.pf-c-form__field-group-header-title{display:flex}.pf-c-form__field-group-header-title-text{flex-grow:1}.pf-c-form__field-group-header-description{margin-top:var(--pf-c-form__field-group-header-description--MarginTop);color:var(--pf-c-form__field-group-header-description--Color)}.pf-c-form__field-group-header-actions{margin-top:var(--pf-c-form__field-group-header-actions--MarginTop);margin-bottom:var(--pf-c-form__field-group-header-actions--MarginBottom);margin-left:var(--pf-c-form__field-group-header-actions--MarginLeft);white-space:nowrap}.pf-c-form__field-group-body{grid-column:var(--pf-c-form__field-group-body--GridColumn);display:grid;gap:var(--pf-c-form__field-group-body--Gap);padding-top:var(--pf-c-form__field-group-body--PaddingTop);padding-bottom:var(--pf-c-form__field-group-body--PaddingBottom)}.pf-c-form__field-group-body>.pf-c-form__field-group:first-child{--pf-c-form__field-group-toggle--PaddingTop:0;--pf-c-form__field-group-header--PaddingTop:0}.pf-c-form__field-group-body>.pf-c-form__field-group:last-child{margin-bottom:var(--pf-c-form__field-group-body__field-group--last-child--MarginBottom)}.pf-c-form-control{--pf-c-form-control--FontSize:var(--pf-global--FontSize--md);--pf-c-form-control--LineHeight:var(--pf-global--LineHeight--md);--pf-c-form-control--BorderWidth:var(--pf-global--BorderWidth--sm);--pf-c-form-control--BorderTopColor:var(--pf-global--BorderColor--300);--pf-c-form-control--BorderRightColor:var(--pf-global--BorderColor--300);--pf-c-form-control--BorderBottomColor:var(--pf-global--BorderColor--200);--pf-c-form-control--BorderLeftColor:var(--pf-global--BorderColor--300);--pf-c-form-control--BorderRadius:0;--pf-c-form-control--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-form-control--Height:calc(var(--pf-c-form-control--FontSize)*var(--pf-c-form-control--LineHeight) + var(--pf-c-form-control--BorderWidth)*2 + var(--pf-c-form-control--PaddingTop) + var(--pf-c-form-control--PaddingBottom));--pf-c-form-control--inset--base:var(--pf-global--spacer--sm);--pf-c-form-control--PaddingTop:calc(var(--pf-global--spacer--form-element) - var(--pf-global--BorderWidth--sm));--pf-c-form-control--PaddingBottom:calc(var(--pf-global--spacer--form-element) - var(--pf-global--BorderWidth--sm));--pf-c-form-control--PaddingRight:var(--pf-c-form-control--inset--base);--pf-c-form-control--PaddingLeft:var(--pf-c-form-control--inset--base);--pf-c-form-control--hover--BorderBottomColor:var(--pf-global--primary-color--100);--pf-c-form-control--focus--BorderBottomWidth:var(--pf-global--BorderWidth--md);--pf-c-form-control--focus--PaddingBottom:calc(var(--pf-global--spacer--form-element) - var(--pf-c-form-control--focus--BorderBottomWidth));--pf-c-form-control--focus--BorderBottomColor:var(--pf-global--primary-color--100);--pf-c-form-control--m-expanded--BorderBottomWidth:var(--pf-global--BorderWidth--md);--pf-c-form-control--m-expanded--PaddingBottom:calc(var(--pf-global--spacer--form-element) - var(--pf-c-form-control--focus--BorderBottomWidth));--pf-c-form-control--m-expanded--BorderBottomColor:var(--pf-global--primary-color--100);--pf-c-form-control--placeholder--Color:var(--pf-global--Color--dark-200);--pf-c-form-control--disabled--Color:var(--pf-global--disabled-color--100);--pf-c-form-control--disabled--BackgroundColor:var(--pf-global--disabled-color--300);--pf-c-form-control--disabled--BorderColor:transparent;--pf-c-form-control--readonly--BackgroundColor:var(--pf-global--disabled-color--300);--pf-c-form-control--readonly--hover--BorderBottomColor:var(--pf-global--BorderColor--200);--pf-c-form-control--readonly--focus--PaddingBottom:calc(var(--pf-global--spacer--form-element) - var(--pf-global--BorderWidth--sm));--pf-c-form-control--readonly--focus--BorderBottomWidth:var(--pf-global--BorderWidth--sm);--pf-c-form-control--readonly--focus--BorderBottomColor:var(--pf-global--BorderColor--200);--pf-c-form-control--success--BorderBottomWidth:var(--pf-global--BorderWidth--md);--pf-c-form-control--success--PaddingBottom:calc(var(--pf-global--spacer--form-element) - var(--pf-c-form-control--success--BorderBottomWidth));--pf-c-form-control--success--BorderBottomColor:var(--pf-global--success-color--100);--pf-c-form-control--success--PaddingRight:var(--pf-global--spacer--xl);--pf-c-form-control--success--BackgroundPositionX:calc(100% - var(--pf-c-form-control--PaddingLeft));--pf-c-form-control--success--BackgroundPositionY:center;--pf-c-form-control--success--BackgroundPosition:var(--pf-c-form-control--success--BackgroundPositionX) var(--pf-c-form-control--success--BackgroundPositionY);--pf-c-form-control--success--BackgroundSizeX:var(--pf-c-form-control--FontSize);--pf-c-form-control--success--BackgroundSizeY:var(--pf-c-form-control--FontSize);--pf-c-form-control--success--BackgroundSize:var(--pf-c-form-control--success--BackgroundSizeX) var(--pf-c-form-control--success--BackgroundSizeY);--pf-c-form-control--success--BackgroundUrl:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='%233e8635' d='M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z'/%3E%3C/svg%3E");--pf-c-form-control--m-warning--BorderBottomWidth:var(--pf-global--BorderWidth--md);--pf-c-form-control--m-warning--PaddingBottom:calc(var(--pf-global--spacer--form-element) - var(--pf-c-form-control--m-warning--BorderBottomWidth));--pf-c-form-control--m-warning--BorderBottomColor:var(--pf-global--warning-color--100);--pf-c-form-control--m-warning--PaddingRight:var(--pf-global--spacer--xl);--pf-c-form-control--m-warning--BackgroundPositionX:calc(100% - var(--pf-c-form-control--PaddingLeft) - 0.0625rem);--pf-c-form-control--m-warning--BackgroundPositionY:center;--pf-c-form-control--m-warning--BackgroundPosition:var(--pf-c-form-control--m-warning--BackgroundPositionX) var(--pf-c-form-control--m-warning--BackgroundPositionY);--pf-c-form-control--m-warning--BackgroundSizeX:1.25rem;--pf-c-form-control--m-warning--BackgroundSizeY:var(--pf-c-form-control--FontSize);--pf-c-form-control--m-warning--BackgroundSize:var(--pf-c-form-control--m-warning--BackgroundSizeX) var(--pf-c-form-control--m-warning--BackgroundSizeY);--pf-c-form-control--m-warning--BackgroundUrl:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='%23f0ab00' d='M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z'/%3E%3C/svg%3E");--pf-c-form-control--invalid--BorderBottomWidth:var(--pf-global--BorderWidth--md);--pf-c-form-control--invalid--PaddingBottom:calc(var(--pf-global--spacer--form-element) - var(--pf-c-form-control--invalid--BorderBottomWidth));--pf-c-form-control--invalid--BorderBottomColor:var(--pf-global--danger-color--100);--pf-c-form-control--invalid--PaddingRight:var(--pf-global--spacer--xl);--pf-c-form-control--invalid--BackgroundPositionX:calc(100% - var(--pf-c-form-control--PaddingLeft));--pf-c-form-control--invalid--BackgroundPositionY:center;--pf-c-form-control--invalid--BackgroundPosition:var(--pf-c-form-control--invalid--BackgroundPositionX) var(--pf-c-form-control--invalid--BackgroundPositionY);--pf-c-form-control--invalid--BackgroundSizeX:var(--pf-c-form-control--FontSize);--pf-c-form-control--invalid--BackgroundSizeY:var(--pf-c-form-control--FontSize);--pf-c-form-control--invalid--BackgroundSize:var(--pf-c-form-control--invalid--BackgroundSizeX) var(--pf-c-form-control--invalid--BackgroundSizeY);--pf-c-form-control--invalid--BackgroundUrl:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='%23c9190b' d='M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zm-248 50c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z'/%3E%3C/svg%3E");--pf-c-form-control--invalid--exclamation--Background:var(--pf-c-form-control--invalid--BackgroundUrl) var(--pf-c-form-control--invalid--BackgroundPosition)/var(--pf-c-form-control--invalid--BackgroundSize) no-repeat;--pf-c-form-control--invalid--Background:var(--pf-c-form-control--BackgroundColor) var(--pf-c-form-control--invalid--exclamation--Background);--pf-c-form-control--m-search--PaddingLeft:var(--pf-global--spacer--xl);--pf-c-form-control--m-search--BackgroundPosition:var(--pf-c-form-control--PaddingRight);--pf-c-form-control--m-search--BackgroundSize:var(--pf-c-form-control--FontSize) var(--pf-c-form-control--FontSize);--pf-c-form-control--m-search--BackgroundUrl:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='%236a6e73' d='M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 336c-70.7 0-128-57.2-128-128 0-70.7 57.2-128 128-128 70.7 0 128 57.2 128 128 0 70.7-57.2 128-128 128z'/%3E%3C/svg%3E");--pf-c-form-control--m-icon--PaddingRight:calc(var(--pf-c-form-control--inset--base) + var(--pf-c-form-control--m-icon--BackgroundSizeX) + var(--pf-c-form-control--m-icon--icon--spacer));--pf-c-form-control--m-icon--BackgroundUrl:none;--pf-c-form-control--m-icon--BackgroundPositionX:calc(100% - var(--pf-c-form-control--inset--base));--pf-c-form-control--m-icon--BackgroundPositionY:center;--pf-c-form-control--m-icon--BackgroundSizeX:var(--pf-c-form-control--FontSize);--pf-c-form-control--m-icon--BackgroundSizeY:var(--pf-c-form-control--FontSize);--pf-c-form-control--m-icon--icon--spacer:var(--pf-global--spacer--sm);--pf-c-form-control--m-icon--icon--PaddingRight:calc(var(--pf-c-form-control--inset--base) + var(--pf-c-form-control--invalid--BackgroundSizeX) + var(--pf-c-form-control--m-icon--icon--spacer) + var(--pf-c-form-control--m-icon--BackgroundSizeX) + var(--pf-c-form-control--m-icon--icon--spacer));--pf-c-form-control--m-icon--icon--BackgroundPositionX:calc(var(--pf-c-form-control--m-icon--BackgroundPositionX) - var(--pf-c-form-control--m-icon--icon--spacer) - var(--pf-c-form-control--invalid--BackgroundSizeX));--pf-c-form-control--m-icon--invalid--BackgroundUrl:var(--pf-c-form-control--invalid--BackgroundUrl),var(--pf-c-form-control--m-icon--BackgroundUrl);--pf-c-form-control--m-icon--invalid--BackgroundPosition:var(--pf-c-form-control--invalid--BackgroundPosition),var(--pf-c-form-control--m-icon--icon--BackgroundPositionX) var(--pf-c-form-control--m-icon--BackgroundPositionY);--pf-c-form-control--m-icon--invalid--BackgroundSize:var(--pf-c-form-control--invalid--BackgroundSize),var(--pf-c-form-control--m-icon--BackgroundSizeX) var(--pf-c-form-control--m-icon--BackgroundSizeY);--pf-c-form-control--m-icon--success--BackgroundUrl:var(--pf-c-form-control--success--BackgroundUrl),var(--pf-c-form-control--m-icon--BackgroundUrl);--pf-c-form-control--m-icon--success--BackgroundPosition:var(--pf-c-form-control--success--BackgroundPosition),var(--pf-c-form-control--m-icon--icon--BackgroundPositionX) var(--pf-c-form-control--m-icon--BackgroundPositionY);--pf-c-form-control--m-icon--success--BackgroundSize:var(--pf-c-form-control--success--BackgroundSize),var(--pf-c-form-control--m-icon--BackgroundSizeX) var(--pf-c-form-control--m-icon--BackgroundSizeY);--pf-c-form-control--m-icon--m-warning--BackgroundUrl:var(--pf-c-form-control--m-warning--BackgroundUrl),var(--pf-c-form-control--m-icon--BackgroundUrl);--pf-c-form-control--m-icon--m-warning--BackgroundPosition:var(--pf-c-form-control--m-warning--BackgroundPosition),var(--pf-c-form-control--m-icon--icon--BackgroundPositionX) var(--pf-c-form-control--m-icon--BackgroundPositionY);--pf-c-form-control--m-icon--m-warning--BackgroundSize:var(--pf-c-form-control--m-warning--BackgroundSize),var(--pf-c-form-control--m-icon--BackgroundSizeX) var(--pf-c-form-control--m-icon--BackgroundSizeY);--pf-c-form-control--m-calendar--BackgroundUrl:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='%236a6e73' d='M0 464c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V192H0v272zm320-196c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40zm0 128c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40zM192 268c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40zm0 128c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40zM64 268c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12H76c-6.6 0-12-5.4-12-12v-40zm0 128c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12H76c-6.6 0-12-5.4-12-12v-40zM400 64h-48V16c0-8.8-7.2-16-16-16h-32c-8.8 0-16 7.2-16 16v48H160V16c0-8.8-7.2-16-16-16h-32c-8.8 0-16 7.2-16 16v48H48C21.5 64 0 85.5 0 112v48h448v-48c0-26.5-21.5-48-48-48z'/%3E%3C/svg%3E");--pf-c-form-control--m-clock--BackgroundUrl:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='%236a6e73' d='M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm61.8-104.4l-84.9-61.7c-3.1-2.3-4.9-5.9-4.9-9.7V116c0-6.6 5.4-12 12-12h32c6.6 0 12 5.4 12 12v141.7l66.8 48.6c5.4 3.9 6.5 11.4 2.6 16.8L334.6 349c-3.9 5.3-11.4 6.5-16.8 2.6z'/%3E%3C/svg%3E");--pf-c-form-control__select--PaddingRight:var(--pf-global--spacer--lg);--pf-c-form-control__select--BackgroundUrl:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 512'%3E%3Cpath fill='%23urrentColor' d='M31.3 192h257.3c17.8 0 26.7 21.5 14.1 34.1L174.1 354.8c-7.8 7.8-20.5 7.8-28.3 0L17.2 226.1C4.6 213.5 13.5 192 31.3 192z'/%3E%3C/svg%3E");--pf-c-form-control__select--BackgroundSize:.625em;--pf-c-form-control__select--BackgroundPositionX:calc(100% - var(--pf-global--spacer--md) + 1px);--pf-c-form-control__select--BackgroundPositionY:center;--pf-c-form-control__select--BackgroundPosition:var(--pf-c-form-control__select--BackgroundPositionX) var(--pf-c-form-control__select--BackgroundPositionY);--pf-c-form-control__select--success--PaddingRight:var(--pf-global--spacer--3xl);--pf-c-form-control__select--success--BackgroundPosition:calc(var(--pf-c-form-control__select--BackgroundPositionX) - var(--pf-global--spacer--lg));--pf-c-form-control__select--m-warning--PaddingRight:var(--pf-global--spacer--3xl);--pf-c-form-control__select--m-warning--BackgroundPosition:calc(var(--pf-c-form-control__select--BackgroundPositionX) - var(--pf-global--spacer--lg) + 0.0625rem);--pf-c-form-control__select--invalid--PaddingRight:var(--pf-global--spacer--3xl);--pf-c-form-control__select--invalid--BackgroundPosition:calc(var(--pf-c-form-control__select--BackgroundPositionX) - var(--pf-global--spacer--lg));--pf-c-form-control--textarea--success--BackgroundPositionY:var(--pf-c-form-control--PaddingLeft);--pf-c-form-control--textarea--m-warning--BackgroundPositionY:var(--pf-c-form-control--PaddingLeft);--pf-c-form-control--textarea--invalid--BackgroundPositionY:var(--pf-c-form-control--PaddingLeft);color:var(--pf-global--Color--100);width:100%;padding:var(--pf-c-form-control--PaddingTop) var(--pf-c-form-control--PaddingRight) var(--pf-c-form-control--PaddingBottom) var(--pf-c-form-control--PaddingLeft);font-size:var(--pf-c-form-control--FontSize);line-height:var(--pf-c-form-control--LineHeight);background-color:var(--pf-c-form-control--BackgroundColor);background-repeat:no-repeat;border:var(--pf-c-form-control--BorderWidth) solid;border-color:var(--pf-c-form-control--BorderTopColor) var(--pf-c-form-control--BorderRightColor) var(--pf-c-form-control--BorderBottomColor) var(--pf-c-form-control--BorderLeftColor);border-radius:var(--pf-c-form-control--BorderRadius);-moz-appearance:none;-webkit-appearance:none}.pf-c-form-control::placeholder{color:var(--pf-c-form-control--placeholder--Color)}.pf-c-form-control:not(textarea){height:var(--pf-c-form-control--Height);text-overflow:ellipsis}.pf-c-form-control[readonly]{background-color:var(--pf-c-form-control--readonly--BackgroundColor)}.pf-c-form-control[readonly]:not(.pf-m-success):not([aria-invalid=true]):hover{--pf-c-form-control--BorderBottomColor:var(--pf-c-form-control--readonly--hover--BorderBottomColor)}.pf-c-form-control[readonly]:not(.pf-m-success):not([aria-invalid=true]):focus{--pf-c-form-control--focus--PaddingBottom:var(--pf-c-form-control--readonly--focus--PaddingBottom);--pf-c-form-control--focus--BorderBottomWidth:var(--pf-c-form-control--readonly--focus--BorderBottomWidth);--pf-c-form-control--focus--BorderBottomColor:var(--pf-c-form-control--readonly--focus--BorderBottomColor)}.pf-c-form-control:hover{--pf-c-form-control--BorderBottomColor:var(--pf-c-form-control--hover--BorderBottomColor)}.pf-c-form-control:focus{--pf-c-form-control--BorderBottomColor:var(--pf-c-form-control--focus--BorderBottomColor);padding-bottom:var(--pf-c-form-control--focus--PaddingBottom);border-bottom-width:var(--pf-c-form-control--focus--BorderBottomWidth)}.pf-c-form-control.pf-m-expanded{--pf-c-form-control--BorderBottomColor:var(--pf-c-form-control--m-expanded--BorderBottomColor);padding-bottom:var(--pf-c-form-control--m-expanded--PaddingBottom);border-bottom-width:var(--pf-c-form-control--m-expanded--BorderBottomWidth)}.pf-c-form-control:disabled{--pf-c-form-control--Color:var(--pf-c-form-control--disabled--Color);--pf-c-form-control--BackgroundColor:var(--pf-c-form-control--disabled--BackgroundColor);cursor:not-allowed;border-color:var(--pf-c-form-control--disabled--BorderColor)}.pf-c-form-control[aria-invalid=true]{--pf-c-form-control--PaddingRight:var(--pf-c-form-control--invalid--PaddingRight);--pf-c-form-control--BorderBottomColor:var(--pf-c-form-control--invalid--BorderBottomColor);padding-bottom:var(--pf-c-form-control--invalid--PaddingBottom);background-image:var(--pf-c-form-control--invalid--BackgroundUrl);background-position:var(--pf-c-form-control--invalid--BackgroundPosition);background-size:var(--pf-c-form-control--invalid--BackgroundSize);border-bottom-width:var(--pf-c-form-control--invalid--BorderBottomWidth)}.pf-c-form-control[aria-invalid=true].pf-m-icon{--pf-c-form-control--PaddingRight:var(--pf-c-form-control--m-icon--icon--PaddingRight);background-image:var(--pf-c-form-control--m-icon--invalid--BackgroundUrl);background-position:var(--pf-c-form-control--m-icon--invalid--BackgroundPosition);background-size:var(--pf-c-form-control--m-icon--invalid--BackgroundSize)}.pf-c-form-control.pf-m-success{--pf-c-form-control--PaddingRight:var(--pf-c-form-control--success--PaddingRight);--pf-c-form-control--BorderBottomColor:var(--pf-c-form-control--success--BorderBottomColor);padding-bottom:var(--pf-c-form-control--success--PaddingBottom);background-image:var(--pf-c-form-control--success--BackgroundUrl);background-position:var(--pf-c-form-control--success--BackgroundPosition);background-size:var(--pf-c-form-control--success--BackgroundSize);border-bottom-width:var(--pf-c-form-control--success--BorderBottomWidth)}.pf-c-form-control.pf-m-success.pf-m-icon{--pf-c-form-control--PaddingRight:var(--pf-c-form-control--m-icon--icon--PaddingRight);background-image:var(--pf-c-form-control--m-icon--success--BackgroundUrl);background-position:var(--pf-c-form-control--m-icon--success--BackgroundPosition);background-size:var(--pf-c-form-control--m-icon--success--BackgroundSize)}.pf-c-form-control.pf-m-warning{--pf-c-form-control--PaddingRight:var(--pf-c-form-control--m-warning--PaddingRight);--pf-c-form-control--BorderBottomColor:var(--pf-c-form-control--m-warning--BorderBottomColor);padding-bottom:var(--pf-c-form-control--m-warning--PaddingBottom);background-image:var(--pf-c-form-control--m-warning--BackgroundUrl);background-position:var(--pf-c-form-control--m-warning--BackgroundPosition);background-size:var(--pf-c-form-control--m-warning--BackgroundSize);border-bottom-width:var(--pf-c-form-control--m-warning--BorderBottomWidth)}.pf-c-form-control.pf-m-warning.pf-m-icon{--pf-c-form-control--PaddingRight:var(--pf-c-form-control--m-icon--icon--PaddingRight);background-image:var(--pf-c-form-control--m-icon--m-warning--BackgroundUrl);background-position:var(--pf-c-form-control--m-icon--m-warning--BackgroundPosition);background-size:var(--pf-c-form-control--m-icon--m-warning--BackgroundSize)}.pf-c-form-control.pf-m-search{--pf-c-form-control--PaddingLeft:var(--pf-c-form-control--m-search--PaddingLeft);background-image:var(--pf-c-form-control--m-search--BackgroundUrl);background-position:var(--pf-c-form-control--m-search--BackgroundPosition);background-size:var(--pf-c-form-control--m-search--BackgroundSize)}.pf-c-form-control.pf-m-icon{--pf-c-form-control--PaddingRight:var(--pf-c-form-control--m-icon--PaddingRight);background-image:var(--pf-c-form-control--m-icon--BackgroundUrl);background-position:var(--pf-c-form-control--m-icon--BackgroundPositionX) var(--pf-c-form-control--m-icon--BackgroundPositionY);background-size:var(--pf-c-form-control--m-icon--BackgroundSizeX) var(--pf-c-form-control--m-icon--BackgroundSizeY)}.pf-c-form-control.pf-m-icon.pf-m-calendar{--pf-c-form-control--m-icon--BackgroundUrl:var(--pf-c-form-control--m-calendar--BackgroundUrl)}.pf-c-form-control.pf-m-icon.pf-m-clock{--pf-c-form-control--m-icon--BackgroundUrl:var(--pf-c-form-control--m-clock--BackgroundUrl)}select.pf-c-form-control{--pf-c-form-control--PaddingRight:var(--pf-c-form-control__select--PaddingRight);background-image:var(--pf-c-form-control__select--BackgroundUrl);background-position:var(--pf-c-form-control__select--BackgroundPosition);background-size:var(--pf-c-form-control__select--BackgroundSize)}select.pf-c-form-control[aria-invalid=true]{--pf-c-form-control--PaddingRight:var(--pf-c-form-control__select--invalid--PaddingRight);--pf-c-form-control--invalid--BackgroundPosition:var(--pf-c-form-control__select--invalid--BackgroundPosition);background-image:var(--pf-c-form-control__select--BackgroundUrl),var(--pf-c-form-control--invalid--BackgroundUrl);background-position:var(--pf-c-form-control__select--BackgroundPosition),var(--pf-c-form-control--invalid--BackgroundPosition);background-size:var(--pf-c-form-control__select--BackgroundSize),var(--pf-c-form-control--invalid--BackgroundSize)}select.pf-c-form-control.pf-m-success{--pf-c-form-control--PaddingRight:var(--pf-c-form-control__select--success--PaddingRight);--pf-c-form-control--success--BackgroundPosition:var(--pf-c-form-control__select--success--BackgroundPosition);background-image:var(--pf-c-form-control__select--BackgroundUrl),var(--pf-c-form-control--success--BackgroundUrl);background-position:var(--pf-c-form-control__select--BackgroundPosition),var(--pf-c-form-control--success--BackgroundPosition);background-size:var(--pf-c-form-control__select--BackgroundSize),var(--pf-c-form-control--success--BackgroundSize)}select.pf-c-form-control.pf-m-warning{--pf-c-form-control--PaddingRight:var(--pf-c-form-control__select--m-warning--PaddingRight);background-image:var(--pf-c-form-control__select--BackgroundUrl),var(--pf-c-form-control--m-warning--BackgroundUrl);background-position:var(--pf-c-form-control__select--BackgroundPosition),var(--pf-c-form-control__select--m-warning--BackgroundPosition);background-size:var(--pf-c-form-control__select--BackgroundSize),var(--pf-c-form-control--m-warning--BackgroundSize)}textarea.pf-c-form-control{--pf-c-form-control--success--BackgroundPositionY:var(--pf-c-form-control--textarea--success--BackgroundPositionY);--pf-c-form-control--invalid--BackgroundPositionY:var(--pf-c-form-control--textarea--invalid--BackgroundPositionY);--pf-c-form-control--m-warning--BackgroundPositionY:var(--pf-c-form-control--textarea--m-warning--BackgroundPositionY)}.pf-c-form-control.pf-m-resize-vertical{resize:vertical}.pf-c-form-control.pf-m-resize-horizontal{resize:horizontal}.pf-c-hint{--pf-c-hint--GridRowGap:var(--pf-global--spacer--md);--pf-c-hint--PaddingTop:var(--pf-global--spacer--lg);--pf-c-hint--PaddingRight:var(--pf-global--spacer--lg);--pf-c-hint--PaddingBottom:var(--pf-global--spacer--lg);--pf-c-hint--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-hint--BackgroundColor:var(--pf-global--palette--blue-50);--pf-c-hint--BorderColor:var(--pf-global--palette--blue-100);--pf-c-hint--BorderWidth:var(--pf-global--BorderWidth--sm);--pf-c-hint--BoxShadow:var(--pf-global--BoxShadow--sm);--pf-c-hint--Color:var(--pf-global--Color--100);--pf-c-hint__title--FontSize:var(--pf-global--FontSize--lg);--pf-c-hint__body--FontSize:var(--pf-global--FontSize--md);--pf-c-hint__footer--child--MarginRight:var(--pf-global--spacer--md);--pf-c-hint__actions--MarginLeft:var(--pf-global--spacer--2xl);--pf-c-hint__actions--c-dropdown--MarginTop:calc(var(--pf-global--spacer--form-element)*-1);display:grid;grid-template-columns:1fr auto;grid-row-gap:var(--pf-c-hint--GridRowGap);padding:var(--pf-c-hint--PaddingTop) var(--pf-c-hint--PaddingRight) var(--pf-c-hint--PaddingBottom) var(--pf-c-hint--PaddingLeft);color:var(--pf-c-hint--Color);background-color:var(--pf-c-hint--BackgroundColor);border:var(--pf-c-hint--BorderWidth) solid var(--pf-c-hint--BorderColor);box-shadow:var(--pf-c-hint--BoxShadow)}.pf-c-hint .pf-c-button.pf-m-link.pf-m-inline{text-align:left;white-space:normal}.pf-c-hint__actions{display:inline-grid;grid-auto-flow:column;margin-left:var(--pf-c-hint__actions--MarginLeft);text-align:right;grid-column:2;grid-row:1}.pf-c-hint__actions .pf-c-dropdown .pf-c-dropdown__toggle.pf-m-plain{margin-top:var(--pf-c-hint__actions--c-dropdown--MarginTop)}.pf-c-hint__actions+.pf-c-hint__body{grid-column:1}.pf-c-hint__title{font-size:var(--pf-c-hint__title--FontSize)}.pf-c-hint__body{grid-column:1/-1;font-size:var(--pf-c-hint__body--FontSize)}.pf-c-hint__footer{grid-column:1/-1}.pf-c-hint__footer>:not(:last-child){margin-right:var(--pf-c-hint__footer--child--MarginRight)}.pf-c-inline-edit{--pf-c-inline-edit__group--item--MarginRight:var(--pf-global--spacer--sm);--pf-c-inline-edit__action--c-button--m-valid--m-plain--Color:var(--pf-global--link--Color);--pf-c-inline-edit__action--c-button--m-valid--m-plain--hover--Color:var(--pf-global--link--Color--hover);--pf-c-inline-edit__action--m-icon-group--item--MarginRight:0;--pf-c-inline-edit__group--m-footer--MarginTop:var(--pf-global--spacer--xl);--pf-c-inline-edit__label--m-bold--FontWeight:var(--pf-global--FontWeight--semi-bold)}.pf-c-inline-edit__group{display:flex;align-items:baseline}.pf-c-inline-edit__group>*{margin-right:var(--pf-c-inline-edit__group--item--MarginRight)}.pf-c-inline-edit__group.pf-m-icon-group{--pf-c-inline-edit__group--item--MarginRight:var(--pf-c-inline-edit__action--m-icon-group--item--MarginRight)}.pf-c-inline-edit__group.pf-m-footer{margin-top:var(--pf-c-inline-edit__group--m-footer--MarginTop)}.pf-c-inline-edit__group.pf-m-column{flex-direction:column}.pf-c-inline-edit__group.pf-m-column,.pf-c-inline-edit__group>:last-child{--pf-c-inline-edit__group--item--MarginRight:0}.pf-c-inline-edit__input{flex:1}.pf-c-inline-edit__action.pf-m-valid .pf-c-button.pf-m-plain{--pf-c-button--m-plain--Color:var(--pf-c-inline-edit__action--c-button--m-valid--m-plain--Color)}.pf-c-inline-edit__action.pf-m-valid .pf-c-button.pf-m-plain:hover{--pf-c-button--m-plain--Color:var(--pf-c-inline-edit__action--c-button--m-valid--m-plain--hover--Color)}.pf-c-inline-edit__action,.pf-c-inline-edit__group.pf-m-action-group,.pf-c-inline-edit__input{display:none;visibility:hidden}.pf-c-inline-edit__action.pf-m-enable-editable{display:inline-block;visibility:visible}.pf-c-inline-edit.pf-m-inline-editable .pf-c-inline-edit__action,.pf-c-inline-edit .pf-m-inline-editable .pf-c-inline-edit__action,.pf-c-inline-edit.pf-m-inline-editable .pf-c-inline-edit__group.pf-m-action-group,.pf-c-inline-edit .pf-m-inline-editable .pf-c-inline-edit__group.pf-m-action-group,.pf-c-inline-edit.pf-m-inline-editable .pf-c-inline-edit__input,.pf-c-inline-edit .pf-m-inline-editable .pf-c-inline-edit__input{visibility:visible}.pf-c-inline-edit.pf-m-inline-editable .pf-c-inline-edit__input,.pf-c-inline-edit .pf-m-inline-editable .pf-c-inline-edit__input{display:block}.pf-c-inline-edit.pf-m-inline-editable .pf-c-inline-edit__action,.pf-c-inline-edit .pf-m-inline-editable .pf-c-inline-edit__action{display:inline-block}.pf-c-inline-edit.pf-m-inline-editable .pf-c-inline-edit__group.pf-m-action-group,.pf-c-inline-edit .pf-m-inline-editable .pf-c-inline-edit__group.pf-m-action-group{display:inline-flex}.pf-c-inline-edit.pf-m-inline-editable .pf-c-inline-edit__action.pf-m-enable-editable,.pf-c-inline-edit .pf-m-inline-editable .pf-c-inline-edit__action.pf-m-enable-editable,.pf-c-inline-edit.pf-m-inline-editable .pf-c-inline-edit__value,.pf-c-inline-edit .pf-m-inline-editable .pf-c-inline-edit__value{display:none;visibility:hidden}.pf-c-inline-edit__label+.pf-c-inline-edit__action.pf-m-enable>.pf-c-button{margin-top:calc(var(--pf-c-button--PaddingTop)*-1);margin-bottom:calc(var(--pf-c-button--PaddingBottom)*-1)}.pf-c-inline-edit__label.pf-m-bold{font-weight:var(--pf-c-inline-edit__label--m-bold--FontWeight)}.pf-c-input-group{--pf-c-input-group--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-input-group__text--FontSize:var(--pf-global--FontSize--md);--pf-c-input-group__text--PaddingRight:var(--pf-global--spacer--sm);--pf-c-input-group__text--PaddingLeft:var(--pf-global--spacer--sm);--pf-c-input-group__text--Color:var(--pf-global--Color--dark-200);--pf-c-input-group__text--BorderWidth:var(--pf-global--BorderWidth--sm);--pf-c-input-group__text--BorderTopColor:var(--pf-global--BorderColor--300);--pf-c-input-group__text--BorderRightColor:var(--pf-global--BorderColor--300);--pf-c-input-group__text--BorderBottomColor:var(--pf-global--BorderColor--200);--pf-c-input-group__text--BorderLeftColor:var(--pf-global--BorderColor--300);--pf-c-input-group__text--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-input-group__textarea--MinHeight:var(--pf-global--spacer--xl);--pf-c-input-group--c-form-control--invalid--ZIndex:var(--pf-global--ZIndex--xs);--pf-c-input-group--c-form-control--MarginRight:0;color:var(--pf-global--Color--100);display:flex;width:100%;background-color:var(--pf-c-input-group--BackgroundColor)}.pf-c-input-group>*+*{margin-left:-1px}.pf-c-input-group .pf-c-form-control[aria-invalid=true]:not(:last-child){margin-right:var(--pf-c-input-group--c-form-control--MarginRight)}.pf-c-input-group input:not([type=checkbox]):not([type=radio]),.pf-c-input-group textarea{flex:2;min-width:0}.pf-c-input-group textarea{min-height:var(--pf-c-input-group__textarea--MinHeight)}.pf-c-input-group__text{display:flex;align-items:center;padding-right:var(--pf-c-input-group__text--PaddingRight);padding-left:var(--pf-c-input-group__text--PaddingLeft);font-size:var(--pf-c-input-group__text--FontSize);color:var(--pf-c-input-group__text--Color);text-align:center;background-color:var(--pf-c-input-group__text--BackgroundColor);border:var(--pf-c-input-group__text--BorderWidth) solid;border-color:var(--pf-c-input-group__text--BorderTopColor) var(--pf-c-input-group__text--BorderRightColor) var(--pf-c-input-group__text--BorderBottomColor) var(--pf-c-input-group__text--BorderLeftColor)}label.pf-c-input-group__text{cursor:pointer}.pf-c-input-group__text.pf-m-plain{--pf-c-input-group__text--BorderWidth:0;margin-left:0}.pf-c-jump-links{--pf-c-jump-links__list--PaddingTop:0;--pf-c-jump-links__list--PaddingRight:var(--pf-global--spacer--md);--pf-c-jump-links__list--PaddingBottom:0;--pf-c-jump-links__list--PaddingLeft:var(--pf-global--spacer--md);--pf-c-jump-links--m-vertical__list--PaddingTop:var(--pf-global--spacer--md);--pf-c-jump-links--m-vertical__list--PaddingRight:0;--pf-c-jump-links--m-vertical__list--PaddingBottom:var(--pf-global--spacer--md);--pf-c-jump-links--m-vertical__list--PaddingLeft:0;--pf-c-jump-links__list--FlexDirection:row;--pf-c-jump-links--m-vertical__list--FlexDirection:column;--pf-c-jump-links__list--before--BorderColor:var(--pf-global--BorderColor--100);--pf-c-jump-links__list--before--BorderTopWidth:var(--pf-global--BorderWidth--sm);--pf-c-jump-links__list--before--BorderRightWidth:0;--pf-c-jump-links__list--before--BorderBottomWidth:0;--pf-c-jump-links__list--before--BorderLeftWidth:0;--pf-c-jump-links--m-vertical__list--before--BorderLeftWidth:var(--pf-global--BorderWidth--sm);--pf-c-jump-links--m-vertical__list--before--BorderTopWidth:0;--pf-c-jump-links__list__list--MarginTop:calc(var(--pf-global--spacer--sm)*-1);--pf-c-jump-links__link--PaddingTop:var(--pf-global--spacer--md);--pf-c-jump-links__link--PaddingRight:var(--pf-global--spacer--md);--pf-c-jump-links__link--PaddingBottom:var(--pf-global--spacer--md);--pf-c-jump-links__link--PaddingLeft:var(--pf-global--spacer--md);--pf-c-jump-links__list__list__link--PaddingTop:var(--pf-global--spacer--sm);--pf-c-jump-links__list__list__link--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-jump-links__list__list__link--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-jump-links__link--OutlineOffset:calc(-1*var(--pf-global--spacer--sm));--pf-c-jump-links__link--before--BorderTopWidth:0;--pf-c-jump-links__link--before--BorderRightWidth:0;--pf-c-jump-links__link--before--BorderBottomWidth:0;--pf-c-jump-links__link--before--BorderLeftWidth:0;--pf-c-jump-links__link--before--BorderColor:transparent;--pf-c-jump-links__link--focus--before--BorderTopWidth:var(--pf-global--BorderWidth--lg);--pf-c-jump-links__link--focus--before--BorderLeftWidth:0;--pf-c-jump-links__link--focus--before--BorderColor:var(--pf-global--primary-color--100);--pf-c-jump-links__item--m-current__link--before--BorderTopWidth:var(--pf-global--BorderWidth--lg);--pf-c-jump-links__item--m-current__link--before--BorderLeftWidth:0;--pf-c-jump-links__item--m-current__link--before--BorderColor:var(--pf-global--primary-color--100);--pf-c-jump-links--m-vertical__link--focus--before--BorderTopWidth:0;--pf-c-jump-links--m-vertical__link--focus--before--BorderLeftWidth:var(--pf-global--BorderWidth--lg);--pf-c-jump-links--m-vertical__item--m-current__link--before--BorderTopWidth:0;--pf-c-jump-links--m-vertical__item--m-current__link--before--BorderLeftWidth:var(--pf-global--BorderWidth--lg);--pf-c-jump-links__link-text--Color:var(--pf-global--Color--200);--pf-c-jump-links__link--hover__link-text--Color:var(--pf-global--Color--100);--pf-c-jump-links__link--focus__link-text--Color:var(--pf-global--Color--100);--pf-c-jump-links__item--m-current__link-text--Color:var(--pf-global--Color--100);--pf-c-jump-links__label--MarginBottom:var(--pf-global--spacer--md);display:flex}.pf-c-jump-links.pf-m-center{justify-content:center}.pf-c-jump-links.pf-m-center .pf-c-jump-links__main{align-items:center}.pf-c-jump-links.pf-m-vertical{--pf-c-jump-links__list--PaddingTop:var(--pf-c-jump-links--m-vertical__list--PaddingTop);--pf-c-jump-links__list--PaddingRight:var(--pf-c-jump-links--m-vertical__list--PaddingRight);--pf-c-jump-links__list--PaddingBottom:var(--pf-c-jump-links--m-vertical__list--PaddingBottom);--pf-c-jump-links__list--PaddingLeft:var(--pf-c-jump-links--m-vertical__list--PaddingLeft);--pf-c-jump-links__list--before--BorderTopWidth:var(--pf-c-jump-links--m-vertical__list--before--BorderTopWidth);--pf-c-jump-links__list--before--BorderLeftWidth:var(--pf-c-jump-links--m-vertical__list--before--BorderLeftWidth);--pf-c-jump-links__link--focus--before--BorderTopWidth:var(--pf-c-jump-links--m-vertical__link--focus--before--BorderTopWidth);--pf-c-jump-links__link--focus--before--BorderLeftWidth:var(--pf-c-jump-links--m-vertical__link--focus--before--BorderLeftWidth);--pf-c-jump-links__item--m-current__link--before--BorderTopWidth:var(--pf-c-jump-links--m-vertical__item--m-current__link--before--BorderTopWidth);--pf-c-jump-links__item--m-current__link--before--BorderLeftWidth:var(--pf-c-jump-links--m-vertical__item--m-current__link--before--BorderLeftWidth);--pf-c-jump-links__list--FlexDirection:var(--pf-c-jump-links--m-vertical__list--FlexDirection);flex-direction:column}.pf-c-jump-links__list{position:relative;display:flex;flex-direction:var(--pf-c-jump-links__list--FlexDirection);padding:var(--pf-c-jump-links__list--PaddingTop) var(--pf-c-jump-links__list--PaddingRight) var(--pf-c-jump-links__list--PaddingBottom) var(--pf-c-jump-links__list--PaddingLeft)}.pf-c-jump-links__list:before{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none;content:"";border:solid var(--pf-c-jump-links__list--before--BorderColor);border-width:var(--pf-c-jump-links__list--before--BorderTopWidth) var(--pf-c-jump-links__list--before--BorderRightWidth) var(--pf-c-jump-links__list--before--BorderBottomWidth) var(--pf-c-jump-links__list--before--BorderLeftWidth)}.pf-c-jump-links__list .pf-c-jump-links__list{--pf-c-jump-links__list--PaddingTop:0;--pf-c-jump-links__list--PaddingBottom:0;--pf-c-jump-links__link--PaddingTop:var(--pf-c-jump-links__list__list__link--PaddingTop);--pf-c-jump-links__link--PaddingBottom:var(--pf-c-jump-links__list__list__link--PaddingBottom);--pf-c-jump-links__link--PaddingLeft:var(--pf-c-jump-links__list__list__link--PaddingLeft);margin-top:var(--pf-c-jump-links__list__list--MarginTop)}.pf-c-jump-links__link{position:relative;display:flex;flex:1;padding:var(--pf-c-jump-links__link--PaddingTop) var(--pf-c-jump-links__link--PaddingRight) var(--pf-c-jump-links__link--PaddingBottom) var(--pf-c-jump-links__link--PaddingLeft);text-decoration:none;outline-offset:var(--pf-c-jump-links__link--OutlineOffset)}.pf-c-jump-links__link:hover{--pf-c-jump-links__link-text--Color:var(--pf-c-jump-links__link--hover__link-text--Color)}.pf-c-jump-links__link:focus{--pf-c-jump-links__link-text--Color:var(--pf-c-jump-links__link--focus__link-text--Color);--pf-c-jump-links__link--before--BorderTopWidth:var(--pf-c-jump-links__link--focus--before--BorderTopWidth);--pf-c-jump-links__link--before--BorderLeftWidth:var(--pf-c-jump-links__link--focus--before--BorderLeftWidth);--pf-c-jump-links__link--before--BorderColor:var(--pf-c-jump-links__link--focus--before--BorderColor)}.pf-c-jump-links__link:before{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none;content:"";border-left:var(--pf-c-jump-links__link--before--BorderLeftWidth) solid var(--pf-c-jump-links__link--before--BorderColor);border-bottom:var(--pf-c-jump-links__link--before--BorderBottomWidth) solid var(--pf-c-jump-links__link--before--BorderColor);border-right:var(--pf-c-jump-links__link--before--BorderRightWidth) solid var(--pf-c-jump-links__link--before--BorderColor);border-top:var(--pf-c-jump-links__link--before--BorderTopWidth) solid var(--pf-c-jump-links__link--before--BorderColor)}.pf-c-jump-links__item{--pf-c-jump-links__list--before--BorderColor:transparent}.pf-c-jump-links__item.pf-m-current>.pf-c-jump-links__link{--pf-c-jump-links__link--before--BorderTopWidth:var(--pf-c-jump-links__item--m-current__link--before--BorderTopWidth);--pf-c-jump-links__link--before--BorderLeftWidth:var(--pf-c-jump-links__item--m-current__link--before--BorderLeftWidth);--pf-c-jump-links__link--before--BorderColor:var(--pf-c-jump-links__item--m-current__link--before--BorderColor);--pf-c-jump-links__link-text--Color:var(--pf-c-jump-links__item--m-current__link-text--Color)}.pf-c-jump-links__link-text{color:var(--pf-c-jump-links__link-text--Color)}.pf-c-jump-links__label{margin-bottom:var(--pf-c-jump-links__label--MarginBottom)}.pf-c-jump-links__main{display:flex;flex-direction:column}.pf-c-label{--pf-c-label--PaddingTop:var(--pf-global--spacer--xs);--pf-c-label--PaddingRight:var(--pf-global--spacer--sm);--pf-c-label--PaddingBottom:var(--pf-global--spacer--xs);--pf-c-label--PaddingLeft:var(--pf-global--spacer--sm);--pf-c-label--BorderRadius:var(--pf-global--BorderRadius--lg);--pf-c-label--BackgroundColor:var(--pf-global--BackgroundColor--200);--pf-c-label--Color:var(--pf-global--Color--100);--pf-c-label--FontSize:var(--pf-global--FontSize--sm);--pf-c-label__content--before--BorderWidth:0;--pf-c-label__content--before--BorderColor:transparent;--pf-c-label--m-outline--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-label--m-outline__content--before--BorderWidth:var(--pf-global--BorderWidth--sm);--pf-c-label--m-outline__content--before--BorderColor:var(--pf-global--BorderColor--100);--pf-c-label__content--link--hover--before--BorderWidth:var(--pf-global--BorderWidth--sm);--pf-c-label__content--link--focus--before--BorderWidth:var(--pf-global--BorderWidth--sm);--pf-c-label__content--link--hover--before--BorderColor:var(--pf-global--BorderColor--200);--pf-c-label__content--link--focus--before--BorderColor:var(--pf-global--BorderColor--200);--pf-c-label--m-outline__content--link--hover--before--BorderWidth:var(--pf-global--BorderWidth--md);--pf-c-label--m-outline__content--link--focus--before--BorderWidth:var(--pf-global--BorderWidth--md);--pf-c-label--m-outline__content--link--hover--before--BorderColor:var(--pf-global--BorderColor--100);--pf-c-label--m-outline__content--link--focus--before--BorderColor:var(--pf-global--BorderColor--100);--pf-c-label--m-blue--BackgroundColor:var(--pf-global--palette--blue-50);--pf-c-label--m-blue__content--Color:var(--pf-global--info-color--200);--pf-c-label--m-blue__icon--Color:var(--pf-global--primary-color--100);--pf-c-label--m-blue__content--link--hover--before--BorderColor:var(--pf-global--primary-color--100);--pf-c-label--m-blue__content--link--focus--before--BorderColor:var(--pf-global--primary-color--100);--pf-c-label--m-outline--m-blue__content--before--BorderColor:var(--pf-global--active-color--200);--pf-c-label--m-outline--m-blue__content--link--hover--before--BorderColor:var(--pf-global--active-color--200);--pf-c-label--m-outline--m-blue__content--link--focus--before--BorderColor:var(--pf-global--active-color--200);--pf-c-label--m-green--BackgroundColor:var(--pf-global--palette--green-50);--pf-c-label--m-green__content--Color:var(--pf-global--success-color--200);--pf-c-label--m-green__icon--Color:var(--pf-global--success-color--100);--pf-c-label--m-green__content--link--hover--before--BorderColor:var(--pf-global--success-color--100);--pf-c-label--m-green__content--link--focus--before--BorderColor:var(--pf-global--success-color--100);--pf-c-label--m-outline--m-green__content--before--BorderColor:var(--pf-global--palette--green-100);--pf-c-label--m-outline--m-green__content--link--hover--before--BorderColor:var(--pf-global--palette--green-100);--pf-c-label--m-outline--m-green__content--link--focus--before--BorderColor:var(--pf-global--palette--green-100);--pf-c-label--m-orange--BackgroundColor:var(--pf-global--palette--gold-50);--pf-c-label--m-orange__content--Color:var(--pf-global--palette--gold-700);--pf-c-label--m-orange__icon--Color:var(--pf-global--palette--orange-300);--pf-c-label--m-orange__content--link--hover--before--BorderColor:var(--pf-global--palette--orange-300);--pf-c-label--m-orange__content--link--focus--before--BorderColor:var(--pf-global--palette--orange-300);--pf-c-label--m-outline--m-orange__content--before--BorderColor:var(--pf-global--palette--gold-100);--pf-c-label--m-outline--m-orange__content--link--hover--before--BorderColor:var(--pf-global--palette--gold-100);--pf-c-label--m-outline--m-orange__content--link--focus--before--BorderColor:var(--pf-global--palette--gold-100);--pf-c-label--m-red--BackgroundColor:var(--pf-global--palette--red-50);--pf-c-label--m-red__content--Color:var(--pf-global--palette--red-300);--pf-c-label--m-red__icon--Color:var(--pf-global--danger-color--100);--pf-c-label--m-red__content--link--hover--before--BorderColor:var(--pf-global--danger-color--100);--pf-c-label--m-red__content--link--focus--before--BorderColor:var(--pf-global--danger-color--100);--pf-c-label--m-outline--m-red__content--before--BorderColor:var(--pf-global--danger-color--100);--pf-c-label--m-outline--m-red__content--link--hover--before--BorderColor:var(--pf-global--danger-color--100);--pf-c-label--m-outline--m-red__content--link--focus--before--BorderColor:var(--pf-global--danger-color--100);--pf-c-label--m-purple--BackgroundColor:var(--pf-global--palette--purple-50);--pf-c-label--m-purple__content--Color:var(--pf-global--palette--purple-700);--pf-c-label--m-purple__icon--Color:var(--pf-global--palette--purple-500);--pf-c-label--m-purple__content--link--hover--before--BorderColor:var(--pf-global--palette--purple-500);--pf-c-label--m-purple__content--link--focus--before--BorderColor:var(--pf-global--palette--purple-500);--pf-c-label--m-outline--m-purple__content--before--BorderColor:var(--pf-global--palette--purple-100);--pf-c-label--m-outline--m-purple__content--link--hover--before--BorderColor:var(--pf-global--palette--purple-100);--pf-c-label--m-outline--m-purple__content--link--focus--before--BorderColor:var(--pf-global--palette--purple-100);--pf-c-label--m-cyan--BackgroundColor:var(--pf-global--palette--cyan-50);--pf-c-label--m-cyan__content--Color:var(--pf-global--default-color--300);--pf-c-label--m-cyan__icon--Color:var(--pf-global--default-color--200);--pf-c-label--m-cyan__content--link--hover--before--BorderColor:var(--pf-global--default-color--200);--pf-c-label--m-cyan__content--link--focus--before--BorderColor:var(--pf-global--default-color--200);--pf-c-label--m-outline--m-cyan__content--before--BorderColor:var(--pf-global--palette--cyan-100);--pf-c-label--m-outline--m-cyan__content--link--hover--before--BorderColor:var(--pf-global--palette--cyan-100);--pf-c-label--m-outline--m-cyan__content--link--focus--before--BorderColor:var(--pf-global--palette--cyan-100);--pf-c-label--m-overflow__content--Color:var(--pf-global--link--Color);--pf-c-label--m-overflow__content--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-label--m-overflow__content--before--BorderWidth:var(--pf-global--BorderWidth--sm);--pf-c-label--m-overflow__content--before--BorderColor:var(--pf-global--BorderColor--300);--pf-c-label--m-overflow__content--link--hover--before--BorderWidth:var(--pf-global--BorderWidth--md);--pf-c-label--m-overflow__content--link--hover--before--BorderColor:var(--pf-global--BorderColor--300);--pf-c-label--m-overflow__content--link--focus--before--BorderWidth:var(--pf-global--BorderWidth--md);--pf-c-label--m-overflow__content--link--focus--before--BorderColor:var(--pf-global--BorderColor--300);--pf-c-label__content--Color:var(--pf-global--Color--100);--pf-c-label__text--MaxWidth:16ch;--pf-c-label__icon--Color:var(--pf-global--Color--100);--pf-c-label__icon--MarginRight:var(--pf-global--spacer--xs);--pf-c-label__c-button--FontSize:var(--pf-global--FontSize--xs);--pf-c-label__c-button--MarginTop:calc(var(--pf-global--spacer--form-element)*-1);--pf-c-label__c-button--MarginRight:calc(var(--pf-global--spacer--form-element)*-1);--pf-c-label__c-button--MarginBottom:calc(var(--pf-global--spacer--form-element)*-1);--pf-c-label__c-button--MarginLeft:var(--pf-global--spacer--xs);--pf-c-label__c-button--PaddingTop:var(--pf-global--spacer--xs);--pf-c-label__c-button--PaddingRight:var(--pf-global--spacer--sm);--pf-c-label__c-button--PaddingBottom:var(--pf-global--spacer--xs);--pf-c-label__c-button--PaddingLeft:var(--pf-global--spacer--sm);position:relative;padding:var(--pf-c-label--PaddingTop) var(--pf-c-label--PaddingRight) var(--pf-c-label--PaddingBottom) var(--pf-c-label--PaddingLeft);font-size:var(--pf-c-label--FontSize);color:var(--pf-c-label--Color);white-space:nowrap;background-color:var(--pf-c-label--BackgroundColor);border:0;border-radius:var(--pf-c-label--BorderRadius)}.pf-c-label.pf-m-blue{--pf-c-label--BackgroundColor:var(--pf-c-label--m-blue--BackgroundColor);--pf-c-label__content--Color:var(--pf-c-label--m-blue__content--Color);--pf-c-label__icon--Color:var(--pf-c-label--m-blue__icon--Color);--pf-c-label--m-outline__content--before--BorderColor:var(--pf-c-label--m-outline--m-blue__content--before--BorderColor);--pf-c-label__content--link--hover--before--BorderColor:var(--pf-c-label--m-blue__content--link--hover--before--BorderColor);--pf-c-label__content--link--focus--before--BorderColor:var(--pf-c-label--m-blue__content--link--focus--before--BorderColor);--pf-c-label--m-outline__content--link--hover--before--BorderColor:var(--pf-c-label--m-outline--m-blue__content--link--hover--before--BorderColor);--pf-c-label--m-outline__content--link--focus--before--BorderColor:var(--pf-c-label--m-outline--m-blue__content--link--focus--before--BorderColor)}.pf-c-label.pf-m-green{--pf-c-label--BackgroundColor:var(--pf-c-label--m-green--BackgroundColor);--pf-c-label__content--Color:var(--pf-c-label--m-green__content--Color);--pf-c-label__icon--Color:var(--pf-c-label--m-green__icon--Color);--pf-c-label--m-outline__content--before--BorderColor:var(--pf-c-label--m-outline--m-green__content--before--BorderColor);--pf-c-label__content--link--hover--before--BorderColor:var(--pf-c-label--m-green__content--link--hover--before--BorderColor);--pf-c-label__content--link--focus--before--BorderColor:var(--pf-c-label--m-green__content--link--focus--before--BorderColor);--pf-c-label--m-outline__content--link--hover--before--BorderColor:var(--pf-c-label--m-outline--m-green__content--link--hover--before--BorderColor);--pf-c-label--m-outline__content--link--focus--before--BorderColor:var(--pf-c-label--m-outline--m-green__content--link--focus--before--BorderColor)}.pf-c-label.pf-m-orange{--pf-c-label--BackgroundColor:var(--pf-c-label--m-orange--BackgroundColor);--pf-c-label__content--Color:var(--pf-c-label--m-orange__content--Color);--pf-c-label__icon--Color:var(--pf-c-label--m-orange__icon--Color);--pf-c-label--m-outline__content--before--BorderColor:var(--pf-c-label--m-outline--m-orange__content--before--BorderColor);--pf-c-label__content--link--hover--before--BorderColor:var(--pf-c-label--m-orange__content--link--hover--before--BorderColor);--pf-c-label__content--link--focus--before--BorderColor:var(--pf-c-label--m-orange__content--link--focus--before--BorderColor);--pf-c-label--m-outline__content--link--hover--before--BorderColor:var(--pf-c-label--m-outline--m-orange__content--link--hover--before--BorderColor);--pf-c-label--m-outline__content--link--focus--before--BorderColor:var(--pf-c-label--m-outline--m-orange__content--link--focus--before--BorderColor)}.pf-c-label.pf-m-red{--pf-c-label--BackgroundColor:var(--pf-c-label--m-red--BackgroundColor);--pf-c-label__content--Color:var(--pf-c-label--m-red__content--Color);--pf-c-label__icon--Color:var(--pf-c-label--m-red__icon--Color);--pf-c-label--m-outline__content--before--BorderColor:var(--pf-c-label--m-outline--m-red__content--before--BorderColor);--pf-c-label__content--link--hover--before--BorderColor:var(--pf-c-label--m-red__content--link--hover--before--BorderColor);--pf-c-label__content--link--focus--before--BorderColor:var(--pf-c-label--m-red__content--link--focus--before--BorderColor);--pf-c-label--m-outline__content--link--hover--before--BorderColor:var(--pf-c-label--m-outline--m-red__content--link--hover--before--BorderColor);--pf-c-label--m-outline__content--link--focus--before--BorderColor:var(--pf-c-label--m-outline--m-red__content--link--focus--before--BorderColor)}.pf-c-label.pf-m-purple{--pf-c-label--BackgroundColor:var(--pf-c-label--m-purple--BackgroundColor);--pf-c-label__content--Color:var(--pf-c-label--m-purple__content--Color);--pf-c-label__icon--Color:var(--pf-c-label--m-purple__icon--Color);--pf-c-label--m-outline__content--before--BorderColor:var(--pf-c-label--m-outline--m-purple__content--before--BorderColor);--pf-c-label__content--link--hover--before--BorderColor:var(--pf-c-label--m-purple__content--link--hover--before--BorderColor);--pf-c-label__content--link--focus--before--BorderColor:var(--pf-c-label--m-purple__content--link--focus--before--BorderColor);--pf-c-label--m-outline__content--link--hover--before--BorderColor:var(--pf-c-label--m-outline--m-purple__content--link--hover--before--BorderColor);--pf-c-label--m-outline__content--link--focus--before--BorderColor:var(--pf-c-label--m-outline--m-purple__content--link--focus--before--BorderColor)}.pf-c-label.pf-m-cyan{--pf-c-label--BackgroundColor:var(--pf-c-label--m-cyan--BackgroundColor);--pf-c-label__content--Color:var(--pf-c-label--m-cyan__content--Color);--pf-c-label__icon--Color:var(--pf-c-label--m-cyan__icon--Color);--pf-c-label--m-outline__content--before--BorderColor:var(--pf-c-label--m-outline--m-cyan__content--before--BorderColor);--pf-c-label__content--link--hover--before--BorderColor:var(--pf-c-label--m-cyan__content--link--hover--before--BorderColor);--pf-c-label__content--link--focus--before--BorderColor:var(--pf-c-label--m-cyan__content--link--focus--before--BorderColor);--pf-c-label--m-outline__content--link--hover--before--BorderColor:var(--pf-c-label--m-outline--m-cyan__content--link--hover--before--BorderColor);--pf-c-label--m-outline__content--link--focus--before--BorderColor:var(--pf-c-label--m-outline--m-cyan__content--link--focus--before--BorderColor)}.pf-c-label.pf-m-outline{--pf-c-label__content--before--BorderWidth:var(--pf-c-label--m-outline__content--before--BorderWidth);--pf-c-label__content--before--BorderColor:var(--pf-c-label--m-outline__content--before--BorderColor);--pf-c-label--BackgroundColor:var(--pf-c-label--m-outline--BackgroundColor)}.pf-c-label.pf-m-outline a.pf-c-label__content:hover,.pf-c-label.pf-m-outline button.pf-c-label__content:hover,.pf-c-label.pf-m-overflow:hover{--pf-c-label__content--before--BorderWidth:var(--pf-c-label--m-outline__content--link--hover--before--BorderWidth);--pf-c-label__content--before--BorderColor:var(--pf-c-label--m-outline__content--link--hover--before--BorderColor)}.pf-c-label.pf-m-outline a.pf-c-label__content:focus,.pf-c-label.pf-m-outline button.pf-c-label__content:focus,.pf-c-label.pf-m-overflow:focus{--pf-c-label__content--before--BorderWidth:var(--pf-c-label--m-outline__content--link--focus--before--BorderWidth);--pf-c-label__content--before--BorderColor:var(--pf-c-label--m-outline__content--link--focus--before--BorderColor)}.pf-c-label .pf-c-button{--pf-c-button--FontSize:var(--pf-c-label__c-button--FontSize);--pf-c-button--PaddingTop:var(--pf-c-label__c-button--PaddingTop);--pf-c-button--PaddingRight:var(--pf-c-label__c-button--PaddingRight);--pf-c-button--PaddingBottom:var(--pf-c-label__c-button--PaddingBottom);--pf-c-button--PaddingLeft:var(--pf-c-label__c-button--PaddingLeft);margin:var(--pf-c-label__c-button--MarginTop) var(--pf-c-label__c-button--MarginRight) var(--pf-c-label__c-button--MarginBottom) var(--pf-c-label__c-button--MarginLeft)}.pf-c-label.pf-m-overflow{--pf-c-label__content--Color:var(--pf-c-label--m-overflow__content--Color);--pf-c-label--BackgroundColor:var(--pf-c-label--m-overflow__content--BackgroundColor);--pf-c-label__content--before--BorderWidth:var(--pf-c-label--m-overflow__content--before--BorderWidth);--pf-c-label__content--before--BorderColor:var(--pf-c-label--m-overflow__content--before--BorderColor);--pf-c-label__content--link--hover--before--BorderWidth:var(--pf-c-label--m-overflow__content--link--hover--before--BorderWidth);--pf-c-label__content--link--hover--before--BorderColor:var(--pf-c-label--m-overflow__content--link--hover--before--BorderColor);--pf-c-label__content--link--focus--before--BorderWidth:var(--pf-c-label--m-overflow__content--link--focus--before--BorderWidth);--pf-c-label__content--link--focus--before--BorderColor:var(--pf-c-label--m-overflow__content--link--focus--before--BorderColor)}.pf-c-label,.pf-c-label__content{display:inline-flex;align-items:center}.pf-c-label__text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:var(--pf-c-label__text--MaxWidth)}.pf-c-label__content{color:var(--pf-c-label__content--Color);border:0}.pf-c-label__content:before{position:absolute;top:0;right:0;bottom:0;left:0;content:"";border:var(--pf-c-label__content--before--BorderWidth) solid var(--pf-c-label__content--before--BorderColor);border-radius:var(--pf-c-label--BorderRadius)}a.pf-c-label__content,button.pf-c-label__content{cursor:pointer;border:none}a.pf-c-label__content,a.pf-c-label__content:focus,a.pf-c-label__content:hover,button.pf-c-label__content,button.pf-c-label__content:focus,button.pf-c-label__content:hover{text-decoration:none}a.pf-c-label__content:hover,button.pf-c-label__content:hover{--pf-c-label__content--before--BorderWidth:var(--pf-c-label__content--link--hover--before--BorderWidth);--pf-c-label__content--before--BorderColor:var(--pf-c-label__content--link--hover--before--BorderColor)}a.pf-c-label__content:focus,button.pf-c-label__content:focus{--pf-c-label__content--before--BorderWidth:var(--pf-c-label__content--link--focus--before--BorderWidth);--pf-c-label__content--before--BorderColor:var(--pf-c-label__content--link--focus--before--BorderColor)}.pf-c-label__icon{margin-right:var(--pf-c-label__icon--MarginRight);color:var(--pf-c-label__icon--Color)}.pf-c-label-group{--pf-c-label-group__list--MarginBottom:calc(var(--pf-global--spacer--xs)*-1);--pf-c-label-group__list--MarginRight:calc(var(--pf-global--spacer--xs)*-1);--pf-c-label-group--m-category--PaddingTop:var(--pf-global--spacer--xs);--pf-c-label-group--m-category--PaddingRight:var(--pf-global--spacer--xs);--pf-c-label-group--m-category--PaddingBottom:var(--pf-global--spacer--xs);--pf-c-label-group--m-category--PaddingLeft:var(--pf-global--spacer--sm);--pf-c-label-group--m-vertical--m-category--PaddingRight:var(--pf-global--spacer--sm);--pf-c-label-group--m-category--BorderRadius:var(--pf-global--BorderRadius--sm);--pf-c-label-group--m-category--BorderWidth:var(--pf-global--BorderWidth--sm);--pf-c-label-group--m-category--BorderColor:var(--pf-global--BorderColor--300);--pf-c-label-group--m-category--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-label-group__label--MarginRight:var(--pf-global--spacer--sm);--pf-c-label-group__label--MarginBottom:0;--pf-c-label-group--m-vertical__label--MarginBottom:var(--pf-global--spacer--sm);--pf-c-label-group__label--FontSize:var(--pf-global--FontSize--sm);--pf-c-label-group__label--MaxWidth:18ch;--pf-c-label-group__close--MarginTop:calc(var(--pf-global--spacer--xs)*-1);--pf-c-label-group__close--MarginBottom:calc(var(--pf-global--spacer--xs)*-1);--pf-c-label-group--m-vertical__close--MarginTop:calc(var(--pf-global--spacer--form-element)*-1);--pf-c-label-group--m-vertical__close--MarginRight:calc(var(--pf-global--spacer--form-element)*-1);--pf-c-label-group--m-vertical__close--MarginLeft:var(--pf-global--spacer--sm);--pf-c-label-group--m-vertical__close--c-button--PaddingRight:var(--pf-global--spacer--sm);--pf-c-label-group--m-vertical__close--c-button--PaddingLeft:var(--pf-global--spacer--sm);--pf-c-label-group__list-item--MarginRight:var(--pf-global--spacer--xs);--pf-c-label-group__list-item--MarginBottom:var(--pf-global--spacer--xs);display:inline-flex}.pf-c-label-group.pf-m-category{padding:var(--pf-c-label-group--m-category--PaddingTop) var(--pf-c-label-group--m-category--PaddingRight) var(--pf-c-label-group--m-category--PaddingBottom) var(--pf-c-label-group--m-category--PaddingLeft);background-color:var(--pf-c-label-group--m-category--BackgroundColor);border:var(--pf-c-label-group--m-category--BorderWidth) solid var(--pf-c-label-group--m-category--BorderColor);border-radius:var(--pf-c-label-group--m-category--BorderRadius)}.pf-c-label-group.pf-m-vertical{--pf-c-label-group__list--MarginRight:0;--pf-c-label-group__list--MarginBottom:0;--pf-c-label-group__list-item--MarginRight:0;--pf-c-label-group__label--MarginRight:0;--pf-c-label-group__label--MarginBottom:var(--pf-c-label-group--m-vertical__label--MarginBottom);--pf-c-label-group__close--MarginTop:var(--pf-c-label-group--m-vertical__close--MarginTop);--pf-c-label-group__close--MarginLeft:var(--pf-c-label-group--m-vertical__close--MarginLeft);--pf-c-label-group__close--MarginBottom:0;--pf-c-label-group__close--MarginRight:var(--pf-c-label-group--m-vertical__close--MarginRight);--pf-c-label-group--m-category--PaddingRight:var(--pf-c-label-group--m-vertical--m-category--PaddingRight)}.pf-c-label-group.pf-m-vertical.pf-c-label-group{align-items:flex-start}.pf-c-label-group.pf-m-vertical .pf-c-label-group__list{flex-direction:column;align-items:flex-start}.pf-c-label-group.pf-m-vertical .pf-c-label-group__main{flex-direction:column}.pf-c-label-group.pf-m-vertical .pf-c-label-group__list-item:last-child{--pf-c-label-group__list-item--MarginBottom:0}.pf-c-label-group.pf-m-vertical .pf-c-label-group__close .pf-c-button{--pf-c-button--PaddingLeft:var(--pf-c-label-group--m-vertical__close--c-button--PaddingLeft);--pf-c-button--PaddingRight:var(--pf-c-label-group--m-vertical__close--c-button--PaddingRight)}.pf-c-label-group__main{display:flex;flex:1;flex-wrap:wrap;align-items:baseline}.pf-c-label-group__list{display:inline-flex;flex-wrap:wrap;margin-right:var(--pf-c-label-group__list--MarginRight);margin-bottom:var(--pf-c-label-group__list--MarginBottom)}.pf-c-label-group__list-item{display:inline-flex;margin-right:var(--pf-c-label-group__list-item--MarginRight);margin-bottom:var(--pf-c-label-group__list-item--MarginBottom)}.pf-c-label-group__label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:var(--pf-c-label-group__label--MaxWidth);margin-right:var(--pf-c-label-group__label--MarginRight);margin-bottom:var(--pf-c-label-group__label--MarginBottom);font-size:var(--pf-c-label-group__label--FontSize)}.pf-c-label-group__close{margin:var(--pf-c-label-group__close--MarginTop) var(--pf-c-label-group__close--MarginRight) var(--pf-c-label-group__close--MarginBottom) var(--pf-c-label-group__close--MarginLeft)}.pf-c-list{--pf-c-list--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-list--nested--MarginTop:var(--pf-global--spacer--sm);--pf-c-list--nested--MarginLeft:var(--pf-global--spacer--sm);--pf-c-list--ul--ListStyle:var(--pf-global--ListStyle);--pf-c-list--li--MarginTop:var(--pf-global--spacer--sm);--pf-c-list--m-inline--li--MarginRight:var(--pf-global--spacer--lg);padding-left:var(--pf-c-list--PaddingLeft)}.pf-c-list ol,.pf-c-list ul{margin-top:var(--pf-c-list--nested--MarginTop);margin-left:var(--pf-c-list--nested--MarginLeft)}.pf-c-list li+li{margin-top:var(--pf-c-list--li--MarginTop)}ul.pf-c-list:not(.pf-m-inline){list-style:var(--pf-c-list--ul--ListStyle)}.pf-c-list.pf-m-inline{--pf-c-list--PaddingLeft:0;display:flex;flex-wrap:wrap}.pf-c-list.pf-m-inline li{--pf-c-list--li--MarginTop:0}.pf-c-list.pf-m-inline li:not(:last-child){margin-right:var(--pf-c-list--m-inline--li--MarginRight)}.pf-c-login{--pf-c-login--PaddingTop:var(--pf-global--spacer--lg);--pf-c-login--PaddingBottom:var(--pf-global--spacer--lg);--pf-c-login--xl--BackgroundImage:none;--pf-c-login__container--xl--GridColumnGap:var(--pf-global--spacer--3xl);--pf-c-login__container--MaxWidth:31.25rem;--pf-c-login__container--xl--MaxWidth:none;--pf-c-login__container--PaddingLeft:6.125rem;--pf-c-login__container--PaddingRight:6.125rem;--pf-c-login__container--xl--GridTemplateColumns:34rem minmax(auto,34rem);--pf-c-login__header--MarginBottom:var(--pf-global--spacer--md);--pf-c-login__header--PaddingLeft:var(--pf-global--spacer--md);--pf-c-login__header--PaddingRight:var(--pf-global--spacer--md);--pf-c-login__header--xl--MarginBottom:var(--pf-global--spacer--2xl);--pf-c-login__header--xl--MarginTop:var(--pf-global--spacer--3xl);--pf-c-login__header--c-brand--MarginBottom:var(--pf-global--spacer--lg);--pf-c-login__header--c-brand--xl--MarginBottom:var(--pf-global--spacer--2xl);--pf-c-login__main--BackgroundColor:var(--pf-global--BackgroundColor--light-100);--pf-c-login__main--MarginBottom:var(--pf-global--spacer--lg);--pf-c-login__main-header--PaddingTop:var(--pf-global--spacer--2xl);--pf-c-login__main-header--PaddingRight:var(--pf-global--spacer--xl);--pf-c-login__main-header--PaddingBottom:var(--pf-global--spacer--md);--pf-c-login__main-header--PaddingLeft:var(--pf-global--spacer--xl);--pf-c-login__main-header--md--PaddingRight:var(--pf-global--spacer--2xl);--pf-c-login__main-header--md--PaddingLeft:var(--pf-global--spacer--2xl);--pf-c-login__main-header--ColumnGap:var(--pf-global--spacer--md);--pf-c-login__main-header--RowGap:var(--pf-global--spacer--md);--pf-c-login__main-header-desc--MarginBottom:var(--pf-global--spacer--sm);--pf-c-login__main-header-desc--md--MarginBottom:0;--pf-c-login__main-header-desc--FontSize:var(--pf-global--FontSize--sm);--pf-c-login__main-body--PaddingRight:var(--pf-global--spacer--xl);--pf-c-login__main-body--PaddingBottom:var(--pf-global--spacer--xl);--pf-c-login__main-body--PaddingLeft:var(--pf-global--spacer--xl);--pf-c-login__main-body--md--PaddingRight:var(--pf-global--spacer--2xl);--pf-c-login__main-body--md--PaddingLeft:var(--pf-global--spacer--2xl);--pf-c-login__main-footer--PaddingBottom:var(--pf-global--spacer--3xl);--pf-c-login__main-footer--c-title--MarginBottom:var(--pf-global--spacer--md);--pf-c-login__main-footer-links--PaddingTop:var(--pf-global--spacer--sm);--pf-c-login__main-footer-links--PaddingRight:var(--pf-global--spacer--3xl);--pf-c-login__main-footer-links--PaddingBottom:var(--pf-global--spacer--xl);--pf-c-login__main-footer-links--PaddingLeft:var(--pf-global--spacer--3xl);--pf-c-login__main-footer-links-item--PaddingRight:var(--pf-global--spacer--md);--pf-c-login__main-footer-links-item--PaddingLeft:var(--pf-global--spacer--md);--pf-c-login__main-footer-links-item--MarginBottom:var(--pf-global--spacer--sm);--pf-c-login__main-footer-links-item-link-svg--Fill:var(--pf-global--icon--Color--light);--pf-c-login__main-footer-links-item-link-svg--Width:var(--pf-global--icon--FontSize--lg);--pf-c-login__main-footer-links-item-link-svg--Height:var(--pf-global--icon--FontSize--lg);--pf-c-login__main-footer-links-item-link-svg--hover--Fill:var(--pf-global--icon--Color--dark);--pf-c-login__main-footer-band--PaddingTop:var(--pf-global--spacer--lg);--pf-c-login__main-footer-band--PaddingRight:var(--pf-global--spacer--md);--pf-c-login__main-footer-band--PaddingBottom:var(--pf-global--spacer--lg);--pf-c-login__main-footer-band--PaddingLeft:var(--pf-global--spacer--md);--pf-c-login__main-footer-band--BackgroundColor:var(--pf-global--BackgroundColor--200);--pf-c-login__main-footer-band-item--PaddingTop:var(--pf-global--spacer--md);--pf-c-login__footer--PaddingLeft:var(--pf-global--spacer--md);--pf-c-login__footer--PaddingRight:var(--pf-global--spacer--md);--pf-c-login__footer--c-list--PaddingTop:var(--pf-global--spacer--md);--pf-c-login__footer--c-list--xl--PaddingTop:var(--pf-global--spacer--2xl);display:flex;justify-content:center;min-height:100vh;padding-top:var(--pf-c-login--PaddingTop);padding-bottom:var(--pf-c-login--PaddingBottom)}@media (min-width:1200px){.pf-c-login{--pf-c-login__container--MaxWidth:var(--pf-c-login__container--xl--MaxWidth)}}@media (min-width:576px){.pf-c-login{--pf-c-login__header--PaddingRight:0;--pf-c-login__header--PaddingLeft:0}}@media (min-width:1200px){.pf-c-login{--pf-c-login__header--MarginBottom:var(--pf-c-login__header--xl--MarginBottom);--pf-c-login__header--c-brand--MarginBottom:var(--pf-c-login__header--c-brand--xl--MarginBottom);--pf-c-login__main--MarginBottom:0}}@media (min-width:768px){.pf-c-login{--pf-c-login__main-header--PaddingRight:var(--pf-c-login__main-header--md--PaddingRight);--pf-c-login__main-header--PaddingLeft:var(--pf-c-login__main-header--md--PaddingLeft);--pf-c-login__main-header-desc--MarginBottom:var(--pf-c-login__main-header-desc--md--MarginBottom);--pf-c-login__main-body--PaddingRight:var(--pf-c-login__main-body--md--PaddingRight);--pf-c-login__main-body--PaddingLeft:var(--pf-c-login__main-body--md--PaddingLeft)}}@media (min-width:576px){.pf-c-login{--pf-c-login__footer--PaddingRight:0;--pf-c-login__footer--PaddingLeft:0}}@media (min-width:1200px){.pf-c-login{--pf-c-login__footer--c-list--PaddingTop:var(--pf-c-login__footer--c-list--xl--PaddingTop);background-image:var(--pf-c-login--xl--BackgroundImage)}}@media (min-width:576px){.pf-c-login{align-items:center}}.pf-c-login__container{width:100%;max-width:var(--pf-c-login__container--MaxWidth)}@media (min-width:1200px){.pf-c-login__container{display:grid;justify-content:center;grid-column-gap:var(--pf-c-login__container--xl--GridColumnGap);grid-template-columns:var(--pf-c-login__container--xl--GridTemplateColumns);grid-template-areas:"main header" "main footer" "main .";padding-right:var(--pf-c-login__container--PaddingRight);padding-left:var(--pf-c-login__container--PaddingLeft)}}.pf-c-login__header{color:var(--pf-global--Color--100);grid-area:header;padding-right:var(--pf-c-login__header--PaddingRight);padding-left:var(--pf-c-login__header--PaddingLeft)}@media (min-width:1200px){.pf-c-login__header{margin-top:var(--pf-c-login__header--xl--MarginTop)}}.pf-c-login__header .pf-c-brand{margin-bottom:var(--pf-c-login__header--c-brand--MarginBottom)}.pf-c-login__main{margin-bottom:var(--pf-c-login__main--MarginBottom);background-color:var(--pf-c-login__main--BackgroundColor);grid-area:main}.pf-c-login__main>:first-child:not(.pf-c-login__main-header){padding-top:var(--pf-c-login__main-header--PaddingTop)}.pf-c-login__main>:last-child:not(.pf-c-login__main-footer){padding-bottom:var(--pf-c-login__main-footer--PaddingBottom)}.pf-c-login__main-header{display:grid;grid-template-columns:100%;column-gap:var(--pf-c-login__main-header--ColumnGap);row-gap:var(--pf-c-login__main-header--RowGap);align-items:center;padding:var(--pf-c-login__main-header--PaddingTop) var(--pf-c-login__main-header--PaddingRight) var(--pf-c-login__main-header--PaddingBottom) var(--pf-c-login__main-header--PaddingLeft)}@media (min-width:768px){.pf-c-login__main-header{grid-template-columns:1fr auto}}.pf-c-login__main-header .pf-c-dropdown{grid-column:auto;grid-row:auto}@media (min-width:768px){.pf-c-login__main-header .pf-c-dropdown{grid-column:2/3;grid-row:1}}.pf-c-login__main-header-desc{margin-bottom:var(--pf-c-login__main-header-desc--MarginBottom);font-size:var(--pf-c-login__main-header-desc--FontSize);grid-column:1/-1}.pf-c-login__main-body{padding-right:var(--pf-c-login__main-body--PaddingRight);padding-bottom:var(--pf-c-login__main-body--PaddingBottom);padding-left:var(--pf-c-login__main-body--PaddingLeft)}.pf-c-login__main-footer{display:flex;flex-wrap:wrap}.pf-c-login__main-footer .pf-c-title{margin-bottom:var(--pf-c-login__main-footer--c-title--MarginBottom);text-align:center}.pf-c-login__main-footer>*{flex-basis:100%}.pf-c-login__main-footer-links{display:flex;flex-wrap:wrap;justify-content:center;padding:var(--pf-c-login__main-footer-links--PaddingTop) var(--pf-c-login__main-footer-links--PaddingRight) var(--pf-c-login__main-footer-links--PaddingBottom) var(--pf-c-login__main-footer-links--PaddingLeft)}.pf-c-login__main-footer-links-item{padding-right:var(--pf-c-login__main-footer-links-item--PaddingRight);padding-left:var(--pf-c-login__main-footer-links-item--PaddingLeft);margin-bottom:var(--pf-c-login__main-footer-links-item--MarginBottom)}.pf-c-login__main-footer-links-item-link svg{fill:var(--pf-c-login__main-footer-links-item-link-svg--Fill);width:100%;max-width:var(--pf-c-login__main-footer-links-item-link-svg--Width);height:100%;max-height:var(--pf-c-login__main-footer-links-item-link-svg--Height)}.pf-c-login__main-footer-links-item-link:hover svg{fill:var(--pf-c-login__main-footer-links-item-link-svg--hover--Fill)}.pf-c-login__main-footer-band{padding:var(--pf-c-login__main-footer-band--PaddingTop) var(--pf-c-login__main-footer-band--PaddingRight) var(--pf-c-login__main-footer-band--PaddingBottom) var(--pf-c-login__main-footer-band--PaddingLeft);text-align:center;background-color:var(--pf-c-login__main-footer-band--BackgroundColor)}.pf-c-login__main-footer-band>*+*{padding-top:var(--pf-c-login__main-footer-band-item--PaddingTop)}.pf-c-login__footer{color:var(--pf-global--Color--100);grid-area:footer;padding-right:var(--pf-c-login__footer--PaddingRight);padding-left:var(--pf-c-login__footer--PaddingLeft)}.pf-c-login__footer .pf-c-list a{color:unset}.pf-c-login__footer .pf-c-list:not(:only-child){padding-top:var(--pf-c-login__footer--c-list--PaddingTop)}.pf-c-menu{color:var(--pf-global--Color--100);--pf-c-menu--BackgroundColor:var(--pf-global--BackgroundColor--light-100);--pf-c-menu--BoxShadow:var(--pf-global--BoxShadow--md);--pf-c-menu--PaddingTop:var(--pf-global--spacer--sm);--pf-c-menu--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-menu--m-flyout__menu--Top:calc(var(--pf-c-menu--PaddingTop)*-1);--pf-c-menu--c-divider--MarginTop:var(--pf-global--spacer--sm);--pf-c-menu--c-divider--MarginBottom:var(--pf-global--spacer--sm);--pf-c-menu__search--PaddingTop:var(--pf-global--spacer--sm);--pf-c-menu__search--PaddingRight:var(--pf-global--spacer--md);--pf-c-menu__search--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-menu__search--PaddingLeft:var(--pf-global--spacer--md);--pf-c-menu__list-item--Color:var(--pf-global--Color--100);--pf-c-menu__list-item--hover--Color:var(--pf-global--Color--100);--pf-c-menu__list-item--BackgroundColor:transparent;--pf-c-menu__list-item--hover--BackgroundColor:var(--pf-global--BackgroundColor--light-300);--pf-c-menu__item--PaddingTop:var(--pf-global--spacer--sm);--pf-c-menu__item--PaddingRight:var(--pf-global--spacer--md);--pf-c-menu__item--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-menu__item--PaddingLeft:var(--pf-global--spacer--md);--pf-c-menu__item--OutlineOffset:-0.125rem;--pf-c-menu__item--FontSize:var(--pf-global--FontSize--md);--pf-c-menu__item--FontWeight:var(--pf-global--FontWeight--normal);--pf-c-menu__item--LineHeight:var(--pf-global--LineHeight--md);--pf-c-menu__item--disabled--Color:var(--pf-global--Color--dark-200);--pf-c-menu__group-title--PaddingTop:var(--pf-c-menu__item--PaddingTop);--pf-c-menu__group-title--PaddingRight:var(--pf-c-menu__item--PaddingRight);--pf-c-menu__group-title--PaddingBottom:var(--pf-c-menu__item--PaddingBottom);--pf-c-menu__group-title--PaddingLeft:var(--pf-c-menu__item--PaddingLeft);--pf-c-menu__group-title--FontSize:var(--pf-global--FontSize--sm);--pf-c-menu__group-title--FontWeight:var(--pf-global--FontWeight--semi-bold);--pf-c-menu__group-title--Color:var(--pf-global--Color--dark-200);--pf-c-menu__item-description--FontSize:var(--pf-global--FontSize--xs);--pf-c-menu__item-description--Color:var(--pf-global--Color--200);--pf-c-menu__item-icon--MarginRight:var(--pf-global--spacer--sm);--pf-c-menu__item-toggle-icon--PaddingRight:var(--pf-global--spacer--sm);--pf-c-menu__item-toggle-icon--PaddingLeft:var(--pf-global--spacer--sm);--pf-c-menu__item-text--item-toggle-icon--MarginLeft:var(--pf-global--spacer--sm);--pf-c-menu__item-toggle-icon--item-text--MarginLeft:var(--pf-global--spacer--sm);--pf-c-menu__item-select-icon--MarginLeft:var(--pf-global--spacer--sm);--pf-c-menu__item-select-icon--Color:var(--pf-global--active-color--100);--pf-c-menu__item-select-icon--FontSize:var(--pf-global--icon--FontSize--sm);--pf-c-menu__item-main__external-icon--MarginLeft:var(--pf-global--spacer--sm);--pf-c-menu__item-main__external-icon--Color:var(--pf-global--link--Color);--pf-c-menu__item-main__external-icon--FontSize:var(--pf-global--icon--FontSize--sm);--pf-c-menu__item-action--PaddingTop:var(--pf-global--spacer--sm);--pf-c-menu__item-action--PaddingRight:var(--pf-global--spacer--md);--pf-c-menu__item-action--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-menu__item-action--PaddingLeft:var(--pf-global--spacer--md);--pf-c-menu__item-action-icon--Color:var(--pf-global--Color--dark-200);--pf-c-menu__item-action-icon--Height:calc(var(--pf-c-menu__item--FontSize)*var(--pf-c-menu__item--LineHeight));--pf-c-menu__item-action--hover__icon--Color:var(--pf-global--Color--dark-100);--pf-c-menu__item-action--m-favorite__icon--Color:var(--pf-global--disabled-color--200);--pf-c-menu__item-action--m-favorite__icon--FontSize:var(--pf-global--icon--FontSize--sm);--pf-c-menu__item-action--m-favorite--m-favorited__icon--Color:var(--pf-global--palette--gold-400);--pf-c-menu--m-drilldown--Width:auto;--pf-c-menu--m-drilldown--Height:auto;--pf-c-menu--m-drilldown--TransitionDuration--transform:var(--pf-global--TransitionDuration);--pf-c-menu--m-drilldown--TransitionDuration--height:var(--pf-global--TransitionDuration);--pf-c-menu--m-drilldown--Transition:transform var(--pf-c-menu--m-drilldown--TransitionDuration--transform),height var(--pf-c-menu--m-drilldown--TransitionDuration--height);--pf-c-menu--m-drilldown--c-menu--Top:calc(var(--pf-c-menu--PaddingTop)*-1);--pf-c-menu--m-drilldown--c-menu--TransitionDuration--transform:var(--pf-global--TransitionDuration);--pf-c-menu--m-drilldown--c-menu--TransitionDuration--visibility:var(--pf-global--TransitionDuration);--pf-c-menu--m-drilldown--c-menu--Transition:transform var(--pf-c-menu--m-drilldown--c-menu--TransitionDuration--transform),visibility var(--pf-c-menu--m-drilldown--c-menu--TransitionDuration--visibility);--pf-c-menu--m-drilldown__list--TransitionDuration--transform:var(--pf-global--TransitionDuration);--pf-c-menu--m-drilldown__list--Transition:transform var(--pf-c-menu--m-drilldown__list--TransitionDuration--transform);--pf-c-menu--m-drilled-in--c-menu__list-item--m-current-path--c-menu--ZIndex:var(--pf-global--ZIndex--2xl);padding-top:var(--pf-c-menu--PaddingTop);padding-bottom:var(--pf-c-menu--PaddingBottom);background-color:var(--pf-c-menu--BackgroundColor);box-shadow:var(--pf-c-menu--BoxShadow)}.pf-c-menu.pf-m-flyout .pf-c-menu{position:absolute;top:var(--pf-c-menu--m-flyout__menu--Top);left:100%}.pf-c-menu.pf-m-flyout .pf-c-menu__list-item{position:relative}.pf-c-menu.pf-m-drilldown{width:var(--pf-c-menu--m-drilldown--Width);height:var(--pf-c-menu--m-drilldown--Height);overflow:hidden;transition:var(--pf-c-menu--m-drilldown--Transition)}.pf-c-menu.pf-m-drilldown.pf-m-drilled-in>.pf-c-menu__content>.pf-c-menu__list,.pf-c-menu.pf-m-drilldown.pf-m-drilled-in>.pf-c-menu__list{transform:translateX(-100%)}.pf-c-menu.pf-m-drilldown .pf-c-menu{--pf-c-menu--BoxShadow:none;position:absolute;top:var(--pf-c-menu--m-drilldown--c-menu--Top);left:100%;width:100%;transition:var(--pf-c-menu--m-drilldown--c-menu--Transition)}.pf-c-menu.pf-m-drilldown .pf-c-menu.pf-m-drilled-in{transform:translateX(-100%)}.pf-c-menu.pf-m-drilldown .pf-c-menu__list{position:relative;transition:var(--pf-c-menu--m-drilldown__list--Transition)}.pf-c-menu.pf-m-drilldown .pf-c-menu__list-item.pf-m-current-path .pf-c-menu{z-index:var(--pf-c-menu--m-drilled-in--c-menu__list-item--m-current-path--c-menu--ZIndex)}.pf-c-menu.pf-m-drilldown .pf-c-menu__list-item:not(.pf-m-current-path) .pf-c-menu{visibility:hidden}.pf-c-menu.pf-m-drilldown .pf-c-menu__item{outline-offset:var(--pf-c-menu__item--OutlineOffset)}.pf-c-menu .pf-c-divider{margin-top:var(--pf-c-menu--c-divider--MarginTop);margin-bottom:var(--pf-c-menu--c-divider--MarginBottom)}.pf-c-menu__search{padding:var(--pf-c-menu__search--PaddingTop) var(--pf-c-menu__search--PaddingRight) var(--pf-c-menu__search--PaddingBottom) var(--pf-c-menu__search--PaddingLeft)}.pf-c-menu__list-item{display:flex;color:var(--pf-c-menu__list-item--Color);background-color:var(--pf-c-menu__list-item--BackgroundColor)}.pf-c-menu__list-item:focus-within:not(.pf-m-disabled),.pf-c-menu__list-item:hover:not(.pf-m-disabled){--pf-c-menu__list-item--Color:var(--pf-c-menu__list-item--hover--Color);--pf-c-menu__list-item--BackgroundColor:var(--pf-c-menu__list-item--hover--BackgroundColor)}.pf-c-menu__list-item:focus-within:not(.pf-m-disabled) .pf-c-menu__item-external-icon,.pf-c-menu__list-item:hover:not(.pf-m-disabled) .pf-c-menu__item-external-icon{opacity:1}.pf-c-menu__list-item.pf-m-disabled .pf-c-menu__item{--pf-c-menu__item--Color:var(--pf-c-menu__item--disabled--Color);pointer-events:none}.pf-c-menu__item{display:flex;flex-basis:100%;flex-direction:column;min-width:0;padding:var(--pf-c-menu__item--PaddingTop) var(--pf-c-menu__item--PaddingRight) var(--pf-c-menu__item--PaddingBottom) var(--pf-c-menu__item--PaddingLeft);font-size:var(--pf-c-menu__item--FontSize);font-weight:var(--pf-c-menu__item--FontWeight);line-height:var(--pf-c-menu__item--LineHeight);color:var(--pf-c-menu__item--Color);text-align:left;background-color:var(--pf-c-menu__item--BackgroundColor);border:none}.pf-c-menu__item:hover{text-decoration:none}.pf-c-menu__item:disabled{--pf-c-menu__item--Color:var(--pf-c-menu__item--disabled--Color);pointer-events:none}.pf-c-menu__item.pf-m-selected .pf-c-menu__item-select-icon{opacity:1}.pf-c-menu__item-main{display:flex;align-items:center;width:100%}.pf-c-menu__item-main .pf-c-menu__item-external-icon{margin-left:var(--pf-c-menu__item-main__external-icon--MarginLeft);font-size:var(--pf-c-menu__item-main__external-icon--FontSize);color:var(--pf-c-menu__item-main__external-icon--Color);opacity:0}.pf-c-menu__item-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-grow:1}.pf-c-menu__group-title{padding:var(--pf-c-menu__group-title--PaddingTop) var(--pf-c-menu__group-title--PaddingRight) var(--pf-c-menu__group-title--PaddingBottom) var(--pf-c-menu__group-title--PaddingLeft);font-size:var(--pf-c-menu__group-title--FontSize);font-weight:var(--pf-c-menu__group-title--FontWeight);color:var(--pf-c-menu__group-title--Color)}.pf-c-menu__item-description{font-size:var(--pf-c-menu__item-description--FontSize);color:var(--pf-c-menu__item-description--Color);word-break:break-all}.pf-c-menu__item-icon{margin-right:var(--pf-c-menu__item-icon--MarginRight)}.pf-c-menu__item-toggle-icon{padding-right:var(--pf-c-menu__item-toggle-icon--PaddingRight);padding-left:var(--pf-c-menu__item-toggle-icon--PaddingLeft)}.pf-c-menu__item-text+.pf-c-menu__item-toggle-icon{margin-left:var(--pf-c-menu__item-text--item-toggle-icon--MarginLeft)}.pf-c-menu__item-toggle-icon+.pf-c-menu__item-text{margin-left:var(--pf-c-menu__item-toggle-icon--item-text--MarginLeft)}.pf-c-menu__item-select-icon{margin-left:var(--pf-c-menu__item-select-icon--MarginLeft);font-size:var(--pf-c-menu__item-select-icon--FontSize);color:var(--pf-c-menu__item-select-icon--Color);opacity:0}.pf-c-menu__item-action{display:flex;padding:var(--pf-c-menu__item-action--PaddingTop) var(--pf-c-menu__item-action--PaddingRight) var(--pf-c-menu__item-action--PaddingBottom) var(--pf-c-menu__item-action--PaddingLeft);border:none}.pf-c-menu__item-action:focus,.pf-c-menu__item-action:hover{--pf-c-menu__item-action-icon--Color:var(--pf-c-menu__item-action--hover__icon--Color)}.pf-c-menu__item-action.pf-m-favorite{--pf-c-menu__item-action-icon--Color:var(--pf-c-menu__item-action--m-favorite__icon--Color)}.pf-c-menu__item-action.pf-m-favorite.pf-m-favorited{--pf-c-menu__item-action-icon--Color:var(--pf-c-menu__item-action--m-favorite--m-favorited__icon--Color)}.pf-c-menu__item-action.pf-m-favorite .pf-c-menu__item-action-icon{font-size:var(--pf-c-menu__item-action--m-favorite__icon--FontSize)}.pf-c-menu__item-action-icon{display:flex;align-items:center;height:var(--pf-c-menu__item-action-icon--Height);color:var(--pf-c-menu__item-action-icon--Color)}.pf-c-modal-box{--pf-c-modal-box--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-modal-box--BoxShadow:var(--pf-global--BoxShadow--xl);--pf-c-modal-box--ZIndex:var(--pf-global--ZIndex--xl);--pf-c-modal-box--Width:100%;--pf-c-modal-box--MaxWidth:calc(100% - var(--pf-global--spacer--xl));--pf-c-modal-box--m-sm--sm--MaxWidth:35rem;--pf-c-modal-box--m-md--Width:52.5rem;--pf-c-modal-box--m-lg--lg--MaxWidth:70rem;--pf-c-modal-box--MaxHeight:calc(100% - var(--pf-global--spacer--2xl));--pf-c-modal-box--m-align-top--spacer:var(--pf-global--spacer--sm);--pf-c-modal-box--m-align-top--xl--spacer:var(--pf-global--spacer--xl);--pf-c-modal-box--m-align-top--MarginTop:var(--pf-c-modal-box--m-align-top--spacer);--pf-c-modal-box--m-align-top--MaxHeight:calc(100% - min(var(--pf-c-modal-box--m-align-top--spacer), var(--pf-global--spacer--2xl)) - var(--pf-c-modal-box--m-align-top--spacer));--pf-c-modal-box--m-align-top--MaxWidth:calc(100% - min(var(--pf-c-modal-box--m-align-top--spacer) * 2, var(--pf-global--spacer--xl)));--pf-c-modal-box--m-danger__title-icon--Color:var(--pf-global--danger-color--100);--pf-c-modal-box--m-warning__title-icon--Color:var(--pf-global--warning-color--100);--pf-c-modal-box--m-success__title-icon--Color:var(--pf-global--success-color--100);--pf-c-modal-box--m-info__title-icon--Color:var(--pf-global--info-color--100);--pf-c-modal-box--m-default__title-icon--Color:var(--pf-global--default-color--200);--pf-c-modal-box__header--PaddingTop:var(--pf-global--spacer--lg);--pf-c-modal-box__header--PaddingRight:var(--pf-global--spacer--lg);--pf-c-modal-box__header--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-modal-box__header--last-child--PaddingBottom:var(--pf-global--spacer--lg);--pf-c-modal-box__title--LineHeight:var(--pf-global--LineHeight--sm);--pf-c-modal-box__title--FontFamily:var(--pf-global--FontFamily--heading--sans-serif);--pf-c-modal-box__title--FontSize:var(--pf-global--FontSize--2xl);--pf-c-modal-box__title-icon--MarginRight:var(--pf-global--spacer--sm);--pf-c-modal-box__title-icon--Color:var(--pf-global--Color--100);--pf-c-modal-box__description--PaddingTop:var(--pf-global--spacer--xs);--pf-c-modal-box__body--MinHeight:calc(var(--pf-global--FontSize--md)*var(--pf-global--LineHeight--md));--pf-c-modal-box__body--PaddingTop:var(--pf-global--spacer--lg);--pf-c-modal-box__body--PaddingRight:var(--pf-global--spacer--lg);--pf-c-modal-box__body--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-modal-box__body--last-child--PaddingBottom:var(--pf-global--spacer--lg);--pf-c-modal-box__header--body--PaddingTop:var(--pf-global--spacer--md);--pf-c-modal-box--c-button--Top:var(--pf-global--spacer--lg);--pf-c-modal-box--c-button--Right:var(--pf-global--spacer--md);--pf-c-modal-box--c-button--sibling--MarginRight:calc(var(--pf-global--spacer--xl) + var(--pf-global--spacer--sm));--pf-c-modal-box__footer--PaddingTop:var(--pf-global--spacer--lg);--pf-c-modal-box__footer--PaddingRight:var(--pf-global--spacer--lg);--pf-c-modal-box__footer--PaddingBottom:var(--pf-global--spacer--lg);--pf-c-modal-box__footer--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-modal-box__footer--c-button--MarginRight:var(--pf-global--spacer--md);--pf-c-modal-box__footer--c-button--sm--MarginRight:calc(var(--pf-c-modal-box__footer--c-button--MarginRight)/2);position:relative;z-index:var(--pf-c-modal-box--ZIndex);display:flex;flex-direction:column;width:var(--pf-c-modal-box--Width);max-width:var(--pf-c-modal-box--MaxWidth);max-height:var(--pf-c-modal-box--MaxHeight);background-color:var(--pf-c-modal-box--BackgroundColor);box-shadow:var(--pf-c-modal-box--BoxShadow)}@media (min-width:1200px){.pf-c-modal-box{--pf-c-modal-box--m-align-top--spacer:var(--pf-c-modal-box--m-align-top--xl--spacer)}}.pf-c-modal-box.pf-m-sm{--pf-c-modal-box--Width:var(--pf-c-modal-box--m-sm--sm--MaxWidth)}.pf-c-modal-box.pf-m-md{--pf-c-modal-box--Width:var(--pf-c-modal-box--m-md--Width)}.pf-c-modal-box.pf-m-lg{--pf-c-modal-box--Width:var(--pf-c-modal-box--m-lg--lg--MaxWidth)}.pf-c-modal-box.pf-m-align-top{top:var(--pf-c-modal-box--m-align-top--MarginTop);align-self:flex-start;max-width:var(--pf-c-modal-box--m-align-top--MaxWidth);max-height:var(--pf-c-modal-box--m-align-top--MaxHeight)}.pf-c-modal-box.pf-m-danger{--pf-c-modal-box__title-icon--Color:var(--pf-c-modal-box--m-danger__title-icon--Color)}.pf-c-modal-box.pf-m-warning{--pf-c-modal-box__title-icon--Color:var(--pf-c-modal-box--m-warning__title-icon--Color)}.pf-c-modal-box.pf-m-success{--pf-c-modal-box__title-icon--Color:var(--pf-c-modal-box--m-success__title-icon--Color)}.pf-c-modal-box.pf-m-default{--pf-c-modal-box__title-icon--Color:var(--pf-c-modal-box--m-default__title-icon--Color)}.pf-c-modal-box.pf-m-info{--pf-c-modal-box__title-icon--Color:var(--pf-c-modal-box--m-info__title-icon--Color)}.pf-c-modal-box>.pf-c-button{position:absolute;top:var(--pf-c-modal-box--c-button--Top);right:var(--pf-c-modal-box--c-button--Right)}.pf-c-modal-box>.pf-c-button+*{margin-right:var(--pf-c-modal-box--c-button--sibling--MarginRight)}.pf-c-modal-box__header{display:flex;flex-direction:column;padding-top:var(--pf-c-modal-box__header--PaddingTop);padding-right:var(--pf-c-modal-box__header--PaddingRight);padding-left:var(--pf-c-modal-box__header--PaddingLeft)}.pf-c-modal-box__header.pf-m-help{display:flex;flex-direction:row}.pf-c-modal-box__header:last-child{padding-bottom:var(--pf-c-modal-box__header--last-child--PaddingBottom)}.pf-c-modal-box__header+.pf-c-modal-box__body{--pf-c-modal-box__body--PaddingTop:var(--pf-c-modal-box__header--body--PaddingTop)}.pf-c-modal-box__header-main{flex-grow:1;min-width:0}.pf-c-modal-box__title,.pf-c-modal-box__title-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pf-c-modal-box__title{flex:0 0 auto;font-family:var(--pf-c-modal-box__title--FontFamily);font-size:var(--pf-c-modal-box__title--FontSize);line-height:var(--pf-c-modal-box__title--LineHeight)}.pf-c-modal-box__title.pf-m-icon{display:flex}.pf-c-modal-box__title-icon{margin-right:var(--pf-c-modal-box__title-icon--MarginRight);color:var(--pf-c-modal-box__title-icon--Color)}.pf-c-modal-box__description{padding-top:var(--pf-c-modal-box__description--PaddingTop)}.pf-c-modal-box__body{flex:1 1 auto;min-height:var(--pf-c-modal-box__body--MinHeight);padding-top:var(--pf-c-modal-box__body--PaddingTop);padding-right:var(--pf-c-modal-box__body--PaddingRight);padding-left:var(--pf-c-modal-box__body--PaddingLeft);overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain;word-break:break-word;-webkit-overflow-scrolling:touch}.pf-c-modal-box__body:last-child{padding-bottom:var(--pf-c-modal-box__body--last-child--PaddingBottom)}.pf-c-modal-box__footer{display:flex;flex:0 0 auto;align-items:center;padding:var(--pf-c-modal-box__footer--PaddingTop) var(--pf-c-modal-box__footer--PaddingRight) var(--pf-c-modal-box__footer--PaddingBottom) var(--pf-c-modal-box__footer--PaddingLeft)}.pf-c-modal-box__footer>.pf-c-button:not(:last-child){margin-right:var(--pf-c-modal-box__footer--c-button--MarginRight)}@media screen and (min-width:576px){.pf-c-modal-box__footer>.pf-c-button:not(:last-child){--pf-c-modal-box__footer--c-button--MarginRight:var(--pf-c-modal-box__footer--c-button--sm--MarginRight)}}.pf-c-nav{--pf-c-nav--Transition:var(--pf-global--Transition);--pf-c-nav__item--m-expanded__toggle-icon--Rotate:90deg;--pf-c-nav--m-light__item--before--BorderColor:var(--pf-global--BorderColor--300);--pf-c-nav--m-light__item--m-current--not--m-expanded__link--BackgroundColor:var(--pf-global--BackgroundColor--light-300);--pf-c-nav--m-light__link--Color:var(--pf-global--Color--dark-100);--pf-c-nav--m-light__link--hover--Color:var(--pf-global--Color--dark-100);--pf-c-nav--m-light__link--focus--Color:var(--pf-global--Color--dark-100);--pf-c-nav--m-light__link--active--Color:var(--pf-global--Color--dark-100);--pf-c-nav--m-light__link--m-current--Color:var(--pf-global--Color--dark-100);--pf-c-nav--m-light__link--hover--BackgroundColor:var(--pf-global--BackgroundColor--light-300);--pf-c-nav--m-light__link--focus--BackgroundColor:var(--pf-global--BackgroundColor--light-300);--pf-c-nav--m-light__link--active--BackgroundColor:var(--pf-global--BackgroundColor--light-300);--pf-c-nav--m-light__link--m-current--BackgroundColor:var(--pf-global--BackgroundColor--light-300);--pf-c-nav--m-light__link--before--BorderColor:var(--pf-global--BorderColor--300);--pf-c-nav--m-light__link--after--BorderColor:var(--pf-global--active-color--100);--pf-c-nav--m-light__link--m-current--after--BorderColor:var(--pf-global--active-color--100);--pf-c-nav--m-light__section-title--Color:var(--pf-global--Color--dark-200);--pf-c-nav--m-light__section-title--BorderBottomColor:var(--pf-global--BorderColor--300);--pf-c-nav--m-light--c-divider--BackgroundColor:var(--pf-global--BorderColor--300);--pf-c-nav--m-light__subnav__link--hover--after--BorderColor:var(--pf-global--BorderColor--dark-100);--pf-c-nav--m-light__subnav__link--focus--after--BorderColor:var(--pf-global--BorderColor--dark-100);--pf-c-nav--m-light__subnav__link--active--after--BorderColor:var(--pf-global--BorderColor--dark-100);--pf-c-nav--m-light__subnav__link--m-current--after--BorderColor:var(--pf-global--active-color--100);--pf-c-nav__item--MarginTop:0;--pf-c-nav__item--m-current--not--m-expanded__link--BackgroundColor:var(--pf-global--BackgroundColor--dark-400);--pf-c-nav__link--m-current--not--m-expanded__link--after--BorderWidth:var(--pf-global--BorderWidth--xl);--pf-c-nav__item--before--BorderColor:var(--pf-global--BackgroundColor--dark-200);--pf-c-nav__item--before--BorderWidth:var(--pf-global--BorderWidth--sm);--pf-c-nav__link--FontSize:var(--pf-global--FontSize--md);--pf-c-nav__link--FontWeight:var(--pf-global--FontWeight--normal);--pf-c-nav__link--PaddingTop:var(--pf-global--spacer--md);--pf-c-nav__link--PaddingRight:var(--pf-global--spacer--md);--pf-c-nav__link--PaddingBottom:var(--pf-global--spacer--md);--pf-c-nav__link--PaddingLeft:var(--pf-global--spacer--md);--pf-c-nav__link--xl--PaddingRight:var(--pf-global--spacer--lg);--pf-c-nav__link--xl--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-nav__link--Color:var(--pf-global--Color--light-100);--pf-c-nav__link--hover--Color:var(--pf-global--Color--light-100);--pf-c-nav__link--focus--Color:var(--pf-global--Color--light-100);--pf-c-nav__link--active--Color:var(--pf-global--Color--light-100);--pf-c-nav__link--m-current--Color:var(--pf-global--Color--light-100);--pf-c-nav__link--BackgroundColor:transparent;--pf-c-nav__link--hover--BackgroundColor:var(--pf-global--BackgroundColor--dark-200);--pf-c-nav__link--focus--BackgroundColor:var(--pf-global--BackgroundColor--dark-200);--pf-c-nav__link--active--BackgroundColor:var(--pf-global--BackgroundColor--dark-200);--pf-c-nav__link--m-current--BackgroundColor:var(--pf-global--BackgroundColor--dark-400);--pf-c-nav__link--OutlineOffset:calc(var(--pf-global--spacer--xs)*-1);--pf-c-nav__link--before--BorderColor:var(--pf-global--BackgroundColor--dark-200);--pf-c-nav__link--before--BorderBottomWidth:var(--pf-global--BorderWidth--sm);--pf-c-nav__link--hover--before--BorderBottomWidth:0;--pf-c-nav__link--focus--before--BorderBottomWidth:0;--pf-c-nav__link--active--before--BorderBottomWidth:0;--pf-c-nav__link--m-current--before--BorderBottomWidth:0;--pf-c-nav__link--after--BorderColor:var(--pf-global--active-color--400);--pf-c-nav__link--hover--after--BorderColor:var(--pf-global--active-color--400);--pf-c-nav__link--focus--after--BorderColor:var(--pf-global--active-color--400);--pf-c-nav__link--active--after--BorderColor:var(--pf-global--active-color--400);--pf-c-nav__link--m-current--after--BorderColor:var(--pf-global--active-color--400);--pf-c-nav__link--after--BorderLeftWidth:0;--pf-c-nav__link--hover--after--BorderLeftWidth:0;--pf-c-nav__link--focus--after--BorderLeftWidth:0;--pf-c-nav__link--active--after--BorderLeftWidth:0;--pf-c-nav__link--m-current--after--BorderLeftWidth:var(--pf-global--BorderWidth--xl);--pf-c-nav--m-horizontal__link--PaddingTop:var(--pf-global--spacer--sm);--pf-c-nav--m-horizontal__link--PaddingRight:var(--pf-global--spacer--md);--pf-c-nav--m-horizontal__link--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-nav--m-horizontal__link--PaddingLeft:var(--pf-global--spacer--md);--pf-c-nav--m-horizontal__link--lg--PaddingTop:var(--pf-global--spacer--lg);--pf-c-nav--m-horizontal__link--lg--PaddingBottom:var(--pf-global--spacer--lg);--pf-c-nav--m-horizontal__link--Right:var(--pf-global--spacer--md);--pf-c-nav--m-horizontal__link--Left:var(--pf-global--spacer--md);--pf-c-nav--m-horizontal__link--Color:var(--pf-global--Color--light-300);--pf-c-nav--m-horizontal__link--hover--Color:var(--pf-global--active-color--400);--pf-c-nav--m-horizontal__link--focus--Color:var(--pf-global--active-color--400);--pf-c-nav--m-horizontal__link--active--Color:var(--pf-global--active-color--400);--pf-c-nav--m-horizontal__link--m-current--Color:var(--pf-global--active-color--400);--pf-c-nav--m-horizontal__link--BackgroundColor:transparent;--pf-c-nav--m-horizontal__link--hover--BackgroundColor:transparent;--pf-c-nav--m-horizontal__link--focus--BackgroundColor:transparent;--pf-c-nav--m-horizontal__link--active--BackgroundColor:transparent;--pf-c-nav--m-horizontal__link--m-current--BackgroundColor:transparent;--pf-c-nav--m-horizontal__link--before--BorderColor:var(--pf-global--active-color--400);--pf-c-nav--m-horizontal__link--before--BorderWidth:0;--pf-c-nav--m-horizontal__link--hover--before--BorderWidth:var(--pf-global--BorderWidth--lg);--pf-c-nav--m-horizontal__link--focus--before--BorderWidth:var(--pf-global--BorderWidth--lg);--pf-c-nav--m-horizontal__link--active--before--BorderWidth:var(--pf-global--BorderWidth--lg);--pf-c-nav--m-horizontal__link--m-current--before--BorderWidth:var(--pf-global--BorderWidth--lg);--pf-c-nav--m-tertiary__link--PaddingTop:var(--pf-global--spacer--sm);--pf-c-nav--m-tertiary__link--PaddingRight:var(--pf-global--spacer--md);--pf-c-nav--m-tertiary__link--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-nav--m-tertiary__link--PaddingLeft:var(--pf-global--spacer--md);--pf-c-nav--m-tertiary__link--Right:var(--pf-global--spacer--md);--pf-c-nav--m-tertiary__link--Left:var(--pf-global--spacer--md);--pf-c-nav--m-tertiary__link--Color:var(--pf-global--Color--dark-100);--pf-c-nav--m-tertiary__link--hover--Color:var(--pf-global--active-color--100);--pf-c-nav--m-tertiary__link--focus--Color:var(--pf-global--active-color--100);--pf-c-nav--m-tertiary__link--active--Color:var(--pf-global--active-color--100);--pf-c-nav--m-tertiary__link--m-current--Color:var(--pf-global--active-color--100);--pf-c-nav--m-tertiary__link--BackgroundColor:transparent;--pf-c-nav--m-tertiary__link--hover--BackgroundColor:transparent;--pf-c-nav--m-tertiary__link--focus--BackgroundColor:transparent;--pf-c-nav--m-tertiary__link--active--BackgroundColor:transparent;--pf-c-nav--m-tertiary__link--m-current--BackgroundColor:transparent;--pf-c-nav--m-tertiary__link--before--BorderColor:var(--pf-global--active-color--100);--pf-c-nav--m-tertiary__link--before--BorderWidth:0;--pf-c-nav--m-tertiary__link--hover--before--BorderWidth:var(--pf-global--BorderWidth--lg);--pf-c-nav--m-tertiary__link--focus--before--BorderWidth:var(--pf-global--BorderWidth--lg);--pf-c-nav--m-tertiary__link--active--before--BorderWidth:var(--pf-global--BorderWidth--lg);--pf-c-nav--m-tertiary__link--m-current--before--BorderWidth:var(--pf-global--BorderWidth--lg);--pf-c-nav--m-tertiary__scroll-button--Color:var(--pf-global--Color--dark-100);--pf-c-nav--m-tertiary__scroll-button--hover--Color:var(--pf-global--active-color--100);--pf-c-nav--m-tertiary__scroll-button--focus--Color:var(--pf-global--active-color--100);--pf-c-nav--m-tertiary__scroll-button--active--Color:var(--pf-global--active-color--100);--pf-c-nav--m-tertiary__scroll-button--disabled--Color:var(--pf-global--disabled-color--200);--pf-c-nav--m-tertiary__scroll-button--before--BorderColor:var(--pf-global--BorderColor--300);--pf-c-nav--m-tertiary__scroll-button--disabled--before--BorderColor:var(--pf-global--disabled-color--300);--pf-c-nav__subnav--PaddingBottom:var(--pf-global--spacer--md);--pf-c-nav__subnav--xl--PaddingLeft:var(--pf-c-nav__link--PaddingLeft);--pf-c-nav__subnav__link--MarginTop:0;--pf-c-nav__subnav__link--PaddingTop:var(--pf-global--spacer--sm);--pf-c-nav__subnav__link--PaddingRight:var(--pf-global--spacer--lg);--pf-c-nav__subnav__link--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-nav__subnav__link--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-nav__subnav__link--FontSize:var(--pf-global--FontSize--sm);--pf-c-nav__subnav__link--hover--after--BorderColor:var(--pf-global--BorderColor--200);--pf-c-nav__subnav__link--focus--after--BorderColor:var(--pf-global--BorderColor--200);--pf-c-nav__subnav__link--active--after--BorderColor:var(--pf-global--BorderColor--200);--pf-c-nav__subnav__link--m-current--after--BorderColor:var(--pf-global--active-color--400);--pf-c-nav__subnav__link--hover--after--BorderWidth:var(--pf-global--BorderWidth--sm);--pf-c-nav__subnav__link--focus--after--BorderWidth:var(--pf-global--BorderWidth--sm);--pf-c-nav__subnav__link--active--after--BorderWidth:var(--pf-global--BorderWidth--sm);--pf-c-nav__subnav__link--m-current--after--BorderWidth:var(--pf-global--BorderWidth--xl);--pf-c-nav__subnav--MaxHeight:0;--pf-c-nav__item--m-expanded__subnav--MaxHeight:100%;--pf-c-nav__subnav--c-divider--PaddingRight:var(--pf-global--spacer--lg);--pf-c-nav__subnav--c-divider--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-nav__section--MarginTop:var(--pf-global--spacer--sm);--pf-c-nav__section__item--MarginTop:var(--pf-global--spacer--sm);--pf-c-nav__section__link--PaddingTop:var(--pf-global--spacer--sm);--pf-c-nav__section__link--PaddingRight:var(--pf-global--spacer--md);--pf-c-nav__section__link--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-nav__section__link--PaddingLeft:var(--pf-global--spacer--md);--pf-c-nav__section__link--xl--PaddingRight:var(--pf-global--spacer--lg);--pf-c-nav__section__link--xl--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-nav__section__link--FontSize:var(--pf-global--FontSize--md);--pf-c-nav__section__link--before--BorderBottomWidth:0;--pf-c-nav__section__link--hover--after--BorderColor:transparent;--pf-c-nav__section__link--focus--after--BorderColor:transparent;--pf-c-nav__section__link--active--after--BorderColor:transparent;--pf-c-nav__section__link--m-current--after--BorderColor:var(--pf-global--active-color--400);--pf-c-nav__section__link--hover--after--BorderWidth:0;--pf-c-nav__section__link--focus--after--BorderWidth:0;--pf-c-nav__section__link--active--after--BorderWidth:0;--pf-c-nav__section__link--m-current--after--BorderWidth:var(--pf-global--BorderWidth--xl);--pf-c-nav__section--section--MarginTop:var(--pf-global--spacer--xl);--pf-c-nav__section-title--PaddingTop:var(--pf-global--spacer--sm);--pf-c-nav__section-title--PaddingRight:var(--pf-global--spacer--md);--pf-c-nav__section-title--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-nav__section-title--PaddingLeft:var(--pf-global--spacer--md);--pf-c-nav__section-title--xl--PaddingRight:var(--pf-global--spacer--lg);--pf-c-nav__section-title--xl--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-nav__section-title--FontSize:var(--pf-global--FontSize--sm);--pf-c-nav__section-title--Color:var(--pf-global--Color--light-100);--pf-c-nav__section-title--BorderBottomColor:var(--pf-global--BackgroundColor--dark-200);--pf-c-nav__section-title--BorderBottomWidth:var(--pf-global--BorderWidth--sm);--pf-c-nav__scroll-button--Color:var(--pf-global--Color--light-100);--pf-c-nav__scroll-button--hover--Color:var(--pf-global--active-color--400);--pf-c-nav__scroll-button--focus--Color:var(--pf-global--active-color--400);--pf-c-nav__scroll-button--active--Color:var(--pf-global--active-color--400);--pf-c-nav__scroll-button--disabled--Color:var(--pf-global--disabled-color--100);--pf-c-nav__scroll-button--BackgroundColor:transparent;--pf-c-nav__scroll-button--Width:var(--pf-global--target-size--MinWidth);--pf-c-nav__scroll-button--OutlineOffset:calc(-1*var(--pf-global--spacer--xs));--pf-c-nav__scroll-button--Transition:margin .125s,transform .125s,opacity .125s;--pf-c-nav__scroll-button--before--BorderColor:var(--pf-global--BackgroundColor--dark-200);--pf-c-nav__scroll-button--before--BorderWidth:var(--pf-global--BorderWidth--sm);--pf-c-nav__scroll-button--before--BorderRightWidth:0;--pf-c-nav__scroll-button--before--BorderLeftWidth:0;--pf-c-nav__scroll-button--disabled--before--BorderColor:transparent;--pf-c-nav__toggle--PaddingRight:var(--pf-global--spacer--sm);--pf-c-nav__toggle--PaddingLeft:var(--pf-global--spacer--sm);--pf-c-nav__toggle--FontSize:var(--pf-global--icon--FontSize--md);--pf-c-nav__toggle-icon--Transition:var(--pf-global--TransitionDuration);--pf-c-nav--c-divider--MarginTop:var(--pf-global--spacer--sm);--pf-c-nav--c-divider--MarginBottom:var(--pf-global--spacer--sm);--pf-c-nav--c-divider--PaddingRight:0;--pf-c-nav--c-divider--PaddingLeft:0;--pf-c-nav--c-divider--BackgroundColor:var(--pf-global--BackgroundColor--dark-200)}@media screen and (min-width:1200px){.pf-c-nav{--pf-c-nav__link--PaddingRight:var(--pf-c-nav__link--xl--PaddingRight);--pf-c-nav__link--PaddingLeft:var(--pf-c-nav__link--xl--PaddingLeft);--pf-c-nav__section__link--PaddingRight:var(--pf-c-nav__section__link--xl--PaddingRight);--pf-c-nav__section__link--PaddingLeft:var(--pf-c-nav__section__link--xl--PaddingLeft);--pf-c-nav__section-title--PaddingRight:var(--pf-c-nav__section-title--xl--PaddingRight);--pf-c-nav__section-title--PaddingLeft:var(--pf-c-nav__section-title--xl--PaddingLeft);--pf-c-nav__subnav--PaddingLeft:var(--pf-c-nav__subnav--xl--PaddingLeft)}}.pf-c-nav.pf-m-horizontal,.pf-c-nav.pf-m-tertiary{overflow:hidden}.pf-c-nav.pf-m-horizontal,.pf-c-nav.pf-m-horizontal .pf-c-nav__list,.pf-c-nav.pf-m-tertiary,.pf-c-nav.pf-m-tertiary .pf-c-nav__list{position:relative;display:flex}.pf-c-nav.pf-m-horizontal .pf-c-nav__list,.pf-c-nav.pf-m-tertiary .pf-c-nav__list{flex:1;max-width:100%;overflow-x:auto;white-space:nowrap;-webkit-overflow-scrolling:touch;scrollbar-width:none;-ms-overflow-style:-ms-autohiding-scrollbar}.pf-c-nav.pf-m-horizontal .pf-c-nav__list::-webkit-scrollbar,.pf-c-nav.pf-m-tertiary .pf-c-nav__list::-webkit-scrollbar{display:none}.pf-c-nav.pf-m-horizontal .pf-c-nav__item,.pf-c-nav.pf-m-tertiary .pf-c-nav__item{display:flex}.pf-c-nav.pf-m-horizontal .pf-c-nav__link,.pf-c-nav.pf-m-tertiary .pf-c-nav__link{align-items:center;align-self:stretch;white-space:nowrap}.pf-c-nav.pf-m-horizontal .pf-c-nav__link:before,.pf-c-nav.pf-m-tertiary .pf-c-nav__link:before{top:auto;bottom:0}.pf-c-nav.pf-m-horizontal .pf-c-nav__link:after,.pf-c-nav.pf-m-tertiary .pf-c-nav__link:after{content:none}.pf-c-nav.pf-m-horizontal .pf-c-nav__link:before{right:var(--pf-c-nav--m-horizontal__link--Right);left:var(--pf-c-nav--m-horizontal__link--Left)}.pf-c-nav.pf-m-tertiary .pf-c-nav__link:before{right:var(--pf-c-nav--m-tertiary__link--Right);left:var(--pf-c-nav--m-tertiary__link--Left)}.pf-c-nav.pf-m-light{--pf-c-nav__item--before--BorderColor:var(--pf-c-nav--m-light__item--before--BorderColor);--pf-c-nav__item--m-current--not--m-expanded__link--BackgroundColor:var(--pf-c-nav--m-light__item--m-current--not--m-expanded__link--BackgroundColor);--pf-c-nav__link--Color:var(--pf-c-nav--m-light__link--Color);--pf-c-nav__link--hover--Color:var(--pf-c-nav--m-light__link--hover--Color);--pf-c-nav__link--focus--Color:var(--pf-c-nav--m-light__link--focus--Color);--pf-c-nav__link--active--Color:var(--pf-c-nav--m-light__link--active--Color);--pf-c-nav__link--m-current--Color:var(--pf-c-nav--m-light__link--m-current--Color);--pf-c-nav__link--hover--BackgroundColor:var(--pf-c-nav--m-light__link--hover--BackgroundColor);--pf-c-nav__link--focus--BackgroundColor:var(--pf-c-nav--m-light__link--focus--BackgroundColor);--pf-c-nav__link--active--BackgroundColor:var(--pf-c-nav--m-light__link--active--BackgroundColor);--pf-c-nav__link--m-current--BackgroundColor:var(--pf-c-nav--m-light__link--m-current--BackgroundColor);--pf-c-nav__link--before--BorderColor:var(--pf-c-nav--m-light__link--before--BorderColor);--pf-c-nav__link--after--BorderColor:var(--pf-c-nav--m-light__link--after--BorderColor);--pf-c-nav__link--m-current--after--BorderColor:var(--pf-c-nav--m-light__link--m-current--after--BorderColor);--pf-c-nav__subnav__link--hover--after--BorderColor:var(--pf-c-nav--m-light__subnav__link--hover--after--BorderColor);--pf-c-nav__subnav__link--focus--after--BorderColor:var(--pf-c-nav--m-light__subnav__link--focus--after--BorderColor);--pf-c-nav__subnav__link--active--after--BorderColor:var(--pf-c-nav--m-light__subnav__link--active--after--BorderColor);--pf-c-nav__subnav__link--m-current--after--BorderColor:var(--pf-c-nav--m-light__subnav__link--m-current--after--BorderColor);--pf-c-nav__section-title--Color:var(--pf-c-nav--m-light__section-title--Color);--pf-c-nav__section-title--BorderBottomColor:var(--pf-c-nav--m-light__section-title--BorderBottomColor)}.pf-c-nav.pf-m-light .pf-c-divider{--pf-c-divider--after--BackgroundColor:var(--pf-c-nav--m-light--c-divider--BackgroundColor)}.pf-c-nav.pf-m-horizontal{--pf-c-nav__link--PaddingTop:var(--pf-c-nav--m-horizontal__link--PaddingTop);--pf-c-nav__link--PaddingRight:var(--pf-c-nav--m-horizontal__link--PaddingRight);--pf-c-nav__link--PaddingBottom:var(--pf-c-nav--m-horizontal__link--PaddingBottom);--pf-c-nav__link--PaddingLeft:var(--pf-c-nav--m-horizontal__link--PaddingLeft);--pf-c-nav__link--Right:var(--pf-c-nav--m-horizontal__link--Right);--pf-c-nav__link--Left:var(--pf-c-nav--m-horizontal__link--Left);--pf-c-nav__link--Color:var(--pf-c-nav--m-horizontal__link--Color);--pf-c-nav__link--hover--Color:var(--pf-c-nav--m-horizontal__link--hover--Color);--pf-c-nav__link--active--Color:var(--pf-c-nav--m-horizontal__link--active--Color);--pf-c-nav__link--focus--Color:var(--pf-c-nav--m-horizontal__link--focus--Color);--pf-c-nav__link--m-current--Color:var(--pf-c-nav--m-horizontal__link--m-current--Color);--pf-c-nav__link--BackgroundColor:var(--pf-c-nav--m-horizontal__link--BackgroundColor);--pf-c-nav__link--hover--BackgroundColor:var(--pf-c-nav--m-horizontal__link--hover--BackgroundColor);--pf-c-nav__link--focus--BackgroundColor:var(--pf-c-nav--m-horizontal__link--focus--BackgroundColor);--pf-c-nav__link--active--BackgroundColor:var(--pf-c-nav--m-horizontal__link--active--BackgroundColor);--pf-c-nav__link--m-current--BackgroundColor:var(--pf-c-nav--m-horizontal__link--m-current--BackgroundColor);--pf-c-nav__link--before--BorderColor:var(--pf-c-nav--m-horizontal__link--before--BorderColor);--pf-c-nav__link--before--BorderBottomWidth:var(--pf-c-nav--m-horizontal__link--before--BorderWidth);--pf-c-nav__link--hover--before--BorderBottomWidth:var(--pf-c-nav--m-horizontal__link--hover--before--BorderWidth);--pf-c-nav__link--focus--before--BorderBottomWidth:var(--pf-c-nav--m-horizontal__link--focus--before--BorderWidth);--pf-c-nav__link--active--before--BorderBottomWidth:var(--pf-c-nav--m-horizontal__link--active--before--BorderWidth);--pf-c-nav__link--m-current--before--BorderBottomWidth:var(--pf-c-nav--m-horizontal__link--m-current--before--BorderWidth)}.pf-c-nav.pf-m-tertiary{--pf-c-nav__link--PaddingTop:var(--pf-c-nav--m-tertiary__link--PaddingTop);--pf-c-nav__link--PaddingRight:var(--pf-c-nav--m-tertiary__link--PaddingRight);--pf-c-nav__link--PaddingBottom:var(--pf-c-nav--m-tertiary__link--PaddingBottom);--pf-c-nav__link--PaddingLeft:var(--pf-c-nav--m-tertiary__link--PaddingLeft);--pf-c-nav__link--Right:var(--pf-c-nav--m-tertiary__link--Right);--pf-c-nav__link--Left:var(--pf-c-nav--m-tertiary__link--Left);--pf-c-nav__link--Color:var(--pf-c-nav--m-tertiary__link--Color);--pf-c-nav__link--hover--Color:var(--pf-c-nav--m-tertiary__link--hover--Color);--pf-c-nav__link--active--Color:var(--pf-c-nav--m-tertiary__link--active--Color);--pf-c-nav__link--focus--Color:var(--pf-c-nav--m-tertiary__link--focus--Color);--pf-c-nav__link--m-current--Color:var(--pf-c-nav--m-tertiary__link--m-current--Color);--pf-c-nav__link--BackgroundColor:var(--pf-c-nav--m-tertiary__link--BackgroundColor);--pf-c-nav__link--hover--BackgroundColor:var(--pf-c-nav--m-tertiary__link--hover--BackgroundColor);--pf-c-nav__link--focus--BackgroundColor:var(--pf-c-nav--m-tertiary__link--focus--BackgroundColor);--pf-c-nav__link--active--BackgroundColor:var(--pf-c-nav--m-tertiary__link--active--BackgroundColor);--pf-c-nav__link--m-current--BackgroundColor:var(--pf-c-nav--m-tertiary__link--m-current--BackgroundColor);--pf-c-nav__link--before--BorderColor:var(--pf-c-nav--m-tertiary__link--before--BorderColor);--pf-c-nav__link--before--BorderBottomWidth:var(--pf-c-nav--m-tertiary__link--before--BorderWidth);--pf-c-nav__link--hover--before--BorderBottomWidth:var(--pf-c-nav--m-tertiary__link--hover--before--BorderWidth);--pf-c-nav__link--focus--before--BorderBottomWidth:var(--pf-c-nav--m-tertiary__link--focus--before--BorderWidth);--pf-c-nav__link--active--before--BorderBottomWidth:var(--pf-c-nav--m-tertiary__link--active--before--BorderWidth);--pf-c-nav__link--m-current--before--BorderBottomWidth:var(--pf-c-nav--m-tertiary__link--m-current--before--BorderWidth);--pf-c-nav__scroll-button--Color:var(--pf-c-nav--m-tertiary__scroll-button--Color);--pf-c-nav__scroll-button--hover--Color:var(--pf-c-nav--m-tertiary__scroll-button--hover--Color);--pf-c-nav__scroll-button--focus--Color:var(--pf-c-nav--m-tertiary__scroll-button--focus--Color);--pf-c-nav__scroll-button--active--Color:var(--pf-c-nav--m-tertiary__scroll-button--active--Color);--pf-c-nav__scroll-button--disabled--Color:var(--pf-c-nav--m-tertiary__scroll-button--disabled--Color);--pf-c-nav__scroll-button--before--BorderColor:var(--pf-c-nav--m-tertiary__scroll-button--before--BorderColor);--pf-c-nav__scroll-button--disabled--before--BorderColor:var(--pf-c-nav--m-tertiary__scroll-button--disabled--before--BorderColor)}.pf-c-nav .pf-c-divider{--pf-c-divider--after--BackgroundColor:var(--pf-c-nav--c-divider--BackgroundColor);padding-right:var(--pf-c-nav--c-divider--PaddingRight);padding-left:var(--pf-c-nav--c-divider--PaddingLeft);margin-top:var(--pf-c-nav--c-divider--MarginTop);margin-bottom:var(--pf-c-nav--c-divider--MarginBottom)}.pf-c-nav.pf-m-scrollable .pf-c-nav__scroll-button{opacity:1}.pf-c-nav.pf-m-scrollable .pf-c-nav__scroll-button:first-of-type{margin-right:0;transform:translateX(0)}.pf-c-nav.pf-m-scrollable .pf-c-nav__scroll-button:nth-of-type(2){margin-left:0;transform:translateX(0)}.pf-c-nav__list{display:block}.pf-c-nav__item{position:relative;margin-top:var(--pf-c-nav__item--MarginTop)}.pf-c-nav__item.pf-m-expandable{--pf-c-nav__link--before--BorderBottomWidth:0}.pf-c-nav__item.pf-m-expandable:before{position:absolute;right:0;bottom:calc(var(--pf-c-nav__item--before--BorderWidth)*-1);left:0;content:"";border-bottom:var(--pf-c-nav__item--before--BorderWidth) solid var(--pf-c-nav__item--before--BorderColor)}.pf-c-nav__link{position:relative;display:flex;align-items:baseline;padding:var(--pf-c-nav__link--PaddingTop) var(--pf-c-nav__link--PaddingRight) var(--pf-c-nav__link--PaddingBottom) var(--pf-c-nav__link--PaddingLeft);font-size:var(--pf-c-nav__link--FontSize);font-weight:var(--pf-c-nav__link--FontWeight);color:var(--pf-c-nav__link--Color);background-color:var(--pf-c-nav__link--BackgroundColor);outline-offset:var(--pf-c-nav__link--OutlineOffset)}.pf-c-nav__link:after,.pf-c-nav__link:before{position:absolute;content:"";border:0 solid}.pf-c-nav__link:before{right:0;bottom:calc(var(--pf-c-nav__link--before--BorderBottomWidth)*-1);left:0;border-color:var(--pf-c-nav__link--before--BorderColor);border-bottom-width:var(--pf-c-nav__link--before--BorderBottomWidth)}.pf-c-nav__link:after{top:0;bottom:0;left:0;border:0 solid;border-color:var(--pf-c-nav__link--after--BorderColor);border-left:var(--pf-c-nav__link--after--BorderLeftWidth) solid var(--pf-c-nav__link--after--BorderColor)}.pf-c-nav__link:hover{color:var(--pf-c-nav__link--hover--Color);background-color:var(--pf-c-nav__link--hover--BackgroundColor)}.pf-c-nav__link:hover:before{border-bottom-width:var(--pf-c-nav__link--hover--before--BorderBottomWidth)}.pf-c-nav__link:hover:after{border-color:var(--pf-c-nav__link--hover--after--BorderColor);border-left-width:var(--pf-c-nav__link--hover--after--BorderLeftWidth)}.pf-c-nav__link:focus{color:var(--pf-c-nav__link--focus--Color);background-color:var(--pf-c-nav__link--focus--BackgroundColor)}.pf-c-nav__link:focus:before{border-bottom-width:var(--pf-c-nav__link--focus--before--BorderBottomWidth)}.pf-c-nav__link:focus:after{border-color:var(--pf-c-nav__link--focus--after--BorderColor);border-left-width:var(--pf-c-nav__link--focus--after--BorderLeftWidth)}.pf-c-nav__link:active{color:var(--pf-c-nav__link--active--Color);background-color:var(--pf-c-nav__link--active--BackgroundColor)}.pf-c-nav__link:active:before{border-bottom-width:var(--pf-c-nav__link--active--before--BorderBottomWidth)}.pf-c-nav__link:active:after{border-color:var(--pf-c-nav__link--active--after--BorderColor);border-left-width:var(--pf-c-nav__link--active--after--BorderLeftWidth)}.pf-c-nav__item.pf-m-current:not(.pf-m-expanded) .pf-c-nav__link,.pf-c-nav__link.pf-m-current,.pf-c-nav__link.pf-m-current:hover{color:var(--pf-c-nav__link--m-current--Color);background-color:var(--pf-c-nav__link--m-current--BackgroundColor)}.pf-c-nav__item.pf-m-current:not(.pf-m-expanded) .pf-c-nav__link:before,.pf-c-nav__link.pf-m-current:before,.pf-c-nav__link.pf-m-current:hover:before{border-bottom-width:var(--pf-c-nav__link--m-current--before--BorderBottomWidth)}.pf-c-nav__item.pf-m-current:not(.pf-m-expanded) .pf-c-nav__link:after,.pf-c-nav__link.pf-m-current:after,.pf-c-nav__link.pf-m-current:hover:after{border-color:var(--pf-c-nav__link--m-current--after--BorderColor);border-left-width:var(--pf-c-nav__link--m-current--after--BorderLeftWidth)}.pf-c-nav__link,.pf-c-nav__link:active,.pf-c-nav__link:focus,.pf-c-nav__link:hover{width:100%;text-decoration:none;border:none}.pf-c-nav__subnav{--pf-c-nav__link--PaddingTop:var(--pf-c-nav__subnav__link--PaddingTop);--pf-c-nav__link--PaddingRight:var(--pf-c-nav__subnav__link--PaddingRight);--pf-c-nav__link--PaddingBottom:var(--pf-c-nav__subnav__link--PaddingBottom);--pf-c-nav__link--PaddingLeft:var(--pf-c-nav__subnav__link--PaddingLeft);--pf-c-nav__link--FontSize:var(--pf-c-nav__subnav__link--FontSize);--pf-c-nav__link--hover--after--BorderColor:var(--pf-c-nav__subnav__link--hover--after--BorderColor);--pf-c-nav__link--focus--after--BorderColor:var(--pf-c-nav__subnav__link--focus--after--BorderColor);--pf-c-nav__link--active--after--BorderColor:var(--pf-c-nav__subnav__link--active--after--BorderColor);--pf-c-nav__link--m-current--after--BorderColor:var(--pf-c-nav__subnav__link--m-current--after--BorderColor);--pf-c-nav__link--hover--after--BorderLeftWidth:var(--pf-c-nav__subnav__link--hover--after--BorderWidth);--pf-c-nav__link--focus--after--BorderLeftWidth:var(--pf-c-nav__subnav__link--focus--after--BorderWidth);--pf-c-nav__link--active--after--BorderLeftWidth:var(--pf-c-nav__subnav__link--active--after--BorderWidth);--pf-c-nav__link--m-current--after--BorderLeftWidth:var(--pf-c-nav__subnav__link--m-current--after--BorderWidth);--pf-c-nav--c-divider--PaddingRight:var(--pf-c-nav__subnav--c-divider--PaddingRight);--pf-c-nav--c-divider--PaddingLeft:var(--pf-c-nav__subnav--c-divider--PaddingLeft);max-height:var(--pf-c-nav__subnav--MaxHeight);padding-bottom:var(--pf-c-nav__subnav--PaddingBottom);padding-left:var(--pf-c-nav__subnav--PaddingLeft);transition:var(--pf-c-nav--Transition);scrollbar-width:none;-ms-overflow-style:-ms-autohiding-scrollbar}.pf-c-nav__item.pf-m-expanded .pf-c-nav__subnav{--pf-c-nav__subnav--MaxHeight:var(--pf-c-nav__item--m-expanded__subnav--MaxHeight);overflow-y:auto;opacity:1}.pf-c-nav__subnav::-webkit-scrollbar{display:none}.pf-c-nav__toggle{flex:none;padding-right:var(--pf-c-nav__toggle--PaddingRight);padding-left:var(--pf-c-nav__toggle--PaddingLeft);margin-left:auto;font-size:var(--pf-c-nav__toggle--FontSize);line-height:1}.pf-c-nav__toggle-icon{display:inline-block;transition:var(--pf-c-nav__toggle-icon--Transition)}.pf-c-nav__item.pf-m-expanded .pf-c-nav__toggle-icon{transform:rotate(var(--pf-c-nav__item--m-expanded__toggle-icon--Rotate))}.pf-c-nav__section{--pf-c-nav__item--MarginTop:var(--pf-c-nav__section__item--MarginTop);--pf-c-nav__link--PaddingTop:var(--pf-c-nav__section__link--PaddingTop);--pf-c-nav__link--PaddingRight:var(--pf-c-nav__section__link--PaddingRight);--pf-c-nav__link--PaddingBottom:var(--pf-c-nav__section__link--PaddingBottom);--pf-c-nav__link--PaddingLeft:var(--pf-c-nav__section__link--PaddingLeft);--pf-c-nav__link--FontSize:var(--pf-c-nav__section__link--FontSize);--pf-c-nav__link--before--BorderBottomWidth:var(--pf-c-nav__section__link--before--BorderBottomWidth);--pf-c-nav__link--hover--after--BorderColor:var(--pf-c-nav__section__link--hover--after--BorderColor);--pf-c-nav__link--focus--after--BorderColor:var(--pf-c-nav__section__link--focus--after--BorderColor);--pf-c-nav__link--active--after--BorderColor:var(--pf-c-nav__section__link--active--after--BorderColor);--pf-c-nav__link--m-current--after--BorderColor:var(--pf-c-nav__section__link--m-current--after--BorderColor);--pf-c-nav__link--hover--after--BorderLeftWidth:var(--pf-c-nav__section__link--hover--after--BorderWidth);--pf-c-nav__link--focus--after--BorderLeftWidth:var(--pf-c-nav__section__link--focus--after--BorderWidth);--pf-c-nav__link--active--after--BorderLeftWidth:var(--pf-c-nav__section__link--active--after--BorderWidth);--pf-c-nav__link--m-current--after--BorderLeftWidth:var(--pf-c-nav__section__link--m-current--after--BorderWidth);margin-top:var(--pf-c-nav__section--MarginTop);--pf-c-nav--c-divider--MarginBottom:0}.pf-c-nav__section+.pf-c-nav__section{--pf-c-nav__section--MarginTop:var(--pf-c-nav__section--section--MarginTop)}.pf-c-nav__section-title{padding:var(--pf-c-nav__section-title--PaddingTop) var(--pf-c-nav__section-title--PaddingRight) var(--pf-c-nav__section-title--PaddingBottom) var(--pf-c-nav__section-title--PaddingLeft);font-size:var(--pf-c-nav__section-title--FontSize);color:var(--pf-c-nav__section-title--Color);border-bottom:var(--pf-c-nav__section-title--BorderBottomWidth) solid var(--pf-c-nav__section-title--BorderBottomColor)}.pf-c-nav__scroll-button{flex:none;width:var(--pf-c-nav__scroll-button--Width);color:var(--pf-c-nav__scroll-button--Color);background-color:var(--pf-c-nav__scroll-button--BackgroundColor);border:0;outline-offset:var(--pf-c-nav__scroll-button--OutlineOffset);opacity:0;transition:var(--pf-c-nav__scroll-button--Transition)}.pf-c-nav__scroll-button:before{position:absolute;top:0;bottom:0;content:"";border:solid var(--pf-c-nav__scroll-button--before--BorderColor);border-left-width:var(--pf-c-nav__scroll-button--before--BorderLeftWidth);border-bottom-width:0;border-right-width:var(--pf-c-nav__scroll-button--before--BorderRightWidth);border-top-width:0}.pf-c-nav__scroll-button:hover{color:var(--pf-c-nav__scroll-button--hover--Color)}.pf-c-nav__scroll-button:focus{color:var(--pf-c-nav__scroll-button--focus--Color)}.pf-c-nav__scroll-button:active{color:var(--pf-c-nav__scroll-button--active--Color)}.pf-c-nav__scroll-button:disabled{color:var(--pf-c-nav__scroll-button--disabled--Color);border-color:var(--pf-c-nav__scroll-button--disabled--before--BorderColor)}.pf-c-nav__scroll-button:first-of-type{--pf-c-nav__scroll-button--before--BorderRightWidth:var(--pf-c-nav__scroll-button--before--BorderWidth);margin-right:calc(var(--pf-c-nav__scroll-button--Width)*-1);transform:translateX(-100%)}.pf-c-nav__scroll-button:first-of-type:before{right:0}.pf-c-nav__scroll-button:nth-of-type(2){--pf-c-nav__scroll-button--before--BorderLeftWidth:var(--pf-c-nav__scroll-button--before--BorderWidth);margin-left:calc(var(--pf-c-nav__scroll-button--Width)*-1);transform:translateX(100%)}.pf-c-nav__scroll-button:nth-of-type(2):before{left:0}.pf-c-notification-badge{--pf-c-notification-badge--PaddingTop:var(--pf-global--spacer--form-element);--pf-c-notification-badge--PaddingRight:var(--pf-global--spacer--md);--pf-c-notification-badge--PaddingBottom:var(--pf-global--spacer--form-element);--pf-c-notification-badge--PaddingLeft:var(--pf-global--spacer--md);--pf-c-notification-badge--MarginTop:calc(-1*var(--pf-global--spacer--form-element));--pf-c-notification-badge--MarginRight:calc(-1*var(--pf-global--spacer--md));--pf-c-notification-badge--MarginBottom:calc(-1*var(--pf-global--spacer--form-element));--pf-c-notification-badge--MarginLeft:calc(-1*var(--pf-global--spacer--md));--pf-c-notification-badge--after--BorderColor:transparent;--pf-c-notification-badge--after--BorderRadius:var(--pf-global--BorderRadius--sm);--pf-c-notification-badge--after--BorderWidth:0;--pf-c-notification-badge--after--Top:0;--pf-c-notification-badge--after--Right:0;--pf-c-notification-badge--after--Width:auto;--pf-c-notification-badge--after--Height:auto;--pf-c-notification-badge--after--BackgroundColor:transparent;--pf-c-notification-badge--after--TranslateX:0;--pf-c-notification-badge--after--TranslateY:0;--pf-c-notification-badge__i--Width:auto;--pf-c-notification-badge__i--Height:auto;--pf-c-notification-badge--m-read--after--BorderColor:transparent;--pf-c-notification-badge--m-read--after--BackgroundColor:transparent;--pf-c-notification-badge--m-unread--Color:var(--pf-global--Color--light-100);--pf-c-notification-badge--m-unread--after--BackgroundColor:var(--pf-global--active-color--100);--pf-c-notification-badge--m-unread--hover--after--BackgroundColor:var(--pf-global--primary-color--200);--pf-c-notification-badge--m-attention--Color:var(--pf-global--Color--light-100);--pf-c-notification-badge--m-attention--after--BackgroundColor:var(--pf-global--danger-color--100);--pf-c-notification-badge--m-attention--hover--after--BackgroundColor:var(--pf-global--danger-color--200);--pf-c-notification-badge__count--MarginLeft:var(--pf-global--spacer--xs);--pf-c-notification-badge--pf-icon-attention-bell--LineHeight:var(--pf-global--LineHeight--sm);position:relative;display:inline-block;padding:var(--pf-c-notification-badge--PaddingTop) var(--pf-c-notification-badge--PaddingRight) var(--pf-c-notification-badge--PaddingBottom) var(--pf-c-notification-badge--PaddingLeft);margin:var(--pf-c-notification-badge--MarginTop) var(--pf-c-notification-badge--MarginRight) var(--pf-c-notification-badge--MarginBottom) var(--pf-c-notification-badge--MarginLeft);background-color:var(--pf-c-notification-badge--after--BackgroundColor);border-radius:var(--pf-c-notification-badge--after--BorderRadius)}.pf-c-notification-badge:before{position:absolute;top:var(--pf-c-notification-badge--after--Top);right:var(--pf-c-notification-badge--after--Right);bottom:0;left:0;width:var(--pf-c-notification-badge--after--Width);height:var(--pf-c-notification-badge--after--Height);content:"";border:var(--pf-c-notification-badge--after--BorderWidth) solid var(--pf-c-notification-badge--after--BorderColor);border-radius:var(--pf-c-notification-badge--after--BorderRadius);transform:translate(var(--pf-c-notification-badge--after--TranslateX),var(--pf-c-notification-badge--after--TranslateY))}.pf-c-notification-badge>i{width:var(--pf-c-notification-badge__i--Width);height:var(--pf-c-notification-badge__i--Height)}.pf-c-notification-badge>*{position:relative}.pf-c-notification-badge .pf-icon-attention-bell,.pf-c-notification-badge .pf-icon-bell{display:inline-block;line-height:var(--pf-c-notification-badge--pf-icon-attention-bell--LineHeight)}.pf-c-notification-badge .pf-icon-attention-bell:before,.pf-c-notification-badge .pf-icon-bell:before{vertical-align:bottom}.pf-c-notification-badge.pf-m-read{--pf-c-notification-badge--after--BackgroundColor:var(--pf-c-notification-badge--m-read--after--BackgroundColor);--pf-c-notification-badge--after--BorderColor:var(--pf-c-notification-badge--m-read--after--BorderColor)}.pf-c-notification-badge.pf-m-unread{--pf-c-notification-badge--after--BackgroundColor:var(--pf-c-notification-badge--m-unread--after--BackgroundColor);color:var(--pf-c-notification-badge--m-unread--Color)}.pf-c-notification-badge.pf-m-unread:hover{--pf-c-notification-badge--after--BackgroundColor:var(--pf-c-notification-badge--m-unread--hover--after--BackgroundColor)}.pf-c-notification-badge.pf-m-attention{--pf-c-notification-badge--after--BackgroundColor:var(--pf-c-notification-badge--m-attention--after--BackgroundColor);color:var(--pf-c-notification-badge--m-attention--Color)}.pf-c-notification-badge.pf-m-attention:hover{--pf-c-notification-badge--after--BackgroundColor:var(--pf-c-notification-badge--m-attention--hover--after--BackgroundColor)}.pf-c-notification-badge__count{margin-left:var(--pf-c-notification-badge__count--MarginLeft)}.pf-c-notification-drawer{--pf-c-notification-drawer--BackgroundColor:var(--pf-global--BackgroundColor--200);--pf-c-notification-drawer__header--PaddingTop:var(--pf-global--spacer--md);--pf-c-notification-drawer__header--PaddingRight:var(--pf-global--spacer--md);--pf-c-notification-drawer__header--PaddingBottom:var(--pf-global--spacer--md);--pf-c-notification-drawer__header--PaddingLeft:var(--pf-global--spacer--md);--pf-c-notification-drawer__header--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-notification-drawer__header--BoxShadow:var(--pf-global--BoxShadow--sm-bottom);--pf-c-notification-drawer__header--ZIndex:var(--pf-global--ZIndex--sm);--pf-c-notification-drawer__header-title--FontSize:var(--pf-global--FontSize--xl);--pf-c-notification-drawer__header-status--MarginLeft:var(--pf-global--spacer--md);--pf-c-notification-drawer__body--ZIndex:var(--pf-global--ZIndex--xs);--pf-c-notification-drawer__list-item--PaddingTop:var(--pf-global--spacer--md);--pf-c-notification-drawer__list-item--PaddingRight:var(--pf-global--spacer--md);--pf-c-notification-drawer__list-item--PaddingBottom:var(--pf-global--spacer--md);--pf-c-notification-drawer__list-item--PaddingLeft:var(--pf-global--spacer--md);--pf-c-notification-drawer__list-item--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-notification-drawer__list-item--BoxShadow:inset var(--pf-global--BoxShadow--sm-bottom);--pf-c-notification-drawer__list-item--BorderBottomWidth:var(--pf-global--BorderWidth--sm);--pf-c-notification-drawer__list-item--BorderBottomColor:transparent;--pf-c-notification-drawer__list-item--OutlineOffset:-0.25rem;--pf-c-notification-drawer__list-item--before--Width:var(--pf-global--BorderWidth--lg);--pf-c-notification-drawer__list-item--before--Top:0;--pf-c-notification-drawer__list-item--before--Bottom:calc(var(--pf-c-notification-drawer__list-item--BorderBottomWidth)*-1);--pf-c-notification-drawer__list-item--m-info__list-item-header-icon--Color:var(--pf-global--info-color--100);--pf-c-notification-drawer__list-item--m-info__list-item--before--BackgroundColor:var(--pf-global--info-color--100);--pf-c-notification-drawer__list-item--m-warning__list-item-header-icon--Color:var(--pf-global--warning-color--100);--pf-c-notification-drawer__list-item--m-warning__list-item--before--BackgroundColor:var(--pf-global--warning-color--100);--pf-c-notification-drawer__list-item--m-danger__list-item-header-icon--Color:var(--pf-global--danger-color--100);--pf-c-notification-drawer__list-item--m-danger__list-item--before--BackgroundColor:var(--pf-global--danger-color--100);--pf-c-notification-drawer__list-item--m-success__list-item-header-icon--Color:var(--pf-global--success-color--100);--pf-c-notification-drawer__list-item--m-success__list-item--before--BackgroundColor:var(--pf-global--success-color--100);--pf-c-notification-drawer__list-item--m-default__list-item-header-icon--Color:var(--pf-global--default-color--200);--pf-c-notification-drawer__list-item--m-default__list-item--before--BackgroundColor:var(--pf-global--default-color--200);--pf-c-notification-drawer__list-item--m-read--BackgroundColor:var(--pf-global--BackgroundColor--200);--pf-c-notification-drawer__list-item--m-read--BorderBottomColor:var(--pf-global--BorderColor--100);--pf-c-notification-drawer__list-item--m-read--before--Top:calc(var(--pf-c-notification-drawer__list-item--BorderBottomWidth)*-1);--pf-c-notification-drawer__list-item--m-read--before--Bottom:0;--pf-c-notification-drawer__list-item--m-read--before--BackgroundColor:transparent;--pf-c-notification-drawer__list-item--list-item--m-read--before--Top:0;--pf-c-notification-drawer__list-item--list-item--m-read--BoxShadow:inset var(--pf-global--BoxShadow--sm-bottom);--pf-c-notification-drawer__list-item--m-hoverable--hover--ZIndex:var(--pf-global--ZIndex--xs);--pf-c-notification-drawer__list-item--m-hoverable--hover--BoxShadow:var(--pf-global--BoxShadow--md-top),var(--pf-global--BoxShadow--md-bottom);--pf-c-notification-drawer__list-item-header--MarginBottom:var(--pf-global--spacer--xs);--pf-c-notification-drawer__list-item-header-icon--Color:inherit;--pf-c-notification-drawer__list-item-header-icon--MarginRight:var(--pf-global--spacer--sm);--pf-c-notification-drawer__list-item-header-title--FontWeight:var(--pf-global--FontWeight--bold);--pf-c-notification-drawer__list-item-header-title--max-lines:1;--pf-c-notification-drawer__list-item--m-read__list-item-header-title--FontWeight:var(--pf-global--FontWeight--normal);--pf-c-notification-drawer__list-item-description--MarginBottom:var(--pf-global--spacer--sm);--pf-c-notification-drawer__list-item-timestamp--Color:var(--pf-global--Color--200);--pf-c-notification-drawer__list-item-timestamp--FontSize:var(--pf-global--FontSize--sm);--pf-c-notification-drawer__group--m-expanded--group--BorderTopWidth:var(--pf-global--BorderWidth--sm);--pf-c-notification-drawer__group--m-expanded--group--BorderTopColor:var(--pf-global--BorderColor--100);--pf-c-notification-drawer__group--m-expanded--MinHeight:0;--pf-c-notification-drawer__group-toggle--PaddingTop:var(--pf-global--spacer--md);--pf-c-notification-drawer__group-toggle--PaddingRight:var(--pf-global--spacer--md);--pf-c-notification-drawer__group-toggle--PaddingBottom:var(--pf-global--spacer--md);--pf-c-notification-drawer__group-toggle--PaddingLeft:var(--pf-global--spacer--md);--pf-c-notification-drawer__group-toggle--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-notification-drawer__group-toggle--BorderColor:var(--pf-global--BorderColor--100);--pf-c-notification-drawer__group-toggle--BorderBottomWidth:var(--pf-global--BorderWidth--sm);--pf-c-notification-drawer__group-toggle--OutlineOffset:-0.25rem;--pf-c-notification-drawer__group-toggle-title--MarginRight:var(--pf-global--spacer--md);--pf-c-notification-drawer__group-toggle-title--max-lines:1;--pf-c-notification-drawer__group-toggle-count--MarginRight:var(--pf-global--spacer--md);--pf-c-notification-drawer__group-toggle-icon--MarginRight:var(--pf-global--spacer--md);--pf-c-notification-drawer__group-toggle-icon--Color:var(--pf-global--Color--200);--pf-c-notification-drawer__group-toggle-icon--Transition:.2s ease-in 0s;--pf-c-notification-drawer__group--m-expanded__group-toggle-icon--Rotate:90deg;display:flex;flex-direction:column;height:100%;background-color:var(--pf-c-notification-drawer--BackgroundColor)}.pf-c-notification-drawer__header{position:relative;z-index:var(--pf-c-notification-drawer__header--ZIndex);display:flex;flex-shrink:0;align-items:baseline;padding:var(--pf-c-notification-drawer__header--PaddingTop) var(--pf-c-notification-drawer__header--PaddingRight) var(--pf-c-notification-drawer__header--PaddingBottom) var(--pf-c-notification-drawer__header--PaddingLeft);background-color:var(--pf-c-notification-drawer__header--BackgroundColor);box-shadow:var(--pf-c-notification-drawer__header--BoxShadow)}.pf-c-notification-drawer__header-title{font-size:var(--pf-c-notification-drawer__header-title--FontSize)}.pf-c-notification-drawer__header-status{margin-left:var(--pf-c-notification-drawer__header-status--MarginLeft)}.pf-c-notification-drawer__header-action{display:flex;align-items:center;margin-left:auto}.pf-c-notification-drawer__body{overflow-y:auto;box-shadow:var(--pf-c-notification-drawer__body--ZIndex)}.pf-c-notification-drawer__list-item{position:relative;display:grid;grid-template-columns:1fr auto;padding:var(--pf-c-notification-drawer__list-item--PaddingTop) var(--pf-c-notification-drawer__list-item--PaddingRight) var(--pf-c-notification-drawer__list-item--PaddingBottom) var(--pf-c-notification-drawer__list-item--PaddingLeft);background-color:var(--pf-c-notification-drawer__list-item--BackgroundColor);border-bottom:var(--pf-c-notification-drawer__list-item--BorderBottomWidth) solid var(--pf-c-notification-drawer__list-item--BorderBottomColor);outline-offset:var(--pf-c-notification-drawer__list-item--OutlineOffset);box-shadow:var(--pf-c-notification-drawer__list-item--BoxShadow)}.pf-c-notification-drawer__list-item.pf-m-read,.pf-c-notification-drawer__list-item:first-child{--pf-c-notification-drawer__list-item--BoxShadow:none}.pf-c-notification-drawer__list-item:not(.pf-m-read)+.pf-c-notification-drawer__list-item.pf-m-read{--pf-c-notification-drawer__list-item--BoxShadow:var(--pf-c-notification-drawer__list-item--list-item--m-read--BoxShadow);--pf-c-notification-drawer__list-item--before--Top:var(--pf-c-notification-drawer__list-item--list-item--m-read--before--Top)}.pf-c-notification-drawer__list-item:before{position:absolute;top:var(--pf-c-notification-drawer__list-item--before--Top);bottom:var(--pf-c-notification-drawer__list-item--before--Bottom);width:var(--pf-c-notification-drawer__list-item--before--Width);content:"";background-color:var(--pf-c-notification-drawer__list-item--before--BackgroundColor)}.pf-c-notification-drawer__list-item.pf-m-info{--pf-c-notification-drawer__list-item--before--BackgroundColor:var(--pf-c-notification-drawer__list-item--m-info__list-item--before--BackgroundColor);--pf-c-notification-drawer__list-item-header-icon--Color:var(--pf-c-notification-drawer__list-item--m-info__list-item-header-icon--Color)}.pf-c-notification-drawer__list-item.pf-m-warning{--pf-c-notification-drawer__list-item--before--BackgroundColor:var(--pf-c-notification-drawer__list-item--m-warning__list-item--before--BackgroundColor);--pf-c-notification-drawer__list-item-header-icon--Color:var(--pf-c-notification-drawer__list-item--m-warning__list-item-header-icon--Color)}.pf-c-notification-drawer__list-item.pf-m-danger{--pf-c-notification-drawer__list-item--before--BackgroundColor:var(--pf-c-notification-drawer__list-item--m-danger__list-item--before--BackgroundColor);--pf-c-notification-drawer__list-item-header-icon--Color:var(--pf-c-notification-drawer__list-item--m-danger__list-item-header-icon--Color)}.pf-c-notification-drawer__list-item.pf-m-success{--pf-c-notification-drawer__list-item--before--BackgroundColor:var(--pf-c-notification-drawer__list-item--m-success__list-item--before--BackgroundColor);--pf-c-notification-drawer__list-item-header-icon--Color:var(--pf-c-notification-drawer__list-item--m-success__list-item-header-icon--Color)}.pf-c-notification-drawer__list-item.pf-m-default{--pf-c-notification-drawer__list-item--before--BackgroundColor:var(--pf-c-notification-drawer__list-item--m-default__list-item--before--BackgroundColor);--pf-c-notification-drawer__list-item-header-icon--Color:var(--pf-c-notification-drawer__list-item--m-default__list-item-header-icon--Color)}.pf-c-notification-drawer__list-item.pf-m-read{--pf-c-notification-drawer__list-item--BorderBottomColor:var(--pf-c-notification-drawer__list-item--m-read--BorderBottomColor);--pf-c-notification-drawer__list-item--BackgroundColor:var(--pf-c-notification-drawer__list-item--m-read--BackgroundColor);--pf-c-notification-drawer__list-item--before--Top:var(--pf-c-notification-drawer__list-item--m-read--before--Top);--pf-c-notification-drawer__list-item--before--Bottom:var(--pf-c-notification-drawer__list-item--m-read--before--Bottom);--pf-c-notification-drawer__list-item--before--BackgroundColor:var(--pf-c-notification-drawer__list-item--m-read--before--BackgroundColor);--pf-c-notification-drawer__list-item-header-title--FontWeight:var(--pf-c-notification-drawer__list-item--m-read__list-item-header-title--FontWeight);position:relative}.pf-c-notification-drawer__list-item.pf-m-hoverable{cursor:pointer}.pf-c-notification-drawer__list-item.pf-m-hoverable:hover{z-index:var(--pf-c-notification-drawer__list-item--m-hoverable--hover--ZIndex);box-shadow:var(--pf-c-notification-drawer__list-item--m-hoverable--hover--BoxShadow)}.pf-c-notification-drawer__list-item-header{display:flex;align-items:baseline;grid-column:1/2;grid-row:1/2;margin-bottom:var(--pf-c-notification-drawer__list-item-header--MarginBottom)}.pf-c-notification-drawer__list-item-header-icon{margin-right:var(--pf-c-notification-drawer__list-item-header-icon--MarginRight);color:var(--pf-c-notification-drawer__list-item-header-icon--Color)}.pf-c-notification-drawer__list-item-header-title{font-weight:var(--pf-c-notification-drawer__list-item-header-title--FontWeight);word-break:break-word}.pf-c-notification-drawer__list-item-header-title.pf-m-truncate{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:var(--pf-c-notification-drawer__list-item-header-title--max-lines);overflow:hidden}.pf-c-notification-drawer__list-item-action{grid-column:2/3;grid-row:1/3}.pf-c-notification-drawer__list-item-description{grid-row:2/3;grid-column:1/2;margin-bottom:var(--pf-c-notification-drawer__list-item-description--MarginBottom);word-break:break-word}.pf-c-notification-drawer__list-item-timestamp{grid-row:3/4;grid-column:1/2;font-size:var(--pf-c-notification-drawer__list-item-timestamp--FontSize);color:var(--pf-c-notification-drawer__list-item-timestamp--Color)}.pf-c-notification-drawer__group-list{display:flex;flex-direction:column}.pf-c-notification-drawer__group.pf-m-expanded{min-height:var(--pf-c-notification-drawer__group--m-expanded--MinHeight)}.pf-c-notification-drawer__group.pf-m-expanded+.pf-c-notification-drawer__group{border-top:var(--pf-c-notification-drawer__group--m-expanded--group--BorderTopWidth) solid var(--pf-c-notification-drawer__group--m-expanded--group--BorderTopColor)}.pf-c-notification-drawer__group .pf-c-notification-drawer__list-item:last-child{--pf-c-notification-drawer__list-item--BorderBottomWidth:0;--pf-c-notification-drawer__list-item--before--Bottom:0}.pf-c-notification-drawer__group-toggle{display:flex;align-items:baseline;width:100%;padding:var(--pf-c-notification-drawer__group-toggle--PaddingTop) var(--pf-c-notification-drawer__group-toggle--PaddingRight) var(--pf-c-notification-drawer__group-toggle--PaddingBottom) var(--pf-c-notification-drawer__group-toggle--PaddingLeft);background-color:var(--pf-c-notification-drawer__group-toggle--BackgroundColor);border:solid var(--pf-c-notification-drawer__group-toggle--BorderColor);border-left-width:0;border-bottom-width:var(--pf-c-notification-drawer__group-toggle--BorderBottomWidth);border-right-width:0;border-top-width:0;outline-offset:var(--pf-c-notification-drawer__group-toggle--OutlineOffset)}.pf-c-notification-drawer__group-toggle-title{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:var(--pf-c-notification-drawer__group-toggle-title--max-lines);overflow:hidden;margin-right:var(--pf-c-notification-drawer__group-toggle-title--MarginRight);text-align:left;word-break:break-word}.pf-c-notification-drawer__group-toggle-count{margin-right:var(--pf-c-notification-drawer__group-toggle-count--MarginRight);margin-left:auto}.pf-c-notification-drawer__group-toggle-icon{margin-right:var(--pf-c-notification-drawer__group-toggle-icon--MarginRight);color:var(--pf-c-notification-drawer__group-toggle-icon--Color);transition:var(--pf-c-notification-drawer__group-toggle-icon--Transition)}.pf-c-notification-drawer__group.pf-m-expanded .pf-c-notification-drawer__group-toggle-icon{transform:rotate(var(--pf-c-notification-drawer__group--m-expanded__group-toggle-icon--Rotate))}.pf-c-options-menu{--pf-c-options-menu__toggle--BackgroundColor:transparent;--pf-c-options-menu__toggle--PaddingTop:var(--pf-global--spacer--form-element);--pf-c-options-menu__toggle--PaddingRight:var(--pf-global--spacer--sm);--pf-c-options-menu__toggle--PaddingBottom:var(--pf-global--spacer--form-element);--pf-c-options-menu__toggle--PaddingLeft:var(--pf-global--spacer--sm);--pf-c-options-menu__toggle--MinWidth:var(--pf-global--target-size--MinWidth);--pf-c-options-menu__toggle--LineHeight:var(--pf-global--LineHeight--md);--pf-c-options-menu__toggle--BorderWidth:var(--pf-global--BorderWidth--sm);--pf-c-options-menu__toggle--BorderTopColor:var(--pf-global--BorderColor--300);--pf-c-options-menu__toggle--BorderRightColor:var(--pf-global--BorderColor--300);--pf-c-options-menu__toggle--BorderBottomColor:var(--pf-global--BorderColor--200);--pf-c-options-menu__toggle--BorderLeftColor:var(--pf-global--BorderColor--300);--pf-c-options-menu__toggle--Color:var(--pf-global--Color--100);--pf-c-options-menu__toggle--hover--BorderBottomColor:var(--pf-global--active-color--100);--pf-c-options-menu__toggle--active--BorderBottomWidth:var(--pf-global--BorderWidth--md);--pf-c-options-menu__toggle--active--BorderBottomColor:var(--pf-global--active-color--100);--pf-c-options-menu__toggle--focus--BorderBottomWidth:var(--pf-global--BorderWidth--md);--pf-c-options-menu__toggle--focus--BorderBottomColor:var(--pf-global--active-color--100);--pf-c-options-menu__toggle--expanded--BorderBottomWidth:var(--pf-global--BorderWidth--md);--pf-c-options-menu__toggle--expanded--BorderBottomColor:var(--pf-global--active-color--100);--pf-c-options-menu__toggle--disabled--BackgroundColor:var(--pf-global--disabled-color--300);--pf-c-options-menu__toggle--m-plain--Color:var(--pf-global--Color--200);--pf-c-options-menu__toggle--m-plain--hover--Color:var(--pf-global--Color--100);--pf-c-options-menu__toggle--m-plain--disabled--Color:var(--pf-global--disabled-color--200);--pf-c-options-menu__toggle-icon--MarginRight:var(--pf-global--spacer--sm);--pf-c-options-menu__toggle-icon--MarginLeft:var(--pf-global--spacer--md);--pf-c-options-menu--m-top--m-expanded__toggle-icon--Rotate:180deg;--pf-c-options-menu__toggle-button--BackgroundColor:transparent;--pf-c-options-menu__toggle-button--PaddingTop:var(--pf-global--spacer--form-element);--pf-c-options-menu__toggle-button--PaddingRight:var(--pf-global--spacer--sm);--pf-c-options-menu__toggle-button--PaddingBottom:var(--pf-global--spacer--form-element);--pf-c-options-menu__toggle-button--PaddingLeft:var(--pf-global--spacer--sm);--pf-c-options-menu__menu--BackgroundColor:var(--pf-global--BackgroundColor--light-100);--pf-c-options-menu__menu--BoxShadow:var(--pf-global--BoxShadow--md);--pf-c-options-menu__menu--PaddingTop:var(--pf-global--spacer--sm);--pf-c-options-menu__menu--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-options-menu__menu--Top:calc(100% + var(--pf-global--spacer--xs));--pf-c-options-menu__menu--ZIndex:var(--pf-global--ZIndex--sm);--pf-c-options-menu--m-top__menu--Top:0;--pf-c-options-menu--m-top__menu--TranslateY:calc(-100% - var(--pf-global--spacer--xs));--pf-c-options-menu__menu-item--BackgroundColor:transparent;--pf-c-options-menu__menu-item--Color:var(--pf-global--Color--100);--pf-c-options-menu__menu-item--FontSize:var(--pf-global--FontSize--md);--pf-c-options-menu__menu-item--PaddingTop:var(--pf-global--spacer--sm);--pf-c-options-menu__menu-item--PaddingRight:var(--pf-global--spacer--md);--pf-c-options-menu__menu-item--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-options-menu__menu-item--PaddingLeft:var(--pf-global--spacer--md);--pf-c-options-menu__menu-item--disabled--Color:var(--pf-global--Color--dark-200);--pf-c-options-menu__menu-item--hover--BackgroundColor:var(--pf-global--BackgroundColor--light-300);--pf-c-options-menu__menu-item--disabled--BackgroundColor:transparent;--pf-c-options-menu__menu-item-icon--Color:var(--pf-global--active-color--100);--pf-c-options-menu__menu-item-icon--FontSize:var(--pf-global--icon--FontSize--sm);--pf-c-options-menu__menu-item-icon--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-options-menu__group--group--PaddingTop:var(--pf-global--spacer--sm);--pf-c-options-menu__group-title--PaddingTop:var(--pf-global--spacer--sm);--pf-c-options-menu__group-title--PaddingRight:var(--pf-c-options-menu__menu-item--PaddingRight);--pf-c-options-menu__group-title--PaddingBottom:var(--pf-c-options-menu__menu-item--PaddingBottom);--pf-c-options-menu__group-title--PaddingLeft:var(--pf-c-options-menu__menu-item--PaddingLeft);--pf-c-options-menu__group-title--FontSize:var(--pf-global--FontSize--sm);--pf-c-options-menu__group-title--FontWeight:var(--pf-global--FontWeight--semi-bold);--pf-c-options-menu__group-title--Color:var(--pf-global--Color--dark-200);--pf-c-options-menu--c-divider--MarginTop:var(--pf-global--spacer--sm);--pf-c-options-menu--c-divider--MarginBottom:var(--pf-global--spacer--sm);position:relative;display:inline-block;max-width:100%}.pf-c-options-menu .pf-c-divider{margin-top:var(--pf-c-options-menu--c-divider--MarginTop);margin-bottom:var(--pf-c-options-menu--c-divider--MarginBottom)}.pf-c-options-menu .pf-c-divider:last-child{--pf-c-options-menu--c-divider--MarginBottom:0}.pf-c-options-menu.pf-m-text:not(.pf-m-plain) .pf-c-options-menu__toggle-button:before,.pf-c-options-menu__toggle:not(.pf-m-plain):before{position:absolute;top:0;right:0;bottom:0;left:0;content:"";border:var(--pf-c-options-menu__toggle--BorderWidth) solid;border-color:var(--pf-c-options-menu__toggle--BorderTopColor) var(--pf-c-options-menu__toggle--BorderRightColor) var(--pf-c-options-menu__toggle--BorderBottomColor) var(--pf-c-options-menu__toggle--BorderLeftColor)}.pf-c-options-menu.pf-m-text:not(.pf-m-plain) .pf-c-options-menu__toggle-button:hover:before,.pf-c-options-menu__toggle:not(.pf-m-plain):hover:before{--pf-c-options-menu__toggle--BorderBottomColor:var(--pf-c-options-menu__toggle--hover--BorderBottomColor)}.pf-c-options-menu.pf-m-text:not(.pf-m-plain) .pf-c-options-menu__toggle-button.pf-m-active:before,.pf-c-options-menu.pf-m-text:not(.pf-m-plain) .pf-c-options-menu__toggle-button:active:before,.pf-c-options-menu__toggle:not(.pf-m-plain).pf-m-active:before,.pf-c-options-menu__toggle:not(.pf-m-plain):active:before{--pf-c-options-menu__toggle--BorderBottomColor:var(--pf-c-options-menu__toggle--active--BorderBottomColor);border-bottom-width:var(--pf-c-options-menu__toggle--active--BorderBottomWidth)}.pf-c-options-menu.pf-m-text:not(.pf-m-plain) .pf-c-options-menu__toggle-button:focus:before,.pf-c-options-menu__toggle:not(.pf-m-plain):focus:before{--pf-c-options-menu__toggle--BorderBottomColor:var(--pf-c-options-menu__toggle--focus--BorderBottomColor);border-bottom-width:var(--pf-c-options-menu__toggle--focus--BorderBottomWidth)}.pf-c-options-menu__toggle{position:relative;display:flex;align-items:center;justify-content:space-between;min-width:var(--pf-c-options-menu__toggle--MinWidth);max-width:100%;padding-left:var(--pf-c-options-menu__toggle--PaddingLeft);line-height:var(--pf-c-options-menu__toggle--LineHeight);color:var(--pf-c-options-menu__toggle--Color);background-color:var(--pf-c-options-menu__toggle--BackgroundColor);border:none}.pf-c-options-menu__toggle:not(.pf-m-text){padding-top:var(--pf-c-options-menu__toggle--PaddingTop);padding-right:var(--pf-c-options-menu__toggle--PaddingRight);padding-bottom:var(--pf-c-options-menu__toggle--PaddingBottom)}.pf-c-options-menu.pf-m-expanded>.pf-c-options-menu__toggle:before{--pf-c-options-menu__toggle--BorderBottomColor:var(--pf-c-options-menu__toggle--expanded--BorderBottomColor);border-bottom-width:var(--pf-c-options-menu__toggle--expanded--BorderBottomWidth)}.pf-c-options-menu__toggle.pf-m-plain:not(.pf-m-text){justify-content:center;color:var(--pf-c-options-menu__toggle--m-plain--Color)}.pf-c-options-menu__toggle.pf-m-plain .pf-c-options-menu__toggle-button-icon{line-height:var(--pf-c-options-menu__toggle--LineHeight)}.pf-c-options-menu.pf-m-expanded>.pf-c-options-menu__toggle.pf-m-plain,.pf-c-options-menu__toggle.pf-m-plain.pf-m-active,.pf-c-options-menu__toggle.pf-m-plain:active,.pf-c-options-menu__toggle.pf-m-plain:focus,.pf-c-options-menu__toggle.pf-m-plain:hover{--pf-c-options-menu__toggle--m-plain--Color:var(--pf-c-options-menu__toggle--m-plain--hover--Color)}.pf-c-options-menu__toggle.pf-m-plain.pf-m-disabled,.pf-c-options-menu__toggle.pf-m-plain:disabled{--pf-c-options-menu__toggle--m-plain--Color:var(--pf-c-options-menu__toggle--m-plain--disabled--Color)}.pf-c-options-menu__toggle.pf-m-disabled,.pf-c-options-menu__toggle:disabled{pointer-events:none}.pf-c-options-menu__toggle.pf-m-disabled.pf-m-text,.pf-c-options-menu__toggle.pf-m-disabled:not(.pf-m-plain),.pf-c-options-menu__toggle:disabled.pf-m-text,.pf-c-options-menu__toggle:disabled:not(.pf-m-plain){--pf-c-options-menu__toggle--BackgroundColor:var(--pf-c-options-menu__toggle--disabled--BackgroundColor)}.pf-c-options-menu__toggle.pf-m-disabled:before,.pf-c-options-menu__toggle:disabled:before{border:0}.pf-c-options-menu__toggle-button-icon{position:relative}.pf-c-options-menu__toggle-button{padding:var(--pf-c-options-menu__toggle-button--PaddingTop) var(--pf-c-options-menu__toggle-button--PaddingRight) var(--pf-c-options-menu__toggle-button--PaddingBottom) var(--pf-c-options-menu__toggle-button--PaddingLeft);background-color:var(--pf-c-options-menu__toggle-button--BackgroundColor);border:0}.pf-c-options-menu__toggle-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pf-c-options-menu__toggle-icon{margin-right:var(--pf-c-options-menu__toggle-icon--MarginRight);margin-left:var(--pf-c-options-menu__toggle-icon--MarginLeft)}.pf-c-options-menu.pf-m-top.pf-m-expanded .pf-c-options-menu__toggle-icon{transform:rotate(var(--pf-c-options-menu--m-top--m-expanded__toggle-icon--Rotate))}.pf-c-options-menu__menu{position:absolute;top:var(--pf-c-options-menu__menu--Top);z-index:var(--pf-c-options-menu__menu--ZIndex);min-width:100%;padding-top:var(--pf-c-options-menu__menu--PaddingTop);padding-bottom:var(--pf-c-options-menu__menu--PaddingBottom);background-color:var(--pf-c-options-menu__menu--BackgroundColor);background-clip:padding-box;box-shadow:var(--pf-c-options-menu__menu--BoxShadow)}.pf-c-options-menu__menu.pf-m-align-right{right:0}.pf-c-options-menu.pf-m-top .pf-c-options-menu__menu{--pf-c-options-menu__menu--Top:var(--pf-c-options-menu--m-top__menu--Top);transform:translateY(var(--pf-c-options-menu--m-top__menu--TranslateY))}.pf-c-options-menu__menu-item{display:flex;align-items:baseline;width:100%;padding:var(--pf-c-options-menu__menu-item--PaddingTop) var(--pf-c-options-menu__menu-item--PaddingRight) var(--pf-c-options-menu__menu-item--PaddingBottom) var(--pf-c-options-menu__menu-item--PaddingLeft);font-size:var(--pf-c-options-menu__menu-item--FontSize);color:var(--pf-c-options-menu__menu-item--Color);white-space:nowrap;background-color:var(--pf-c-options-menu__menu-item--BackgroundColor);border:none}.pf-c-options-menu__menu-item:focus,.pf-c-options-menu__menu-item:hover{text-decoration:none;background-color:var(--pf-c-options-menu__menu-item--hover--BackgroundColor)}.pf-c-options-menu__menu-item.pf-m-disabled,.pf-c-options-menu__menu-item:disabled{color:var(--pf-c-options-menu__menu-item--disabled--Color);pointer-events:none;background-color:var(--pf-c-options-menu__menu-item--disabled--BackgroundColor)}.pf-c-options-menu__menu-item-icon{align-self:center;width:auto;padding-left:var(--pf-c-options-menu__menu-item-icon--PaddingLeft);margin-left:auto;font-size:var(--pf-c-options-menu__menu-item-icon--FontSize);color:var(--pf-c-options-menu__menu-item-icon--Color)}.pf-c-options-menu__group+.pf-c-options-menu__group{padding-top:var(--pf-c-options-menu__group--group--PaddingTop)}.pf-c-options-menu__group-title{padding:var(--pf-c-options-menu__group-title--PaddingTop) var(--pf-c-options-menu__group-title--PaddingRight) var(--pf-c-options-menu__group-title--PaddingBottom) var(--pf-c-options-menu__group-title--PaddingLeft);font-size:var(--pf-c-options-menu__group-title--FontSize);font-weight:var(--pf-c-options-menu__group-title--FontWeight);color:var(--pf-c-options-menu__group-title--Color)}.pf-c-overflow-menu{--pf-c-overflow-menu--spacer--base:var(--pf-global--spacer--md);--pf-c-overflow-menu--spacer:var(--pf-global--spacer--sm);--pf-c-overflow-menu__group--spacer:var(--pf-c-overflow-menu--spacer--base);--pf-c-overflow-menu__item--spacer:var(--pf-c-overflow-menu--spacer--base);--pf-c-overflow-menu--c-divider--m-vertical--spacer:var(--pf-c-overflow-menu--spacer--base);--pf-c-overflow-menu__group--m-button-group--spacer:var(--pf-c-overflow-menu--spacer--base);--pf-c-overflow-menu__group--m-button-group--space-items:var(--pf-global--spacer--sm);--pf-c-overflow-menu__group--m-icon-button-group--spacer:var(--pf-c-overflow-menu--spacer--base);--pf-c-overflow-menu__group--m-icon-button-group--space-items:0;display:inline-flex;align-items:center}.pf-c-overflow-menu__content,.pf-c-overflow-menu__group{display:flex;align-items:center}.pf-c-overflow-menu__group{--pf-c-overflow-menu--spacer:var(--pf-c-overflow-menu__group--spacer)}.pf-c-overflow-menu__group.pf-m-button-group{--pf-c-overflow-menu--spacer:var(--pf-c-overflow-menu__group--m-button-group--spacer)}.pf-c-overflow-menu__group.pf-m-button-group>*{--pf-c-overflow-menu--spacer:var(--pf-c-overflow-menu__group--m-button-group--space-items)}.pf-c-overflow-menu__group.pf-m-icon-button-group{--pf-c-overflow-menu--spacer:var(--pf-c-overflow-menu__group--m-icon-button-group--spacer)}.pf-c-overflow-menu__group.pf-m-icon-button-group>*{--pf-c-overflow-menu--spacer:var(--pf-c-overflow-menu__group--m-icon-button-group--space-items)}.pf-c-overflow-menu__item{--pf-c-overflow-menu--spacer:var(--pf-c-overflow-menu__item--spacer)}.pf-c-overflow-menu__content,.pf-c-overflow-menu__control,.pf-c-overflow-menu__group,.pf-c-overflow-menu__item{margin-right:var(--pf-c-overflow-menu--spacer)}.pf-c-overflow-menu__content:last-child,.pf-c-overflow-menu__control:last-child,.pf-c-overflow-menu__group:last-child,.pf-c-overflow-menu__item:last-child{--pf-c-overflow-menu--spacer:0}.pf-c-overflow-menu>.pf-c-divider,.pf-c-overflow-menu__group>.pf-c-divider{--pf-c-overflow-menu--spacer:var(--pf-c-overflow-menu--c-divider--m-vertical--spacer)}.pf-c-overflow-menu>.pf-c-divider.pf-m-vertical,.pf-c-overflow-menu__group>.pf-c-divider.pf-m-vertical{margin-right:var(--pf-c-overflow-menu--spacer)}.pf-c-overflow-menu>.pf-c-divider.pf-m-vertical:last-child,.pf-c-overflow-menu__group>.pf-c-divider.pf-m-vertical:last-child{--pf-c-overflow-menu--spacer:0}.pf-c-page{--pf-c-page--BackgroundColor:var(--pf-global--BackgroundColor--light-300);--pf-c-page__header--BackgroundColor:var(--pf-global--BackgroundColor--dark-100);--pf-c-page__header--ZIndex:var(--pf-global--ZIndex--md);--pf-c-page__header--MinHeight:4.75rem;--pf-c-page__header-brand--PaddingLeft:var(--pf-global--spacer--md);--pf-c-page__header-brand--xl--PaddingRight:var(--pf-global--spacer--xl);--pf-c-page__header-brand--xl--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-page__header-sidebar-toggle__c-button--PaddingTop:var(--pf-global--spacer--sm);--pf-c-page__header-sidebar-toggle__c-button--PaddingRight:var(--pf-global--spacer--sm);--pf-c-page__header-sidebar-toggle__c-button--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-page__header-sidebar-toggle__c-button--PaddingLeft:var(--pf-global--spacer--sm);--pf-c-page__header-sidebar-toggle__c-button--MarginRight:var(--pf-global--spacer--md);--pf-c-page__header-sidebar-toggle__c-button--MarginLeft:calc(var(--pf-c-page__header-sidebar-toggle__c-button--PaddingLeft)*-1);--pf-c-page__header-sidebar-toggle__c-button--FontSize:var(--pf-global--FontSize--2xl);--pf-c-page__header-brand-link--c-brand--MaxHeight:3.75rem;--pf-c-page__header-nav--BackgroundColor:var(--pf-global--BackgroundColor--dark-300);--pf-c-page__header-nav--xl--BackgroundColor:transparent;--pf-c-page__header-nav--xl--PaddingRight:var(--pf-global--spacer--xl);--pf-c-page__header-nav--xl--PaddingLeft:var(--pf-global--spacer--xl);--pf-c-page__header-tools--MarginRight:var(--pf-global--spacer--md);--pf-c-page__header-tools--xl--MarginRight:var(--pf-global--spacer--lg);--pf-c-page__header-tools--c-avatar--MarginLeft:var(--pf-global--spacer--md);--pf-c-page__header-tools-group--MarginLeft:var(--pf-global--spacer--xl);--pf-c-page__header-tools-group--Display:flex;--pf-c-page__header-tools-item--Display:block;--pf-c-page__header-tools-item--c-notification-badge--hover--BackgroundColor:var(--pf-global--BackgroundColor--dark-200);--pf-c-page__header-tools--c-button--notification-badge--m-unread--after--BackgroundColor:var(--pf-global--primary-color--200);--pf-c-page__header-tools--c-button--notification-badge--m-attention--after--BackgroundColor:var(--pf-global--danger-color--200);--pf-c-page__header-tools--c-button--m-selected--notification-badge--m-unread--after--BackgroundColor:var(--pf-global--primary-color--200);--pf-c-page__header-tools--c-button--m-selected--notification-badge--m-attention--after--BackgroundColor:var(--pf-global--danger-color--200);--pf-c-page__header-tools--c-button--m-selected--before--Width:auto;--pf-c-page__header-tools--c-button--m-selected--before--Height:auto;--pf-c-page__header-tools--c-button--m-selected--before--BackgroundColor:var(--pf-global--BackgroundColor--dark-200);--pf-c-page__header-tools--c-button--m-selected--before--BorderRadius:var(--pf-global--BorderRadius--sm);--pf-c-page__header-tools--c-button--m-selected--c-notification-badge--m-unread--after--BorderColor:transparent;--pf-c-page__sidebar--ZIndex:var(--pf-global--ZIndex--sm);--pf-c-page__sidebar--Width:80%;--pf-c-page__sidebar--Width:18.125rem;--pf-c-page__sidebar--BackgroundColor:var(--pf-global--BackgroundColor--dark-300);--pf-c-page__sidebar--m-light--BackgroundColor:var(--pf-global--BackgroundColor--light-100);--pf-c-page__sidebar--BoxShadow:var(--pf-global--BoxShadow--lg-right);--pf-c-page__sidebar--Transition:var(--pf-global--Transition);--pf-c-page__sidebar--TranslateX:-100%;--pf-c-page__sidebar--TranslateZ:0;--pf-c-page__sidebar--m-expanded--TranslateX:0;--pf-c-page__sidebar--xl--TranslateX:0;--pf-c-page__sidebar-body--PaddingTop:var(--pf-global--spacer--sm);--pf-c-page__sidebar-body--PaddingBottom:var(--pf-global--spacer--md);--pf-c-page__main--ZIndex:var(--pf-global--ZIndex--xs);--pf-c-page__main-section--PaddingTop:var(--pf-global--spacer--md);--pf-c-page__main-section--PaddingRight:var(--pf-global--spacer--md);--pf-c-page__main-section--PaddingBottom:var(--pf-global--spacer--md);--pf-c-page__main-section--PaddingLeft:var(--pf-global--spacer--md);--pf-c-page__main-section--xl--PaddingTop:var(--pf-global--spacer--lg);--pf-c-page__main-section--xl--PaddingRight:var(--pf-global--spacer--lg);--pf-c-page__main-section--xl--PaddingBottom:var(--pf-global--spacer--lg);--pf-c-page__main-section--xl--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-page__main-breadcrumb--main-section--PaddingTop:var(--pf-global--spacer--md);--pf-c-page__main-section--BackgroundColor:var(--pf-global--BackgroundColor--light-300);--pf-c-page__main-section--m-light--BackgroundColor:var(--pf-global--BackgroundColor--light-100);--pf-c-page__main-section--m-dark-100--BackgroundColor:var(--pf-global--BackgroundColor--dark-transparent-100);--pf-c-page__main-section--m-dark-200--BackgroundColor:var(--pf-global--BackgroundColor--dark-transparent-200);--pf-c-page--section--m-limit-width--MaxWidth:calc(125rem - var(--pf-c-page__sidebar--Width));--pf-c-page--section--m-sticky-top--ZIndex:var(--pf-global--ZIndex--xs);--pf-c-page--section--m-sticky-top--BoxShadow:var(--pf-global--BoxShadow--sm-bottom);--pf-c-page--section--m-sticky-bottom--ZIndex:var(--pf-global--ZIndex--xs);--pf-c-page--section--m-sticky-bottom--BoxShadow:var(--pf-global--BoxShadow--sm-top);--pf-c-page--section--m-shadow-bottom--BoxShadow:var(--pf-global--BoxShadow--sm-bottom);--pf-c-page--section--m-shadow-bottom--ZIndex:var(--pf-global--ZIndex--xs);--pf-c-page--section--m-shadow-top--BoxShadow:var(--pf-global--BoxShadow--sm-top);--pf-c-page--section--m-shadow-top--ZIndex:var(--pf-global--ZIndex--xs);--pf-c-page__main-nav--BackgroundColor:var(--pf-global--BackgroundColor--light-100);--pf-c-page__main-nav--PaddingTop:var(--pf-global--spacer--md);--pf-c-page__main-nav--PaddingRight:0;--pf-c-page__main-nav--PaddingLeft:0;--pf-c-page__main-nav--m-sticky-top--PaddingBottom:var(--pf-global--spacer--md);--pf-c-page__main-nav--xl--PaddingRight:var(--pf-global--spacer--sm);--pf-c-page__main-nav--xl--PaddingLeft:var(--pf-global--spacer--sm);--pf-c-page__main-breadcrumb--BackgroundColor:var(--pf-global--BackgroundColor--light-100);--pf-c-page__main-breadcrumb--PaddingTop:var(--pf-global--spacer--md);--pf-c-page__main-breadcrumb--PaddingRight:var(--pf-global--spacer--md);--pf-c-page__main-breadcrumb--PaddingBottom:0;--pf-c-page__main-breadcrumb--PaddingLeft:var(--pf-global--spacer--md);--pf-c-page__main-breadcrumb--m-sticky-top--PaddingBottom:var(--pf-global--spacer--md);--pf-c-page__main-breadcrumb--xl--PaddingRight:var(--pf-global--spacer--lg);--pf-c-page__main-breadcrumb--xl--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-page__main-wizard--BackgroundColor:var(--pf-global--BackgroundColor--light-100);--pf-c-page__main-wizard--BorderTopColor:var(--pf-global--BorderColor--100);--pf-c-page__main-wizard--BorderTopWidth:var(--pf-global--BorderWidth--sm);display:grid;height:100%;grid-template-columns:1fr;grid-template-rows:max-content 1fr;grid-template-areas:"header" "main";background-color:var(--pf-c-page--BackgroundColor)}@media (min-width:1200px){.pf-c-page{--pf-c-page__header-brand--PaddingLeft:var(--pf-c-page__header-brand--xl--PaddingLeft)}}@media screen and (min-width:1200px){.pf-c-page{--pf-c-page__header-nav--BackgroundColor:var(--pf-c-page__header-nav--xl--BackgroundColor);--pf-c-page__header-nav--PaddingRight:var(--pf-c-page__header-nav--xl--PaddingRight);--pf-c-page__header-nav--PaddingLeft:var(--pf-c-page__header-nav--xl--PaddingLeft);--pf-c-page__header-tools--MarginRight:var(--pf-c-page__header-tools--xl--MarginRight);--pf-c-page__sidebar--TranslateX:var(--pf-c-page__sidebar--xl--TranslateX);--pf-c-page__main-section--PaddingTop:var(--pf-c-page__main-section--xl--PaddingTop);--pf-c-page__main-section--PaddingRight:var(--pf-c-page__main-section--xl--PaddingRight);--pf-c-page__main-section--PaddingBottom:var(--pf-c-page__main-section--xl--PaddingBottom);--pf-c-page__main-section--PaddingLeft:var(--pf-c-page__main-section--xl--PaddingLeft);--pf-c-page__main-nav--PaddingRight:var(--pf-c-page__main-nav--xl--PaddingRight);--pf-c-page__main-nav--PaddingLeft:var(--pf-c-page__main-nav--xl--PaddingLeft);--pf-c-page__main-breadcrumb--PaddingRight:var(--pf-c-page__main-breadcrumb--xl--PaddingRight);--pf-c-page__main-breadcrumb--PaddingLeft:var(--pf-c-page__main-breadcrumb--xl--PaddingLeft)}}@media (min-width:1200px){.pf-c-page{grid-template-columns:max-content 1fr;grid-template-areas:"header header" "nav main"}}.pf-c-page__header{color:var(--pf-global--Color--100);z-index:var(--pf-c-page__header--ZIndex);grid-template-columns:auto auto;display:grid;grid-area:header;align-items:center;min-width:0;min-height:var(--pf-c-page__header--MinHeight);background-color:var(--pf-c-page__header--BackgroundColor)}.pf-c-page__header>*{display:flex;align-items:center}@media screen and (min-width:992px){.pf-c-page__header{grid-template-columns:auto 1fr auto}}.pf-c-page__header-brand{grid-column:1/2;padding-left:var(--pf-c-page__header-brand--PaddingLeft)}@media (min-width:1200px){.pf-c-page__header-brand{padding-right:var(--pf-c-page__header-brand--xl--PaddingRight)}}.pf-c-page__header-brand-link{display:flex;flex:1;align-items:center}.pf-c-page__header-brand-link .pf-c-brand{max-height:var(--pf-c-page__header-brand-link--c-brand--MaxHeight)}.pf-c-page__header-brand-toggle .pf-c-button{padding:var(--pf-c-page__header-sidebar-toggle__c-button--PaddingTop) var(--pf-c-page__header-sidebar-toggle__c-button--PaddingRight) var(--pf-c-page__header-sidebar-toggle__c-button--PaddingBottom) var(--pf-c-page__header-sidebar-toggle__c-button--PaddingLeft);margin-right:var(--pf-c-page__header-sidebar-toggle__c-button--MarginRight);margin-left:var(--pf-c-page__header-sidebar-toggle__c-button--MarginLeft);font-size:var(--pf-c-page__header-sidebar-toggle__c-button--FontSize);line-height:1}.pf-c-page__header-nav{align-self:stretch;min-width:0;padding-right:var(--pf-c-page__header-nav--PaddingRight);padding-left:var(--pf-c-page__header-nav--PaddingLeft);background-color:var(--pf-c-page__header-nav--BackgroundColor);grid-column:1/-1;grid-row:2/3}@media screen and (min-width:1200px){.pf-c-page__header-nav{grid-column:2/3;grid-row:1/2}}.pf-c-page__header-nav .pf-c-nav{align-self:stretch}.pf-c-page__header-tools{grid-column:2/3;margin-right:var(--pf-c-page__header-tools--MarginRight);margin-left:auto}.pf-c-page__header-tools .pf-c-avatar{margin-left:var(--pf-c-page__header-tools--c-avatar--MarginLeft)}@media screen and (min-width:992px){.pf-c-page__header-tools{grid-column:3/4}}.pf-c-page__header-tools-group{--pf-hidden-visible--visible--Display:var(--pf-c-page__header-tools-group--Display);align-items:center}.pf-c-page__header-tools-group+.pf-c-page__header-tools-group{margin-left:var(--pf-c-page__header-tools-group--MarginLeft)}.pf-c-page__header-tools-item{--pf-hidden-visible--visible--Display:var(--pf-c-page__header-tools-item--Display)}.pf-c-page__header-tools-item .pf-c-notification-badge.pf-m-read:hover{--pf-c-notification-badge--after--BackgroundColor:var(--pf-c-page__header-tools-item--c-notification-badge--hover--BackgroundColor)}.pf-c-page__header-tools-item.pf-m-selected .pf-c-button{background-color:var(--pf-c-page__header-tools--c-button--m-selected--before--BackgroundColor);border-radius:var(--pf-c-page__header-tools--c-button--m-selected--before--BorderRadius)}.pf-c-page__header-tools-item.pf-m-selected .pf-c-button:before{position:absolute;top:0;right:0;bottom:0;left:0;width:var(--pf-c-page__header-tools--c-button--m-selected--before--Width);height:var(--pf-c-page__header-tools--c-button--m-selected--before--Height);content:""}.pf-c-page__header-tools-item.pf-m-selected .pf-c-button .pf-c-notification-badge.pf-m-unread{--pf-c-notification-badge--after--BackgroundColor:var(--pf-c-page__header-tools--c-button--m-selected--notification-badge--m-unread--after--BackgroundColor)}.pf-c-page__header-tools-item.pf-m-selected .pf-c-button .pf-c-notification-badge.pf-m-unread:after{border-color:var(--pf-c-page__header-tools--c-button--m-selected--c-notification-badge--m-unread--after--BorderColor)}.pf-c-page__header-tools-item.pf-m-selected .pf-c-button .pf-c-notification-badge.pf-m-attention{--pf-c-notification-badge--after--BackgroundColor:var(--pf-global--danger-color--200)}.pf-c-page__header-tools-item .pf-c-button:focus .pf-c-notification-badge.pf-m-unread{--pf-c-notification-badge--after--BackgroundColor:var(--pf-c-page__header-tools--c-button--notification-badge--m-unread--after--BackgroundColor)}.pf-c-page__header-tools-item .pf-c-button:focus .pf-c-notification-badge.pf-m-attention{--pf-c-notification-badge--after--BackgroundColor:var(--pf-c-page__header-tools--c-button--notification-badge--m-attention--after--BackgroundColor)}.pf-c-page__sidebar{grid-area:nav;grid-row-start:2;grid-column-start:1;z-index:var(--pf-c-page__sidebar--ZIndex);width:var(--pf-c-page__sidebar--Width);overflow-x:hidden;overflow-y:auto;-webkit-overflow-scrolling:touch;background-color:var(--pf-c-page__sidebar--BackgroundColor);transition:var(--pf-c-page__sidebar--Transition);transform:translateX(var(--pf-c-page__sidebar--TranslateX)) translateZ(var(--pf-c-page__sidebar--TranslateZ))}@media screen and (min-width:1200px){.pf-c-page__sidebar{box-shadow:var(--pf-c-page__sidebar--BoxShadow)}}.pf-c-page__sidebar.pf-m-expanded{--pf-c-page__sidebar--TranslateX:var(--pf-c-page__sidebar--m-expanded--TranslateX);box-shadow:var(--pf-c-page__sidebar--BoxShadow)}.pf-c-page__sidebar.pf-m-collapsed{max-width:0;overflow:hidden}.pf-c-page__sidebar.pf-m-light{color:var(--pf-global--Color--100);--pf-c-page__sidebar--BackgroundColor:var(--pf-c-page__sidebar--m-light--BackgroundColor)}.pf-c-page__sidebar-body{padding-top:var(--pf-c-page__sidebar-body--PaddingTop);padding-bottom:var(--pf-c-page__sidebar-body--PaddingBottom)}.pf-c-page__main-breadcrumb.pf-m-limit-width,.pf-c-page__main-nav.pf-m-limit-width,.pf-c-page__main-section.pf-m-limit-width,.pf-c-page__main-wizard.pf-m-limit-width{display:flex;flex-direction:column;padding:0}.pf-c-page__main-breadcrumb.pf-m-limit-width>.pf-c-page__main-body,.pf-c-page__main-nav.pf-m-limit-width>.pf-c-page__main-body,.pf-c-page__main-section.pf-m-limit-width>.pf-c-page__main-body,.pf-c-page__main-wizard.pf-m-limit-width>.pf-c-page__main-body{flex:1;max-width:var(--pf-c-page--section--m-limit-width--MaxWidth)}.pf-c-page__main-breadcrumb,.pf-c-page__main-group,.pf-c-page__main-nav,.pf-c-page__main-section,.pf-c-page__main-wizard{flex-shrink:0}.pf-c-page__main-breadcrumb.pf-m-sticky-top,.pf-c-page__main-group.pf-m-sticky-top,.pf-c-page__main-nav.pf-m-sticky-top,.pf-c-page__main-section.pf-m-sticky-top,.pf-c-page__main-wizard.pf-m-sticky-top{position:sticky;top:0;z-index:var(--pf-c-page--section--m-sticky-top--ZIndex);box-shadow:var(--pf-c-page--section--m-sticky-top--BoxShadow)}.pf-c-page__main-breadcrumb.pf-m-sticky-bottom,.pf-c-page__main-group.pf-m-sticky-bottom,.pf-c-page__main-nav.pf-m-sticky-bottom,.pf-c-page__main-section.pf-m-sticky-bottom,.pf-c-page__main-wizard.pf-m-sticky-bottom{position:sticky;bottom:0;z-index:var(--pf-c-page--section--m-sticky-bottom--ZIndex);box-shadow:var(--pf-c-page--section--m-sticky-bottom--BoxShadow)}.pf-c-page__main-breadcrumb.pf-m-overflow-scroll,.pf-c-page__main-group.pf-m-overflow-scroll,.pf-c-page__main-nav.pf-m-overflow-scroll,.pf-c-page__main-section.pf-m-overflow-scroll,.pf-c-page__main-wizard.pf-m-overflow-scroll{position:relative;flex-shrink:1;overflow:auto}.pf-c-page__main-breadcrumb.pf-m-shadow-bottom,.pf-c-page__main-group.pf-m-shadow-bottom,.pf-c-page__main-nav.pf-m-shadow-bottom,.pf-c-page__main-section.pf-m-shadow-bottom,.pf-c-page__main-wizard.pf-m-shadow-bottom{z-index:var(--pf-c-page--section--m-shadow-bottom--ZIndex);box-shadow:var(--pf-c-page--section--m-shadow-bottom--BoxShadow)}.pf-c-page__main-breadcrumb.pf-m-shadow-top,.pf-c-page__main-group.pf-m-shadow-top,.pf-c-page__main-nav.pf-m-shadow-top,.pf-c-page__main-section.pf-m-shadow-top,.pf-c-page__main-wizard.pf-m-shadow-top{z-index:var(--pf-c-page--section--m-shadow-top--ZIndex);box-shadow:var(--pf-c-page--section--m-shadow-top--BoxShadow)}.pf-c-page__drawer,.pf-c-page__main{grid-area:main;z-index:var(--pf-c-page__main--ZIndex);overflow-x:hidden;overflow-y:auto;-webkit-overflow-scrolling:touch}.pf-c-page__drawer:focus,.pf-c-page__main:focus{outline:0}.pf-c-page__main,.pf-c-page__main-drawer,.pf-c-page__main-group{display:flex;flex-direction:column}.pf-c-page__main-nav{padding-top:var(--pf-c-page__main-nav--PaddingTop);padding-right:var(--pf-c-page__main-nav--PaddingRight);padding-left:var(--pf-c-page__main-nav--PaddingLeft);background-color:var(--pf-c-page__main-nav--BackgroundColor)}.pf-c-page__main-group.pf-m-sticky-top .pf-c-page__main-nav:last-child,.pf-c-page__main-nav.pf-m-sticky-top{padding-bottom:var(--pf-c-page__main-nav--m-sticky-top--PaddingBottom)}.pf-c-page__main-breadcrumb{padding:var(--pf-c-page__main-breadcrumb--PaddingTop) var(--pf-c-page__main-breadcrumb--PaddingRight) var(--pf-c-page__main-breadcrumb--PaddingBottom) var(--pf-c-page__main-breadcrumb--PaddingLeft);background-color:var(--pf-c-page__main-breadcrumb--BackgroundColor)}.pf-c-page__main-breadcrumb+.pf-c-page__main-section{--pf-c-page__main-section--PaddingTop:var(--pf-c-page__main-breadcrumb--main-section--PaddingTop)}.pf-c-page__main-breadcrumb.pf-m-sticky-top,.pf-c-page__main-group.pf-m-sticky-top .pf-c-page__main-breadcrumb:last-child{--pf-c-page__main-breadcrumb--PaddingBottom:var(--pf-c-page__main-breadcrumb--m-sticky-top--PaddingBottom)}.pf-c-page__main-group.pf-m-fill,.pf-c-page__main-group:last-child,.pf-c-page__main-group:only-child,.pf-c-page__main-section.pf-m-fill,.pf-c-page__main-section:last-child,.pf-c-page__main-section:only-child,.pf-c-page__main-wizard.pf-m-fill,.pf-c-page__main-wizard:last-child,.pf-c-page__main-wizard:only-child{flex-grow:1}.pf-c-page__main-group.pf-m-no-fill,.pf-c-page__main-section.pf-m-no-fill,.pf-c-page__main-wizard.pf-m-no-fill{flex-grow:0}.pf-c-page__main-section{padding:var(--pf-c-page__main-section--PaddingTop) var(--pf-c-page__main-section--PaddingRight) var(--pf-c-page__main-section--PaddingBottom) var(--pf-c-page__main-section--PaddingLeft);background-color:var(--pf-c-page__main-section--BackgroundColor)}.pf-c-page__main-section.pf-m-light{--pf-c-page__main-section--BackgroundColor:var(--pf-c-page__main-section--m-light--BackgroundColor)}.pf-c-page__main-section[class*=pf-m-dark-]{color:var(--pf-global--Color--100)}.pf-c-page__main-section.pf-m-dark-100{--pf-c-page__main-section--BackgroundColor:var(--pf-c-page__main-section--m-dark-100--BackgroundColor)}.pf-c-page__main-section.pf-m-dark-200{--pf-c-page__main-section--BackgroundColor:var(--pf-c-page__main-section--m-dark-200--BackgroundColor)}.pf-c-page__main-section.pf-m-padding{padding:var(--pf-c-page__main-section--PaddingTop) var(--pf-c-page__main-section--PaddingRight) var(--pf-c-page__main-section--PaddingBottom) var(--pf-c-page__main-section--PaddingLeft)}.pf-c-page__main-section.pf-m-no-padding{--pf-c-page__main-section--PaddingTop:0;--pf-c-page__main-section--PaddingRight:0;--pf-c-page__main-section--PaddingBottom:0;--pf-c-page__main-section--PaddingLeft:0}@media (min-width:576px){.pf-c-page__main-section.pf-m-padding-on-sm{padding:var(--pf-c-page__main-section--PaddingTop) var(--pf-c-page__main-section--PaddingRight) var(--pf-c-page__main-section--PaddingBottom) var(--pf-c-page__main-section--PaddingLeft)}.pf-c-page__main-section.pf-m-no-padding-on-sm{--pf-c-page__main-section--PaddingTop:0;--pf-c-page__main-section--PaddingRight:0;--pf-c-page__main-section--PaddingBottom:0;--pf-c-page__main-section--PaddingLeft:0}}@media (min-width:768px){.pf-c-page__main-section.pf-m-padding-on-md{padding:var(--pf-c-page__main-section--PaddingTop) var(--pf-c-page__main-section--PaddingRight) var(--pf-c-page__main-section--PaddingBottom) var(--pf-c-page__main-section--PaddingLeft)}.pf-c-page__main-section.pf-m-no-padding-on-md{--pf-c-page__main-section--PaddingTop:0;--pf-c-page__main-section--PaddingRight:0;--pf-c-page__main-section--PaddingBottom:0;--pf-c-page__main-section--PaddingLeft:0}}@media (min-width:992px){.pf-c-page__main-section.pf-m-padding-on-lg{padding:var(--pf-c-page__main-section--PaddingTop) var(--pf-c-page__main-section--PaddingRight) var(--pf-c-page__main-section--PaddingBottom) var(--pf-c-page__main-section--PaddingLeft)}.pf-c-page__main-section.pf-m-no-padding-on-lg{--pf-c-page__main-section--PaddingTop:0;--pf-c-page__main-section--PaddingRight:0;--pf-c-page__main-section--PaddingBottom:0;--pf-c-page__main-section--PaddingLeft:0}}@media (min-width:1200px){.pf-c-page__main-section.pf-m-padding-on-xl{padding:var(--pf-c-page__main-section--PaddingTop) var(--pf-c-page__main-section--PaddingRight) var(--pf-c-page__main-section--PaddingBottom) var(--pf-c-page__main-section--PaddingLeft)}.pf-c-page__main-section.pf-m-no-padding-on-xl{--pf-c-page__main-section--PaddingTop:0;--pf-c-page__main-section--PaddingRight:0;--pf-c-page__main-section--PaddingBottom:0;--pf-c-page__main-section--PaddingLeft:0}}@media (min-width:1450px){.pf-c-page__main-section.pf-m-padding-on-2xl{padding:var(--pf-c-page__main-section--PaddingTop) var(--pf-c-page__main-section--PaddingRight) var(--pf-c-page__main-section--PaddingBottom) var(--pf-c-page__main-section--PaddingLeft)}.pf-c-page__main-section.pf-m-no-padding-on-2xl{--pf-c-page__main-section--PaddingTop:0;--pf-c-page__main-section--PaddingRight:0;--pf-c-page__main-section--PaddingBottom:0;--pf-c-page__main-section--PaddingLeft:0}}.pf-c-page__main-wizard{flex-grow:1;background-color:var(--pf-c-page__main-wizard--BackgroundColor);border-top:var(--pf-c-page__main-wizard--BorderTopWidth) solid var(--pf-c-page__main-wizard--BorderTopColor)}.pf-c-page__main-group{flex-shrink:0}.pf-c-page__main-nav .pf-c-page__main-body{padding-top:var(--pf-c-page__main-nav--PaddingTop);padding-right:var(--pf-c-page__main-nav--PaddingRight);padding-left:var(--pf-c-page__main-nav--PaddingLeft)}.pf-c-page__main-breadcrumb .pf-c-page__main-body{padding:var(--pf-c-page__main-breadcrumb--PaddingTop) var(--pf-c-page__main-breadcrumb--PaddingRight) var(--pf-c-page__main-breadcrumb--PaddingBottom) var(--pf-c-page__main-breadcrumb--PaddingLeft)}.pf-c-page__main-section .pf-c-page__main-body{padding:var(--pf-c-page__main-section--PaddingTop) var(--pf-c-page__main-section--PaddingRight) var(--pf-c-page__main-section--PaddingBottom) var(--pf-c-page__main-section--PaddingLeft)}.pf-c-page__drawer{grid-area:main}.pf-c-page__drawer>.pf-c-drawer{flex:1 0 auto}.pf-c-pagination{--pf-c-pagination--child--MarginRight:var(--pf-global--spacer--lg);--pf-c-pagination--m-bottom--child--MarginRight:0;--pf-c-pagination--m-bottom--child--md--MarginRight:var(--pf-global--spacer--lg);--pf-c-pagination--m-compact--child--MarginRight:var(--pf-global--spacer--sm);--pf-c-pagination--c-options-menu__toggle--FontSize:var(--pf-global--FontSize--sm);--pf-c-pagination__nav--Display:none;--pf-c-pagination__nav--Visibility:hidden;--pf-c-pagination--m-display-summary__nav--Display:none;--pf-c-pagination--m-display-summary__nav--Visibility:hidden;--pf-c-pagination--m-display-full__nav--Display:inline-flex;--pf-c-pagination--m-display-full__nav--Visibility:visible;--pf-c-pagination__nav-control--c-button--PaddingRight:var(--pf-global--spacer--sm);--pf-c-pagination__nav-control--c-button--PaddingLeft:var(--pf-global--spacer--sm);--pf-c-pagination__nav-control--c-button--FontSize:var(--pf-global--FontSize--md);--pf-c-pagination--m-bottom__nav-control--c-button--OutlineOffset:calc(var(--pf-global--spacer--xs)*-1);--pf-c-pagination--m-bottom__nav-control--c-button--PaddingTop:var(--pf-global--spacer--md);--pf-c-pagination--m-bottom__nav-control--c-button--PaddingBottom:var(--pf-global--spacer--md);--pf-c-pagination--m-bottom__nav-control--c-button--PaddingRight:var(--pf-global--spacer--md);--pf-c-pagination--m-bottom__nav-control--c-button--md--PaddingTop:var(--pf-global--spacer--form-element);--pf-c-pagination--m-bottom__nav-control--c-button--md--PaddingRight:var(--pf-global--spacer--sm);--pf-c-pagination--m-bottom__nav-control--c-button--md--PaddingBottom:var(--pf-global--spacer--form-element);--pf-c-pagination--m-bottom__nav-control--c-button--md--PaddingLeft:var(--pf-global--spacer--sm);--pf-c-pagination--m-compact__nav-control--nav-control--MarginLeft:var(--pf-global--spacer--md);--pf-c-pagination__nav-page-select--FontSize:var(--pf-global--FontSize--sm);--pf-c-pagination__nav-page-select--PaddingLeft:var(--pf-global--spacer--md);--pf-c-pagination__nav-page-select--PaddingRight:var(--pf-global--spacer--md);--pf-c-pagination__nav-page-select--child--MarginRight:var(--pf-global--spacer--xs);--pf-c-pagination__nav-page-select--c-form-control--width-base:3.5ch;--pf-c-pagination__nav-page-select--c-form-control--width-chars:2;--pf-c-pagination__nav-page-select--c-form-control--Width:calc(var(--pf-c-pagination__nav-page-select--c-form-control--width-base) + var(--pf-c-pagination__nav-page-select--c-form-control--width-chars)*1ch);--pf-c-pagination__total-items--Display:block;--pf-c-pagination__total-items--Visibility:visible;--pf-c-pagination--m-display-summary__total-items--Display:block;--pf-c-pagination--m-display-summary__total-items--Visibility:visible;--pf-c-pagination--m-display-full__total-items--Display:none;--pf-c-pagination--m-display-full__total-items--Visibility:hidden;--pf-c-pagination--m-sticky--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-pagination--m-sticky--BoxShadow:var(--pf-global--BoxShadow--sm-bottom);--pf-c-pagination--m-sticky--md--PaddingTop:var(--pf-global--spacer--md);--pf-c-pagination--m-sticky--md--PaddingRight:var(--pf-global--spacer--md);--pf-c-pagination--m-sticky--md--PaddingBottom:var(--pf-global--spacer--md);--pf-c-pagination--m-sticky--md--PaddingLeft:var(--pf-global--spacer--md);--pf-c-pagination--m-sticky--ZIndex:var(--pf-global--ZIndex--xs);--pf-c-pagination--m-sticky--Top:0;--pf-c-pagination--m-bottom--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-pagination--m-bottom--BoxShadow:var(--pf-global--BoxShadow--sm-top);--pf-c-pagination--m-bottom--Bottom:0;--pf-c-pagination--m-bottom--md--PaddingTop:var(--pf-global--spacer--md);--pf-c-pagination--m-bottom--md--PaddingRight:var(--pf-global--spacer--md);--pf-c-pagination--m-bottom--md--PaddingBottom:var(--pf-global--spacer--md);--pf-c-pagination--m-bottom--md--PaddingLeft:var(--pf-global--spacer--md);--pf-c-pagination--m-bottom--xl--PaddingRight:var(--pf-global--spacer--lg);--pf-c-pagination--m-bottom--xl--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-pagination--m-bottom--m-sticky--BoxShadow:var(--pf-global--BoxShadow--sm-top);--pf-c-pagination--c-options-menu--Display:none;--pf-c-pagination--c-options-menu--Visibility:hidden;--pf-c-pagination--m-display-summary--c-options-menu--Display:none;--pf-c-pagination--m-display-summary--c-options-menu--Visibility:hidden;--pf-c-pagination--m-display-full--c-options-menu--Display:inline-flex;--pf-c-pagination--m-display-full--c-options-menu--Visibility:visible;display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end}@media screen and (min-width:768px){.pf-c-pagination{--pf-c-pagination--m-bottom__nav-control--c-button--PaddingTop:var(--pf-c-pagination--m-bottom__nav-control--c-button--md--PaddingTop);--pf-c-pagination--m-bottom__nav-control--c-button--PaddingRight:var(--pf-c-pagination--m-bottom__nav-control--c-button--md--PaddingRight);--pf-c-pagination--m-bottom__nav-control--c-button--PaddingBottom:var(--pf-c-pagination--m-bottom__nav-control--c-button--md--PaddingBottom);--pf-c-pagination--m-bottom__nav-control--c-button--PaddingLeft:var(--pf-c-pagination--m-bottom__nav-control--c-button--md--PaddingLeft);--pf-c-pagination--m-bottom--child--MarginRight:var(--pf-c-pagination--m-bottom--child--md--MarginRight);--pf-c-pagination--m-bottom__nav-control--c-button--OutlineOffset:0;--pf-c-pagination--m-bottom--BoxShadow:none;--pf-c-pagination--c-options-menu--Display:inline-flex;--pf-c-pagination--c-options-menu--Visibility:visible;--pf-c-pagination__nav--Display:inline-flex;--pf-c-pagination__nav--Visibility:visible;--pf-c-pagination__total-items--Display:none;--pf-c-pagination__total-items--Visibility:hidden}}@media screen and (min-width:1200px){.pf-c-pagination{--pf-c-pagination--m-bottom--md--PaddingRight:var(--pf-c-pagination--m-bottom--xl--PaddingRight);--pf-c-pagination--m-bottom--md--PaddingLeft:var(--pf-c-pagination--m-bottom--xl--PaddingLeft)}}.pf-c-pagination>:not(:last-child):not(.pf-c-pagination__total-items){margin-right:var(--pf-c-pagination--child--MarginRight)}.pf-c-pagination .pf-c-options-menu{display:var(--pf-c-pagination--c-options-menu--Display);visibility:var(--pf-c-pagination--c-options-menu--Visibility)}.pf-c-pagination.pf-m-bottom{--pf-c-pagination--child--MarginRight:var(--pf-c-pagination--m-bottom--child--MarginRight);--pf-c-pagination__nav-control--c-button--PaddingRight:var(--pf-c-pagination--m-bottom__nav-control--c-button--PaddingRight);--pf-c-pagination__nav-control--c-button--PaddingLeft:var(--pf-c-pagination--m-bottom__nav-control--c-button--PaddingRight);--pf-c-pagination--m-sticky--BoxShadow:var(--pf-c-pagination--m-bottom--m-sticky--BoxShadow);--pf-c-pagination--m-sticky--Top:auto;position:sticky;bottom:var(--pf-c-pagination--m-bottom--Bottom);justify-content:center;background-color:var(--pf-c-pagination--m-bottom--BackgroundColor);box-shadow:var(--pf-c-pagination--m-bottom--BoxShadow)}.pf-c-pagination.pf-m-bottom .pf-c-pagination__nav-control .pf-c-button{--pf-c-button--PaddingTop:var(--pf-c-pagination--m-bottom__nav-control--c-button--PaddingTop);--pf-c-button--PaddingBottom:var(--pf-c-pagination--m-bottom__nav-control--c-button--PaddingBottom);outline-offset:var(--pf-c-pagination--m-bottom__nav-control--c-button--OutlineOffset)}.pf-c-pagination.pf-m-bottom.pf-m-static{--pf-c-pagination--m-bottom--MarginTop:0;--pf-c-pagination--m-bottom--BorderTopWidth:0;position:relative;box-shadow:none}.pf-c-pagination.pf-m-bottom .pf-c-pagination__nav-control.pf-m-first,.pf-c-pagination.pf-m-bottom .pf-c-pagination__nav-control.pf-m-last,.pf-c-pagination.pf-m-bottom .pf-c-pagination__nav-page-select{display:none;visibility:hidden}.pf-c-pagination.pf-m-bottom .pf-c-options-menu{position:absolute;display:block;visibility:visible}.pf-c-pagination.pf-m-bottom .pf-c-pagination__nav{display:flex;flex-basis:100%;justify-content:space-between;visibility:visible}@media screen and (min-width:768px){.pf-c-pagination.pf-m-bottom{--pf-c-pagination--m-bottom--BorderTopWidth:0;--pf-c-pagination--m-bottom--MarginTop:0;--pf-c-pagination--m-bottom--Bottom:auto;position:relative;justify-content:flex-end;padding:var(--pf-c-pagination--m-bottom--md--PaddingTop) var(--pf-c-pagination--m-bottom--md--PaddingRight) var(--pf-c-pagination--m-bottom--md--PaddingBottom) var(--pf-c-pagination--m-bottom--md--PaddingLeft)}.pf-c-pagination.pf-m-bottom .pf-c-pagination__nav-control.pf-m-first,.pf-c-pagination.pf-m-bottom .pf-c-pagination__nav-control.pf-m-last,.pf-c-pagination.pf-m-bottom .pf-c-pagination__nav-page-select{display:block;visibility:visible}.pf-c-pagination.pf-m-bottom .pf-c-options-menu{position:relative}.pf-c-pagination.pf-m-bottom .pf-c-pagination__nav{display:inline-flex;flex-basis:auto}}.pf-c-pagination.pf-m-sticky{--pf-c-pagination--m-bottom--Bottom:0;position:sticky;top:var(--pf-c-pagination--m-sticky--Top);z-index:var(--pf-c-pagination--m-sticky--ZIndex);padding:var(--pf-c-pagination--m-sticky--PaddingTop) var(--pf-c-pagination--m-sticky--PaddingRight) var(--pf-c-pagination--m-sticky--PaddingBottom) var(--pf-c-pagination--m-sticky--PaddingLeft);background-color:var(--pf-c-pagination--m-sticky--BackgroundColor);box-shadow:var(--pf-c-pagination--m-sticky--BoxShadow)}@media screen and (min-width:768px){.pf-c-pagination.pf-m-sticky{padding:var(--pf-c-pagination--m-sticky--md--PaddingTop) var(--pf-c-pagination--m-sticky--md--PaddingRight) var(--pf-c-pagination--m-sticky--md--PaddingBottom) var(--pf-c-pagination--m-sticky--md--PaddingLeft)}}.pf-c-pagination .pf-c-options-menu__toggle{font-size:var(--pf-c-pagination--c-options-menu__toggle--FontSize)}.pf-c-pagination.pf-m-compact{--pf-c-pagination--child--MarginRight:var(--pf-c-pagination--m-compact--child--MarginRight)}.pf-c-pagination__nav{display:var(--pf-c-pagination__nav--Display);justify-content:flex-end;visibility:var(--pf-c-pagination__nav--Visibility)}.pf-c-pagination__nav-control .pf-c-button{padding-right:var(--pf-c-pagination__nav-control--c-button--PaddingRight);padding-left:var(--pf-c-pagination__nav-control--c-button--PaddingLeft);font-size:var(--pf-c-pagination__nav-control--c-button--FontSize)}.pf-c-pagination.pf-m-compact .pf-c-pagination__nav-control+.pf-c-pagination__nav-control{margin-left:var(--pf-c-pagination--m-compact__nav-control--nav-control--MarginLeft)}.pf-c-pagination__nav-page-select{display:flex;align-items:center;padding-right:var(--pf-c-pagination__nav-page-select--PaddingRight);padding-left:var(--pf-c-pagination__nav-page-select--PaddingLeft)}.pf-c-pagination__nav-page-select>*{font-size:var(--pf-c-pagination__nav-page-select--FontSize);white-space:nowrap}.pf-c-pagination__nav-page-select>:not(:last-child){margin-right:var(--pf-c-pagination__nav-page-select--child--MarginRight)}.pf-c-pagination__nav-page-select .pf-c-form-control{width:var(--pf-c-pagination__nav-page-select--c-form-control--Width)}.pf-c-pagination__total-items{display:var(--pf-c-pagination__total-items--Display);visibility:var(--pf-c-pagination__total-items--Visibility)}.pf-c-pagination.pf-m-display-summary{--pf-c-pagination__nav--Display:var(--pf-c-pagination--m-display-summary__nav--Display);--pf-c-pagination__nav--Visibility:var(--pf-c-pagination--m-display-summary__nav--Visibility);--pf-c-pagination--c-options-menu--Display:var(--pf-c-pagination--m-display-summary--c-options-menu--Display);--pf-c-pagination--c-options-menu--Visibility:var(--pf-c-pagination--m-display-summary--c-options-menu--Visibility);--pf-c-pagination__total-items--Display:var(--pf-c-pagination--m-display-summary__total-items--Display);--pf-c-pagination__total-items--Visibility:var(--pf-c-pagination--m-display-summary__total-items--Visibility)}.pf-c-pagination.pf-m-display-full{--pf-c-pagination__nav--Display:var(--pf-c-pagination--m-display-full__nav--Display);--pf-c-pagination__nav--Visibility:var(--pf-c-pagination--m-display-full__nav--Visibility);--pf-c-pagination--c-options-menu--Display:var(--pf-c-pagination--m-display-full--c-options-menu--Display);--pf-c-pagination--c-options-menu--Visibility:var(--pf-c-pagination--m-display-full--c-options-menu--Visibility);--pf-c-pagination__total-items--Display:var(--pf-c-pagination--m-display-full__total-items--Display);--pf-c-pagination__total-items--Visibility:var(--pf-c-pagination--m-display-full__total-items--Visibility)}@media (min-width:576px){.pf-c-pagination.pf-m-display-summary-on-sm{--pf-c-pagination__nav--Display:var(--pf-c-pagination--m-display-summary__nav--Display);--pf-c-pagination__nav--Visibility:var(--pf-c-pagination--m-display-summary__nav--Visibility);--pf-c-pagination--c-options-menu--Display:var(--pf-c-pagination--m-display-summary--c-options-menu--Display);--pf-c-pagination--c-options-menu--Visibility:var(--pf-c-pagination--m-display-summary--c-options-menu--Visibility);--pf-c-pagination__total-items--Display:var(--pf-c-pagination--m-display-summary__total-items--Display);--pf-c-pagination__total-items--Visibility:var(--pf-c-pagination--m-display-summary__total-items--Visibility)}.pf-c-pagination.pf-m-display-full-on-sm{--pf-c-pagination__nav--Display:var(--pf-c-pagination--m-display-full__nav--Display);--pf-c-pagination__nav--Visibility:var(--pf-c-pagination--m-display-full__nav--Visibility);--pf-c-pagination--c-options-menu--Display:var(--pf-c-pagination--m-display-full--c-options-menu--Display);--pf-c-pagination--c-options-menu--Visibility:var(--pf-c-pagination--m-display-full--c-options-menu--Visibility);--pf-c-pagination__total-items--Display:var(--pf-c-pagination--m-display-full__total-items--Display);--pf-c-pagination__total-items--Visibility:var(--pf-c-pagination--m-display-full__total-items--Visibility)}}@media (min-width:768px){.pf-c-pagination.pf-m-display-summary-on-md{--pf-c-pagination__nav--Display:var(--pf-c-pagination--m-display-summary__nav--Display);--pf-c-pagination__nav--Visibility:var(--pf-c-pagination--m-display-summary__nav--Visibility);--pf-c-pagination--c-options-menu--Display:var(--pf-c-pagination--m-display-summary--c-options-menu--Display);--pf-c-pagination--c-options-menu--Visibility:var(--pf-c-pagination--m-display-summary--c-options-menu--Visibility);--pf-c-pagination__total-items--Display:var(--pf-c-pagination--m-display-summary__total-items--Display);--pf-c-pagination__total-items--Visibility:var(--pf-c-pagination--m-display-summary__total-items--Visibility)}.pf-c-pagination.pf-m-display-full-on-md{--pf-c-pagination__nav--Display:var(--pf-c-pagination--m-display-full__nav--Display);--pf-c-pagination__nav--Visibility:var(--pf-c-pagination--m-display-full__nav--Visibility);--pf-c-pagination--c-options-menu--Display:var(--pf-c-pagination--m-display-full--c-options-menu--Display);--pf-c-pagination--c-options-menu--Visibility:var(--pf-c-pagination--m-display-full--c-options-menu--Visibility);--pf-c-pagination__total-items--Display:var(--pf-c-pagination--m-display-full__total-items--Display);--pf-c-pagination__total-items--Visibility:var(--pf-c-pagination--m-display-full__total-items--Visibility)}}@media (min-width:992px){.pf-c-pagination.pf-m-display-summary-on-lg{--pf-c-pagination__nav--Display:var(--pf-c-pagination--m-display-summary__nav--Display);--pf-c-pagination__nav--Visibility:var(--pf-c-pagination--m-display-summary__nav--Visibility);--pf-c-pagination--c-options-menu--Display:var(--pf-c-pagination--m-display-summary--c-options-menu--Display);--pf-c-pagination--c-options-menu--Visibility:var(--pf-c-pagination--m-display-summary--c-options-menu--Visibility);--pf-c-pagination__total-items--Display:var(--pf-c-pagination--m-display-summary__total-items--Display);--pf-c-pagination__total-items--Visibility:var(--pf-c-pagination--m-display-summary__total-items--Visibility)}.pf-c-pagination.pf-m-display-full-on-lg{--pf-c-pagination__nav--Display:var(--pf-c-pagination--m-display-full__nav--Display);--pf-c-pagination__nav--Visibility:var(--pf-c-pagination--m-display-full__nav--Visibility);--pf-c-pagination--c-options-menu--Display:var(--pf-c-pagination--m-display-full--c-options-menu--Display);--pf-c-pagination--c-options-menu--Visibility:var(--pf-c-pagination--m-display-full--c-options-menu--Visibility);--pf-c-pagination__total-items--Display:var(--pf-c-pagination--m-display-full__total-items--Display);--pf-c-pagination__total-items--Visibility:var(--pf-c-pagination--m-display-full__total-items--Visibility)}}@media (min-width:1200px){.pf-c-pagination.pf-m-display-summary-on-xl{--pf-c-pagination__nav--Display:var(--pf-c-pagination--m-display-summary__nav--Display);--pf-c-pagination__nav--Visibility:var(--pf-c-pagination--m-display-summary__nav--Visibility);--pf-c-pagination--c-options-menu--Display:var(--pf-c-pagination--m-display-summary--c-options-menu--Display);--pf-c-pagination--c-options-menu--Visibility:var(--pf-c-pagination--m-display-summary--c-options-menu--Visibility);--pf-c-pagination__total-items--Display:var(--pf-c-pagination--m-display-summary__total-items--Display);--pf-c-pagination__total-items--Visibility:var(--pf-c-pagination--m-display-summary__total-items--Visibility)}.pf-c-pagination.pf-m-display-full-on-xl{--pf-c-pagination__nav--Display:var(--pf-c-pagination--m-display-full__nav--Display);--pf-c-pagination__nav--Visibility:var(--pf-c-pagination--m-display-full__nav--Visibility);--pf-c-pagination--c-options-menu--Display:var(--pf-c-pagination--m-display-full--c-options-menu--Display);--pf-c-pagination--c-options-menu--Visibility:var(--pf-c-pagination--m-display-full--c-options-menu--Visibility);--pf-c-pagination__total-items--Display:var(--pf-c-pagination--m-display-full__total-items--Display);--pf-c-pagination__total-items--Visibility:var(--pf-c-pagination--m-display-full__total-items--Visibility)}}@media (min-width:1450px){.pf-c-pagination.pf-m-display-summary-on-2xl{--pf-c-pagination__nav--Display:var(--pf-c-pagination--m-display-summary__nav--Display);--pf-c-pagination__nav--Visibility:var(--pf-c-pagination--m-display-summary__nav--Visibility);--pf-c-pagination--c-options-menu--Display:var(--pf-c-pagination--m-display-summary--c-options-menu--Display);--pf-c-pagination--c-options-menu--Visibility:var(--pf-c-pagination--m-display-summary--c-options-menu--Visibility);--pf-c-pagination__total-items--Display:var(--pf-c-pagination--m-display-summary__total-items--Display);--pf-c-pagination__total-items--Visibility:var(--pf-c-pagination--m-display-summary__total-items--Visibility)}.pf-c-pagination.pf-m-display-full-on-2xl{--pf-c-pagination__nav--Display:var(--pf-c-pagination--m-display-full__nav--Display);--pf-c-pagination__nav--Visibility:var(--pf-c-pagination--m-display-full__nav--Visibility);--pf-c-pagination--c-options-menu--Display:var(--pf-c-pagination--m-display-full--c-options-menu--Display);--pf-c-pagination--c-options-menu--Visibility:var(--pf-c-pagination--m-display-full--c-options-menu--Visibility);--pf-c-pagination__total-items--Display:var(--pf-c-pagination--m-display-full__total-items--Display);--pf-c-pagination__total-items--Visibility:var(--pf-c-pagination--m-display-full__total-items--Visibility)}}.pf-c-popover{--pf-c-popover--FontSize:var(--pf-global--FontSize--sm);--pf-c-popover--MinWidth:calc(var(--pf-c-popover__content--PaddingLeft) + var(--pf-c-popover__content--PaddingRight) + 18.75rem);--pf-c-popover--MaxWidth:calc(var(--pf-c-popover__content--PaddingLeft) + var(--pf-c-popover__content--PaddingRight) + 18.75rem);--pf-c-popover--BoxShadow:var(--pf-global--BoxShadow--md);--pf-c-popover__content--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-popover__content--PaddingTop:var(--pf-global--spacer--md);--pf-c-popover__content--PaddingRight:var(--pf-global--spacer--md);--pf-c-popover__content--PaddingBottom:var(--pf-global--spacer--md);--pf-c-popover__content--PaddingLeft:var(--pf-global--spacer--md);--pf-c-popover__arrow--Width:var(--pf-global--arrow--width-lg);--pf-c-popover__arrow--Height:var(--pf-global--arrow--width-lg);--pf-c-popover__arrow--BoxShadow:var(--pf-global--BoxShadow--md);--pf-c-popover__arrow--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-popover__arrow--m-top--TranslateX:-50%;--pf-c-popover__arrow--m-top--TranslateY:50%;--pf-c-popover__arrow--m-top--Rotate:45deg;--pf-c-popover__arrow--m-right--TranslateX:-50%;--pf-c-popover__arrow--m-right--TranslateY:-50%;--pf-c-popover__arrow--m-right--Rotate:45deg;--pf-c-popover__arrow--m-bottom--TranslateX:-50%;--pf-c-popover__arrow--m-bottom--TranslateY:-50%;--pf-c-popover__arrow--m-bottom--Rotate:45deg;--pf-c-popover__arrow--m-left--TranslateX:50%;--pf-c-popover__arrow--m-left--TranslateY:-50%;--pf-c-popover__arrow--m-left--Rotate:45deg;--pf-c-popover--c-button--MarginLeft:var(--pf-global--spacer--sm);--pf-c-popover--c-button--Top:calc(var(--pf-c-popover__content--PaddingTop) - var(--pf-global--spacer--form-element));--pf-c-popover--c-button--Right:var(--pf-global--spacer--md);--pf-c-popover--c-button--sibling--PaddingRight:var(--pf-global--spacer--2xl);--pf-c-popover--c-title--MarginBottom:var(--pf-global--spacer--sm);--pf-c-popover__footer--MarginTop:var(--pf-global--spacer--md);position:relative;min-width:var(--pf-c-popover--MinWidth);max-width:var(--pf-c-popover--MaxWidth);font-size:var(--pf-c-popover--FontSize);box-shadow:var(--pf-c-popover--BoxShadow)}.pf-c-popover.pf-m-no-padding{--pf-c-popover__content--PaddingTop:0px;--pf-c-popover__content--PaddingRight:0px;--pf-c-popover__content--PaddingBottom:0px;--pf-c-popover__content--PaddingLeft:0px}.pf-c-popover.pf-m-width-auto{--pf-c-popover--MinWidth:auto;--pf-c-popover--MaxWidth:none}.pf-c-popover.pf-m-top .pf-c-popover__arrow{bottom:0;left:50%;transform:translateX(var(--pf-c-popover__arrow--m-top--TranslateX)) translateY(var(--pf-c-popover__arrow--m-top--TranslateY)) rotate(var(--pf-c-popover__arrow--m-top--Rotate))}.pf-c-popover.pf-m-bottom .pf-c-popover__arrow{top:0;left:50%;transform:translateX(var(--pf-c-popover__arrow--m-bottom--TranslateX)) translateY(var(--pf-c-popover__arrow--m-bottom--TranslateY)) rotate(var(--pf-c-popover__arrow--m-bottom--Rotate))}.pf-c-popover.pf-m-left .pf-c-popover__arrow{top:50%;right:0;transform:translateX(var(--pf-c-popover__arrow--m-left--TranslateX)) translateY(var(--pf-c-popover__arrow--m-left--TranslateY)) rotate(var(--pf-c-popover__arrow--m-left--Rotate))}.pf-c-popover.pf-m-right .pf-c-popover__arrow{top:50%;left:0;transform:translateX(var(--pf-c-popover__arrow--m-right--TranslateX)) translateY(var(--pf-c-popover__arrow--m-right--TranslateY)) rotate(var(--pf-c-popover__arrow--m-right--Rotate))}.pf-c-popover__content{position:relative;padding:var(--pf-c-popover__content--PaddingTop) var(--pf-c-popover__content--PaddingRight) var(--pf-c-popover__content--PaddingBottom) var(--pf-c-popover__content--PaddingLeft);background-color:var(--pf-c-popover__content--BackgroundColor)}.pf-c-popover__content>.pf-c-title{margin-bottom:var(--pf-c-popover--c-title--MarginBottom)}.pf-c-popover__content>.pf-c-button{position:absolute;top:var(--pf-c-popover--c-button--Top);right:var(--pf-c-popover--c-button--Right)}.pf-c-popover__content>.pf-c-button+*{padding-right:var(--pf-c-popover--c-button--sibling--PaddingRight)}.pf-c-popover__arrow{position:absolute;width:var(--pf-c-popover__arrow--Width);height:var(--pf-c-popover__arrow--Height);pointer-events:none;background-color:var(--pf-c-popover__arrow--BackgroundColor);box-shadow:var(--pf-c-popover__arrow--BoxShadow)}.pf-c-popover__body{word-wrap:break-word}.pf-c-popover__footer{margin-top:var(--pf-c-popover__footer--MarginTop)}.pf-c-progress{--pf-c-progress--GridGap:var(--pf-global--spacer--md);--pf-c-progress__bar--before--BackgroundColor:var(--pf-global--primary-color--100);--pf-c-progress__bar--Height:var(--pf-global--spacer--md);--pf-c-progress__bar--BackgroundColor:var(--pf-global--BackgroundColor--light-100);--pf-c-progress__measure--m-static-width--MinWidth:4.5ch;--pf-c-progress__status-icon--Color:var(--pf-global--Color--100);--pf-c-progress__status-icon--MarginLeft:var(--pf-global--spacer--sm);--pf-c-progress__bar--before--Opacity:.2;--pf-c-progress__indicator--Height:var(--pf-c-progress__bar--Height);--pf-c-progress__indicator--BackgroundColor:var(--pf-c-progress__bar--before--BackgroundColor);--pf-c-progress--m-success__bar--BackgroundColor:var(--pf-global--success-color--100);--pf-c-progress--m-warning__bar--BackgroundColor:var(--pf-global--warning-color--100);--pf-c-progress--m-danger__bar--BackgroundColor:var(--pf-global--danger-color--100);--pf-c-progress--m-success__status-icon--Color:var(--pf-global--success-color--100);--pf-c-progress--m-warning__status-icon--Color:var(--pf-global--warning-color--100);--pf-c-progress--m-danger__status-icon--Color:var(--pf-global--danger-color--100);--pf-c-progress--m-inside__indicator--MinWidth:var(--pf-global--spacer--xl);--pf-c-progress--m-inside__measure--Color:var(--pf-global--Color--light-100);--pf-c-progress--m-success--m-inside__measure--Color:var(--pf-global--Color--light-100);--pf-c-progress--m-warning--m-inside__measure--Color:var(--pf-global--Color--dark-100);--pf-c-progress--m-inside__measure--FontSize:var(--pf-global--FontSize--sm);--pf-c-progress--m-outside__measure--FontSize:var(--pf-global--FontSize--sm);--pf-c-progress--m-sm__bar--Height:var(--pf-global--spacer--sm);--pf-c-progress--m-sm__description--FontSize:var(--pf-global--FontSize--sm);--pf-c-progress--m-sm__measure--FontSize:var(--pf-global--FontSize--sm);--pf-c-progress--m-lg__bar--Height:var(--pf-global--spacer--lg);display:grid;align-items:end;grid-gap:var(--pf-c-progress--GridGap);grid-template-columns:auto auto;grid-template-rows:1fr auto}.pf-c-progress.pf-m-sm{--pf-c-progress__bar--Height:var(--pf-c-progress--m-sm__bar--Height)}.pf-c-progress.pf-m-sm .pf-c-progress__description{font-size:var(--pf-c-progress--m-sm__description--FontSize)}.pf-c-progress.pf-m-sm .pf-c-progress__measure{font-size:var(--pf-c-progress--m-sm__measure--FontSize)}.pf-c-progress.pf-m-lg{--pf-c-progress__bar--Height:var(--pf-c-progress--m-lg__bar--Height)}.pf-c-progress.pf-m-inside .pf-c-progress__indicator{display:flex;align-items:center;justify-content:center;min-width:var(--pf-c-progress--m-inside__indicator--MinWidth)}.pf-c-progress.pf-m-inside .pf-c-progress__measure{font-size:var(--pf-c-progress--m-inside__measure--FontSize);color:var(--pf-c-progress--m-inside__measure--Color);text-align:center}.pf-c-progress.pf-m-outside .pf-c-progress__description{grid-column:1/3}.pf-c-progress.pf-m-outside .pf-c-progress__status{grid-column:2/3;grid-row:2/3;align-self:center}.pf-c-progress.pf-m-outside .pf-c-progress__measure{display:inline-block;font-size:var(--pf-c-progress--m-outside__measure--FontSize)}.pf-c-progress.pf-m-outside .pf-c-progress__measure.pf-m-static-width{min-width:var(--pf-c-progress__measure--m-static-width--MinWidth);text-align:left}.pf-c-progress.pf-m-outside .pf-c-progress__bar,.pf-c-progress.pf-m-outside .pf-c-progress__indicator{grid-column:1/2}.pf-c-progress.pf-m-singleline{grid-template-rows:1fr}.pf-c-progress.pf-m-singleline .pf-c-progress__description{display:none;visibility:hidden}.pf-c-progress.pf-m-singleline .pf-c-progress__bar{grid-row:1/2;grid-column:1/2}.pf-c-progress.pf-m-singleline .pf-c-progress__status{grid-row:1/2;grid-column:2/3}.pf-c-progress.pf-m-outside,.pf-c-progress.pf-m-singleline{grid-template-columns:1fr fit-content(50%)}.pf-c-progress.pf-m-success{--pf-c-progress__bar--before--BackgroundColor:var(--pf-c-progress--m-success__bar--BackgroundColor);--pf-c-progress__status-icon--Color:var(--pf-c-progress--m-success__status-icon--Color);--pf-c-progress--m-inside__measure--Color:var(--pf-c-progress--m-success--m-inside__measure--Color)}.pf-c-progress.pf-m-warning{--pf-c-progress__bar--before--BackgroundColor:var(--pf-c-progress--m-warning__bar--BackgroundColor);--pf-c-progress__status-icon--Color:var(--pf-c-progress--m-warning__status-icon--Color);--pf-c-progress--m-inside__measure--Color:var(--pf-c-progress--m-warning--m-inside__measure--Color)}.pf-c-progress.pf-m-danger{--pf-c-progress__bar--before--BackgroundColor:var(--pf-c-progress--m-danger__bar--BackgroundColor);--pf-c-progress__status-icon--Color:var(--pf-c-progress--m-danger__status-icon--Color)}.pf-c-progress__description{word-break:break-word;grid-column:1/2}.pf-c-progress__description.pf-m-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pf-c-progress__status{grid-column:2/3;grid-row:1/2;text-align:right;word-break:break-word}.pf-c-progress__status-icon{margin-left:var(--pf-c-progress__status-icon--MarginLeft);color:var(--pf-c-progress__status-icon--Color)}.pf-c-progress__bar{position:relative;grid-column:1/3;grid-row:2/3;align-self:center;height:var(--pf-c-progress__bar--Height);background-color:var(--pf-c-progress__bar--BackgroundColor)}.pf-c-progress__bar:before{position:absolute;top:0;left:0;width:100%;height:100%;content:"";background-color:var(--pf-c-progress__bar--before--BackgroundColor);opacity:var(--pf-c-progress__bar--before--Opacity)}.pf-c-progress__indicator{position:absolute;top:0;left:0;height:var(--pf-c-progress__indicator--Height);background-color:var(--pf-c-progress__indicator--BackgroundColor)}.pf-c-radio{--pf-c-radio--GridGap:var(--pf-global--spacer--xs) var(--pf-global--spacer--sm);--pf-c-radio__label--disabled--Color:var(--pf-global--disabled-color--100);--pf-c-radio__label--Color:var(--pf-global--Color--100);--pf-c-radio__label--FontWeight:var(--pf-global--FontWeight--normal);--pf-c-radio__label--FontSize:var(--pf-global--FontSize--md);--pf-c-radio__label--LineHeight:var(--pf-global--LineHeight--sm);--pf-c-radio__input--MarginTop:-0.1875rem;--pf-c-radio__input--first-child--MarginLeft:0.0625rem;--pf-c-radio__input--last-child--MarginRight:0.0625rem;--pf-c-radio__description--FontSize:var(--pf-global--FontSize--sm);--pf-c-radio__description--Color:var(--pf-global--Color--200);display:grid;grid-template-columns:auto 1fr;grid-gap:var(--pf-c-radio--GridGap);align-items:center;justify-items:start}.pf-c-radio__label{font-size:var(--pf-c-radio__label--FontSize);font-weight:var(--pf-c-radio__label--FontWeight);line-height:var(--pf-c-radio__label--LineHeight);color:var(--pf-c-radio__label--Color)}.pf-c-radio__input{margin-top:var(--pf-c-radio__input--MarginTop)}.pf-c-radio__input:first-child{margin-left:var(--pf-c-radio__input--first-child--MarginLeft)}.pf-c-radio__input:last-child{margin-right:var(--pf-c-radio__input--last-child--MarginRight)}.pf-c-radio__description{grid-column:2;font-size:var(--pf-c-radio__description--FontSize);color:var(--pf-c-radio__description--Color)}.pf-c-radio__input,.pf-c-radio__label,label.pf-c-radio{cursor:pointer}.pf-c-radio__input.pf-m-disabled,.pf-c-radio__input:disabled,.pf-c-radio__label.pf-m-disabled,.pf-c-radio__label:disabled{--pf-c-radio__label--Color:var(--pf-c-radio__label--disabled--Color);cursor:not-allowed}.pf-c-search-input{--pf-c-search-input__text--before--BorderWidth:var(--pf-global--BorderWidth--sm);--pf-c-search-input__text--before--BorderColor:var(--pf-global--BorderColor--300);--pf-c-search-input__text--after--BorderBottomWidth:var(--pf-global--BorderWidth--sm);--pf-c-search-input__text--after--BorderBottomColor:var(--pf-global--BorderColor--200);--pf-c-search-input--hover__text--after--BorderBottomColor:var(--pf-global--primary-color--100);--pf-c-search-input__text--focus-within--after--BorderBottomWidth:var(--pf-global--BorderWidth--md);--pf-c-search-input__text--focus-within--after--BorderBottomColor:var(--pf-global--primary-color--100);--pf-c-search-input__text-input--PaddingTop:var(--pf-global--spacer--form-element);--pf-c-search-input__text-input--PaddingRight:var(--pf-global--spacer--sm);--pf-c-search-input__text-input--PaddingBottom:var(--pf-global--spacer--form-element);--pf-c-search-input__text-input--PaddingLeft:var(--pf-global--spacer--xl);--pf-c-search-input__text-input--MinWidth:6ch;--pf-c-search-input__icon--Left:var(--pf-global--spacer--sm);--pf-c-search-input__icon--Color:var(--pf-global--Color--200);--pf-c-search-input__text--hover__icon--Color:var(--pf-global--Color--100);--pf-c-search-input__icon--TranslateY:-50%;--pf-c-search-input__utilities--MarginRight:var(--pf-global--spacer--sm);--pf-c-search-input__utilities--MarginLeft:var(--pf-global--spacer--xs);--pf-c-search-input__utilities--child--MarginLeft:var(--pf-global--spacer--xs);--pf-c-search-input__utilities--c-button--PaddingRight:var(--pf-global--spacer--xs);--pf-c-search-input__utilities--c-button--PaddingLeft:var(--pf-global--spacer--xs);position:relative;display:flex;padding:var(--pf-c-search-input--PaddingTop) var(--pf-c-search-input--PaddingRight) var(--pf-c-search-input--PaddingBottom) var(--pf-c-search-input--PaddingLeft)}.pf-c-search-input:hover{--pf-c-search-input__text--after--BorderBottomColor:var(--pf-c-search-input--hover__text--after--BorderBottomColor)}.pf-c-search-input__text{flex:1}.pf-c-search-input__text:after,.pf-c-search-input__text:before{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none;content:""}.pf-c-search-input__text:before{border:var(--pf-c-search-input__text--before--BorderWidth) solid var(--pf-c-search-input__text--before--BorderColor)}.pf-c-search-input__text:after{border-bottom:var(--pf-c-search-input__text--after--BorderBottomWidth) solid var(--pf-c-search-input__text--after--BorderBottomColor)}.pf-c-search-input__text:focus-within,.pf-c-search-input__text:hover{--pf-c-search-input__icon--Color:var(--pf-c-search-input__text--hover__icon--Color)}.pf-c-search-input__text:focus-within{--pf-c-search-input__text--after--BorderBottomWidth:var(--pf-c-search-input__text--focus-within--after--BorderBottomWidth);--pf-c-search-input__text--after--BorderBottomColor:var(--pf-c-search-input__text--focus-within--after--BorderBottomColor)}.pf-c-search-input__icon{position:absolute;top:50%;left:var(--pf-c-search-input__icon--Left);color:var(--pf-c-search-input__icon--Color);transform:translateY(var(--pf-c-search-input__icon--TranslateY))}.pf-c-search-input__text-input{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;position:relative;width:100%;min-width:var(--pf-c-search-input__text-input--MinWidth);padding:var(--pf-c-search-input__text-input--PaddingTop) var(--pf-c-search-input__text-input--PaddingRight) var(--pf-c-search-input__text-input--PaddingBottom) var(--pf-c-search-input__text-input--PaddingLeft);border:0}.pf-c-search-input__utilities{display:flex;margin-right:var(--pf-c-search-input__utilities--MarginRight);margin-left:var(--pf-c-search-input__utilities--MarginLeft)}.pf-c-search-input__utilities>*+*{margin-left:var(--pf-c-search-input__utilities--child--MarginLeft)}.pf-c-search-input__utilities .pf-c-button{--pf-c-button--PaddingRight:var(--pf-c-search-input__utilities--c-button--PaddingRight);--pf-c-button--PaddingLeft:var(--pf-c-search-input__utilities--c-button--PaddingLeft)}.pf-c-search-input__nav{display:flex}.pf-c-search-input__count{display:flex;align-items:center}.pf-c-select{color:var(--pf-global--Color--100);--pf-c-select__toggle--PaddingTop:var(--pf-global--spacer--form-element);--pf-c-select__toggle--PaddingRight:var(--pf-global--spacer--sm);--pf-c-select__toggle--PaddingBottom:var(--pf-global--spacer--form-element);--pf-c-select__toggle--PaddingLeft:var(--pf-global--spacer--sm);--pf-c-select__toggle--MinWidth:var(--pf-global--target-size--MinWidth);--pf-c-select__toggle--FontSize:var(--pf-global--FontSize--md);--pf-c-select__toggle--FontWeight:var(--pf-global--FontWeight--normal);--pf-c-select__toggle--LineHeight:var(--pf-global--LineHeight--md);--pf-c-select__toggle--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-select__toggle--before--BorderWidth:var(--pf-global--BorderWidth--sm);--pf-c-select__toggle--before--BorderTopColor:var(--pf-global--BorderColor--300);--pf-c-select__toggle--before--BorderRightColor:var(--pf-global--BorderColor--300);--pf-c-select__toggle--before--BorderBottomColor:var(--pf-global--BorderColor--200);--pf-c-select__toggle--before--BorderLeftColor:var(--pf-global--BorderColor--300);--pf-c-select__toggle--Color:var(--pf-global--Color--100);--pf-c-select__toggle--hover--before--BorderBottomColor:var(--pf-global--active-color--100);--pf-c-select__toggle--focus--before--BorderBottomColor:var(--pf-global--active-color--100);--pf-c-select__toggle--active--before--BorderBottomColor:var(--pf-global--active-color--100);--pf-c-select__toggle--m-expanded--before--BorderBottomColor:var(--pf-global--active-color--100);--pf-c-select__toggle--focus--before--BorderBottomWidth:var(--pf-global--BorderWidth--md);--pf-c-select__toggle--active--before--BorderBottomWidth:var(--pf-global--BorderWidth--md);--pf-c-select__toggle--m-expanded--before--BorderBottomWidth:var(--pf-global--BorderWidth--md);--pf-c-select__toggle--disabled--BackgroundColor:var(--pf-global--disabled-color--300);--pf-c-select__toggle--m-plain--before--BorderColor:transparent;--pf-c-select__toggle-wrapper--not-last-child--MarginRight:var(--pf-global--spacer--xs);--pf-c-select__toggle-wrapper--MaxWidth:calc(100% - var(--pf-global--spacer--lg));--pf-c-select__toggle-wrapper--c-chip-group--MarginTop:0.3125rem;--pf-c-select__toggle-wrapper--c-chip-group--MarginBottom:0.3125rem;--pf-c-select__toggle-typeahead--FlexBasis:10em;--pf-c-select__toggle-typeahead--BackgroundColor:transparent;--pf-c-select__toggle-typeahead--BorderTop:none;--pf-c-select__toggle-typeahead--BorderRight:none;--pf-c-select__toggle-typeahead--BorderLeft:none;--pf-c-select__toggle-typeahead--MinWidth:7.5rem;--pf-c-select__toggle-typeahead--focus--PaddingBottom:calc(var(--pf-global--spacer--form-element) - var(--pf-global--BorderWidth--sm));--pf-c-select__toggle-icon--toggle-text--MarginLeft:var(--pf-global--spacer--xs);--pf-c-select__toggle-badge--PaddingLeft:var(--pf-global--spacer--sm);--pf-c-select__toggle-arrow--MarginLeft:var(--pf-global--spacer--md);--pf-c-select__toggle-arrow--MarginRight:var(--pf-global--spacer--sm);--pf-c-select__toggle-arrow--with-clear--MarginLeft:var(--pf-global--spacer--sm);--pf-c-select__toggle-arrow--m-top--m-expanded__toggle-arrow--Rotate:180deg;--pf-c-select__toggle-clear--PaddingRight:var(--pf-global--spacer--sm);--pf-c-select__toggle-clear--PaddingLeft:var(--pf-global--spacer--md);--pf-c-select__toggle-clear--toggle-button--PaddingLeft:var(--pf-global--spacer--sm);--pf-c-select__toggle-button--Color:var(--pf-global--Color--100);--pf-c-select__menu--BackgroundColor:var(--pf-global--BackgroundColor--light-100);--pf-c-select__menu--BoxShadow:var(--pf-global--BoxShadow--md);--pf-c-select__menu--PaddingTop:var(--pf-global--spacer--sm);--pf-c-select__menu--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-select__menu--Top:calc(100% + var(--pf-global--spacer--xs));--pf-c-select__menu--ZIndex:var(--pf-global--ZIndex--sm);--pf-c-select__menu--m-top--TranslateY:calc(-100% - var(--pf-global--spacer--xs));--pf-c-select__menu-item--PaddingTop:var(--pf-global--spacer--sm);--pf-c-select__menu-item--PaddingRight:var(--pf-global--spacer--md);--pf-c-select__menu-item--m-selected--PaddingRight:var(--pf-global--spacer--2xl);--pf-c-select__menu-item--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-select__menu-item--PaddingLeft:var(--pf-global--spacer--md);--pf-c-select__menu-item--FontSize:var(--pf-global--FontSize--md);--pf-c-select__menu-item--FontWeight:var(--pf-global--FontWeight--normal);--pf-c-select__menu-item--LineHeight:var(--pf-global--LineHeight--md);--pf-c-select__menu-item--Color:var(--pf-global--Color--dark-100);--pf-c-select__menu-item--Width:100%;--pf-c-select__menu-item--disabled--Color:var(--pf-global--Color--dark-200);--pf-c-select__menu-item--hover--BackgroundColor:var(--pf-global--BackgroundColor--light-300);--pf-c-select__menu-item--focus--BackgroundColor:var(--pf-global--BackgroundColor--light-300);--pf-c-select__menu-item--disabled--BackgroundColor:transparent;--pf-c-select__menu-item--m-link--Width:auto;--pf-c-select__menu-item--m-link--hover--BackgroundColor:transparent;--pf-c-select__menu-item--m-link--focus--BackgroundColor:transparent;--pf-c-select__menu-item--m-action--Color:var(--pf-global--disabled-color--200);--pf-c-select__menu-item--m-action--Width:auto;--pf-c-select__menu-item--m-action--FontSize:var(--pf-global--icon--FontSize--sm);--pf-c-select__menu-item--m-action--hover--BackgroundColor:transparent;--pf-c-select__menu-item--m-action--focus--BackgroundColor:transparent;--pf-c-select__menu-item--hover__menu-item--m-action--Color:var(--pf-global--Color--200);--pf-c-select__menu-item--m-action--hover--Color:var(--pf-global--Color--100);--pf-c-select__menu-item--m-action--focus--Color:var(--pf-global--Color--100);--pf-c-select__menu-wrapper--m-favorite__menu-item--m-favorite-action--Color:var(--pf-global--palette--gold-400);--pf-c-select__menu-item-icon--Color:var(--pf-global--active-color--100);--pf-c-select__menu-item-icon--FontSize:var(--pf-global--icon--FontSize--sm);--pf-c-select__menu-item-icon--Right:var(--pf-global--spacer--md);--pf-c-select__menu-item-icon--Top:50%;--pf-c-select__menu-item-icon--TranslateY:-50%;--pf-c-select__menu-item-action-icon--MinHeight:calc(var(--pf-c-select__menu-item--FontSize)*var(--pf-c-select__menu-item--LineHeight));--pf-c-select__menu-item--match--FontWeight:var(--pf-global--FontWeight--bold);--pf-c-select__menu-search--PaddingTop:var(--pf-global--spacer--sm);--pf-c-select__menu-search--PaddingRight:var(--pf-c-select__menu-item--PaddingRight);--pf-c-select__menu-search--PaddingBottom:var(--pf-global--spacer--md);--pf-c-select__menu-search--PaddingLeft:var(--pf-c-select__menu-item--PaddingLeft);--pf-c-select__menu-group--menu-group--PaddingTop:var(--pf-global--spacer--sm);--pf-c-select__menu-group-title--PaddingTop:var(--pf-c-select__menu-item--PaddingTop);--pf-c-select__menu-group-title--PaddingRight:var(--pf-c-select__menu-item--PaddingRight);--pf-c-select__menu-group-title--PaddingBottom:var(--pf-c-select__menu-item--PaddingBottom);--pf-c-select__menu-group-title--PaddingLeft:var(--pf-c-select__menu-item--PaddingLeft);--pf-c-select__menu-group-title--FontSize:var(--pf-global--FontSize--sm);--pf-c-select__menu-group-title--FontWeight:var(--pf-global--FontWeight--semi-bold);--pf-c-select__menu-group-title--Color:var(--pf-global--Color--dark-200);--pf-c-select__menu-item-description--FontSize:var(--pf-global--FontSize--xs);--pf-c-select__menu-item-description--Color:var(--pf-global--Color--200);--pf-c-select__menu-item-description--PaddingRight:var(--pf-c-select__menu-item--PaddingRight);--pf-c-select__menu-item-main--PaddingRight:var(--pf-c-select__menu-item--PaddingRight);--pf-c-select__menu-item--m-selected__menu-item-main--PaddingRight:var(--pf-c-select__menu-item--m-selected--PaddingRight);--pf-c-select-menu--c-divider--MarginTop:var(--pf-global--spacer--sm);--pf-c-select-menu--c-divider--MarginBottom:var(--pf-global--spacer--sm);position:relative;display:inline-block;width:100%}.pf-c-select .pf-c-divider{margin-top:var(--pf-c-select-menu--c-divider--MarginTop);margin-bottom:var(--pf-c-select-menu--c-divider--MarginBottom)}.pf-c-select .pf-c-divider:last-child{--pf-c-select-menu--c-divider--MarginBottom:0}.pf-c-select__menu-search+.pf-c-divider{--pf-c-select-menu--c-divider--MarginTop:0}.pf-c-select__toggle{position:relative;display:flex;align-items:center;justify-content:space-between;width:100%;min-width:var(--pf-c-select__toggle--MinWidth);padding:var(--pf-c-select__toggle--PaddingTop) var(--pf-c-select__toggle--PaddingRight) var(--pf-c-select__toggle--PaddingBottom) var(--pf-c-select__toggle--PaddingLeft);font-size:var(--pf-c-select__toggle--FontSize);font-weight:var(--pf-c-select__toggle--FontWeight);line-height:var(--pf-c-select__toggle--LineHeight);color:var(--pf-c-select__toggle--Color);white-space:nowrap;cursor:pointer;background-color:var(--pf-c-select__toggle--BackgroundColor);border:none}.pf-c-select__toggle.pf-m-disabled,.pf-c-select__toggle:disabled{--pf-c-select__toggle--BackgroundColor:var(--pf-c-select__toggle--disabled--BackgroundColor);pointer-events:none}.pf-c-select__toggle.pf-m-disabled:before,.pf-c-select__toggle:disabled:before{border:0}.pf-c-select__toggle:before{position:absolute;top:0;right:0;bottom:0;left:0;content:"";border:var(--pf-c-select__toggle--before--BorderWidth) solid;border-color:var(--pf-c-select__toggle--before--BorderTopColor) var(--pf-c-select__toggle--before--BorderRightColor) var(--pf-c-select__toggle--before--BorderBottomColor) var(--pf-c-select__toggle--before--BorderLeftColor)}.pf-c-select__toggle:hover:before{--pf-c-select__toggle--before--BorderBottomColor:var(--pf-c-select__toggle--hover--before--BorderBottomColor)}.pf-c-select__toggle:focus-within:before,.pf-c-select__toggle:focus:before{--pf-c-select__toggle--before--BorderBottomColor:var(--pf-c-select__toggle--focus--before--BorderBottomColor);border-bottom-width:var(--pf-c-select__toggle--focus--before--BorderBottomWidth)}.pf-c-select__toggle.pf-m-active:before,.pf-c-select__toggle:active:before{--pf-c-select__toggle--before--BorderBottomColor:var(--pf-c-select__toggle--active--before--BorderBottomColor);border-bottom-width:var(--pf-c-select__toggle--active--before--BorderBottomWidth)}.pf-m-expanded>.pf-c-select__toggle:before{--pf-c-select__toggle--before--BorderBottomColor:var(--pf-c-select__toggle--m-expanded--before--BorderBottomColor);border-bottom-width:var(--pf-c-select__toggle--m-expanded--before--BorderBottomWidth)}.pf-c-select__toggle.pf-m-plain:before{border-color:var(--pf-c-select__toggle--m-plain--before--BorderColor)}.pf-c-select__toggle.pf-m-typeahead{--pf-c-select__toggle--PaddingTop:0;--pf-c-select__toggle--PaddingRight:0;--pf-c-select__toggle--PaddingBottom:0}.pf-c-select__toggle.pf-m-typeahead .pf-c-form-control{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;position:relative;height:auto}.pf-c-select__toggle .pf-c-select__toggle-clear{padding-right:var(--pf-c-select__toggle-clear--PaddingRight);padding-left:var(--pf-c-select__toggle-clear--PaddingLeft);margin-left:auto}.pf-c-select__toggle .pf-c-select__toggle-button{color:var(--pf-c-select__toggle-button--Color)}.pf-c-select__toggle .pf-c-select__toggle-clear+.pf-c-select__toggle-button{padding-left:var(--pf-c-select__toggle-clear--toggle-button--PaddingLeft)}*+.pf-c-select__toggle-arrow{margin-right:var(--pf-c-select__toggle-arrow--MarginRight);margin-left:var(--pf-c-select__toggle-arrow--MarginLeft)}.pf-c-select.pf-m-top.pf-m-expanded .pf-c-select__toggle-arrow{transform:rotate(var(--pf-c-select__toggle-arrow--m-top--m-expanded__toggle-arrow--Rotate))}.pf-c-select__toggle-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pf-c-select__toggle-wrapper{display:flex;flex:1;flex-wrap:wrap;align-items:center;justify-content:flex-start;min-width:0;max-width:var(--pf-c-select__toggle-wrapper--MaxWidth);white-space:normal}.pf-c-select__toggle-wrapper>:not(:last-child){margin-right:var(--pf-c-select__toggle-wrapper--not-last-child--MarginRight)}.pf-c-select__toggle-wrapper>.pf-c-form-control{margin-top:calc(-1*var(--pf-c-select__toggle-wrapper--m-typeahead--PaddingTop))}.pf-c-select__toggle-wrapper .pf-c-chip-group{margin-top:var(--pf-c-select__toggle-wrapper--c-chip-group--MarginTop);margin-bottom:var(--pf-c-select__toggle-wrapper--c-chip-group--MarginBottom)}.pf-c-select__toggle-wrapper>.pf-c-select__toggle-typeahead:first-child{margin-left:calc(-1*var(--pf-c-select__toggle--PaddingLeft))}.pf-c-select__toggle-icon+.pf-c-select__toggle-text{margin-left:var(--pf-c-select__toggle-icon--toggle-text--MarginLeft)}.pf-c-select__toggle-badge{display:flex;padding-left:var(--pf-c-select__toggle-badge--PaddingLeft)}.pf-c-select__toggle-typeahead{flex-basis:var(--pf-c-select__toggle-typeahead--FlexBasis);flex-grow:1;min-width:var(--pf-c-select__toggle-typeahead--MinWidth);background-color:var(--pf-c-select__toggle-typeahead--BackgroundColor);border-top:var(--pf-c-select__toggle-typeahead--BorderTop);border-right:var(--pf-c-select__toggle-typeahead--BorderRight);border-bottom:inherit;border-left:var(--pf-c-select__toggle-typeahead--BorderLeft);flex-shrink:0}.pf-c-select__toggle-typeahead:focus{padding-bottom:var(--pf-c-select__toggle-typeahead--focus--PaddingBottom)}.pf-c-select__menu{position:absolute;top:var(--pf-c-select__menu--Top);z-index:var(--pf-c-select__menu--ZIndex);min-width:100%;padding-top:var(--pf-c-select__menu--PaddingTop);padding-bottom:var(--pf-c-select__menu--PaddingBottom);background-color:var(--pf-c-select__menu--BackgroundColor);background-clip:padding-box;box-shadow:var(--pf-c-select__menu--BoxShadow)}.pf-c-select__menu.pf-m-align-right{right:0}.pf-c-select.pf-m-top .pf-c-select__menu{top:0;transform:translateY(var(--pf-c-select__menu--m-top--TranslateY))}.pf-c-select__menu-fieldset{border:0}.pf-c-select__menu-wrapper{display:flex}.pf-c-select__menu-wrapper.pf-m-favorite .pf-c-select__menu-item.pf-m-favorite-action{--pf-c-select__menu-item--Color:var(--pf-c-select__menu-wrapper--m-favorite__menu-item--m-favorite-action--Color)}.pf-c-select__menu-item{position:relative;width:var(--pf-c-select__menu-item--Width);padding:var(--pf-c-select__menu-item--PaddingTop) var(--pf-c-select__menu-item--PaddingRight) var(--pf-c-select__menu-item--PaddingBottom) var(--pf-c-select__menu-item--PaddingLeft);font-size:var(--pf-c-select__menu-item--FontSize);font-weight:var(--pf-c-select__menu-item--FontWeight);line-height:var(--pf-c-select__menu-item--LineHeight);color:var(--pf-c-select__menu-item--Color);text-align:left;white-space:nowrap;background-color:transparent;border:none}.pf-c-select__menu-item.pf-m-focus,.pf-c-select__menu-item:focus,.pf-c-select__menu-item:hover{--pf-c-select__menu-item--m-action--Color:var(--pf-c-select__menu-item--hover__menu-item--m-action--Color);text-decoration:none}.pf-c-select__menu-item:hover,.pf-c-select__menu-wrapper:hover{background-color:var(--pf-c-select__menu-item--hover--BackgroundColor)}.pf-c-select__menu-item.pf-m-focus,.pf-c-select__menu-item:focus,.pf-c-select__menu-wrapper.pf-m-focus,.pf-c-select__menu-wrapper:focus-within{position:relative;background-color:var(--pf-c-select__menu-item--focus--BackgroundColor)}.pf-c-select__menu-item.pf-m-link{--pf-c-select__menu-item--PaddingRight:0;--pf-c-select__menu-item-main--PaddingRight:0;--pf-c-select__menu-item-description--PaddingRight:0;--pf-c-select__menu-item--Width:var(--pf-c-select__menu-item--m-link--Width);--pf-c-select__menu-item--hover--BackgroundColor:var(--pf-c-select__menu-item--m-link--hover--BackgroundColor);--pf-c-select__menu-item--focus--BackgroundColor:var(--pf-c-select__menu-item--m-link--focus--BackgroundColor);flex-grow:1}.pf-c-select__menu-item.pf-m-action{--pf-c-select__menu-item--Color:var(--pf-c-select__menu-item--m-action--Color);--pf-c-select__menu-item--Width:var(--pf-c-select__menu-item--m-action--Width);--pf-c-select__menu-item--hover--BackgroundColor:var(--pf-c-select__menu-item--m-action--hover--BackgroundColor);--pf-c-select__menu-item--focus--BackgroundColor:var(--pf-c-select__menu-item--m-action--focus--BackgroundColor);display:flex;align-items:flex-start;font-size:var(--pf-c-select__menu-item--m-action--FontSize)}.pf-c-select__menu-item.pf-m-action:hover{--pf-c-select__menu-item--m-action--Color:var(--pf-c-select__menu-item--m-action--hover--Color)}.pf-c-select__menu-item.pf-m-action:focus{--pf-c-select__menu-item--m-action--Color:var(--pf-c-select__menu-item--m-action--focus--Color)}.pf-c-select__menu-item.pf-m-selected{--pf-c-select__menu-item--PaddingRight:var(--pf-c-select__menu-item--m-selected--PaddingRight);--pf-c-select__menu-item-main--PaddingRight:var(--pf-c-select__menu-item--m-selected__menu-item-main--PaddingRight)}.pf-c-select__menu-item.pf-m-description{white-space:normal}.pf-c-select__menu-item.pf-m-description:not(.pf-c-check){--pf-c-select__menu-item--PaddingRight:0}.pf-c-select__menu-item.pf-m-description .pf-c-check__label{white-space:nowrap}.pf-c-select__menu-item.pf-m-disabled,.pf-c-select__menu-item:disabled,.pf-c-select__menu-wrapper.pf-m-disabled{color:var(--pf-c-select__menu-item--disabled--Color);pointer-events:none;background-color:var(--pf-c-select__menu-item--disabled--BackgroundColor)}.pf-c-select__menu-item-main{position:relative;display:block;padding-right:var(--pf-c-select__menu-item-main--PaddingRight);white-space:nowrap}.pf-c-select__menu-item-description{display:block;padding-right:var(--pf-c-select__menu-item-description--PaddingRight);font-size:var(--pf-c-select__menu-item-description--FontSize);color:var(--pf-c-select__menu-item-description--Color)}.pf-c-select__menu-item-icon{position:absolute;top:var(--pf-c-select__menu-item-icon--Top);right:var(--pf-c-select__menu-item-icon--Right);font-size:var(--pf-c-select__menu-item-icon--FontSize);color:var(--pf-c-select__menu-item-icon--Color);transform:translateY(var(--pf-c-select__menu-item-icon--TranslateY))}.pf-c-select__menu-item-action-icon{display:flex;align-items:center;min-height:var(--pf-c-select__menu-item-action-icon--MinHeight)}.pf-c-select__menu-item--match{font-weight:var(--pf-c-select__menu-item--match--FontWeight);background-color:inherit}.pf-c-select__menu-group+.pf-c-select__menu-group{padding-top:var(--pf-c-select__menu-group--menu-group--PaddingTop)}.pf-c-select__menu-search{padding:var(--pf-c-select__menu-search--PaddingTop) var(--pf-c-select__menu-search--PaddingRight) var(--pf-c-select__menu-search--PaddingBottom) var(--pf-c-select__menu-search--PaddingLeft)}.pf-c-select__menu-group-title{padding:var(--pf-c-select__menu-group-title--PaddingTop) var(--pf-c-select__menu-group-title--PaddingRight) var(--pf-c-select__menu-group-title--PaddingBottom) var(--pf-c-select__menu-group-title--PaddingLeft);font-size:var(--pf-c-select__menu-group-title--FontSize);font-weight:var(--pf-c-select__menu-group-title--FontWeight);color:var(--pf-c-select__menu-group-title--Color)}.pf-c-simple-list{--pf-c-simple-list__item-link--PaddingTop:var(--pf-global--spacer--xs);--pf-c-simple-list__item-link--PaddingRight:var(--pf-global--spacer--md);--pf-c-simple-list__item-link--PaddingBottom:var(--pf-global--spacer--xs);--pf-c-simple-list__item-link--PaddingLeft:var(--pf-global--spacer--md);--pf-c-simple-list__item-link--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-simple-list__item-link--Color:var(--pf-global--Color--100);--pf-c-simple-list__item-link--FontSize:var(--pf-global--FontSize--sm);--pf-c-simple-list__item-link--FontWeight:var(--pf-global--FontWeight--normal);--pf-c-simple-list__item-link--m-current--Color:var(--pf-global--link--Color);--pf-c-simple-list__item-link--m-current--BackgroundColor:var(--pf-global--BackgroundColor--200);--pf-c-simple-list__item-link--m-current--FontWeight:var(--pf-global--FontWeight--semi-bold);--pf-c-simple-list__item-link--hover--Color:var(--pf-global--link--Color);--pf-c-simple-list__item-link--hover--BackgroundColor:var(--pf-global--BackgroundColor--200);--pf-c-simple-list__item-link--focus--Color:var(--pf-global--link--Color);--pf-c-simple-list__item-link--focus--BackgroundColor:var(--pf-global--BackgroundColor--200);--pf-c-simple-list__item-link--focus--FontWeight:var(--pf-global--FontWeight--semi-bold);--pf-c-simple-list__item-link--active--Color:var(--pf-global--link--Color);--pf-c-simple-list__item-link--active--BackgroundColor:var(--pf-global--BackgroundColor--200);--pf-c-simple-list__item-link--active--FontWeight:var(--pf-global--FontWeight--semi-bold);--pf-c-simple-list__title--PaddingTop:var(--pf-global--spacer--sm);--pf-c-simple-list__title--PaddingRight:var(--pf-global--spacer--md);--pf-c-simple-list__title--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-simple-list__title--PaddingLeft:var(--pf-global--spacer--md);--pf-c-simple-list__title--FontSize:var(--pf-global--FontSize--sm);--pf-c-simple-list__title--Color:var(--pf-global--Color--dark-200);--pf-c-simple-list__title--FontWeight:var(--pf-global--FontWeight--semi-bold);--pf-c-simple-list__section--section--MarginTop:var(--pf-global--spacer--sm)}.pf-c-simple-list__item-link{display:block;width:100%;padding:var(--pf-c-simple-list__item-link--PaddingTop) var(--pf-c-simple-list__item-link--PaddingRight) var(--pf-c-simple-list__item-link--PaddingBottom) var(--pf-c-simple-list__item-link--PaddingLeft);font-size:var(--pf-c-simple-list__item-link--FontSize);font-weight:var(--pf-c-simple-list__item-link--FontWeight);color:var(--pf-c-simple-list__item-link--Color);text-align:left;background-color:var(--pf-c-simple-list__item-link--BackgroundColor);border:none}.pf-c-simple-list__item-link.pf-m-current{--pf-c-simple-list__item-link--FontWeight:var(--pf-c-simple-list__item-link--m-current--FontWeight);--pf-c-simple-list__item-link--BackgroundColor:var(--pf-c-simple-list__item-link--m-current--BackgroundColor);--pf-c-simple-list__item-link--Color:var(--pf-c-simple-list__item-link--m-current--Color)}.pf-c-simple-list__item-link:hover{text-decoration:none;--pf-c-simple-list__item-link--BackgroundColor:var(--pf-c-simple-list__item-link--hover--BackgroundColor);--pf-c-simple-list__item-link--Color:var(--pf-c-simple-list__item-link--hover--Color)}.pf-c-simple-list__item-link:focus{--pf-c-simple-list__item-link--FontWeight:var(--pf-c-simple-list__item-link--focus--FontWeight);--pf-c-simple-list__item-link--BackgroundColor:var(--pf-c-simple-list__item-link--focus--BackgroundColor);--pf-c-simple-list__item-link--Color:var(--pf-c-simple-list__item-link--focus--Color)}.pf-c-simple-list__item-link:active{--pf-c-simple-list__item-link--FontWeight:var(--pf-c-simple-list__item-link--active--FontWeight);--pf-c-simple-list__item-link--BackgroundColor:var(--pf-c-simple-list__item-link--active--BackgroundColor);--pf-c-simple-list__item-link--Color:var(--pf-c-simple-list__item-link--active--Color)}.pf-c-simple-list__title{padding:var(--pf-c-simple-list__title--PaddingTop) var(--pf-c-simple-list__title--PaddingRight) var(--pf-c-simple-list__title--PaddingBottom) var(--pf-c-simple-list__title--PaddingLeft);font-size:var(--pf-c-simple-list__title--FontSize);font-weight:var(--pf-c-simple-list__title--FontWeight);color:var(--pf-c-simple-list__title--Color)}.pf-c-simple-list__section+.pf-c-simple-list__section{margin-top:var(--pf-c-simple-list__section--section--MarginTop)}.pf-c-skeleton{--pf-c-skeleton--BackgroundColor:var(--pf-global--palette--black-150);--pf-c-skeleton--Width:auto;--pf-c-skeleton--Height:auto;--pf-c-skeleton--BorderRadius:var(--pf-global--BorderRadius--sm);--pf-c-skeleton--before--PaddingBottom:0;--pf-c-skeleton--before--Height:auto;--pf-c-skeleton--before--Content:"\00a0";--pf-c-skeleton--after--LinearGradientAngle:90deg;--pf-c-skeleton--after--LinearGradientColorStop1:hsla(0,0%,92.9%,0);--pf-c-skeleton--after--LinearGradientColorStop2:#ededed;--pf-c-skeleton--after--LinearGradientColorStop3:hsla(0,0%,92.9%,0);--pf-c-skeleton--after--TranslateX:-100%;--pf-c-skeleton--after--AnimationName:pf-c-skeleton-loading;--pf-c-skeleton--after--AnimationDuration:2s;--pf-c-skeleton--after--AnimationIterationCount:infinite;--pf-c-skeleton--after--AnimationTimingFunction:linear;--pf-c-skeleton--after--AnimationDelay:.5s;--pf-c-skeleton--m-circle--BorderRadius:var(--pf-global--BorderRadius--lg);--pf-c-skeleton--m-circle--before--PaddingBottom:100%;--pf-c-skeleton--m-text-4xl--Height:calc(var(--pf-global--FontSize--4xl)*var(--pf-global--LineHeight--sm));--pf-c-skeleton--m-text-3xl--Height:calc(var(--pf-global--FontSize--3xl)*var(--pf-global--LineHeight--sm));--pf-c-skeleton--m-text-2xl--Height:calc(var(--pf-global--FontSize--2xl)*var(--pf-global--LineHeight--sm));--pf-c-skeleton--m-text-xl--Height:calc(var(--pf-global--FontSize--xl)*var(--pf-global--LineHeight--sm));--pf-c-skeleton--m-text-lg--Height:calc(var(--pf-global--FontSize--lg)*var(--pf-global--LineHeight--md));--pf-c-skeleton--m-text-md--Height:calc(var(--pf-global--FontSize--md)*var(--pf-global--LineHeight--md));--pf-c-skeleton--m-text-sm--Height:calc(var(--pf-global--FontSize--sm)*var(--pf-global--LineHeight--md));--pf-c-skeleton--m-width-sm--Width:6.25rem;--pf-c-skeleton--m-width-md--Width:12.5rem;--pf-c-skeleton--m-width-lg--Width:18.75rem;--pf-c-skeleton--m-width-25--Width:25%;--pf-c-skeleton--m-width-33--Width:33.33333%;--pf-c-skeleton--m-width-50--Width:50%;--pf-c-skeleton--m-width-66--Width:66.66667%;--pf-c-skeleton--m-width-75--Width:75%;--pf-c-skeleton--m-height-sm--Height:6.25rem;--pf-c-skeleton--m-height-md--Height:12.5rem;--pf-c-skeleton--m-height-lg--Height:18.75rem;--pf-c-skeleton--m-height-25--Height:25%;--pf-c-skeleton--m-height-33--Height:33.33333%;--pf-c-skeleton--m-height-50--Height:50%;--pf-c-skeleton--m-height-66--Height:66.66667%;--pf-c-skeleton--m-height-75--Height:75%;--pf-c-skeleton--m-height-100--Height:100%;position:relative;width:var(--pf-c-skeleton--Width);height:var(--pf-c-skeleton--Height);overflow:hidden;background-color:var(--pf-c-skeleton--BackgroundColor);border-radius:var(--pf-c-skeleton--BorderRadius);transform:translate(0)}.pf-c-skeleton:before{display:block;height:var(--pf-c-skeleton--before--Height);padding-bottom:var(--pf-c-skeleton--before--PaddingBottom);content:var(--pf-c-skeleton--before--Content)}.pf-c-skeleton:after{position:absolute;top:0;right:0;bottom:0;left:0;display:block;content:"";background:linear-gradient(var(--pf-c-skeleton--after--LinearGradientAngle),var(--pf-c-skeleton--after--LinearGradientColorStop1),var(--pf-c-skeleton--after--LinearGradientColorStop2),var(--pf-c-skeleton--after--LinearGradientColorStop3));transform:translateX(var(--pf-c-skeleton--after--TranslateX));animation:var(--pf-c-skeleton--after--AnimationName) var(--pf-c-skeleton--after--AnimationDuration) var(--pf-c-skeleton--after--AnimationTimingFunction) var(--pf-c-skeleton--after--AnimationDelay) var(--pf-c-skeleton--after--AnimationIterationCount)}.pf-c-skeleton.pf-m-circle{--pf-c-skeleton--BorderRadius:var(--pf-c-skeleton--m-circle--BorderRadius)}.pf-c-skeleton.pf-m-circle,.pf-c-skeleton.pf-m-square{--pf-c-skeleton--before--Height:0;--pf-c-skeleton--before--PaddingBottom:var(--pf-c-skeleton--m-circle--before--PaddingBottom)}.pf-c-skeleton.pf-m-width-sm{--pf-c-skeleton--Width:var(--pf-c-skeleton--m-width-sm--Width)}.pf-c-skeleton.pf-m-width-md{--pf-c-skeleton--Width:var(--pf-c-skeleton--m-width-md--Width)}.pf-c-skeleton.pf-m-width-lg{--pf-c-skeleton--Width:var(--pf-c-skeleton--m-width-lg--Width)}.pf-c-skeleton.pf-m-width-25{--pf-c-skeleton--Width:var(--pf-c-skeleton--m-width-25--Width)}.pf-c-skeleton.pf-m-width-33{--pf-c-skeleton--Width:var(--pf-c-skeleton--m-width-33--Width)}.pf-c-skeleton.pf-m-width-50{--pf-c-skeleton--Width:var(--pf-c-skeleton--m-width-50--Width)}.pf-c-skeleton.pf-m-width-66{--pf-c-skeleton--Width:var(--pf-c-skeleton--m-width-66--Width)}.pf-c-skeleton.pf-m-width-75{--pf-c-skeleton--Width:var(--pf-c-skeleton--m-width-75--Width)}.pf-c-skeleton.pf-m-height-sm{--pf-c-skeleton--Height:var(--pf-c-skeleton--m-height-sm--Height)}.pf-c-skeleton.pf-m-height-md{--pf-c-skeleton--Height:var(--pf-c-skeleton--m-height-md--Height)}.pf-c-skeleton.pf-m-height-lg{--pf-c-skeleton--Height:var(--pf-c-skeleton--m-height-lg--Height)}.pf-c-skeleton.pf-m-height-25{--pf-c-skeleton--Height:var(--pf-c-skeleton--m-height-25--Height)}.pf-c-skeleton.pf-m-height-33{--pf-c-skeleton--Height:var(--pf-c-skeleton--m-height-33--Height)}.pf-c-skeleton.pf-m-height-50{--pf-c-skeleton--Height:var(--pf-c-skeleton--m-height-50--Height)}.pf-c-skeleton.pf-m-height-66{--pf-c-skeleton--Height:var(--pf-c-skeleton--m-height-66--Height)}.pf-c-skeleton.pf-m-height-75{--pf-c-skeleton--Height:var(--pf-c-skeleton--m-height-75--Height)}.pf-c-skeleton.pf-m-height-100{--pf-c-skeleton--Height:var(--pf-c-skeleton--m-height-100--Height)}.pf-c-skeleton.pf-m-text-4xl{--pf-c-skeleton--Height:var(--pf-c-skeleton--m-text-4xl--Height)}.pf-c-skeleton.pf-m-text-3xl{--pf-c-skeleton--Height:var(--pf-c-skeleton--m-text-3xl--Height)}.pf-c-skeleton.pf-m-text-2xl{--pf-c-skeleton--Height:var(--pf-c-skeleton--m-text-2xl--Height)}.pf-c-skeleton.pf-m-text-xl{--pf-c-skeleton--Height:var(--pf-c-skeleton--m-text-xl--Height)}.pf-c-skeleton.pf-m-text-lg{--pf-c-skeleton--Height:var(--pf-c-skeleton--m-text-lg--Height)}.pf-c-skeleton.pf-m-text-md{--pf-c-skeleton--Height:var(--pf-c-skeleton--m-text-md--Height)}.pf-c-skeleton.pf-m-text-sm{--pf-c-skeleton--Height:var(--pf-c-skeleton--m-text-sm--Height)}@keyframes pf-c-skeleton-loading{0%{transform:translateX(-100%)}60%{transform:translateX(100%)}to{transform:translateX(100%)}}.pf-c-skip-to-content{--pf-c-skip-to-content--Top:var(--pf-global--spacer--md);--pf-c-skip-to-content--ZIndex:var(--pf-global--ZIndex--2xl);--pf-c-skip-to-content--focus--Left:var(--pf-global--spacer--md);position:absolute;top:var(--pf-c-skip-to-content--Top);left:-300%;z-index:var(--pf-c-skip-to-content--ZIndex)}.pf-c-skip-to-content:focus{left:var(--pf-c-skip-to-content--focus--Left)}.pf-c-slider{--pf-c-slider__rail--PaddingTop:var(--pf-global--spacer--md);--pf-c-slider__rail--PaddingBottom:var(--pf-global--spacer--md);--pf-c-slider__rail-track--Height:0.25rem;--pf-c-slider__rail-track--before--base--BackgroundColor:var(--pf-global--BorderColor--100);--pf-c-slider__rail-track--before--fill--BackgroundColor:var(--pf-global--active-color--300);--pf-c-slider__rail-track--before--BorderRadius:var(--pf-global--BorderRadius--lg);--pf-c-slider__rail-track--before--fill--BackgroundColor--gradient-stop:var(--pf-c-slider--value);--pf-c-slider__steps--FontSize:var(--pf-global--FontSize--sm);--pf-c-slider__steps--Height:var(--pf-c-slider__steps--FontSize);--pf-c-slider__step-tick--Top:var(--pf-global--spacer--md);--pf-c-slider__step-tick--Width:0.25rem;--pf-c-slider__step-tick--Height:0.25rem;--pf-c-slider__step-tick--BackgroundColor:var(--pf-global--BorderColor--200);--pf-c-slider__step-tick--TranslateX:-50%;--pf-c-slider__step-tick--BorderRadius:var(--pf-global--BorderRadius--lg);--pf-c-slider__step--m-active__slider-tick--BackgroundColor:var(--pf-global--primary-color--100);--pf-c-slider__step--first-child__step-tick--TranslateX:0;--pf-c-slider__step--last-child__step-tick--TranslateX:-100%;--pf-c-slider__step-label--TranslateX:-50%;--pf-c-slider__step-label--Top:calc(var(--pf-global--spacer--xl) + var(--pf-c-slider__rail-track--Height));--pf-c-slider__step--first-child__step-label--TranslateX:0;--pf-c-slider__step--last-child__step-label--TranslateX:-100%;--pf-c-slider__thumb--Top:calc(var(--pf-c-slider__rail-track--Height)/2 + var(--pf-global--spacer--md));--pf-c-slider__thumb--Width:1rem;--pf-c-slider__thumb--Height:1rem;--pf-c-slider__thumb--Left:var(--pf-c-slider--value);--pf-c-slider__thumb--BackgroundColor:var(--pf-global--primary-color--100);--pf-c-slider__thumb--TranslateX:-50%;--pf-c-slider__thumb--TranslateY:-50%;--pf-c-slider__thumb--BorderRadius:var(--pf-global--BorderRadius--lg);--pf-c-slider__thumb--BoxShadow--base:0 0 0 2px var(--pf-global--BackgroundColor--100),0 0 0 3px var(--pf-global--primary-color--100);--pf-c-slider__thumb--hover--BoxShadow:var(--pf-c-slider__thumb--BoxShadow--base);--pf-c-slider__thumb--focus--BoxShadow:var(--pf-c-slider__thumb--BoxShadow--base);--pf-c-slider__thumb--active--BoxShadow:var(--pf-c-slider__thumb--BoxShadow--base),0 0 2px 5px var(--pf-global--active-color--200);--pf-c-slider__value--MarginLeft:var(--pf-global--spacer--md);--pf-c-slider__value--c-form-control--width-base:3.5ch;--pf-c-slider__value--c-form-control--width-chars:3;--pf-c-slider__value--c-form-control--Width:calc(var(--pf-c-slider__value--c-form-control--width-base) + var(--pf-c-slider__value--c-form-control--width-chars)*1ch);--pf-c-slider__value--m-floating--TranslateX:-50%;--pf-c-slider__value--m-floating--TranslateY:-100%;--pf-c-slider__value--m-floating--Left:var(--pf-c-slider--value);--pf-c-slider__value--m-floating--ZIndex:var(--pf-global--ZIndex--sm);--pf-c-slider__actions--MarginRight:var(--pf-global--spacer--sm);--pf-c-slider__main--actions--MarginLeft:var(--pf-global--spacer--sm);display:flex}.pf-c-slider__main{position:relative;flex-grow:1}.pf-c-slider__rail{padding-top:var(--pf-c-slider__rail--PaddingTop);padding-bottom:var(--pf-c-slider__rail--PaddingBottom)}.pf-c-slider__rail-track{position:relative;height:var(--pf-c-slider__rail-track--Height)}.pf-c-slider__rail-track:before{position:absolute;top:0;right:0;bottom:0;left:0;content:"";background:linear-gradient(90deg,var(--pf-c-slider__rail-track--before--fill--BackgroundColor),var(--pf-c-slider__rail-track--before--fill--BackgroundColor) var(--pf-c-slider__rail-track--before--fill--BackgroundColor--gradient-stop),var(--pf-c-slider__rail-track--before--base--BackgroundColor) var(--pf-c-slider__rail-track--before--fill--BackgroundColor--gradient-stop));border-radius:var(--pf-c-slider__rail-track--before--BorderRadius)}.pf-c-slider__steps{height:var(--pf-c-slider__steps--Height);font-size:var(--pf-c-slider__steps--FontSize);line-height:1}.pf-c-slider__step{position:absolute;top:0;left:var(--pf-c-slider__step--Left);content:""}.pf-c-slider__step.pf-m-active{--pf-c-slider__step-tick--BackgroundColor:var(--pf-c-slider__step--m-active__slider-tick--BackgroundColor)}.pf-c-slider__step:first-child{--pf-c-slider__step-tick--TranslateX:var(--pf-c-slider__step--first-child__step-tick--TranslateX);--pf-c-slider__step-label--TranslateX:var(--pf-c-slider__step--first-child__step-label--TranslateX)}.pf-c-slider__step:last-child{--pf-c-slider__step-tick--TranslateX:var(--pf-c-slider__step--last-child__step-tick--TranslateX);--pf-c-slider__step-label--TranslateX:var(--pf-c-slider__step--last-child__step-label--TranslateX)}.pf-c-slider__step-tick{position:absolute;top:var(--pf-c-slider__step-tick--Top);left:0;width:var(--pf-c-slider__step-tick--Width);height:var(--pf-c-slider__step-tick--Height);background-color:var(--pf-c-slider__step-tick--BackgroundColor);border-radius:var(--pf-c-slider__step-tick--BorderRadius);transform:translateX(var(--pf-c-slider__step-tick--TranslateX))}.pf-c-slider__step-label{position:absolute;top:var(--pf-c-slider__step-label--Top);transform:translateX(var(--pf-c-slider__step-label--TranslateX))}.pf-c-slider__thumb{position:absolute;top:var(--pf-c-slider__thumb--Top);left:var(--pf-c-slider__thumb--Left);width:var(--pf-c-slider__thumb--Width);height:var(--pf-c-slider__thumb--Height);cursor:pointer;background-color:var(--pf-c-slider__thumb--BackgroundColor);border-radius:var(--pf-c-slider__thumb--BorderRadius);box-shadow:var(--pf-c-slider__thumb--BoxShadow);transform:translate(var(--pf-c-slider__thumb--TranslateX),var(--pf-c-slider__thumb--TranslateY))}.pf-c-slider__thumb:hover{--pf-c-slider__thumb--BoxShadow:var(--pf-c-slider__thumb--hover--BoxShadow)}.pf-c-slider__thumb:focus{--pf-c-slider__thumb--BoxShadow:var(--pf-c-slider__thumb--focus--BoxShadow);outline:0}.pf-c-slider__thumb:active{--pf-c-slider__thumb--BoxShadow:var(--pf-c-slider__thumb--active--BoxShadow)}.pf-c-slider__value{margin-left:var(--pf-c-slider__value--MarginLeft)}.pf-c-slider__value.pf-m-floating{--pf-c-slider__value--MarginLeft:0;position:absolute;top:0;left:var(--pf-c-slider__value--m-floating--Left);z-index:var(--pf-c-slider__value--m-floating--ZIndex);transform:translate(var(--pf-c-slider__value--m-floating--TranslateX),var(--pf-c-slider__value--m-floating--TranslateY))}.pf-c-slider__value.pf-m-floating .pf-c-input-group{align-items:center}.pf-c-slider__value.pf-m-floating .pf-c-input-group__text{position:absolute;left:100%}.pf-c-slider__value .pf-c-form-control{width:var(--pf-c-slider__value--c-form-control--Width)}.pf-c-slider__actions{display:flex;margin-right:var(--pf-c-slider__actions--MarginRight)}.pf-c-slider__main~.pf-c-slider__actions{--pf-c-slider__actions--MarginRight:0;margin-left:var(--pf-c-slider__main--actions--MarginLeft)}.pf-c-spinner{--pf-c-spinner--AnimationDuration:1.5s;--pf-c-spinner--AnimationTimingFunction:cubic-bezier(.77,.005,.315,1);--pf-c-spinner--diameter:var(--pf-global--icon--FontSize--xl);--pf-c-spinner--stroke-width-multiplier:.1;--pf-c-spinner--stroke-width:calc(var(--pf-c-spinner--diameter)*var(--pf-c-spinner--stroke-width-multiplier));--pf-c-spinner--Width:var(--pf-c-spinner--diameter);--pf-c-spinner--Height:var(--pf-c-spinner--diameter);--pf-c-spinner--Color:var(--pf-global--primary-color--100);--pf-c-spinner--m-sm--diameter:var(--pf-global--icon--FontSize--sm);--pf-c-spinner--m-md--diameter:var(--pf-global--icon--FontSize--md);--pf-c-spinner--m-lg--diameter:var(--pf-global--icon--FontSize--lg);--pf-c-spinner--m-xl--diameter:var(--pf-global--icon--FontSize--xl);--pf-c-spinner__clipper--Width:var(--pf-c-spinner--diameter);--pf-c-spinner__clipper--Height:var(--pf-c-spinner--diameter);--pf-c-spinner__clipper--after--BoxShadowColor:var(--pf-c-spinner--Color);--pf-c-spinner__clipper--after--Width:var(--pf-c-spinner--diameter);--pf-c-spinner__clipper--after--Height:var(--pf-c-spinner--diameter);--pf-c-spinner__clipper--after--BoxShadowSpreadRadius:var(--pf-c-spinner--stroke-width);--pf-c-spinner__lead-ball--after--BackgroundColor:var(--pf-c-spinner--Color);--pf-c-spinner__ball--after--Width:var(--pf-c-spinner--stroke-width);--pf-c-spinner__ball--after--Height:var(--pf-c-spinner--stroke-width);--pf-c-spinner__tail-ball--after--BackgroundColor:var(--pf-c-spinner--Color);position:relative;display:inline-block;width:var(--pf-c-spinner--Width);height:var(--pf-c-spinner--Height);text-align:left;animation:pf-animation-spinner-parent calc(var(--pf-c-spinner--AnimationDuration)*2) var(--pf-c-spinner--AnimationTimingFunction) infinite}.pf-c-spinner.pf-m-sm{--pf-c-spinner--diameter:var(--pf-c-spinner--m-sm--diameter)}.pf-c-spinner.pf-m-md{--pf-c-spinner--diameter:var(--pf-c-spinner--m-md--diameter)}.pf-c-spinner.pf-m-lg{--pf-c-spinner--diameter:var(--pf-c-spinner--m-lg--diameter)}.pf-c-spinner.pf-m-xl{--pf-c-spinner--diameter:var(--pf-c-spinner--m-xl--diameter)}@keyframes pf-animation-spinner-parent{0%{transform:rotate(0deg)}50%{transform:rotate(-540deg)}to{transform:rotate(-3turn)}}.pf-c-spinner__clipper{position:absolute;width:var(--pf-c-spinner__clipper--Width);height:var(--pf-c-spinner__clipper--Height);clip-path:inset(0 0 50% 50%);animation:pf-animation-spinner__clipper var(--pf-c-spinner--AnimationDuration) linear infinite}@keyframes pf-animation-spinner__clipper{0%{transform:rotate(0deg)}to{transform:rotate(-270deg)}}.pf-c-spinner__clipper:after{position:absolute;width:var(--pf-c-spinner__clipper--after--Width);height:var(--pf-c-spinner__clipper--after--Height);clip-path:inset(0 0 0 50%);content:"";border-radius:50%;box-shadow:inset 0 0 0 var(--pf-c-spinner__clipper--after--BoxShadowSpreadRadius) var(--pf-c-spinner__clipper--after--BoxShadowColor);animation:pf-animation-spinner__clipper-after var(--pf-c-spinner--AnimationDuration) linear infinite}@keyframes pf-animation-spinner__clipper-after{0%{transform:rotate(90deg)}to{transform:rotate(-180deg)}}.pf-c-spinner__lead-ball{position:absolute;top:0;left:0;width:100%;height:100%;animation:pf-animation-spinner__lead-ball var(--pf-c-spinner--AnimationDuration) linear infinite}.pf-c-spinner__lead-ball:after{position:absolute;top:calc(50% - var(--pf-c-spinner__ball--after--Height)/2);right:0;width:var(--pf-c-spinner__ball--after--Width);height:var(--pf-c-spinner__ball--after--Height);content:"";background-color:var(--pf-c-spinner__lead-ball--after--BackgroundColor);border-radius:50%;transform-origin:top right}@keyframes pf-animation-spinner__lead-ball{0%{transform:rotate(0deg)}34%{transform:rotate(-180deg)}to{transform:rotate(-1turn)}}.pf-c-spinner__tail-ball{position:absolute;top:0;left:0;width:100%;height:100%;animation:pf-animation-spinner__tail-ball var(--pf-c-spinner--AnimationDuration) linear infinite}.pf-c-spinner__tail-ball:after{position:absolute;top:calc(50% - var(--pf-c-spinner__ball--after--Height)/2);right:0;width:var(--pf-c-spinner__ball--after--Width);height:var(--pf-c-spinner__ball--after--Height);content:"";background-color:var(--pf-c-spinner__tail-ball--after--BackgroundColor);border-radius:50%;transform-origin:top right}@keyframes pf-animation-spinner__tail-ball{0%{transform:rotate(0deg)}67.5%{transform:rotate(-180deg)}to{transform:rotate(-1turn)}}.pf-c-switch{--pf-c-switch--FontSize:var(--pf-global--FontSize--md);--pf-c-switch__toggle-icon--FontSize:calc(var(--pf-c-switch--FontSize)*0.625);--pf-c-switch__toggle-icon--Color:var(--pf-global--Color--light-100);--pf-c-switch__toggle-icon--Left:calc(var(--pf-c-switch--FontSize)*0.4);--pf-c-switch__toggle-icon--Offset:0.125rem;--pf-c-switch--LineHeight:var(--pf-global--LineHeight--md);--pf-c-switch--Height:calc(var(--pf-c-switch--FontSize)*var(--pf-c-switch--LineHeight));--pf-c-switch__input--checked__toggle--BackgroundColor:var(--pf-global--primary-color--100);--pf-c-switch__input--checked__toggle--before--TranslateX:calc(100% + var(--pf-c-switch__toggle-icon--Offset));--pf-c-switch__input--checked__label--Color:var(--pf-global--Color--dark-100);--pf-c-switch__input--not-checked__label--Color:var(--pf-global--disabled-color--100);--pf-c-switch__input--disabled__label--Color:var(--pf-global--disabled-color--100);--pf-c-switch__input--disabled__toggle--BackgroundColor:var(--pf-global--Color--dark-200);--pf-c-switch__input--disabled__toggle--before--BackgroundColor:var(--pf-global--disabled-color--200);--pf-c-switch__input--focus__toggle--OutlineWidth:var(--pf-global--BorderWidth--md);--pf-c-switch__input--focus__toggle--OutlineOffset:var(--pf-global--spacer--sm);--pf-c-switch__input--focus__toggle--OutlineColor:var(--pf-global--primary-color--100);--pf-c-switch__toggle--Height:calc(var(--pf-c-switch--FontSize)*var(--pf-c-switch--LineHeight));--pf-c-switch__toggle--BackgroundColor:var(--pf-global--disabled-color--200);--pf-c-switch__toggle--BorderRadius:var(--pf-c-switch--Height);--pf-c-switch__toggle--before--Width:calc(var(--pf-c-switch--FontSize) - var(--pf-c-switch__toggle-icon--Offset));--pf-c-switch__toggle--before--Height:var(--pf-c-switch__toggle--before--Width);--pf-c-switch__toggle--before--Top:calc((var(--pf-c-switch--Height) - var(--pf-c-switch__toggle--before--Height))/2);--pf-c-switch__toggle--before--Left:var(--pf-c-switch__toggle--before--Top);--pf-c-switch__toggle--before--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-switch__toggle--before--BorderRadius:var(--pf-global--BorderRadius--lg);--pf-c-switch__toggle--before--BoxShadow:var(--pf-global--BoxShadow--md);--pf-c-switch__toggle--before--Transition:transform .25s ease 0s;--pf-c-switch__toggle--Width:calc(var(--pf-c-switch--Height) + var(--pf-c-switch__toggle-icon--Offset) + var(--pf-c-switch__toggle--before--Width));--pf-c-switch__label--PaddingLeft:var(--pf-global--spacer--md);--pf-c-switch__label--Color:var(--pf-global--Color--dark-100);position:relative;display:inline-block;height:var(--pf-c-switch--Height);font-size:var(--pf-c-switch--FontSize);line-height:var(--pf-c-switch--LineHeight);vertical-align:middle;cursor:pointer}.pf-c-switch__input{position:absolute;cursor:pointer;opacity:0}.pf-c-switch__input:focus~.pf-c-switch__toggle{outline:var(--pf-c-switch__input--focus__toggle--OutlineWidth) solid var(--pf-c-switch__input--focus__toggle--OutlineColor);outline-offset:var(--pf-c-switch__input--focus__toggle--OutlineOffset)}.pf-c-switch__input:checked~.pf-c-switch__label{color:var(--pf-c-switch__input--checked__label--Color)}.pf-c-switch__input:checked~.pf-c-switch__toggle{background-color:var(--pf-c-switch__input--checked__toggle--BackgroundColor)}.pf-c-switch__input:checked~.pf-c-switch__toggle:before{transform:translateX(var(--pf-c-switch__input--checked__toggle--before--TranslateX))}.pf-c-switch__input:checked~.pf-m-off{display:none}.pf-c-switch__input:not(:checked)~.pf-c-switch__label{color:var(--pf-c-switch__input--not-checked__label--Color)}.pf-c-switch__input:not(:checked)~.pf-c-switch__toggle .pf-c-switch__toggle-icon{display:none;visibility:hidden}.pf-c-switch__input:not(:checked)~.pf-m-on{display:none}.pf-c-switch__input:disabled{cursor:not-allowed}.pf-c-switch__input:disabled~.pf-c-switch__label{color:var(--pf-c-switch__input--disabled__label--Color);cursor:not-allowed}.pf-c-switch__input:disabled~.pf-c-switch__toggle{cursor:not-allowed;background-color:var(--pf-c-switch__input--disabled__toggle--BackgroundColor)}.pf-c-switch__input:disabled~.pf-c-switch__toggle:before{background-color:var(--pf-c-switch__input--disabled__toggle--before--BackgroundColor)}.pf-c-switch__toggle{position:relative;display:inline-block;width:var(--pf-c-switch__toggle--Width);height:var(--pf-c-switch__toggle--Height);background-color:var(--pf-c-switch__toggle--BackgroundColor);border-radius:var(--pf-c-switch__toggle--BorderRadius)}.pf-c-switch__toggle:before{position:absolute;top:var(--pf-c-switch__toggle--before--Top);left:var(--pf-c-switch__toggle--before--Left);display:block;width:var(--pf-c-switch__toggle--before--Width);height:var(--pf-c-switch__toggle--before--Height);content:"";background-color:var(--pf-c-switch__toggle--before--BackgroundColor);border-radius:var(--pf-c-switch__toggle--before--BorderRadius);box-shadow:var(--pf-c-switch__toggle--before--BoxShadow);transition:var(--pf-c-switch__toggle--before--Transition)}.pf-c-switch__toggle-icon{position:absolute;top:0;bottom:0;left:var(--pf-c-switch__toggle-icon--Left);display:flex;align-items:center;font-size:var(--pf-c-switch__toggle-icon--FontSize);color:var(--pf-c-switch__toggle-icon--Color)}.pf-c-switch__label{display:inline-block;padding-left:var(--pf-c-switch__label--PaddingLeft);color:var(--pf-c-switch__label--Color);vertical-align:top}.pf-c-tab-content{--pf-c-tab-content--m-light-300:var(--pf-global--BackgroundColor--light-300)}.pf-c-tab-content.pf-m-light-300{background-color:var(--pf-c-tab-content--m-light-300)}.pf-c-table[class*=pf-m-grid]{--pf-c-table--responsive--BorderColor:var(--pf-global--BorderColor--300);--pf-c-table--tbody--responsive--border-width--base:var(--pf-global--spacer--sm);--pf-c-table--tbody--after--border-width--base:var(--pf-global--BorderWidth--lg);--pf-c-table--tbody--after--BorderLeftWidth:0;--pf-c-table--tbody--after--BorderColor:var(--pf-global--active-color--100);--pf-c-table-tr--responsive--border-width--base:var(--pf-global--spacer--sm);--pf-c-table-tr--responsive--last-child--BorderBottomWidth:var(--pf-global--BorderWidth--sm);--pf-c-table-tr--responsive--GridColumnGap:var(--pf-global--spacer--md);--pf-c-table-tr--responsive--MarginTop:var(--pf-global--spacer--sm);--pf-c-table-tr--responsive--PaddingTop:var(--pf-global--spacer--md);--pf-c-table-tr--responsive--PaddingRight:var(--pf-global--spacer--lg);--pf-c-table-tr--responsive--xl--PaddingRight:var(--pf-global--spacer--md);--pf-c-table-tr--responsive--PaddingBottom:var(--pf-global--spacer--md);--pf-c-table-tr--responsive--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-table-tr--responsive--xl--PaddingLeft:var(--pf-global--spacer--md);--pf-c-table-tr--responsive--nested-table--PaddingTop:var(--pf-global--spacer--xl);--pf-c-table-tr--responsive--nested-table--PaddingRight:var(--pf-global--spacer--lg);--pf-c-table-tr--responsive--nested-table--PaddingBottom:var(--pf-global--spacer--xl);--pf-c-table-tr--responsive--nested-table--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-table--m-grid--cell--hidden-visible--Display:grid;--pf-c-table--m-grid--cell--PaddingTop:0;--pf-c-table--m-grid--cell--PaddingRight:0;--pf-c-table--m-grid--cell--PaddingBottom:0;--pf-c-table--m-grid--cell--PaddingLeft:0;--pf-c-table-td--responsive--GridColumnGap:var(--pf-global--spacer--md);--pf-c-table--cell--responsive--PaddingTop:var(--pf-global--spacer--md);--pf-c-table--cell--responsive--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-table--cell--first-child--responsive--PaddingTop:var(--pf-global--spacer--sm);--pf-c-table--cell--responsive--PaddingRight:0;--pf-c-table--cell--responsive--PaddingLeft:0;--pf-c-table--m-compact-tr--responsive--PaddingTop:var(--pf-global--spacer--sm);--pf-c-table--m-compact-tr--responsive--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-table--m-compact-tr-td--responsive--PaddingTop:var(--pf-global--spacer--xs);--pf-c-table--m-compact-tr-td--responsive--PaddingBottom:var(--pf-global--spacer--xs);--pf-c-table--m-compact__action--responsive--MarginTop:calc(var(--pf-global--spacer--xs)*-1);--pf-c-table--m-compact__action--responsive--MarginBottom:calc(var(--pf-global--spacer--xs)*-1);--pf-c-table--m-compact__toggle--c-button--responsive--MarginBottom:-0.375rem;--pf-c-table__expandable-row-content--responsive--PaddingRight:var(--pf-global--spacer--lg);--pf-c-table__expandable-row-content--responsive--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-table__expandable-row-content--responsive--xl--PaddingRight:var(--pf-global--spacer--md);--pf-c-table__expandable-row-content--responsive--xl--PaddingLeft:var(--pf-global--spacer--md);--pf-c-table__expandable-row-content--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-table__check--responsive--MarginLeft:var(--pf-global--spacer--sm);--pf-c-table__check--responsive--MarginTop:0.875rem;--pf-c-table--m-grid__favorite--MarginTop:0.5rem;--pf-c-table--m-grid__check--favorite--MarginLeft:var(--pf-global--spacer--xl);--pf-c-table--m-grid__action--MarginTop:0.375rem;--pf-c-table__action--responsive--MarginLeft:var(--pf-global--spacer--xl);--pf-c-table--m-grid__favorite--action--MarginLeft:var(--pf-global--spacer--2xl);--pf-c-table--m-grid__check--favorite--action--MarginLeft:calc(var(--pf-c-table--m-grid__check--favorite--MarginLeft) + var(--pf-c-table--m-grid__favorite--action--MarginLeft));--pf-c-table__toggle__icon--Transition:.2s ease-in 0s;--pf-c-table__toggle--m-expanded__icon--Rotate:180deg}@media screen and (max-width:1200px){.pf-c-table[class*=pf-m-grid]{--pf-c-table-tr--responsive--PaddingRight:var(--pf-c-table-tr--responsive--xl--PaddingRight);--pf-c-table-tr--responsive--PaddingLeft:var(--pf-c-table-tr--responsive--xl--PaddingLeft);--pf-c-table__expandable-row-content--responsive--PaddingRight:var(--pf-c-table__expandable-row-content--responsive--xl--PaddingRight);--pf-c-table__expandable-row-content--responsive--PaddingLeft:var(--pf-c-table__expandable-row-content--responsive--xl--PaddingLeft)}}.pf-m-grid.pf-c-table{--pf-c-table--cell--PaddingTop:var(--pf-c-table--m-grid--cell--PaddingTop);--pf-c-table--cell--PaddingRight:var(--pf-c-table--m-grid--cell--PaddingRight);--pf-c-table--cell--PaddingBottom:var(--pf-c-table--m-grid--cell--PaddingBottom);--pf-c-table--cell--PaddingLeft:var(--pf-c-table--m-grid--cell--PaddingLeft);--pf-c-table__favorite--c-button--MarginTop:auto;--pf-c-table__favorite--c-button--MarginRight:auto;--pf-c-table__favorite--c-button--MarginBottom:auto;--pf-c-table__favorite--c-button--MarginLeft:auto;display:grid;border:none}.pf-m-grid.pf-c-table tr>*{width:auto;min-width:0;max-width:none;overflow:visible;text-overflow:clip;white-space:normal}.pf-m-grid.pf-c-table .pf-c-table__text{position:relative;width:auto;min-width:0;max-width:none;overflow:var(--pf-c-table--cell--Overflow);text-overflow:var(--pf-c-table--cell--TextOverflow);white-space:var(--pf-c-table--cell--WhiteSpace)}.pf-m-grid.pf-c-table thead{display:none;visibility:hidden}.pf-m-grid.pf-c-table tbody{display:block}.pf-m-grid.pf-c-table tbody:first-of-type{border-top:var(--pf-c-table--tbody--responsive--border-width--base) solid var(--pf-c-table--responsive--BorderColor)}.pf-m-grid.pf-c-table table.pf-m-compact>tbody{border-top:0}.pf-m-grid.pf-c-table tr:not(.pf-c-table__expandable-row){border-bottom:var(--pf-c-table-tr--responsive--border-width--base) solid var(--pf-c-table--responsive--BorderColor)}.pf-m-grid.pf-c-table tbody:last-of-type:not(:only-of-type)>tr,.pf-m-grid.pf-c-table tr:last-child{border-bottom-width:var(--pf-c-table-tr--responsive--last-child--BorderBottomWidth)}.pf-m-grid.pf-c-table tbody.pf-m-expanded{border-bottom:var(--pf-c-table--border-width--base) solid var(--pf-c-table--BorderColor)}.pf-m-grid.pf-c-table tbody.pf-m-expanded tr:not(.pf-c-table__expandable-row){border-bottom:0}.pf-m-grid.pf-c-table tbody.pf-m-expanded:not(:last-of-type){border-bottom:var(--pf-c-table--tbody--responsive--border-width--base) solid var(--pf-c-table--responsive--BorderColor)}.pf-m-grid.pf-c-table tr:not(.pf-c-table__expandable-row){display:grid;grid-template-columns:1fr;height:auto;grid-auto-columns:max-content;grid-column-gap:var(--pf-c-table-tr--responsive--GridColumnGap);padding:var(--pf-c-table-tr--responsive--PaddingTop) var(--pf-c-table-tr--responsive--PaddingRight) var(--pf-c-table-tr--responsive--PaddingBottom) var(--pf-c-table-tr--responsive--PaddingLeft)}.pf-m-grid.pf-c-table tr:not(.pf-c-table__expandable-row)>*{padding:var(--pf-c-table--cell--responsive--PaddingTop) var(--pf-c-table--cell--responsive--PaddingRight) var(--pf-c-table--cell--responsive--PaddingBottom) var(--pf-c-table--cell--responsive--PaddingLeft)}.pf-m-grid.pf-c-table tr:not(.pf-c-table__expandable-row)>:first-child{--pf-c-table--cell--responsive--PaddingTop:var(--pf-c-table--cell--first-child--responsive--PaddingTop)}.pf-m-grid.pf-c-table.pf-m-compact{--pf-c-table-tr--responsive--PaddingTop:var(--pf-c-table--m-compact-tr--responsive--PaddingTop);--pf-c-table-tr--responsive--PaddingBottom:var(--pf-c-table--m-compact-tr--responsive--PaddingBottom);--pf-c-table--cell--responsive--PaddingTop:var(--pf-c-table--m-compact-tr-td--responsive--PaddingTop);--pf-c-table--cell--responsive--PaddingBottom:var(--pf-c-table--m-compact-tr-td--responsive--PaddingBottom);--pf-c-table__check--input--MarginTop:0}.pf-m-grid.pf-c-table.pf-m-compact .pf-c-table__action{margin-top:var(--pf-c-table--m-compact__action--responsive--MarginTop);margin-bottom:var(--pf-c-table--m-compact__action--responsive--MarginTop)}.pf-m-grid.pf-c-table.pf-m-compact .pf-c-table__toggle .pf-c-button{margin-bottom:var(--pf-c-table--m-compact__toggle--c-button--responsive--MarginBottom)}.pf-m-grid.pf-c-table .pf-c-table__icon>*{text-align:left}.pf-m-grid.pf-c-table [data-label]{--pf-c-table--cell--hidden-visible--Display:var(--pf-c-table--m-grid--cell--hidden-visible--Display);grid-column:1;grid-column-gap:var(--pf-c-table-td--responsive--GridColumnGap);grid-template-columns:1fr minmax(0,1.5fr);align-items:start}.pf-m-grid.pf-c-table [data-label]>*{grid-column:2}.pf-m-grid.pf-c-table [data-label]:before{font-weight:700;text-align:left;content:attr(data-label)}.pf-m-grid.pf-c-table tr>:first-child{--pf-c-table--cell--PaddingLeft:0}.pf-m-grid.pf-c-table tr>:last-child{--pf-c-table--cell--PaddingRight:0}.pf-m-grid.pf-c-table .pf-c-table{--pf-c-table-tr--responsive--PaddingTop:var(--pf-c-table-tr--responsive--nested-table--PaddingTop);--pf-c-table-tr--responsive--PaddingRight:var(--pf-c-table-tr--responsive--nested-table--PaddingRight);--pf-c-table-tr--responsive--PaddingBottom:var(--pf-c-table-tr--responsive--nested-table--PaddingBottom);--pf-c-table-tr--responsive--PaddingLeft:var(--pf-c-table-tr--responsive--nested-table--PaddingLeft);border:0}.pf-m-grid.pf-c-table .pf-c-table tr:not(.pf-c-table__expandable-row)+tr:not(.pf-c-table__expandable-row){--pf-c-table-tr--responsive--PaddingTop:0}.pf-m-grid.pf-c-table .pf-c-table__compound-expansion-toggle{--pf-c-table__compound-expansion-toggle__button--before--BorderRightWidth:0;--pf-c-table__compound-expansion-toggle__button--before--BorderLeftWidth:0;--pf-c-table__compound-expansion-toggle__button--after--Top:100%}.pf-m-grid.pf-c-table tbody{position:relative}.pf-m-grid.pf-c-table tbody:after{position:absolute;top:0;bottom:0;left:0;content:"";border:0;border-left:var(--pf-c-table--tbody--after--BorderLeftWidth) solid var(--pf-c-table--tbody--after--BorderColor)}.pf-m-grid.pf-c-table tbody.pf-m-expanded{--pf-c-table--tbody--after--BorderLeftWidth:var(--pf-c-table--tbody--after--border-width--base)}.pf-m-grid.pf-c-table tbody.pf-m-expanded tbody{--pf-c-table--tbody--after--BorderLeftWidth:0}.pf-m-grid.pf-c-table tbody>tr>:first-child:not(.pf-c-table__check):after{--pf-c-table__expandable-row--after--BorderLeftWidth:0;position:static;width:auto;background-color:transparent}.pf-m-grid.pf-c-table .pf-c-table__expandable-row{--pf-c-table--cell--responsive--PaddingTop:0;--pf-c-table--cell--responsive--PaddingRight:0;--pf-c-table--cell--responsive--PaddingBottom:0;--pf-c-table--cell--responsive--PaddingLeft:0;--pf-c-table--cell--PaddingRight:0;--pf-c-table--cell--PaddingLeft:0;display:block;max-height:var(--pf-c-table__expandable-row--MaxHeight);overflow-y:auto;border-bottom:none;box-shadow:none}.pf-m-grid.pf-c-table .pf-c-table__expandable-row>*{position:static;display:block}.pf-m-grid.pf-c-table .pf-c-table__expandable-row.pf-m-expanded{border-top-color:var(--pf-c-table--BorderColor)}.pf-m-grid.pf-c-table .pf-c-table__expandable-row>:first-child:not(.pf-c-table__check):after{content:none}.pf-m-grid.pf-c-table .pf-c-table__expandable-row td.pf-m-no-padding .pf-c-table__expandable-row-content,.pf-m-grid.pf-c-table .pf-c-table__expandable-row th.pf-m-no-padding .pf-c-table__expandable-row-content{padding:0}.pf-m-grid.pf-c-table .pf-c-table__expandable-row:not(.pf-m-expanded){display:none;visibility:hidden}.pf-m-grid.pf-c-table .pf-c-table__expandable-row .pf-c-table__expandable-row-content{padding-right:var(--pf-c-table__expandable-row-content--responsive--PaddingRight);padding-left:var(--pf-c-table__expandable-row-content--responsive--PaddingLeft)}.pf-m-grid.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__action,.pf-m-grid.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__check,.pf-m-grid.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__favorite,.pf-m-grid.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__toggle{width:auto;padding:0}.pf-m-grid.pf-c-table .pf-c-table__toggle{grid-row-start:20;grid-column:-1;justify-self:end;padding-right:0}.pf-m-grid.pf-c-table .pf-c-table__toggle:after{content:none}.pf-m-grid.pf-c-table .pf-c-table__button{--pf-c-table--cell--PaddingTop:var(--pf-c-table--m-grid--cell--PaddingTop);--pf-c-table--cell--PaddingRight:var(--pf-c-table--m-grid--cell--PaddingRight);--pf-c-table--cell--PaddingBottom:var(--pf-c-table--m-grid--cell--PaddingBottom);--pf-c-table--cell--PaddingLeft:var(--pf-c-table--m-grid--cell--PaddingLeft)}.pf-m-grid.pf-c-table .pf-c-table__action,.pf-m-grid.pf-c-table .pf-c-table__check,.pf-m-grid.pf-c-table .pf-c-table__favorite{grid-row-start:1;grid-column-start:2}.pf-m-grid.pf-c-table .pf-c-table__check{margin-top:var(--pf-c-table__check--responsive--MarginTop);margin-left:var(--pf-c-table__check--responsive--MarginLeft)}.pf-m-grid.pf-c-table .pf-c-table__check~.pf-c-table__favorite{margin-left:var(--pf-c-table--m-grid__check--favorite--MarginLeft)}.pf-m-grid.pf-c-table .pf-c-table__check~.pf-c-table__favorite~.pf-c-table__action{margin-left:var(--pf-c-table--m-grid__check--favorite--action--MarginLeft)}.pf-m-grid.pf-c-table .pf-c-table__check~.pf-c-table__action{margin-left:var(--pf-c-table__action--responsive--MarginLeft)}.pf-m-grid.pf-c-table .pf-c-table__favorite{margin-top:var(--pf-c-table--m-grid__favorite--MarginTop)}.pf-m-grid.pf-c-table .pf-c-table__favorite~.pf-c-table__action{margin-left:var(--pf-c-table--m-grid__favorite--action--MarginLeft)}.pf-m-grid.pf-c-table .pf-c-table__action{margin-top:var(--pf-c-table--m-grid__action--MarginTop);text-align:right}@media screen and (max-width:576px){.pf-m-grid.pf-c-table .pf-c-table__action{grid-row-start:1;grid-column-start:2;margin-left:0}}.pf-m-grid.pf-c-table .pf-c-table__inline-edit-action{grid-column:2;grid-row:2}.pf-m-grid.pf-c-table .pf-c-table__toggle-icon{transition:var(--pf-c-table__toggle__icon--Transition)}.pf-c-button.pf-m-expanded>.pf-m-grid.pf-c-table .pf-c-table__toggle-icon{transform:rotate(var(--pf-c-table__toggle--m-expanded__icon--Rotate))}.pf-m-grid.pf-c-table .pf-m-nowrap{--pf-c-table--cell--Overflow:auto}.pf-m-grid.pf-c-table .pf-m-fit-content{width:auto;white-space:normal}.pf-m-grid.pf-c-table .pf-m-truncate{--pf-c-table--cell--MaxWidth:100%}.pf-m-grid.pf-c-table [class*=pf-m-width]{--pf-c-table--cell--Width:auto}@media screen and (max-width:768px){.pf-m-grid-md.pf-c-table{--pf-c-table--cell--PaddingTop:var(--pf-c-table--m-grid--cell--PaddingTop);--pf-c-table--cell--PaddingRight:var(--pf-c-table--m-grid--cell--PaddingRight);--pf-c-table--cell--PaddingBottom:var(--pf-c-table--m-grid--cell--PaddingBottom);--pf-c-table--cell--PaddingLeft:var(--pf-c-table--m-grid--cell--PaddingLeft);--pf-c-table__favorite--c-button--MarginTop:auto;--pf-c-table__favorite--c-button--MarginRight:auto;--pf-c-table__favorite--c-button--MarginBottom:auto;--pf-c-table__favorite--c-button--MarginLeft:auto;display:grid;border:none}.pf-m-grid-md.pf-c-table tr>*{width:auto;min-width:0;max-width:none;overflow:visible;text-overflow:clip;white-space:normal}.pf-m-grid-md.pf-c-table .pf-c-table__text{position:relative;width:auto;min-width:0;max-width:none;overflow:var(--pf-c-table--cell--Overflow);text-overflow:var(--pf-c-table--cell--TextOverflow);white-space:var(--pf-c-table--cell--WhiteSpace)}.pf-m-grid-md.pf-c-table thead{display:none;visibility:hidden}.pf-m-grid-md.pf-c-table tbody{display:block}.pf-m-grid-md.pf-c-table tbody:first-of-type{border-top:var(--pf-c-table--tbody--responsive--border-width--base) solid var(--pf-c-table--responsive--BorderColor)}.pf-m-grid-md.pf-c-table table.pf-m-compact>tbody{border-top:0}.pf-m-grid-md.pf-c-table tr:not(.pf-c-table__expandable-row){border-bottom:var(--pf-c-table-tr--responsive--border-width--base) solid var(--pf-c-table--responsive--BorderColor)}.pf-m-grid-md.pf-c-table tbody:last-of-type:not(:only-of-type)>tr,.pf-m-grid-md.pf-c-table tr:last-child{border-bottom-width:var(--pf-c-table-tr--responsive--last-child--BorderBottomWidth)}.pf-m-grid-md.pf-c-table tbody.pf-m-expanded{border-bottom:var(--pf-c-table--border-width--base) solid var(--pf-c-table--BorderColor)}.pf-m-grid-md.pf-c-table tbody.pf-m-expanded tr:not(.pf-c-table__expandable-row){border-bottom:0}.pf-m-grid-md.pf-c-table tbody.pf-m-expanded:not(:last-of-type){border-bottom:var(--pf-c-table--tbody--responsive--border-width--base) solid var(--pf-c-table--responsive--BorderColor)}.pf-m-grid-md.pf-c-table tr:not(.pf-c-table__expandable-row){display:grid;grid-template-columns:1fr;height:auto;grid-auto-columns:max-content;grid-column-gap:var(--pf-c-table-tr--responsive--GridColumnGap);padding:var(--pf-c-table-tr--responsive--PaddingTop) var(--pf-c-table-tr--responsive--PaddingRight) var(--pf-c-table-tr--responsive--PaddingBottom) var(--pf-c-table-tr--responsive--PaddingLeft)}.pf-m-grid-md.pf-c-table tr:not(.pf-c-table__expandable-row)>*{padding:var(--pf-c-table--cell--responsive--PaddingTop) var(--pf-c-table--cell--responsive--PaddingRight) var(--pf-c-table--cell--responsive--PaddingBottom) var(--pf-c-table--cell--responsive--PaddingLeft)}.pf-m-grid-md.pf-c-table tr:not(.pf-c-table__expandable-row)>:first-child{--pf-c-table--cell--responsive--PaddingTop:var(--pf-c-table--cell--first-child--responsive--PaddingTop)}.pf-m-grid-md.pf-c-table.pf-m-compact{--pf-c-table-tr--responsive--PaddingTop:var(--pf-c-table--m-compact-tr--responsive--PaddingTop);--pf-c-table-tr--responsive--PaddingBottom:var(--pf-c-table--m-compact-tr--responsive--PaddingBottom);--pf-c-table--cell--responsive--PaddingTop:var(--pf-c-table--m-compact-tr-td--responsive--PaddingTop);--pf-c-table--cell--responsive--PaddingBottom:var(--pf-c-table--m-compact-tr-td--responsive--PaddingBottom);--pf-c-table__check--input--MarginTop:0}.pf-m-grid-md.pf-c-table.pf-m-compact .pf-c-table__action{margin-top:var(--pf-c-table--m-compact__action--responsive--MarginTop);margin-bottom:var(--pf-c-table--m-compact__action--responsive--MarginTop)}.pf-m-grid-md.pf-c-table.pf-m-compact .pf-c-table__toggle .pf-c-button{margin-bottom:var(--pf-c-table--m-compact__toggle--c-button--responsive--MarginBottom)}.pf-m-grid-md.pf-c-table .pf-c-table__icon>*{text-align:left}.pf-m-grid-md.pf-c-table [data-label]{--pf-c-table--cell--hidden-visible--Display:var(--pf-c-table--m-grid--cell--hidden-visible--Display);grid-column:1;grid-column-gap:var(--pf-c-table-td--responsive--GridColumnGap);grid-template-columns:1fr minmax(0,1.5fr);align-items:start}.pf-m-grid-md.pf-c-table [data-label]>*{grid-column:2}.pf-m-grid-md.pf-c-table [data-label]:before{font-weight:700;text-align:left;content:attr(data-label)}.pf-m-grid-md.pf-c-table tr>:first-child{--pf-c-table--cell--PaddingLeft:0}.pf-m-grid-md.pf-c-table tr>:last-child{--pf-c-table--cell--PaddingRight:0}.pf-m-grid-md.pf-c-table .pf-c-table{--pf-c-table-tr--responsive--PaddingTop:var(--pf-c-table-tr--responsive--nested-table--PaddingTop);--pf-c-table-tr--responsive--PaddingRight:var(--pf-c-table-tr--responsive--nested-table--PaddingRight);--pf-c-table-tr--responsive--PaddingBottom:var(--pf-c-table-tr--responsive--nested-table--PaddingBottom);--pf-c-table-tr--responsive--PaddingLeft:var(--pf-c-table-tr--responsive--nested-table--PaddingLeft);border:0}.pf-m-grid-md.pf-c-table .pf-c-table tr:not(.pf-c-table__expandable-row)+tr:not(.pf-c-table__expandable-row){--pf-c-table-tr--responsive--PaddingTop:0}.pf-m-grid-md.pf-c-table .pf-c-table__compound-expansion-toggle{--pf-c-table__compound-expansion-toggle__button--before--BorderRightWidth:0;--pf-c-table__compound-expansion-toggle__button--before--BorderLeftWidth:0;--pf-c-table__compound-expansion-toggle__button--after--Top:100%}.pf-m-grid-md.pf-c-table tbody{position:relative}.pf-m-grid-md.pf-c-table tbody:after{position:absolute;top:0;bottom:0;left:0;content:"";border:0;border-left:var(--pf-c-table--tbody--after--BorderLeftWidth) solid var(--pf-c-table--tbody--after--BorderColor)}.pf-m-grid-md.pf-c-table tbody.pf-m-expanded{--pf-c-table--tbody--after--BorderLeftWidth:var(--pf-c-table--tbody--after--border-width--base)}.pf-m-grid-md.pf-c-table tbody.pf-m-expanded tbody{--pf-c-table--tbody--after--BorderLeftWidth:0}.pf-m-grid-md.pf-c-table tbody>tr>:first-child:not(.pf-c-table__check):after{--pf-c-table__expandable-row--after--BorderLeftWidth:0;position:static;width:auto;background-color:transparent}.pf-m-grid-md.pf-c-table .pf-c-table__expandable-row{--pf-c-table--cell--responsive--PaddingTop:0;--pf-c-table--cell--responsive--PaddingRight:0;--pf-c-table--cell--responsive--PaddingBottom:0;--pf-c-table--cell--responsive--PaddingLeft:0;--pf-c-table--cell--PaddingRight:0;--pf-c-table--cell--PaddingLeft:0;display:block;max-height:var(--pf-c-table__expandable-row--MaxHeight);overflow-y:auto;border-bottom:none;box-shadow:none}.pf-m-grid-md.pf-c-table .pf-c-table__expandable-row>*{position:static;display:block}.pf-m-grid-md.pf-c-table .pf-c-table__expandable-row.pf-m-expanded{border-top-color:var(--pf-c-table--BorderColor)}.pf-m-grid-md.pf-c-table .pf-c-table__expandable-row>:first-child:not(.pf-c-table__check):after{content:none}.pf-m-grid-md.pf-c-table .pf-c-table__expandable-row td.pf-m-no-padding .pf-c-table__expandable-row-content,.pf-m-grid-md.pf-c-table .pf-c-table__expandable-row th.pf-m-no-padding .pf-c-table__expandable-row-content{padding:0}.pf-m-grid-md.pf-c-table .pf-c-table__expandable-row:not(.pf-m-expanded){display:none;visibility:hidden}.pf-m-grid-md.pf-c-table .pf-c-table__expandable-row .pf-c-table__expandable-row-content{padding-right:var(--pf-c-table__expandable-row-content--responsive--PaddingRight);padding-left:var(--pf-c-table__expandable-row-content--responsive--PaddingLeft)}.pf-m-grid-md.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__action,.pf-m-grid-md.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__check,.pf-m-grid-md.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__favorite,.pf-m-grid-md.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__toggle{width:auto;padding:0}.pf-m-grid-md.pf-c-table .pf-c-table__toggle{grid-row-start:20;grid-column:-1;justify-self:end;padding-right:0}.pf-m-grid-md.pf-c-table .pf-c-table__toggle:after{content:none}.pf-m-grid-md.pf-c-table .pf-c-table__button{--pf-c-table--cell--PaddingTop:var(--pf-c-table--m-grid--cell--PaddingTop);--pf-c-table--cell--PaddingRight:var(--pf-c-table--m-grid--cell--PaddingRight);--pf-c-table--cell--PaddingBottom:var(--pf-c-table--m-grid--cell--PaddingBottom);--pf-c-table--cell--PaddingLeft:var(--pf-c-table--m-grid--cell--PaddingLeft)}.pf-m-grid-md.pf-c-table .pf-c-table__action,.pf-m-grid-md.pf-c-table .pf-c-table__check,.pf-m-grid-md.pf-c-table .pf-c-table__favorite{grid-row-start:1;grid-column-start:2}.pf-m-grid-md.pf-c-table .pf-c-table__check{margin-top:var(--pf-c-table__check--responsive--MarginTop);margin-left:var(--pf-c-table__check--responsive--MarginLeft)}.pf-m-grid-md.pf-c-table .pf-c-table__check~.pf-c-table__favorite{margin-left:var(--pf-c-table--m-grid__check--favorite--MarginLeft)}.pf-m-grid-md.pf-c-table .pf-c-table__check~.pf-c-table__favorite~.pf-c-table__action{margin-left:var(--pf-c-table--m-grid__check--favorite--action--MarginLeft)}.pf-m-grid-md.pf-c-table .pf-c-table__check~.pf-c-table__action{margin-left:var(--pf-c-table__action--responsive--MarginLeft)}.pf-m-grid-md.pf-c-table .pf-c-table__favorite{margin-top:var(--pf-c-table--m-grid__favorite--MarginTop)}.pf-m-grid-md.pf-c-table .pf-c-table__favorite~.pf-c-table__action{margin-left:var(--pf-c-table--m-grid__favorite--action--MarginLeft)}.pf-m-grid-md.pf-c-table .pf-c-table__action{margin-top:var(--pf-c-table--m-grid__action--MarginTop);text-align:right}}@media screen and (max-width:768px) and (max-width:576px){.pf-m-grid-md.pf-c-table .pf-c-table__action{grid-row-start:1;grid-column-start:2;margin-left:0}}@media screen and (max-width:768px){.pf-m-grid-md.pf-c-table .pf-c-table__inline-edit-action{grid-column:2;grid-row:2}.pf-m-grid-md.pf-c-table .pf-c-table__toggle-icon{transition:var(--pf-c-table__toggle__icon--Transition)}.pf-c-button.pf-m-expanded>.pf-m-grid-md.pf-c-table .pf-c-table__toggle-icon{transform:rotate(var(--pf-c-table__toggle--m-expanded__icon--Rotate))}.pf-m-grid-md.pf-c-table .pf-m-nowrap{--pf-c-table--cell--Overflow:auto}.pf-m-grid-md.pf-c-table .pf-m-fit-content{width:auto;white-space:normal}.pf-m-grid-md.pf-c-table .pf-m-truncate{--pf-c-table--cell--MaxWidth:100%}.pf-m-grid-md.pf-c-table [class*=pf-m-width]{--pf-c-table--cell--Width:auto}}@media screen and (max-width:992px){.pf-m-grid-lg.pf-c-table{--pf-c-table--cell--PaddingTop:var(--pf-c-table--m-grid--cell--PaddingTop);--pf-c-table--cell--PaddingRight:var(--pf-c-table--m-grid--cell--PaddingRight);--pf-c-table--cell--PaddingBottom:var(--pf-c-table--m-grid--cell--PaddingBottom);--pf-c-table--cell--PaddingLeft:var(--pf-c-table--m-grid--cell--PaddingLeft);--pf-c-table__favorite--c-button--MarginTop:auto;--pf-c-table__favorite--c-button--MarginRight:auto;--pf-c-table__favorite--c-button--MarginBottom:auto;--pf-c-table__favorite--c-button--MarginLeft:auto;display:grid;border:none}.pf-m-grid-lg.pf-c-table tr>*{width:auto;min-width:0;max-width:none;overflow:visible;text-overflow:clip;white-space:normal}.pf-m-grid-lg.pf-c-table .pf-c-table__text{position:relative;width:auto;min-width:0;max-width:none;overflow:var(--pf-c-table--cell--Overflow);text-overflow:var(--pf-c-table--cell--TextOverflow);white-space:var(--pf-c-table--cell--WhiteSpace)}.pf-m-grid-lg.pf-c-table thead{display:none;visibility:hidden}.pf-m-grid-lg.pf-c-table tbody{display:block}.pf-m-grid-lg.pf-c-table tbody:first-of-type{border-top:var(--pf-c-table--tbody--responsive--border-width--base) solid var(--pf-c-table--responsive--BorderColor)}.pf-m-grid-lg.pf-c-table table.pf-m-compact>tbody{border-top:0}.pf-m-grid-lg.pf-c-table tr:not(.pf-c-table__expandable-row){border-bottom:var(--pf-c-table-tr--responsive--border-width--base) solid var(--pf-c-table--responsive--BorderColor)}.pf-m-grid-lg.pf-c-table tbody:last-of-type:not(:only-of-type)>tr,.pf-m-grid-lg.pf-c-table tr:last-child{border-bottom-width:var(--pf-c-table-tr--responsive--last-child--BorderBottomWidth)}.pf-m-grid-lg.pf-c-table tbody.pf-m-expanded{border-bottom:var(--pf-c-table--border-width--base) solid var(--pf-c-table--BorderColor)}.pf-m-grid-lg.pf-c-table tbody.pf-m-expanded tr:not(.pf-c-table__expandable-row){border-bottom:0}.pf-m-grid-lg.pf-c-table tbody.pf-m-expanded:not(:last-of-type){border-bottom:var(--pf-c-table--tbody--responsive--border-width--base) solid var(--pf-c-table--responsive--BorderColor)}.pf-m-grid-lg.pf-c-table tr:not(.pf-c-table__expandable-row){display:grid;grid-template-columns:1fr;height:auto;grid-auto-columns:max-content;grid-column-gap:var(--pf-c-table-tr--responsive--GridColumnGap);padding:var(--pf-c-table-tr--responsive--PaddingTop) var(--pf-c-table-tr--responsive--PaddingRight) var(--pf-c-table-tr--responsive--PaddingBottom) var(--pf-c-table-tr--responsive--PaddingLeft)}.pf-m-grid-lg.pf-c-table tr:not(.pf-c-table__expandable-row)>*{padding:var(--pf-c-table--cell--responsive--PaddingTop) var(--pf-c-table--cell--responsive--PaddingRight) var(--pf-c-table--cell--responsive--PaddingBottom) var(--pf-c-table--cell--responsive--PaddingLeft)}.pf-m-grid-lg.pf-c-table tr:not(.pf-c-table__expandable-row)>:first-child{--pf-c-table--cell--responsive--PaddingTop:var(--pf-c-table--cell--first-child--responsive--PaddingTop)}.pf-m-grid-lg.pf-c-table.pf-m-compact{--pf-c-table-tr--responsive--PaddingTop:var(--pf-c-table--m-compact-tr--responsive--PaddingTop);--pf-c-table-tr--responsive--PaddingBottom:var(--pf-c-table--m-compact-tr--responsive--PaddingBottom);--pf-c-table--cell--responsive--PaddingTop:var(--pf-c-table--m-compact-tr-td--responsive--PaddingTop);--pf-c-table--cell--responsive--PaddingBottom:var(--pf-c-table--m-compact-tr-td--responsive--PaddingBottom);--pf-c-table__check--input--MarginTop:0}.pf-m-grid-lg.pf-c-table.pf-m-compact .pf-c-table__action{margin-top:var(--pf-c-table--m-compact__action--responsive--MarginTop);margin-bottom:var(--pf-c-table--m-compact__action--responsive--MarginTop)}.pf-m-grid-lg.pf-c-table.pf-m-compact .pf-c-table__toggle .pf-c-button{margin-bottom:var(--pf-c-table--m-compact__toggle--c-button--responsive--MarginBottom)}.pf-m-grid-lg.pf-c-table .pf-c-table__icon>*{text-align:left}.pf-m-grid-lg.pf-c-table [data-label]{--pf-c-table--cell--hidden-visible--Display:var(--pf-c-table--m-grid--cell--hidden-visible--Display);grid-column:1;grid-column-gap:var(--pf-c-table-td--responsive--GridColumnGap);grid-template-columns:1fr minmax(0,1.5fr);align-items:start}.pf-m-grid-lg.pf-c-table [data-label]>*{grid-column:2}.pf-m-grid-lg.pf-c-table [data-label]:before{font-weight:700;text-align:left;content:attr(data-label)}.pf-m-grid-lg.pf-c-table tr>:first-child{--pf-c-table--cell--PaddingLeft:0}.pf-m-grid-lg.pf-c-table tr>:last-child{--pf-c-table--cell--PaddingRight:0}.pf-m-grid-lg.pf-c-table .pf-c-table{--pf-c-table-tr--responsive--PaddingTop:var(--pf-c-table-tr--responsive--nested-table--PaddingTop);--pf-c-table-tr--responsive--PaddingRight:var(--pf-c-table-tr--responsive--nested-table--PaddingRight);--pf-c-table-tr--responsive--PaddingBottom:var(--pf-c-table-tr--responsive--nested-table--PaddingBottom);--pf-c-table-tr--responsive--PaddingLeft:var(--pf-c-table-tr--responsive--nested-table--PaddingLeft);border:0}.pf-m-grid-lg.pf-c-table .pf-c-table tr:not(.pf-c-table__expandable-row)+tr:not(.pf-c-table__expandable-row){--pf-c-table-tr--responsive--PaddingTop:0}.pf-m-grid-lg.pf-c-table .pf-c-table__compound-expansion-toggle{--pf-c-table__compound-expansion-toggle__button--before--BorderRightWidth:0;--pf-c-table__compound-expansion-toggle__button--before--BorderLeftWidth:0;--pf-c-table__compound-expansion-toggle__button--after--Top:100%}.pf-m-grid-lg.pf-c-table tbody{position:relative}.pf-m-grid-lg.pf-c-table tbody:after{position:absolute;top:0;bottom:0;left:0;content:"";border:0;border-left:var(--pf-c-table--tbody--after--BorderLeftWidth) solid var(--pf-c-table--tbody--after--BorderColor)}.pf-m-grid-lg.pf-c-table tbody.pf-m-expanded{--pf-c-table--tbody--after--BorderLeftWidth:var(--pf-c-table--tbody--after--border-width--base)}.pf-m-grid-lg.pf-c-table tbody.pf-m-expanded tbody{--pf-c-table--tbody--after--BorderLeftWidth:0}.pf-m-grid-lg.pf-c-table tbody>tr>:first-child:not(.pf-c-table__check):after{--pf-c-table__expandable-row--after--BorderLeftWidth:0;position:static;width:auto;background-color:transparent}.pf-m-grid-lg.pf-c-table .pf-c-table__expandable-row{--pf-c-table--cell--responsive--PaddingTop:0;--pf-c-table--cell--responsive--PaddingRight:0;--pf-c-table--cell--responsive--PaddingBottom:0;--pf-c-table--cell--responsive--PaddingLeft:0;--pf-c-table--cell--PaddingRight:0;--pf-c-table--cell--PaddingLeft:0;display:block;max-height:var(--pf-c-table__expandable-row--MaxHeight);overflow-y:auto;border-bottom:none;box-shadow:none}.pf-m-grid-lg.pf-c-table .pf-c-table__expandable-row>*{position:static;display:block}.pf-m-grid-lg.pf-c-table .pf-c-table__expandable-row.pf-m-expanded{border-top-color:var(--pf-c-table--BorderColor)}.pf-m-grid-lg.pf-c-table .pf-c-table__expandable-row>:first-child:not(.pf-c-table__check):after{content:none}.pf-m-grid-lg.pf-c-table .pf-c-table__expandable-row td.pf-m-no-padding .pf-c-table__expandable-row-content,.pf-m-grid-lg.pf-c-table .pf-c-table__expandable-row th.pf-m-no-padding .pf-c-table__expandable-row-content{padding:0}.pf-m-grid-lg.pf-c-table .pf-c-table__expandable-row:not(.pf-m-expanded){display:none;visibility:hidden}.pf-m-grid-lg.pf-c-table .pf-c-table__expandable-row .pf-c-table__expandable-row-content{padding-right:var(--pf-c-table__expandable-row-content--responsive--PaddingRight);padding-left:var(--pf-c-table__expandable-row-content--responsive--PaddingLeft)}.pf-m-grid-lg.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__action,.pf-m-grid-lg.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__check,.pf-m-grid-lg.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__favorite,.pf-m-grid-lg.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__toggle{width:auto;padding:0}.pf-m-grid-lg.pf-c-table .pf-c-table__toggle{grid-row-start:20;grid-column:-1;justify-self:end;padding-right:0}.pf-m-grid-lg.pf-c-table .pf-c-table__toggle:after{content:none}.pf-m-grid-lg.pf-c-table .pf-c-table__button{--pf-c-table--cell--PaddingTop:var(--pf-c-table--m-grid--cell--PaddingTop);--pf-c-table--cell--PaddingRight:var(--pf-c-table--m-grid--cell--PaddingRight);--pf-c-table--cell--PaddingBottom:var(--pf-c-table--m-grid--cell--PaddingBottom);--pf-c-table--cell--PaddingLeft:var(--pf-c-table--m-grid--cell--PaddingLeft)}.pf-m-grid-lg.pf-c-table .pf-c-table__action,.pf-m-grid-lg.pf-c-table .pf-c-table__check,.pf-m-grid-lg.pf-c-table .pf-c-table__favorite{grid-row-start:1;grid-column-start:2}.pf-m-grid-lg.pf-c-table .pf-c-table__check{margin-top:var(--pf-c-table__check--responsive--MarginTop);margin-left:var(--pf-c-table__check--responsive--MarginLeft)}.pf-m-grid-lg.pf-c-table .pf-c-table__check~.pf-c-table__favorite{margin-left:var(--pf-c-table--m-grid__check--favorite--MarginLeft)}.pf-m-grid-lg.pf-c-table .pf-c-table__check~.pf-c-table__favorite~.pf-c-table__action{margin-left:var(--pf-c-table--m-grid__check--favorite--action--MarginLeft)}.pf-m-grid-lg.pf-c-table .pf-c-table__check~.pf-c-table__action{margin-left:var(--pf-c-table__action--responsive--MarginLeft)}.pf-m-grid-lg.pf-c-table .pf-c-table__favorite{margin-top:var(--pf-c-table--m-grid__favorite--MarginTop)}.pf-m-grid-lg.pf-c-table .pf-c-table__favorite~.pf-c-table__action{margin-left:var(--pf-c-table--m-grid__favorite--action--MarginLeft)}.pf-m-grid-lg.pf-c-table .pf-c-table__action{margin-top:var(--pf-c-table--m-grid__action--MarginTop);text-align:right}}@media screen and (max-width:992px) and (max-width:576px){.pf-m-grid-lg.pf-c-table .pf-c-table__action{grid-row-start:1;grid-column-start:2;margin-left:0}}@media screen and (max-width:992px){.pf-m-grid-lg.pf-c-table .pf-c-table__inline-edit-action{grid-column:2;grid-row:2}.pf-m-grid-lg.pf-c-table .pf-c-table__toggle-icon{transition:var(--pf-c-table__toggle__icon--Transition)}.pf-c-button.pf-m-expanded>.pf-m-grid-lg.pf-c-table .pf-c-table__toggle-icon{transform:rotate(var(--pf-c-table__toggle--m-expanded__icon--Rotate))}.pf-m-grid-lg.pf-c-table .pf-m-nowrap{--pf-c-table--cell--Overflow:auto}.pf-m-grid-lg.pf-c-table .pf-m-fit-content{width:auto;white-space:normal}.pf-m-grid-lg.pf-c-table .pf-m-truncate{--pf-c-table--cell--MaxWidth:100%}.pf-m-grid-lg.pf-c-table [class*=pf-m-width]{--pf-c-table--cell--Width:auto}}@media screen and (max-width:1200px){.pf-m-grid-xl.pf-c-table{--pf-c-table--cell--PaddingTop:var(--pf-c-table--m-grid--cell--PaddingTop);--pf-c-table--cell--PaddingRight:var(--pf-c-table--m-grid--cell--PaddingRight);--pf-c-table--cell--PaddingBottom:var(--pf-c-table--m-grid--cell--PaddingBottom);--pf-c-table--cell--PaddingLeft:var(--pf-c-table--m-grid--cell--PaddingLeft);--pf-c-table__favorite--c-button--MarginTop:auto;--pf-c-table__favorite--c-button--MarginRight:auto;--pf-c-table__favorite--c-button--MarginBottom:auto;--pf-c-table__favorite--c-button--MarginLeft:auto;display:grid;border:none}.pf-m-grid-xl.pf-c-table tr>*{width:auto;min-width:0;max-width:none;overflow:visible;text-overflow:clip;white-space:normal}.pf-m-grid-xl.pf-c-table .pf-c-table__text{position:relative;width:auto;min-width:0;max-width:none;overflow:var(--pf-c-table--cell--Overflow);text-overflow:var(--pf-c-table--cell--TextOverflow);white-space:var(--pf-c-table--cell--WhiteSpace)}.pf-m-grid-xl.pf-c-table thead{display:none;visibility:hidden}.pf-m-grid-xl.pf-c-table tbody{display:block}.pf-m-grid-xl.pf-c-table tbody:first-of-type{border-top:var(--pf-c-table--tbody--responsive--border-width--base) solid var(--pf-c-table--responsive--BorderColor)}.pf-m-grid-xl.pf-c-table table.pf-m-compact>tbody{border-top:0}.pf-m-grid-xl.pf-c-table tr:not(.pf-c-table__expandable-row){border-bottom:var(--pf-c-table-tr--responsive--border-width--base) solid var(--pf-c-table--responsive--BorderColor)}.pf-m-grid-xl.pf-c-table tbody:last-of-type:not(:only-of-type)>tr,.pf-m-grid-xl.pf-c-table tr:last-child{border-bottom-width:var(--pf-c-table-tr--responsive--last-child--BorderBottomWidth)}.pf-m-grid-xl.pf-c-table tbody.pf-m-expanded{border-bottom:var(--pf-c-table--border-width--base) solid var(--pf-c-table--BorderColor)}.pf-m-grid-xl.pf-c-table tbody.pf-m-expanded tr:not(.pf-c-table__expandable-row){border-bottom:0}.pf-m-grid-xl.pf-c-table tbody.pf-m-expanded:not(:last-of-type){border-bottom:var(--pf-c-table--tbody--responsive--border-width--base) solid var(--pf-c-table--responsive--BorderColor)}.pf-m-grid-xl.pf-c-table tr:not(.pf-c-table__expandable-row){display:grid;grid-template-columns:1fr;height:auto;grid-auto-columns:max-content;grid-column-gap:var(--pf-c-table-tr--responsive--GridColumnGap);padding:var(--pf-c-table-tr--responsive--PaddingTop) var(--pf-c-table-tr--responsive--PaddingRight) var(--pf-c-table-tr--responsive--PaddingBottom) var(--pf-c-table-tr--responsive--PaddingLeft)}.pf-m-grid-xl.pf-c-table tr:not(.pf-c-table__expandable-row)>*{padding:var(--pf-c-table--cell--responsive--PaddingTop) var(--pf-c-table--cell--responsive--PaddingRight) var(--pf-c-table--cell--responsive--PaddingBottom) var(--pf-c-table--cell--responsive--PaddingLeft)}.pf-m-grid-xl.pf-c-table tr:not(.pf-c-table__expandable-row)>:first-child{--pf-c-table--cell--responsive--PaddingTop:var(--pf-c-table--cell--first-child--responsive--PaddingTop)}.pf-m-grid-xl.pf-c-table.pf-m-compact{--pf-c-table-tr--responsive--PaddingTop:var(--pf-c-table--m-compact-tr--responsive--PaddingTop);--pf-c-table-tr--responsive--PaddingBottom:var(--pf-c-table--m-compact-tr--responsive--PaddingBottom);--pf-c-table--cell--responsive--PaddingTop:var(--pf-c-table--m-compact-tr-td--responsive--PaddingTop);--pf-c-table--cell--responsive--PaddingBottom:var(--pf-c-table--m-compact-tr-td--responsive--PaddingBottom);--pf-c-table__check--input--MarginTop:0}.pf-m-grid-xl.pf-c-table.pf-m-compact .pf-c-table__action{margin-top:var(--pf-c-table--m-compact__action--responsive--MarginTop);margin-bottom:var(--pf-c-table--m-compact__action--responsive--MarginTop)}.pf-m-grid-xl.pf-c-table.pf-m-compact .pf-c-table__toggle .pf-c-button{margin-bottom:var(--pf-c-table--m-compact__toggle--c-button--responsive--MarginBottom)}.pf-m-grid-xl.pf-c-table .pf-c-table__icon>*{text-align:left}.pf-m-grid-xl.pf-c-table [data-label]{--pf-c-table--cell--hidden-visible--Display:var(--pf-c-table--m-grid--cell--hidden-visible--Display);grid-column:1;grid-column-gap:var(--pf-c-table-td--responsive--GridColumnGap);grid-template-columns:1fr minmax(0,1.5fr);align-items:start}.pf-m-grid-xl.pf-c-table [data-label]>*{grid-column:2}.pf-m-grid-xl.pf-c-table [data-label]:before{font-weight:700;text-align:left;content:attr(data-label)}.pf-m-grid-xl.pf-c-table tr>:first-child{--pf-c-table--cell--PaddingLeft:0}.pf-m-grid-xl.pf-c-table tr>:last-child{--pf-c-table--cell--PaddingRight:0}.pf-m-grid-xl.pf-c-table .pf-c-table{--pf-c-table-tr--responsive--PaddingTop:var(--pf-c-table-tr--responsive--nested-table--PaddingTop);--pf-c-table-tr--responsive--PaddingRight:var(--pf-c-table-tr--responsive--nested-table--PaddingRight);--pf-c-table-tr--responsive--PaddingBottom:var(--pf-c-table-tr--responsive--nested-table--PaddingBottom);--pf-c-table-tr--responsive--PaddingLeft:var(--pf-c-table-tr--responsive--nested-table--PaddingLeft);border:0}.pf-m-grid-xl.pf-c-table .pf-c-table tr:not(.pf-c-table__expandable-row)+tr:not(.pf-c-table__expandable-row){--pf-c-table-tr--responsive--PaddingTop:0}.pf-m-grid-xl.pf-c-table .pf-c-table__compound-expansion-toggle{--pf-c-table__compound-expansion-toggle__button--before--BorderRightWidth:0;--pf-c-table__compound-expansion-toggle__button--before--BorderLeftWidth:0;--pf-c-table__compound-expansion-toggle__button--after--Top:100%}.pf-m-grid-xl.pf-c-table tbody{position:relative}.pf-m-grid-xl.pf-c-table tbody:after{position:absolute;top:0;bottom:0;left:0;content:"";border:0;border-left:var(--pf-c-table--tbody--after--BorderLeftWidth) solid var(--pf-c-table--tbody--after--BorderColor)}.pf-m-grid-xl.pf-c-table tbody.pf-m-expanded{--pf-c-table--tbody--after--BorderLeftWidth:var(--pf-c-table--tbody--after--border-width--base)}.pf-m-grid-xl.pf-c-table tbody.pf-m-expanded tbody{--pf-c-table--tbody--after--BorderLeftWidth:0}.pf-m-grid-xl.pf-c-table tbody>tr>:first-child:not(.pf-c-table__check):after{--pf-c-table__expandable-row--after--BorderLeftWidth:0;position:static;width:auto;background-color:transparent}.pf-m-grid-xl.pf-c-table .pf-c-table__expandable-row{--pf-c-table--cell--responsive--PaddingTop:0;--pf-c-table--cell--responsive--PaddingRight:0;--pf-c-table--cell--responsive--PaddingBottom:0;--pf-c-table--cell--responsive--PaddingLeft:0;--pf-c-table--cell--PaddingRight:0;--pf-c-table--cell--PaddingLeft:0;display:block;max-height:var(--pf-c-table__expandable-row--MaxHeight);overflow-y:auto;border-bottom:none;box-shadow:none}.pf-m-grid-xl.pf-c-table .pf-c-table__expandable-row>*{position:static;display:block}.pf-m-grid-xl.pf-c-table .pf-c-table__expandable-row.pf-m-expanded{border-top-color:var(--pf-c-table--BorderColor)}.pf-m-grid-xl.pf-c-table .pf-c-table__expandable-row>:first-child:not(.pf-c-table__check):after{content:none}.pf-m-grid-xl.pf-c-table .pf-c-table__expandable-row td.pf-m-no-padding .pf-c-table__expandable-row-content,.pf-m-grid-xl.pf-c-table .pf-c-table__expandable-row th.pf-m-no-padding .pf-c-table__expandable-row-content{padding:0}.pf-m-grid-xl.pf-c-table .pf-c-table__expandable-row:not(.pf-m-expanded){display:none;visibility:hidden}.pf-m-grid-xl.pf-c-table .pf-c-table__expandable-row .pf-c-table__expandable-row-content{padding-right:var(--pf-c-table__expandable-row-content--responsive--PaddingRight);padding-left:var(--pf-c-table__expandable-row-content--responsive--PaddingLeft)}.pf-m-grid-xl.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__action,.pf-m-grid-xl.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__check,.pf-m-grid-xl.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__favorite,.pf-m-grid-xl.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__toggle{width:auto;padding:0}.pf-m-grid-xl.pf-c-table .pf-c-table__toggle{grid-row-start:20;grid-column:-1;justify-self:end;padding-right:0}.pf-m-grid-xl.pf-c-table .pf-c-table__toggle:after{content:none}.pf-m-grid-xl.pf-c-table .pf-c-table__button{--pf-c-table--cell--PaddingTop:var(--pf-c-table--m-grid--cell--PaddingTop);--pf-c-table--cell--PaddingRight:var(--pf-c-table--m-grid--cell--PaddingRight);--pf-c-table--cell--PaddingBottom:var(--pf-c-table--m-grid--cell--PaddingBottom);--pf-c-table--cell--PaddingLeft:var(--pf-c-table--m-grid--cell--PaddingLeft)}.pf-m-grid-xl.pf-c-table .pf-c-table__action,.pf-m-grid-xl.pf-c-table .pf-c-table__check,.pf-m-grid-xl.pf-c-table .pf-c-table__favorite{grid-row-start:1;grid-column-start:2}.pf-m-grid-xl.pf-c-table .pf-c-table__check{margin-top:var(--pf-c-table__check--responsive--MarginTop);margin-left:var(--pf-c-table__check--responsive--MarginLeft)}.pf-m-grid-xl.pf-c-table .pf-c-table__check~.pf-c-table__favorite{margin-left:var(--pf-c-table--m-grid__check--favorite--MarginLeft)}.pf-m-grid-xl.pf-c-table .pf-c-table__check~.pf-c-table__favorite~.pf-c-table__action{margin-left:var(--pf-c-table--m-grid__check--favorite--action--MarginLeft)}.pf-m-grid-xl.pf-c-table .pf-c-table__check~.pf-c-table__action{margin-left:var(--pf-c-table__action--responsive--MarginLeft)}.pf-m-grid-xl.pf-c-table .pf-c-table__favorite{margin-top:var(--pf-c-table--m-grid__favorite--MarginTop)}.pf-m-grid-xl.pf-c-table .pf-c-table__favorite~.pf-c-table__action{margin-left:var(--pf-c-table--m-grid__favorite--action--MarginLeft)}.pf-m-grid-xl.pf-c-table .pf-c-table__action{margin-top:var(--pf-c-table--m-grid__action--MarginTop);text-align:right}}@media screen and (max-width:1200px) and (max-width:576px){.pf-m-grid-xl.pf-c-table .pf-c-table__action{grid-row-start:1;grid-column-start:2;margin-left:0}}@media screen and (max-width:1200px){.pf-m-grid-xl.pf-c-table .pf-c-table__inline-edit-action{grid-column:2;grid-row:2}.pf-m-grid-xl.pf-c-table .pf-c-table__toggle-icon{transition:var(--pf-c-table__toggle__icon--Transition)}.pf-c-button.pf-m-expanded>.pf-m-grid-xl.pf-c-table .pf-c-table__toggle-icon{transform:rotate(var(--pf-c-table__toggle--m-expanded__icon--Rotate))}.pf-m-grid-xl.pf-c-table .pf-m-nowrap{--pf-c-table--cell--Overflow:auto}.pf-m-grid-xl.pf-c-table .pf-m-fit-content{width:auto;white-space:normal}.pf-m-grid-xl.pf-c-table .pf-m-truncate{--pf-c-table--cell--MaxWidth:100%}.pf-m-grid-xl.pf-c-table [class*=pf-m-width]{--pf-c-table--cell--Width:auto}}@media screen and (max-width:1450px){.pf-m-grid-2xl.pf-c-table{--pf-c-table--cell--PaddingTop:var(--pf-c-table--m-grid--cell--PaddingTop);--pf-c-table--cell--PaddingRight:var(--pf-c-table--m-grid--cell--PaddingRight);--pf-c-table--cell--PaddingBottom:var(--pf-c-table--m-grid--cell--PaddingBottom);--pf-c-table--cell--PaddingLeft:var(--pf-c-table--m-grid--cell--PaddingLeft);--pf-c-table__favorite--c-button--MarginTop:auto;--pf-c-table__favorite--c-button--MarginRight:auto;--pf-c-table__favorite--c-button--MarginBottom:auto;--pf-c-table__favorite--c-button--MarginLeft:auto;display:grid;border:none}.pf-m-grid-2xl.pf-c-table tr>*{width:auto;min-width:0;max-width:none;overflow:visible;text-overflow:clip;white-space:normal}.pf-m-grid-2xl.pf-c-table .pf-c-table__text{position:relative;width:auto;min-width:0;max-width:none;overflow:var(--pf-c-table--cell--Overflow);text-overflow:var(--pf-c-table--cell--TextOverflow);white-space:var(--pf-c-table--cell--WhiteSpace)}.pf-m-grid-2xl.pf-c-table thead{display:none;visibility:hidden}.pf-m-grid-2xl.pf-c-table tbody{display:block}.pf-m-grid-2xl.pf-c-table tbody:first-of-type{border-top:var(--pf-c-table--tbody--responsive--border-width--base) solid var(--pf-c-table--responsive--BorderColor)}.pf-m-grid-2xl.pf-c-table table.pf-m-compact>tbody{border-top:0}.pf-m-grid-2xl.pf-c-table tr:not(.pf-c-table__expandable-row){border-bottom:var(--pf-c-table-tr--responsive--border-width--base) solid var(--pf-c-table--responsive--BorderColor)}.pf-m-grid-2xl.pf-c-table tbody:last-of-type:not(:only-of-type)>tr,.pf-m-grid-2xl.pf-c-table tr:last-child{border-bottom-width:var(--pf-c-table-tr--responsive--last-child--BorderBottomWidth)}.pf-m-grid-2xl.pf-c-table tbody.pf-m-expanded{border-bottom:var(--pf-c-table--border-width--base) solid var(--pf-c-table--BorderColor)}.pf-m-grid-2xl.pf-c-table tbody.pf-m-expanded tr:not(.pf-c-table__expandable-row){border-bottom:0}.pf-m-grid-2xl.pf-c-table tbody.pf-m-expanded:not(:last-of-type){border-bottom:var(--pf-c-table--tbody--responsive--border-width--base) solid var(--pf-c-table--responsive--BorderColor)}.pf-m-grid-2xl.pf-c-table tr:not(.pf-c-table__expandable-row){display:grid;grid-template-columns:1fr;height:auto;grid-auto-columns:max-content;grid-column-gap:var(--pf-c-table-tr--responsive--GridColumnGap);padding:var(--pf-c-table-tr--responsive--PaddingTop) var(--pf-c-table-tr--responsive--PaddingRight) var(--pf-c-table-tr--responsive--PaddingBottom) var(--pf-c-table-tr--responsive--PaddingLeft)}.pf-m-grid-2xl.pf-c-table tr:not(.pf-c-table__expandable-row)>*{padding:var(--pf-c-table--cell--responsive--PaddingTop) var(--pf-c-table--cell--responsive--PaddingRight) var(--pf-c-table--cell--responsive--PaddingBottom) var(--pf-c-table--cell--responsive--PaddingLeft)}.pf-m-grid-2xl.pf-c-table tr:not(.pf-c-table__expandable-row)>:first-child{--pf-c-table--cell--responsive--PaddingTop:var(--pf-c-table--cell--first-child--responsive--PaddingTop)}.pf-m-grid-2xl.pf-c-table.pf-m-compact{--pf-c-table-tr--responsive--PaddingTop:var(--pf-c-table--m-compact-tr--responsive--PaddingTop);--pf-c-table-tr--responsive--PaddingBottom:var(--pf-c-table--m-compact-tr--responsive--PaddingBottom);--pf-c-table--cell--responsive--PaddingTop:var(--pf-c-table--m-compact-tr-td--responsive--PaddingTop);--pf-c-table--cell--responsive--PaddingBottom:var(--pf-c-table--m-compact-tr-td--responsive--PaddingBottom);--pf-c-table__check--input--MarginTop:0}.pf-m-grid-2xl.pf-c-table.pf-m-compact .pf-c-table__action{margin-top:var(--pf-c-table--m-compact__action--responsive--MarginTop);margin-bottom:var(--pf-c-table--m-compact__action--responsive--MarginTop)}.pf-m-grid-2xl.pf-c-table.pf-m-compact .pf-c-table__toggle .pf-c-button{margin-bottom:var(--pf-c-table--m-compact__toggle--c-button--responsive--MarginBottom)}.pf-m-grid-2xl.pf-c-table .pf-c-table__icon>*{text-align:left}.pf-m-grid-2xl.pf-c-table [data-label]{--pf-c-table--cell--hidden-visible--Display:var(--pf-c-table--m-grid--cell--hidden-visible--Display);grid-column:1;grid-column-gap:var(--pf-c-table-td--responsive--GridColumnGap);grid-template-columns:1fr minmax(0,1.5fr);align-items:start}.pf-m-grid-2xl.pf-c-table [data-label]>*{grid-column:2}.pf-m-grid-2xl.pf-c-table [data-label]:before{font-weight:700;text-align:left;content:attr(data-label)}.pf-m-grid-2xl.pf-c-table tr>:first-child{--pf-c-table--cell--PaddingLeft:0}.pf-m-grid-2xl.pf-c-table tr>:last-child{--pf-c-table--cell--PaddingRight:0}.pf-m-grid-2xl.pf-c-table .pf-c-table{--pf-c-table-tr--responsive--PaddingTop:var(--pf-c-table-tr--responsive--nested-table--PaddingTop);--pf-c-table-tr--responsive--PaddingRight:var(--pf-c-table-tr--responsive--nested-table--PaddingRight);--pf-c-table-tr--responsive--PaddingBottom:var(--pf-c-table-tr--responsive--nested-table--PaddingBottom);--pf-c-table-tr--responsive--PaddingLeft:var(--pf-c-table-tr--responsive--nested-table--PaddingLeft);border:0}.pf-m-grid-2xl.pf-c-table .pf-c-table tr:not(.pf-c-table__expandable-row)+tr:not(.pf-c-table__expandable-row){--pf-c-table-tr--responsive--PaddingTop:0}.pf-m-grid-2xl.pf-c-table .pf-c-table__compound-expansion-toggle{--pf-c-table__compound-expansion-toggle__button--before--BorderRightWidth:0;--pf-c-table__compound-expansion-toggle__button--before--BorderLeftWidth:0;--pf-c-table__compound-expansion-toggle__button--after--Top:100%}.pf-m-grid-2xl.pf-c-table tbody{position:relative}.pf-m-grid-2xl.pf-c-table tbody:after{position:absolute;top:0;bottom:0;left:0;content:"";border:0;border-left:var(--pf-c-table--tbody--after--BorderLeftWidth) solid var(--pf-c-table--tbody--after--BorderColor)}.pf-m-grid-2xl.pf-c-table tbody.pf-m-expanded{--pf-c-table--tbody--after--BorderLeftWidth:var(--pf-c-table--tbody--after--border-width--base)}.pf-m-grid-2xl.pf-c-table tbody.pf-m-expanded tbody{--pf-c-table--tbody--after--BorderLeftWidth:0}.pf-m-grid-2xl.pf-c-table tbody>tr>:first-child:not(.pf-c-table__check):after{--pf-c-table__expandable-row--after--BorderLeftWidth:0;position:static;width:auto;background-color:transparent}.pf-m-grid-2xl.pf-c-table .pf-c-table__expandable-row{--pf-c-table--cell--responsive--PaddingTop:0;--pf-c-table--cell--responsive--PaddingRight:0;--pf-c-table--cell--responsive--PaddingBottom:0;--pf-c-table--cell--responsive--PaddingLeft:0;--pf-c-table--cell--PaddingRight:0;--pf-c-table--cell--PaddingLeft:0;display:block;max-height:var(--pf-c-table__expandable-row--MaxHeight);overflow-y:auto;border-bottom:none;box-shadow:none}.pf-m-grid-2xl.pf-c-table .pf-c-table__expandable-row>*{position:static;display:block}.pf-m-grid-2xl.pf-c-table .pf-c-table__expandable-row.pf-m-expanded{border-top-color:var(--pf-c-table--BorderColor)}.pf-m-grid-2xl.pf-c-table .pf-c-table__expandable-row>:first-child:not(.pf-c-table__check):after{content:none}.pf-m-grid-2xl.pf-c-table .pf-c-table__expandable-row td.pf-m-no-padding .pf-c-table__expandable-row-content,.pf-m-grid-2xl.pf-c-table .pf-c-table__expandable-row th.pf-m-no-padding .pf-c-table__expandable-row-content{padding:0}.pf-m-grid-2xl.pf-c-table .pf-c-table__expandable-row:not(.pf-m-expanded){display:none;visibility:hidden}.pf-m-grid-2xl.pf-c-table .pf-c-table__expandable-row .pf-c-table__expandable-row-content{padding-right:var(--pf-c-table__expandable-row-content--responsive--PaddingRight);padding-left:var(--pf-c-table__expandable-row-content--responsive--PaddingLeft)}.pf-m-grid-2xl.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__action,.pf-m-grid-2xl.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__check,.pf-m-grid-2xl.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__favorite,.pf-m-grid-2xl.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__toggle{width:auto;padding:0}.pf-m-grid-2xl.pf-c-table .pf-c-table__toggle{grid-row-start:20;grid-column:-1;justify-self:end;padding-right:0}.pf-m-grid-2xl.pf-c-table .pf-c-table__toggle:after{content:none}.pf-m-grid-2xl.pf-c-table .pf-c-table__button{--pf-c-table--cell--PaddingTop:var(--pf-c-table--m-grid--cell--PaddingTop);--pf-c-table--cell--PaddingRight:var(--pf-c-table--m-grid--cell--PaddingRight);--pf-c-table--cell--PaddingBottom:var(--pf-c-table--m-grid--cell--PaddingBottom);--pf-c-table--cell--PaddingLeft:var(--pf-c-table--m-grid--cell--PaddingLeft)}.pf-m-grid-2xl.pf-c-table .pf-c-table__action,.pf-m-grid-2xl.pf-c-table .pf-c-table__check,.pf-m-grid-2xl.pf-c-table .pf-c-table__favorite{grid-row-start:1;grid-column-start:2}.pf-m-grid-2xl.pf-c-table .pf-c-table__check{margin-top:var(--pf-c-table__check--responsive--MarginTop);margin-left:var(--pf-c-table__check--responsive--MarginLeft)}.pf-m-grid-2xl.pf-c-table .pf-c-table__check~.pf-c-table__favorite{margin-left:var(--pf-c-table--m-grid__check--favorite--MarginLeft)}.pf-m-grid-2xl.pf-c-table .pf-c-table__check~.pf-c-table__favorite~.pf-c-table__action{margin-left:var(--pf-c-table--m-grid__check--favorite--action--MarginLeft)}.pf-m-grid-2xl.pf-c-table .pf-c-table__check~.pf-c-table__action{margin-left:var(--pf-c-table__action--responsive--MarginLeft)}.pf-m-grid-2xl.pf-c-table .pf-c-table__favorite{margin-top:var(--pf-c-table--m-grid__favorite--MarginTop)}.pf-m-grid-2xl.pf-c-table .pf-c-table__favorite~.pf-c-table__action{margin-left:var(--pf-c-table--m-grid__favorite--action--MarginLeft)}.pf-m-grid-2xl.pf-c-table .pf-c-table__action{margin-top:var(--pf-c-table--m-grid__action--MarginTop);text-align:right}}@media screen and (max-width:1450px) and (max-width:576px){.pf-m-grid-2xl.pf-c-table .pf-c-table__action{grid-row-start:1;grid-column-start:2;margin-left:0}}@media screen and (max-width:1450px){.pf-m-grid-2xl.pf-c-table .pf-c-table__inline-edit-action{grid-column:2;grid-row:2}.pf-m-grid-2xl.pf-c-table .pf-c-table__toggle-icon{transition:var(--pf-c-table__toggle__icon--Transition)}.pf-c-button.pf-m-expanded>.pf-m-grid-2xl.pf-c-table .pf-c-table__toggle-icon{transform:rotate(var(--pf-c-table__toggle--m-expanded__icon--Rotate))}.pf-m-grid-2xl.pf-c-table .pf-m-nowrap{--pf-c-table--cell--Overflow:auto}.pf-m-grid-2xl.pf-c-table .pf-m-fit-content{width:auto;white-space:normal}.pf-m-grid-2xl.pf-c-table .pf-m-truncate{--pf-c-table--cell--MaxWidth:100%}.pf-m-grid-2xl.pf-c-table [class*=pf-m-width]{--pf-c-table--cell--Width:auto}}.pf-c-table{--pf-c-table--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-table--BorderColor:var(--pf-global--BorderColor--100);--pf-c-table--border-width--base:var(--pf-global--BorderWidth--sm);--pf-c-table-caption--FontSize:var(--pf-global--FontSize--sm);--pf-c-table-caption--Color:var(--pf-global--Color--200);--pf-c-table-caption--PaddingTop:var(--pf-global--spacer--md);--pf-c-table-caption--PaddingRight:var(--pf-global--spacer--lg);--pf-c-table-caption--PaddingBottom:var(--pf-global--spacer--md);--pf-c-table-caption--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-table-caption--xl--PaddingRight:var(--pf-global--spacer--md);--pf-c-table-caption--xl--PaddingLeft:var(--pf-global--spacer--md);--pf-c-table--thead--cell--FontSize:var(--pf-global--FontSize--sm);--pf-c-table--thead--cell--FontWeight:var(--pf-global--FontWeight--bold);--pf-c-table--tbody--cell--PaddingTop:var(--pf-global--spacer--lg);--pf-c-table--tbody--cell--PaddingBottom:var(--pf-global--spacer--lg);--pf-c-table--cell--FontSize:var(--pf-global--FontSize--md);--pf-c-table--cell--FontWeight:var(--pf-global--FontWeight--normal);--pf-c-table--cell--Color:var(--pf-global--Color--100);--pf-c-table--cell--PaddingTop:var(--pf-global--spacer--md);--pf-c-table--cell--PaddingRight:var(--pf-global--spacer--md);--pf-c-table--cell--PaddingBottom:var(--pf-global--spacer--md);--pf-c-table--cell--PaddingLeft:var(--pf-global--spacer--md);--pf-c-table--cell--first-last-child--PaddingLeft:var(--pf-global--spacer--md);--pf-c-table--cell--first-last-child--PaddingRight:var(--pf-global--spacer--md);--pf-c-table--cell--first-last-child--xl--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-table--cell--first-last-child--xl--PaddingRight:var(--pf-global--spacer--lg);--pf-c-table--cell--MinWidth:0;--pf-c-table--cell--MaxWidth:none;--pf-c-table--cell--Width:auto;--pf-c-table--cell--Overflow:visible;--pf-c-table--cell--TextOverflow:clip;--pf-c-table--cell--WhiteSpace:normal;--pf-c-table--cell--WordBreak:normal;--pf-c-table--cell--m-help--MinWidth:11ch;--pf-c-table--m-truncate--cell--MaxWidth:1px;--pf-c-table--m-truncate--cell--MinWidth:calc(5ch + var(--pf-c-table--cell--PaddingRight) + var(--pf-c-table--cell--PaddingLeft));--pf-c-table--cell--hidden-visible--Display:table-cell;--pf-c-table__toggle--c-button--MarginTop:-0.375rem;--pf-c-table__toggle--c-button__toggle-icon--Rotate:270deg;--pf-c-table__toggle--c-button__toggle-icon--Transition:.2s ease-in 0s;--pf-c-table__toggle--c-button--m-expanded__toggle-icon--Rotate:360deg;--pf-c-table__button--BackgroundColor:transparent;--pf-c-table__button--Color:var(--pf-global--Color--100);--pf-c-table__button--hover--Color:var(--pf-global--Color--100);--pf-c-table__button--focus--Color:var(--pf-global--Color--100);--pf-c-table__button--active--Color:var(--pf-global--Color--100);--pf-c-table__button--OutlineOffset:calc(var(--pf-global--BorderWidth--lg)*-1);--pf-c-table--m-compact__toggle--PaddingTop:0;--pf-c-table--m-compact__toggle--PaddingBottom:0;--pf-c-table__check--input--MarginTop:0.25rem;--pf-c-table__check--input--FontSize:var(--pf-global--FontSize--md);--pf-c-table--cell--m-favorite--Color:var(--pf-global--Color--light-300);--pf-c-table__favorite--c-button--Color:var(--pf-global--Color--light-300);--pf-c-table__favorite--c-button--FontSize:var(--pf-global--FontSize--sm);--pf-c-table__favorite--c-button--MarginTop:calc(var(--pf-global--spacer--form-element)*-1);--pf-c-table__favorite--c-button--MarginRight:calc(var(--pf-global--spacer--md)*-1);--pf-c-table__favorite--c-button--MarginBottom:calc(var(--pf-global--spacer--form-element)*-1);--pf-c-table__favorite--c-button--MarginLeft:calc(var(--pf-global--spacer--md)*-1);--pf-c-table__favorite--m-favorited--c-button--Color:var(--pf-global--palette--gold-400);--pf-c-table__sort--m-favorite__button__text--Color:var(--pf-global--Color--200);--pf-c-table__sort--m-favorite__button--hover__text--Color:var(--pf-global--Color--100);--pf-c-table__sort--m-favorite__button--focus__text--Color:var(--pf-global--Color--100);--pf-c-table__sort--m-favorite__button--active__text--Color:var(--pf-global--Color--100);--pf-c-table__action--PaddingTop:0;--pf-c-table__action--PaddingRight:0;--pf-c-table__action--PaddingBottom:0;--pf-c-table__action--PaddingLeft:0;--pf-c-table__inline-edit-action--PaddingTop:0;--pf-c-table__inline-edit-action--PaddingRight:0;--pf-c-table__inline-edit-action--PaddingBottom:0;--pf-c-table__inline-edit-action--PaddingLeft:0;--pf-c-table__expandable-row--Transition:var(--pf-global--Transition);--pf-c-table__expandable-row--MaxHeight:28.125rem;--pf-c-table__expandable-row-content--Transition:var(--pf-global--Transition);--pf-c-table__expandable-row-content--PaddingTop:var(--pf-global--spacer--lg);--pf-c-table__expandable-row-content--PaddingBottom:var(--pf-global--spacer--lg);--pf-c-table__expandable-row--after--Top:calc(var(--pf-c-table--border-width--base)*-1);--pf-c-table__expandable-row--after--Bottom:calc(var(--pf-c-table--border-width--base)*-1);--pf-c-table__expandable-row--after--border-width--base:var(--pf-global--BorderWidth--lg);--pf-c-table__expandable-row--after--BorderLeftWidth:0;--pf-c-table__expandable-row--after--BorderColor:var(--pf-global--active-color--100);--pf-c-table__icon-inline--MarginRight:var(--pf-global--spacer--sm);--pf-c-table__sort--MinWidth:calc(6ch + var(--pf-c-table--cell--PaddingRight) + var(--pf-c-table--cell--PaddingLeft) + var(--pf-c-table__sort-indicator--MarginLeft));--pf-c-table__sort__button--PaddingTop:var(--pf-global--spacer--form-element);--pf-c-table__sort__button--PaddingRight:var(--pf-global--spacer--sm);--pf-c-table__sort__button--PaddingBottom:var(--pf-global--spacer--form-element);--pf-c-table__sort__button--PaddingLeft:var(--pf-global--spacer--sm);--pf-c-table__sort__button--MarginTop:calc(var(--pf-c-table__sort__button--PaddingTop)*-1);--pf-c-table__sort__button--MarginBottom:calc(var(--pf-c-table__sort__button--PaddingBottom)*-1);--pf-c-table__sort__button--MarginLeft:calc(var(--pf-c-table__sort__button--PaddingLeft)*-1);--pf-c-table__sort__button--Color:var(--pf-global--Color--100);--pf-c-table__sort--m-selected__button--Color:var(--pf-global--active-color--100);--pf-c-table__sort--m-help--MinWidth:15ch;--pf-c-table__sort__button__text--Color:currentColor;--pf-c-table__sort__button--hover__text--Color:currentColor;--pf-c-table__sort__button--focus__text--Color:currentColor;--pf-c-table__sort__button--active__text--Color:currentColor;--pf-c-table__sort-indicator--Color:var(--pf-global--disabled-color--200);--pf-c-table__sort-indicator--MarginLeft:var(--pf-global--spacer--md);--pf-c-table__sort--m-selected__sort-indicator--Color:var(--pf-global--active-color--100);--pf-c-table__sort__button--hover__sort-indicator--Color:var(--pf-global--Color--100);--pf-c-table__sort__button--active__sort-indicator--Color:var(--pf-global--Color--100);--pf-c-table__sort__button--focus__sort-indicator--Color:var(--pf-global--Color--100);--pf-c-table--th--m-help--MinWidth:11ch;--pf-c-table__column-help--MarginLeft:var(--pf-global--spacer--xs);--pf-c-table__column-help--TranslateY:0.125rem;--pf-c-table__column-help--c-button--MarginTop:calc(var(--pf-global--spacer--form-element)*-1);--pf-c-table__column-help--c-button--MarginBottom:calc(var(--pf-global--spacer--form-element)*-1);--pf-c-table__column-help--c-button--PaddingRight:var(--pf-global--spacer--sm);--pf-c-table__column-help--c-button--PaddingLeft:var(--pf-global--spacer--sm);--pf-c-table__compound-expansion-toggle__button--Color:var(--pf-global--active-color--100);--pf-c-table__compound-expansion-toggle__button--hover--Color:var(--pf-global--link--Color--hover);--pf-c-table__compound-expansion-toggle__button--focus--Color:var(--pf-global--link--Color--hover);--pf-c-table__compound-expansion-toggle__button--active--Color:var(--pf-global--link--Color--hover);--pf-c-table__compound-expansion-toggle__button--before--border-width--base:var(--pf-global--BorderWidth--sm);--pf-c-table__compound-expansion-toggle__button--before--BorderColor:var(--pf-global--BorderColor--100);--pf-c-table__compound-expansion-toggle__button--before--BorderRightWidth:0;--pf-c-table__compound-expansion-toggle__button--before--BorderLeftWidth:0;--pf-c-table__compound-expansion-toggle__button--before--Bottom:calc(var(--pf-c-table__compound-expansion-toggle__button--before--border-width--base)*-1);--pf-c-table__compound-expansion-toggle__button--before--Left:calc(var(--pf-c-table__compound-expansion-toggle__button--before--border-width--base)*-1);--pf-c-table__compound-expansion-toggle__button--after--border-width--base:var(--pf-global--BorderWidth--lg);--pf-c-table__compound-expansion-toggle__button--after--BorderColor:var(--pf-global--primary-color--100);--pf-c-table__compound-expansion-toggle__button--after--BorderTopWidth:0;--pf-c-table__compound-expansion-toggle__button--after--Top:calc(var(--pf-c-table__compound-expansion-toggle__button--before--border-width--base)*-1);--pf-c-table__compound-expansion-toggle__button--after--Left:calc(var(--pf-c-table__compound-expansion-toggle__button--before--border-width--base)*-1);--pf-c-table--m-compact-th--PaddingTop:calc(var(--pf-global--spacer--sm) + var(--pf-global--spacer--xs));--pf-c-table--m-compact-th--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-table--m-compact--cell--PaddingTop:var(--pf-global--spacer--sm);--pf-c-table--m-compact--cell--PaddingRight:var(--pf-global--spacer--sm);--pf-c-table--m-compact--cell--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-table--m-compact--cell--PaddingLeft:var(--pf-global--spacer--sm);--pf-c-table--m-compact--cell--first-last-child--PaddingLeft:var(--pf-global--spacer--md);--pf-c-table--m-compact--cell--first-last-child--PaddingRight:var(--pf-global--spacer--md);--pf-c-table--m-compact--cell--first-last-child--xl--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-table--m-compact--cell--first-last-child--xl--PaddingRight:var(--pf-global--spacer--lg);--pf-c-table--m-compact--FontSize:var(--pf-global--FontSize--sm);--pf-c-table--m-compact__expandable-row-content--PaddingTop:var(--pf-global--spacer--lg);--pf-c-table--m-compact__expandable-row-content--PaddingRight:var(--pf-global--spacer--lg);--pf-c-table--m-compact__expandable-row-content--PaddingBottom:var(--pf-global--spacer--lg);--pf-c-table--m-compact__expandable-row-content--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-table--nested--first-last-child--PaddingRight:var(--pf-global--spacer--3xl);--pf-c-table--nested--first-last-child--PaddingLeft:var(--pf-global--spacer--3xl);--pf-c-table__expandable-row--m-expanded--BorderBottomColor:var(--pf-global--BorderColor--100);color:var(--pf-global--Color--100);width:100%;background-color:var(--pf-c-table--BackgroundColor)}@media screen and (max-width:1200px){.pf-c-table{--pf-c-table-caption--PaddingRight:var(--pf-c-table-caption--xl--PaddingRight);--pf-c-table-caption--PaddingLeft:var(--pf-c-table-caption--xl--PaddingLeft)}}@media screen and (min-width:1200px){.pf-c-table{--pf-c-table--cell--first-last-child--PaddingRight:var(--pf-c-table--cell--first-last-child--xl--PaddingRight);--pf-c-table--cell--first-last-child--PaddingLeft:var(--pf-c-table--cell--first-last-child--xl--PaddingLeft);--pf-c-table--m-compact--cell--first-last-child--PaddingLeft:var(--pf-c-table--m-compact--cell--first-last-child--xl--PaddingLeft);--pf-c-table--m-compact--cell--first-last-child--PaddingRight:var(--pf-c-table--m-compact--cell--first-last-child--xl--PaddingRight)}}.pf-c-table.pf-m-fixed{table-layout:fixed}.pf-c-table.pf-m-sticky-header{position:relative}.pf-c-table.pf-m-sticky-header>thead>tr{border-bottom:0}.pf-c-table.pf-m-sticky-header>thead>tr>*{position:sticky;top:0;z-index:var(--pf-global--ZIndex--xs);background:var(--pf-c-table--BackgroundColor)}.pf-c-table.pf-m-sticky-header>thead>tr>:after{position:absolute;right:0;bottom:0;left:0;content:""}.pf-c-table.pf-m-sticky-header>thead>tr>:after,.pf-c-table tr:not(.pf-c-table__expandable-row){border-bottom:var(--pf-c-table--border-width--base) solid var(--pf-c-table--BorderColor)}.pf-c-table tr>*{--pf-hidden-visible--visible--Display:var(--pf-c-table--cell--hidden-visible--Display);position:relative;width:var(--pf-c-table--cell--Width);min-width:var(--pf-c-table--cell--MinWidth);max-width:var(--pf-c-table--cell--MaxWidth);padding:var(--pf-c-table--cell--PaddingTop) var(--pf-c-table--cell--PaddingRight) var(--pf-c-table--cell--PaddingBottom) var(--pf-c-table--cell--PaddingLeft);overflow:var(--pf-c-table--cell--Overflow);font-size:var(--pf-c-table--cell--FontSize);font-weight:var(--pf-c-table--cell--FontWeight);color:var(--pf-c-table--cell--Color);text-overflow:var(--pf-c-table--cell--TextOverflow);word-break:var(--pf-c-table--cell--WordBreak);white-space:var(--pf-c-table--cell--WhiteSpace)}.pf-c-table tr>:first-child{--pf-c-table--cell--PaddingLeft:var(--pf-c-table--cell--first-last-child--PaddingLeft)}.pf-c-table tr>:last-child{--pf-c-table--cell--PaddingRight:var(--pf-c-table--cell--first-last-child--PaddingRight)}.pf-c-table tr>.pf-m-center{text-align:center}.pf-c-table tr>:empty{width:auto;min-width:0;padding:0}.pf-c-table tr>.pf-m-help{--pf-c-table--cell--MinWidth:var(--pf-c-table--cell--m-help--MinWidth)}.pf-c-table tr>.pf-m-favorite{--pf-c-table__button--Color:var(--pf-c-table--cell--m-favorite--Color);--pf-c-table__sort--MinWidth:fit-content;--pf-c-table--cell--MaxWidth:fit-content;--pf-c-table--cell--Overflow:visible}.pf-c-table caption{padding-top:var(--pf-c-table-caption--PaddingTop);padding-bottom:var(--pf-c-table-caption--PaddingBottom);padding-left:var(--pf-c-table-caption--PaddingLeft);font-size:var(--pf-c-table-caption--FontSize);color:var(--pf-c-table-caption--Color);text-align:left;background-color:var(--pf-c-table--BackgroundColor)}.pf-c-table thead{--pf-c-table--cell--FontSize:var(--pf-c-table--thead--cell--FontSize);--pf-c-table--cell--FontWeight:var(--pf-c-table--thead--cell--FontWeight);vertical-align:bottom}.pf-c-table tbody{--pf-c-table--cell--PaddingTop:var(--pf-c-table--tbody--cell--PaddingTop);--pf-c-table--cell--PaddingBottom:var(--pf-c-table--tbody--cell--PaddingBottom)}.pf-c-table tbody>tr>*{overflow-wrap:break-word;vertical-align:baseline}.pf-c-table tbody>tr>:first-child:after{position:absolute;top:var(--pf-c-table__expandable-row--after--Top);bottom:var(--pf-c-table__expandable-row--after--Bottom);left:0;content:"";background-color:transparent;border-left:var(--pf-c-table__expandable-row--after--BorderLeftWidth) solid var(--pf-c-table__expandable-row--after--BorderColor)}.pf-c-table tbody .pf-c-table__check>input{margin-top:var(--pf-c-table__check--input--MarginTop);vertical-align:top}.pf-c-table .pf-c-table__compound-expansion-toggle,.pf-c-table .pf-c-table__compound-expansion-toggle:first-child,.pf-c-table .pf-c-table__compound-expansion-toggle:last-child{padding:0}.pf-c-table .pf-c-table__sort{min-width:var(--pf-c-table__sort--MinWidth)}.pf-c-table .pf-m-help{min-width:var(--pf-c-table--th--m-help--MinWidth)}.pf-c-table .pf-m-truncate,.pf-c-table thead{--pf-c-table--cell--MinWidth:var(--pf-c-table--m-truncate--cell--MinWidth);--pf-c-table--cell--MaxWidth:var(--pf-c-table--m-truncate--cell--MaxWidth);--pf-c-table--cell--Overflow:hidden;--pf-c-table--cell--TextOverflow:ellipsis;--pf-c-table--cell--WhiteSpace:nowrap}.pf-c-table .pf-m-wrap{--pf-c-table--cell--WhiteSpace:normal}.pf-c-table .pf-m-nowrap,.pf-c-table .pf-m-wrap{--pf-c-table--cell--MinWidth:0;--pf-c-table--cell--MaxWidth:none;--pf-c-table--cell--Overflow:visible;--pf-c-table--cell--TextOverflow:clip}.pf-c-table .pf-m-nowrap{--pf-c-table--cell--WhiteSpace:nowrap}.pf-c-table .pf-c-table__icon,.pf-c-table .pf-m-fit-content{--pf-c-table--cell--MinWidth:fit-content;--pf-c-table--cell--MaxWidth:fit-content;--pf-c-table--cell--Width:1%;--pf-c-table--cell--Overflow:visible;--pf-c-table--cell--TextOverflow:clip;--pf-c-table--cell--WhiteSpace:nowrap}.pf-c-table .pf-m-break-word{--pf-c-table--cell--WordBreak:break-word;--pf-c-table--cell--WhiteSpace:normal}.pf-c-table.pf-m-no-border-rows>tbody>tr{border-bottom:0}.pf-c-table.pf-m-no-border-rows>tbody>tr>:first-child:after{border-left:0}.pf-c-table.pf-m-no-border-rows>tbody:not(.pf-m-expanded) .pf-c-table__compound-expansion-toggle .pf-c-table__button:before{display:none}.pf-c-table.pf-m-no-border-rows>tbody.pf-m-expanded>.pf-c-table__control-row{border-bottom:var(--pf-c-table--border-width--base) solid var(--pf-c-table--BorderColor)}.pf-c-table.pf-m-no-border-rows>tbody .pf-c-table__control-row>.pf-c-table__compound-expansion-toggle:first-child>:before{border-left-width:0}.pf-c-table__text{--pf-c-table--cell--MaxWidth:100%;position:relative;display:block;width:var(--pf-c-table--cell--Width);min-width:var(--pf-c-table--cell--MinWidth);max-width:var(--pf-c-table--cell--MaxWidth);overflow:var(--pf-c-table--cell--Overflow);text-overflow:var(--pf-c-table--cell--TextOverflow);word-break:var(--pf-c-table--cell--WordBreak);white-space:var(--pf-c-table--cell--WhiteSpace)}.pf-c-table__text.pf-m-truncate{--pf-c-table--cell--MinWidth:100%}.pf-c-table__text.pf-m-truncate>*{overflow:var(--pf-c-table--cell--Overflow);text-overflow:var(--pf-c-table--cell--TextOverflow);white-space:var(--pf-c-table--cell--WhiteSpace)}.pf-c-table__button{position:static;width:100%;padding:var(--pf-c-table--cell--PaddingTop) var(--pf-c-table--cell--PaddingRight) var(--pf-c-table--cell--PaddingBottom) var(--pf-c-table--cell--PaddingLeft);font-size:inherit;font-weight:inherit;color:var(--pf-c-table__button--Color);text-align:left;white-space:inherit;user-select:text;background-color:var(--pf-c-table__button--BackgroundColor);border:0}.pf-c-table__button:before{position:absolute;top:0;right:0;bottom:0;left:0;cursor:pointer;content:""}.pf-c-table__button:hover{color:var(--pf-c-table__button--hover--Color)}.pf-c-table__button:focus{color:var(--pf-c-table__button--focus--Color)}.pf-c-table__button:active{color:var(--pf-c-table__button--active--Color)}.pf-c-table__compound-expansion-toggle .pf-c-table__text,.pf-c-table__sort .pf-c-table__text{display:block;width:auto;overflow:var(--pf-c-table--cell--Overflow);text-overflow:var(--pf-c-table--cell--TextOverflow);white-space:var(--pf-c-table--cell--WhiteSpace)}.pf-c-table__sort .pf-c-table__text{--pf-c-table--cell--MinWidth:0}.pf-c-table__button-content,.pf-c-table__column-help{display:inline-grid;align-items:end;justify-content:start;grid-template-columns:auto max-content}.pf-c-table__button-content .pf-c-table__text,.pf-c-table__column-help .pf-c-table__text{min-width:auto}.pf-c-table th.pf-m-nowrap .pf-c-table__button-content,.pf-c-table th.pf-m-nowrap .pf-c-table__column-help,.pf-c-table thead.pf-m-nowrap .pf-c-table__button-content,.pf-c-table thead.pf-m-nowrap .pf-c-table__column-help,.pf-c-table tr.pf-m-nowrap .pf-c-table__button-content,.pf-c-table tr.pf-m-nowrap .pf-c-table__column-help{grid-template-columns:min-content max-content}.pf-c-table th.pf-m-fit-content .pf-c-table__button-content,.pf-c-table th.pf-m-fit-content .pf-c-table__column-help,.pf-c-table thead.pf-m-fit-content .pf-c-table__button-content,.pf-c-table thead.pf-m-fit-content .pf-c-table__column-help,.pf-c-table tr.pf-m-fit-content .pf-c-table__button-content,.pf-c-table tr.pf-m-fit-content .pf-c-table__column-help{grid-template-columns:fit-content max-content}.pf-c-table th.pf-m-truncate .pf-c-table__button-content,.pf-c-table th.pf-m-truncate .pf-c-table__column-help,.pf-c-table th.pf-m-wrap .pf-c-table__button-content,.pf-c-table th.pf-m-wrap .pf-c-table__column-help,.pf-c-table thead.pf-m-truncate .pf-c-table__button-content,.pf-c-table thead.pf-m-truncate .pf-c-table__column-help,.pf-c-table thead.pf-m-wrap .pf-c-table__button-content,.pf-c-table thead.pf-m-wrap .pf-c-table__column-help,.pf-c-table tr.pf-m-truncate .pf-c-table__button-content,.pf-c-table tr.pf-m-truncate .pf-c-table__column-help,.pf-c-table tr.pf-m-wrap .pf-c-table__button-content,.pf-c-table tr.pf-m-wrap .pf-c-table__column-help{grid-template-columns:auto max-content}.pf-c-table .pf-c-table__action,.pf-c-table .pf-c-table__inline-edit-action,.pf-c-table .pf-c-table__toggle{--pf-c-table--cell--PaddingBottom:0}.pf-c-table .pf-c-table__action,.pf-c-table .pf-c-table__check,.pf-c-table .pf-c-table__favorite,.pf-c-table .pf-c-table__inline-edit-action,.pf-c-table .pf-c-table__toggle,.pf-c-table th.pf-m-favorite{--pf-c-table--cell--MinWidth:0;--pf-c-table--cell--Width:1%}.pf-c-table__toggle{--pf-c-table--cell--PaddingRight:0;--pf-c-table--cell--PaddingLeft:0;vertical-align:top}.pf-c-table__toggle .pf-c-button{margin-top:var(--pf-c-table__toggle--c-button--MarginTop)}.pf-c-table__toggle .pf-c-button.pf-m-expanded .pf-c-table__toggle-icon{transform:rotate(var(--pf-c-table__toggle--c-button--m-expanded__toggle-icon--Rotate))}.pf-c-table__toggle .pf-c-table__toggle-icon{transition:var(--pf-c-table__toggle--c-button__toggle-icon--Transition);transform:rotate(var(--pf-c-table__toggle--c-button__toggle-icon--Rotate))}.pf-c-table__toggle svg{pointer-events:none}.pf-c-table__check{--pf-c-table--cell--FontSize:var(--pf-c-table__check--input--FontSize)}.pf-c-table__favorite .pf-c-button{--pf-c-button--m-plain--Color:var(--pf-c-table__favorite--c-button--Color);--pf-c-button--FontSize:var(--pf-c-table__favorite--c-button--FontSize);margin:var(--pf-c-table__favorite--c-button--MarginTop) var(--pf-c-table__favorite--c-button--MarginRight) var(--pf-c-table__favorite--c-button--MarginBottom) var(--pf-c-table__favorite--c-button--MarginLeft)}.pf-m-favorited.pf-c-table__favorite .pf-c-button{--pf-c-button--m-plain--Color:var(--pf-c-table__favorite--m-favorited--c-button--Color)}.pf-c-table__action,.pf-c-table__inline-edit-action{--pf-c-table--cell--PaddingTop:0;--pf-c-table--cell--PaddingRight:var(--pf-c-table__action--PaddingRight);--pf-c-table--cell--PaddingBottom:0;--pf-c-table--cell--PaddingLeft:var(--pf-c-table__action--PaddingLeft);padding-top:0;padding-bottom:0;vertical-align:middle}.pf-c-table__inline-edit-action{--pf-c-table--cell--PaddingLeft:0;--pf-c-table--cell--PaddingRight:0;text-align:right}.pf-c-table__compound-expansion-toggle{--pf-c-table__button--Color:var(--pf-c-table__compound-expansion-toggle__button--Color);--pf-c-table__button--hover--Color:var(--pf-c-table__compound-expansion-toggle__button--hover--Color);--pf-c-table__button--focus--Color:var(--pf-c-table__compound-expansion-toggle__button--focus--Color);--pf-c-table__button--active--Color:var(--pf-c-table__compound-expansion-toggle__button--active--Color);position:relative}.pf-c-table__compound-expansion-toggle.pf-m-truncate{overflow:visible}.pf-c-table__compound-expansion-toggle .pf-c-table__button{min-width:100%;overflow:hidden}.pf-c-table__compound-expansion-toggle .pf-c-table__button:active,.pf-c-table__compound-expansion-toggle .pf-c-table__button:focus,.pf-c-table__compound-expansion-toggle .pf-c-table__button:hover{outline:0}.pf-c-table__compound-expansion-toggle .pf-c-table__button:after,.pf-c-table__compound-expansion-toggle .pf-c-table__button:before{position:absolute;right:0;content:"";border-style:solid;border-width:0}.pf-c-table__compound-expansion-toggle .pf-c-table__button:before{top:0;bottom:var(--pf-c-table__compound-expansion-toggle__button--before--Bottom);left:var(--pf-c-table__compound-expansion-toggle__button--before--Left);border-color:var(--pf-c-table__compound-expansion-toggle__button--before--BorderColor);border-right-width:var(--pf-c-table__compound-expansion-toggle__button--before--BorderRightWidth);border-left-width:var(--pf-c-table__compound-expansion-toggle__button--before--BorderLeftWidth)}.pf-c-table__compound-expansion-toggle .pf-c-table__button:after{top:var(--pf-c-table__compound-expansion-toggle__button--after--Top);left:var(--pf-c-table__compound-expansion-toggle__button--after--Left);pointer-events:none;border-color:var(--pf-c-table__compound-expansion-toggle__button--after--BorderColor);border-top-width:var(--pf-c-table__compound-expansion-toggle__button--after--BorderTopWidth)}.pf-c-table__compound-expansion-toggle.pf-m-expanded,.pf-c-table__compound-expansion-toggle:focus-within,.pf-c-table__compound-expansion-toggle:hover{--pf-c-table__compound-expansion-toggle__button--before--BorderRightWidth:var(--pf-c-table__compound-expansion-toggle__button--before--border-width--base);--pf-c-table__compound-expansion-toggle__button--before--BorderLeftWidth:var(--pf-c-table__compound-expansion-toggle__button--before--border-width--base);--pf-c-table__compound-expansion-toggle__button--after--BorderTopWidth:var(--pf-c-table__compound-expansion-toggle__button--after--border-width--base)}.pf-c-table__compound-expansion-toggle:first-child{--pf-c-table__compound-expansion-toggle__button--before--Left:0;--pf-c-table__compound-expansion-toggle__button--after--Left:0}.pf-c-table__compound-expansion-toggle.pf-m-expanded .pf-c-table__button:before{border-bottom:var(--pf-c-table--BackgroundColor) solid var(--pf-c-table__compound-expansion-toggle__button--before--border-width--base)}.pf-c-table__compound-expansion-toggle.pf-m-expanded:first-child{--pf-c-table__compound-expansion-toggle__button--before--BorderLeftWidth:0}.pf-c-table__compound-expansion-toggle:focus-within{outline-offset:var(--pf-c-table__button--OutlineOffset)}@media (-webkit-min-device-pixel-ratio:0){.pf-c-table__compound-expansion-toggle:focus-within{outline-style:auto;outline-color:-webkit-focus-ring-color}}.pf-c-table__column-help-action{margin-left:var(--pf-c-table__column-help--MarginLeft);transform:translateY(var(--pf-c-table__column-help--TranslateY))}.pf-c-table__column-help-action .pf-c-button{--pf-c-button--PaddingRight:var(--pf-c-table__column-help--c-button--PaddingRight);--pf-c-button--PaddingLeft:var(--pf-c-table__column-help--c-button--PaddingLeft);margin-top:var(--pf-c-table__column-help--c-button--MarginTop);margin-bottom:var(--pf-c-table__column-help--c-button--MarginBottom);font-size:inherit;line-height:1}.pf-c-table__sort .pf-c-table__button{--pf-c-table--cell--PaddingTop:var(--pf-c-table__sort__button--PaddingTop);--pf-c-table--cell--PaddingRight:var(--pf-c-table__sort__button--PaddingRight);--pf-c-table--cell--PaddingBottom:var(--pf-c-table__sort__button--PaddingBottom);--pf-c-table--cell--PaddingLeft:var(--pf-c-table__sort__button--PaddingLeft);display:flex;width:auto;margin-top:var(--pf-c-table__sort__button--MarginTop);margin-bottom:var(--pf-c-table__sort__button--MarginBottom);margin-left:var(--pf-c-table__sort__button--MarginLeft)}.pf-c-table__sort .pf-c-table__button:hover{--pf-c-table__sort-indicator--Color:var(--pf-c-table__sort__button--hover__sort-indicator--Color);--pf-c-table__sort__button__text--Color:var(--pf-c-table__sort__button--hover__text--Color)}.pf-c-table__sort .pf-c-table__button:focus{--pf-c-table__sort-indicator--Color:var(--pf-c-table__sort__button--focus__sort-indicator--Color);--pf-c-table__sort__button__text--Color:var(--pf-c-table__sort__button--focus__text--Color)}.pf-c-table__sort .pf-c-table__button:active{--pf-c-table__sort-indicator--Color:var(--pf-c-table__sort__button--active__sort-indicator--Color);--pf-c-table__sort__button__text--Color:var(--pf-c-table__sort__button--active__text--Color)}.pf-c-table__sort .pf-c-table__button .pf-c-table__text{color:var(--pf-c-table__sort__button__text--Color)}.pf-c-table__sort.pf-m-selected .pf-c-table__button{--pf-c-table__sort-indicator--Color:var(--pf-c-table__sort--m-selected__sort-indicator--Color);--pf-c-table__sort__button__text--Color:var(--pf-c-table__sort--m-selected__button__text--Color);color:var(--pf-c-table__sort--m-selected__button--Color)}.pf-c-table__sort.pf-m-help{--pf-c-table--th--m-help--MinWidth:var(--pf-c-table__sort--m-help--MinWidth)}.pf-c-table__sort.pf-m-favorite{--pf-c-table__sort__button__text--Color:var(--pf-c-table__sort--m-favorite__button__text--Color);--pf-c-table__sort__button--hover__text--Color:var(--pf-c-table__sort--m-favorite__button--hover__text--Color);--pf-c-table__sort__button--focus__text--Color:var(--pf-c-table__sort--m-favorite__button--focus__text--Color);--pf-c-table__sort__button--active__text--Color:var(--pf-c-table__sort--m-favorite__button--active__text--Color);--pf-c-table__sort--m-selected__button__text--Color:currentColor}.pf-c-table__sort-indicator{grid-column:2;margin-left:var(--pf-c-table__sort-indicator--MarginLeft);color:var(--pf-c-table__sort-indicator--Color);pointer-events:none}.pf-c-table__expandable-row{--pf-c-table--cell--PaddingTop:0;--pf-c-table--cell--PaddingBottom:0;position:relative;border-bottom:0 solid transparent;box-shadow:0 0 0 0 transparent}.pf-c-table__expandable-row,.pf-c-table__expandable-row td:first-child:after{transition:var(--pf-c-table__expandable-row--Transition)}.pf-c-table__expandable-row td.pf-m-no-padding,.pf-c-table__expandable-row th.pf-m-no-padding{padding:0 0 0 var(--pf-c-table__expandable-row--after--border-width--base)}.pf-c-table__expandable-row td.pf-m-no-padding .pf-c-table__expandable-row-content,.pf-c-table__expandable-row th.pf-m-no-padding .pf-c-table__expandable-row-content{padding:0}.pf-c-table__expandable-row .pf-c-table__expandable-row-content{padding-top:var(--pf-c-table__expandable-row-content--PaddingTop);padding-bottom:var(--pf-c-table__expandable-row-content--PaddingBottom)}.pf-c-table__expandable-row.pf-m-expanded{border-bottom-color:var(--pf-c-table__expandable-row--m-expanded--BorderBottomColor);border-bottom-width:var(--pf-c-table--border-width--base);box-shadow:var(--pf-c-table__expandable-row--m-expanded--BoxShadow)}.pf-c-table__expandable-row:not(.pf-m-expanded){display:none;visibility:hidden}.pf-c-table__compound-expansion-toggle.pf-m-expanded:first-child,.pf-c-table__expandable-row.pf-m-expanded>:first-child,.pf-c-table tbody.pf-m-expanded>tr>:not(.pf-c-table__compound-expansion-toggle){--pf-c-table__expandable-row--after--BorderLeftWidth:var(--pf-c-table__expandable-row--after--border-width--base)}.pf-c-table .pf-c-table tr>:first-child{--pf-c-table--cell--PaddingLeft:var(--pf-c-table--nested--first-last-child--PaddingLeft)}.pf-c-table .pf-c-table tr>:last-child{--pf-c-table--cell--PaddingRight:var(--pf-c-table--nested--first-last-child--PaddingRight)}.pf-c-table.pf-m-compact{--pf-c-table--cell--FontSize:var(--pf-c-table--m-compact--FontSize);--pf-c-table--cell--PaddingTop:var(--pf-c-table--m-compact--cell--PaddingTop);--pf-c-table--cell--PaddingRight:var(--pf-c-table--m-compact--cell--PaddingRight);--pf-c-table--cell--PaddingBottom:var(--pf-c-table--m-compact--cell--PaddingBottom);--pf-c-table--cell--PaddingRight:var(--pf-c-table--m-compact--cell--PaddingLeft)}.pf-c-table.pf-m-compact tr{--pf-c-table--cell--PaddingLeft:var(--pf-c-table--m-compact--cell--PaddingLeft);--pf-c-table--cell--PaddingRight:var(--pf-c-table--m-compact--cell--PaddingRight)}.pf-c-table.pf-m-compact tr:not(.pf-c-table__expandable-row){--pf-c-table--cell--FontSize:var(--pf-c-table--m-compact--FontSize);--pf-c-table--cell--PaddingTop:var(--pf-c-table--m-compact--cell--PaddingTop);--pf-c-table--cell--PaddingBottom:var(--pf-c-table--m-compact--cell--PaddingBottom)}.pf-c-table.pf-m-compact tr:not(.pf-c-table__expandable-row)>:first-child{--pf-c-table--cell--PaddingLeft:var(--pf-c-table--m-compact--cell--first-last-child--PaddingLeft)}.pf-c-table.pf-m-compact tr:not(.pf-c-table__expandable-row)>:last-child{--pf-c-table--cell--PaddingRight:var(--pf-c-table--m-compact--cell--first-last-child--PaddingRight)}.pf-c-table.pf-m-compact thead th{--pf-c-table--cell--PaddingTop:var(--pf-c-table--m-compact-th--PaddingTop);--pf-c-table--cell--PaddingBottom:var(--pf-c-table--m-compact-th--PaddingBottom)}.pf-c-table.pf-m-compact .pf-c-table__action{--pf-c-table--cell--PaddingTop:var(--pf-c-table__action--PaddingTop);--pf-c-table--cell--PaddingBottom:var(--pf-c-table__action--PaddingBottom);--pf-c-table--cell--PaddingLeft:var(--pf-c-table__action--PaddingLeft)}.pf-c-table.pf-m-compact .pf-c-table__toggle{--pf-c-table--cell--PaddingTop:var(--pf-c-table--m-compact__toggle--PaddingTop);--pf-c-table--cell--PaddingBottom:var(--pf-c-table--m-compact__toggle--PaddingBottom)}.pf-c-table.pf-m-compact .pf-c-table__icon{width:auto;min-width:0;text-align:center}.pf-c-table .pf-c-table.pf-m-compact tr>:first-child{--pf-c-table--cell--PaddingLeft:var(--pf-c-table--nested--first-last-child--PaddingLeft)}.pf-c-table .pf-c-table.pf-m-compact tr>:last-child{--pf-c-table--cell--PaddingRight:var(--pf-c-table--nested--first-last-child--PaddingRight)}.pf-c-table.pf-m-compact .pf-c-table__expandable-row-content{--pf-c-table__expandable-row-content--PaddingTop:var(--pf-c-table--m-compact__expandable-row-content--PaddingTop);--pf-c-table__expandable-row-content--PaddingBottom:var(--pf-c-table--m-compact__expandable-row-content--PaddingBottom)}.pf-c-table__icon-inline{display:flex;align-items:center}.pf-c-table__icon-inline>:not(:last-child){margin-right:var(--pf-c-table__icon-inline--MarginRight)}.pf-c-table .pf-m-width-10{--pf-c-table--cell--Width:10%}.pf-c-table .pf-m-width-15{--pf-c-table--cell--Width:15%}.pf-c-table .pf-m-width-20{--pf-c-table--cell--Width:20%}.pf-c-table .pf-m-width-25{--pf-c-table--cell--Width:25%}.pf-c-table .pf-m-width-30{--pf-c-table--cell--Width:30%}.pf-c-table .pf-m-width-35{--pf-c-table--cell--Width:35%}.pf-c-table .pf-m-width-40{--pf-c-table--cell--Width:40%}.pf-c-table .pf-m-width-45{--pf-c-table--cell--Width:45%}.pf-c-table .pf-m-width-50{--pf-c-table--cell--Width:50%}.pf-c-table .pf-m-width-60{--pf-c-table--cell--Width:60%}.pf-c-table .pf-m-width-70{--pf-c-table--cell--Width:70%}.pf-c-table .pf-m-width-80{--pf-c-table--cell--Width:80%}.pf-c-table .pf-m-width-90{--pf-c-table--cell--Width:90%}.pf-c-table .pf-m-width-100{--pf-c-table--cell--Width:100%}.pf-c-tabs{--pf-c-tabs--inset:0;--pf-c-tabs--before--BorderColor:var(--pf-global--BorderColor--100);--pf-c-tabs--before--border-width--base:var(--pf-global--BorderWidth--sm);--pf-c-tabs--before--BorderTopWidth:0;--pf-c-tabs--before--BorderRightWidth:0;--pf-c-tabs--before--BorderBottomWidth:var(--pf-c-tabs--before--border-width--base);--pf-c-tabs--before--BorderLeftWidth:0;--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--lg);--pf-c-tabs--m-vertical--MaxWidth:15.625rem;--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--xl);--pf-c-tabs--m-box__item--m-current--first-child__link--before--BorderLeftWidth:var(--pf-c-tabs__link--before--border-width--base);--pf-c-tabs--m-box__item--m-current--last-child__link--before--BorderRightWidth:var(--pf-c-tabs--before--border-width--base);--pf-c-tabs--m-color-scheme--light-300__link--BackgroundColor:transparent;--pf-c-tabs--m-color-scheme--light-300__item--m-current__link--BackgroundColor:var(--pf-global--BackgroundColor--light-300);--pf-c-tabs__link--Color:var(--pf-global--Color--200);--pf-c-tabs__link--FontSize:var(--pf-global--FontSize--md);--pf-c-tabs__link--BackgroundColor:transparent;--pf-c-tabs__link--OutlineOffset:-0.375rem;--pf-c-tabs__link--PaddingTop:var(--pf-global--spacer--sm);--pf-c-tabs__link--PaddingRight:var(--pf-global--spacer--md);--pf-c-tabs__link--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-tabs__link--PaddingLeft:var(--pf-global--spacer--md);--pf-c-tabs__item--m-current__link--Color:var(--pf-global--Color--100);--pf-c-tabs__item--m-current__link--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-tabs--m-vertical__link--PaddingTop:var(--pf-global--spacer--md);--pf-c-tabs--m-vertical__link--PaddingBottom:var(--pf-global--spacer--md);--pf-c-tabs--m-box__link--BackgroundColor:var(--pf-global--BackgroundColor--200);--pf-c-tabs--m-secondary__link--FontSize:var(--pf-global--FontSize--sm);--pf-c-tabs__link--before--border-color--base:var(--pf-global--BorderColor--100);--pf-c-tabs__link--before--BorderRightColor:var(--pf-c-tabs__link--before--border-color--base);--pf-c-tabs__link--before--BorderBottomColor:var(--pf-c-tabs__link--before--border-color--base);--pf-c-tabs__link--before--border-width--base:var(--pf-global--BorderWidth--sm);--pf-c-tabs__link--before--BorderTopWidth:0;--pf-c-tabs__link--before--BorderRightWidth:0;--pf-c-tabs__link--before--BorderBottomWidth:0;--pf-c-tabs__link--before--BorderLeftWidth:0;--pf-c-tabs__link--before--Left:calc(var(--pf-c-tabs__link--before--border-width--base)*-1);--pf-c-tabs__link--after--Top:auto;--pf-c-tabs__link--after--Right:0;--pf-c-tabs__link--after--Bottom:0;--pf-c-tabs__link--after--BorderColor:var(--pf-global--BorderColor--light-100);--pf-c-tabs__link--after--BorderWidth:0;--pf-c-tabs__link--after--BorderTopWidth:0;--pf-c-tabs__link--after--BorderRightWidth:0;--pf-c-tabs__link--after--BorderLeftWidth:0;--pf-c-tabs__link--hover--after--BorderWidth:var(--pf-global--BorderWidth--lg);--pf-c-tabs__link--focus--after--BorderWidth:var(--pf-global--BorderWidth--lg);--pf-c-tabs__link--active--after--BorderWidth:var(--pf-global--BorderWidth--lg);--pf-c-tabs__item--m-current__link--after--BorderColor:var(--pf-global--active-color--100);--pf-c-tabs__item--m-current__link--after--BorderWidth:var(--pf-global--BorderWidth--lg);--pf-c-tabs__link--child--MarginRight:var(--pf-global--spacer--md);--pf-c-tabs__scroll-button--Color:var(--pf-global--Color--100);--pf-c-tabs__scroll-button--hover--Color:var(--pf-global--active-color--100);--pf-c-tabs__scroll-button--disabled--Color:var(--pf-global--disabled-color--200);--pf-c-tabs__scroll-button--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-tabs__scroll-button--Width:var(--pf-global--spacer--2xl);--pf-c-tabs__scroll-button--xl--Width:var(--pf-global--spacer--3xl);--pf-c-tabs__scroll-button--OutlineOffset:calc(-1*var(--pf-global--spacer--xs));--pf-c-tabs__scroll-button--TransitionDuration--margin:.125s;--pf-c-tabs__scroll-button--TransitionDuration--transform:.125s;--pf-c-tabs__scroll-button--TransitionDuration--opacity:.125s;--pf-c-tabs__scroll-button--before--BorderColor:var(--pf-c-tabs--before--BorderColor);--pf-c-tabs__scroll-button--before--border-width--base:var(--pf-global--BorderWidth--sm);--pf-c-tabs__scroll-button--before--BorderRightWidth:0;--pf-c-tabs__scroll-button--before--BorderBottomWidth:var(--pf-c-tabs__scroll-button--before--border-width--base);--pf-c-tabs__scroll-button--before--BorderLeftWidth:0;position:relative;display:flex;padding-right:var(--pf-c-tabs--inset);padding-left:var(--pf-c-tabs--inset);overflow:hidden}@media screen and (min-width:1200px){.pf-c-tabs{--pf-c-tabs__scroll-button--Width:var(--pf-c-tabs__scroll-button--xl--Width)}}.pf-c-tabs:before{position:absolute;right:0;bottom:0;left:0;border:solid var(--pf-c-tabs--before--BorderColor);border-width:var(--pf-c-tabs--before--BorderTopWidth) var(--pf-c-tabs--before--BorderRightWidth) var(--pf-c-tabs--before--BorderBottomWidth) var(--pf-c-tabs--before--BorderLeftWidth)}.pf-c-tabs.pf-m-fill .pf-c-tabs__list{flex-basis:100%}.pf-c-tabs.pf-m-fill .pf-c-tabs__item{flex-grow:1}.pf-c-tabs.pf-m-fill .pf-c-tabs__item:first-child{--pf-c-tabs--m-box__item--m-current--first-child__link--before--BorderLeftWidth:0}.pf-c-tabs.pf-m-fill .pf-c-tabs__item:last-child{--pf-c-tabs--m-box__item--m-current--last-child__link--before--BorderRightWidth:0}.pf-c-tabs.pf-m-fill .pf-c-tabs__link{flex-basis:100%;justify-content:center}.pf-c-tabs.pf-m-scrollable .pf-c-tabs__scroll-button{opacity:1}.pf-c-tabs.pf-m-scrollable .pf-c-tabs__scroll-button:first-of-type{margin-right:0;transform:translateX(0)}.pf-c-tabs.pf-m-scrollable .pf-c-tabs__scroll-button:nth-of-type(2){margin-left:0;transform:translateX(0)}.pf-c-tabs.pf-m-no-border-bottom,.pf-c-tabs.pf-m-secondary{--pf-c-tabs--before--BorderBottomWidth:0}.pf-c-tabs.pf-m-box .pf-c-tabs__link,.pf-c-tabs.pf-m-vertical .pf-c-tabs__link{--pf-c-tabs__link--after--BorderBottomWidth:0}.pf-c-tabs.pf-m-box{--pf-c-tabs__link--BackgroundColor:var(--pf-c-tabs--m-box__link--BackgroundColor);--pf-c-tabs__link--before--BorderBottomWidth:var(--pf-c-tabs__link--before--border-width--base);--pf-c-tabs__link--before--BorderRightWidth:var(--pf-c-tabs__link--before--border-width--base);--pf-c-tabs__link--after--Top:0;--pf-c-tabs__link--after--Bottom:auto}.pf-c-tabs.pf-m-box .pf-c-tabs__link{--pf-c-tabs__link--after--BorderTopWidth:var(--pf-c-tabs__link--after--BorderWidth)}.pf-c-tabs.pf-m-box .pf-c-tabs__item:last-child{--pf-c-tabs__link--before--BorderRightWidth:0}.pf-c-tabs.pf-m-box .pf-c-tabs__item.pf-m-current{--pf-c-tabs__link--BackgroundColor:var(--pf-c-tabs__item--m-current__link--BackgroundColor);--pf-c-tabs__link--before--BorderBottomColor:var(--pf-c-tabs__link--BackgroundColor)}.pf-c-tabs.pf-m-box .pf-c-tabs__item.pf-m-current:first-child .pf-c-tabs__link:before{border-left-width:var(--pf-c-tabs--m-box__item--m-current--first-child__link--before--BorderLeftWidth)}.pf-c-tabs.pf-m-box .pf-c-tabs__item.pf-m-current:last-child .pf-c-tabs__link:before{border-right-width:var(--pf-c-tabs--m-box__item--m-current--last-child__link--before--BorderRightWidth)}.pf-c-tabs.pf-m-box.pf-m-scrollable .pf-c-tabs__item.pf-m-current:first-child .pf-c-tabs__link:before,.pf-c-tabs.pf-m-box.pf-m-scrollable .pf-c-tabs__scroll-button:nth-of-type(2):before{left:calc(var(--pf-c-tabs__link--before--border-width--base)*-1)}.pf-c-tabs.pf-m-box .pf-c-tabs__item.pf-m-current+.pf-c-tabs__item{--pf-c-tabs__link--before--Left:0}.pf-c-tabs.pf-m-box.pf-m-color-scheme--light-300{--pf-c-tabs__link--BackgroundColor:var(--pf-c-tabs--m-color-scheme--light-300__link--BackgroundColor);--pf-c-tabs__item--m-current__link--BackgroundColor:var(--pf-c-tabs--m-color-scheme--light-300__item--m-current__link--BackgroundColor)}.pf-c-tabs.pf-m-vertical{--pf-c-tabs--inset:var(--pf-c-tabs--m-vertical--inset);--pf-c-tabs--before--BorderBottomWidth:0;--pf-c-tabs--before--BorderLeftWidth:var(--pf-c-tabs--before--border-width--base);--pf-c-tabs__link--PaddingTop:var(--pf-c-tabs--m-vertical__link--PaddingTop);--pf-c-tabs__link--PaddingBottom:var(--pf-c-tabs--m-vertical__link--PaddingBottom);--pf-c-tabs__link--before--Left:0;--pf-c-tabs__link--after--Top:0;--pf-c-tabs__link--after--Bottom:0;--pf-c-tabs__link--after--Right:auto;display:inline-flex;flex-direction:column;height:100%;padding:0}.pf-c-tabs.pf-m-vertical:before{top:0;right:auto}.pf-c-tabs.pf-m-vertical .pf-c-tabs__list{flex-direction:column;max-width:var(--pf-c-tabs--m-vertical--MaxWidth)}.pf-c-tabs.pf-m-vertical .pf-c-tabs__item:first-child{margin-top:var(--pf-c-tabs--inset)}.pf-c-tabs.pf-m-vertical .pf-c-tabs__item:last-child{margin-bottom:var(--pf-c-tabs--inset)}.pf-c-tabs.pf-m-vertical .pf-c-tabs__link{--pf-c-tabs__link--after--BorderTopWidth:0;--pf-c-tabs__link--after--BorderLeftWidth:var(--pf-c-tabs__link--after--BorderWidth);max-width:100%;text-align:left}.pf-c-tabs.pf-m-vertical .pf-c-tabs__item-text{max-width:100%;overflow-wrap:break-word}.pf-c-tabs.pf-m-box.pf-m-vertical{--pf-c-tabs--inset:var(--pf-c-tabs--m-vertical--m-box--inset);--pf-c-tabs--before--BorderLeftWidth:0;--pf-c-tabs--before--BorderRightWidth:var(--pf-c-tabs--before--border-width--base)}.pf-c-tabs.pf-m-box.pf-m-vertical:before{right:0;left:auto}.pf-c-tabs.pf-m-box.pf-m-vertical .pf-c-tabs__item:last-child{--pf-c-tabs__link--before--BorderBottomWidth:0;--pf-c-tabs__link--before--BorderRightWidth:var(--pf-c-tabs__link--before--border-width--base)}.pf-c-tabs.pf-m-box.pf-m-vertical .pf-c-tabs__item.pf-m-current{--pf-c-tabs__link--before--BorderRightColor:var(--pf-c-tabs__item--m-current__link--BackgroundColor);--pf-c-tabs__link--before--BorderBottomColor:var(--pf-c-tabs__link--before--border-color--base);--pf-c-tabs__link--before--BorderBottomWidth:var(--pf-c-tabs__link--before--border-width--base)}.pf-c-tabs.pf-m-box.pf-m-vertical .pf-c-tabs__item.pf-m-current:first-child,.pf-c-tabs.pf-m-box.pf-m-vertical .pf-c-tabs__item:first-child.pf-m-current{--pf-c-tabs__link--before--BorderTopWidth:var(--pf-c-tabs__link--before--border-width--base)}.pf-c-tabs.pf-m-box.pf-m-vertical .pf-c-tabs__link:after{top:calc(var(--pf-c-tabs__link--before--border-width--base)*-1)}.pf-c-tabs.pf-m-box.pf-m-vertical .pf-c-tabs__item.pf-m-current+.pf-c-tabs__item .pf-c-tabs__link:after,.pf-c-tabs.pf-m-box.pf-m-vertical .pf-c-tabs__item:first-child .pf-c-tabs__link:after{top:0}.pf-c-tabs.pf-m-secondary{--pf-c-tabs__link--FontSize:var(--pf-c-tabs--m-secondary__link--FontSize)}.pf-c-tabs__list{scrollbar-width:none;-ms-overflow-style:-ms-autohiding-scrollbar;position:relative;display:flex;max-width:100%;overflow-x:auto;scroll-behavior:smooth;-webkit-overflow-scrolling:touch}.pf-c-tabs__list::-webkit-scrollbar{display:none}.pf-c-tabs__item{display:flex;flex:none}.pf-c-tabs__item.pf-m-current{--pf-c-tabs__link--Color:var(--pf-c-tabs__item--m-current__link--Color);--pf-c-tabs__link--after--BorderColor:var(--pf-c-tabs__item--m-current__link--after--BorderColor);--pf-c-tabs__link--after--BorderWidth:var(--pf-c-tabs__item--m-current__link--after--BorderWidth)}.pf-c-tabs__link,.pf-c-tabs__scroll-button{border:0}.pf-c-tabs:before,.pf-c-tabs__link:after,.pf-c-tabs__link:before,.pf-c-tabs__scroll-button:before{position:absolute;right:0;bottom:0;left:0;content:"";border-style:solid}.pf-c-tabs__link:after,.pf-c-tabs__link:before,.pf-c-tabs__scroll-button:before{top:0}.pf-c-tabs__link{--pf-c-tabs__link--after--BorderBottomWidth:var(--pf-c-tabs__link--after--BorderWidth);position:relative;display:flex;flex:1;padding:var(--pf-c-tabs__link--PaddingTop) var(--pf-c-tabs__link--PaddingRight) var(--pf-c-tabs__link--PaddingBottom) var(--pf-c-tabs__link--PaddingLeft);font-size:var(--pf-c-tabs__link--FontSize);color:var(--pf-c-tabs__link--Color);text-decoration:none;background-color:var(--pf-c-tabs__link--BackgroundColor);outline-offset:var(--pf-c-tabs__link--OutlineOffset)}.pf-c-tabs__link:before{pointer-events:none;border-bottom-color:var(--pf-c-tabs__link--before--border-color--base);border-right-color:var(--pf-c-tabs__link--before--border-color--base);border-width:var(--pf-c-tabs__link--before--BorderTopWidth) var(--pf-c-tabs__link--before--BorderRightWidth) var(--pf-c-tabs__link--before--BorderBottomWidth) var(--pf-c-tabs__link--before--BorderLeftWidth);border-color:var(--pf-c-tabs__link--before--border-color--base) var(--pf-c-tabs__link--before--BorderRightColor) var(--pf-c-tabs__link--before--BorderBottomColor) var(--pf-c-tabs__link--before--border-color--base)}.pf-c-tabs__link:after{top:var(--pf-c-tabs__link--after--Top);right:var(--pf-c-tabs__link--after--Right);bottom:var(--pf-c-tabs__link--after--Bottom);left:var(--pf-c-tabs__link--before--Left);border-color:var(--pf-c-tabs__link--after--BorderColor);border-width:var(--pf-c-tabs__link--after--BorderTopWidth) var(--pf-c-tabs__link--after--BorderRightWidth) var(--pf-c-tabs__link--after--BorderBottomWidth) var(--pf-c-tabs__link--after--BorderLeftWidth)}.pf-c-tabs__link:hover{--pf-c-tabs__link--after--BorderWidth:var(--pf-c-tabs__link--hover--after--BorderWidth)}.pf-c-tabs__link:focus{--pf-c-tabs__link--after--BorderWidth:var(--pf-c-tabs__link--focus--after--BorderWidth)}.pf-c-tabs__link:active{--pf-c-tabs__link--after--BorderWidth:var(--pf-c-tabs__link--active--after--BorderWidth)}.pf-c-tabs__link .pf-c-tabs__item-icon,.pf-c-tabs__link .pf-c-tabs__item-text{margin-right:var(--pf-c-tabs__link--child--MarginRight)}.pf-c-tabs__link .pf-c-tabs__item-icon:last-child,.pf-c-tabs__link .pf-c-tabs__item-text:last-child{--pf-c-tabs__link--child--MarginRight:0}.pf-c-tabs__scroll-button{flex:none;width:var(--pf-c-tabs__scroll-button--Width);line-height:1;color:var(--pf-c-tabs__scroll-button--Color);background-color:var(--pf-c-tabs__scroll-button--BackgroundColor);outline-offset:var(--pf-c-tabs__scroll-button--OutlineOffset);opacity:0;transition:margin var(--pf-c-tabs__scroll-button--TransitionDuration--margin),transform var(--pf-c-tabs__scroll-button--TransitionDuration--transform),opacity var(--pf-c-tabs__scroll-button--TransitionDuration--opacity)}.pf-c-tabs__scroll-button:active,.pf-c-tabs__scroll-button:focus,.pf-c-tabs__scroll-button:hover{--pf-c-tabs__scroll-button--Color:var(--pf-c-tabs__scroll-button--hover--Color)}.pf-c-tabs__scroll-button:before{border-color:var(--pf-c-tabs__scroll-button--before--BorderColor);border-left-width:var(--pf-c-tabs__scroll-button--before--BorderLeftWidth);border-bottom-width:var(--pf-c-tabs__scroll-button--before--BorderBottomWidth);border-right-width:var(--pf-c-tabs__scroll-button--before--BorderRightWidth);border-top-width:0}.pf-c-tabs__scroll-button:first-of-type{--pf-c-tabs__scroll-button--before--BorderRightWidth:var(--pf-c-tabs__scroll-button--before--border-width--base);margin-right:calc(var(--pf-c-tabs__scroll-button--Width)*-1);transform:translateX(-100%)}.pf-c-tabs__scroll-button:nth-of-type(2){--pf-c-tabs__scroll-button--before--BorderLeftWidth:var(--pf-c-tabs__scroll-button--before--border-width--base);margin-left:calc(var(--pf-c-tabs__scroll-button--Width)*-1);transform:translateX(100%)}.pf-c-tabs__scroll-button:disabled{--pf-c-tabs__scroll-button--Color:var(--pf-c-tabs__scroll-button--disabled--Color);pointer-events:none}.pf-c-tabs.pf-m-inset-none{--pf-c-tabs--inset:0;--pf-c-tabs--m-vertical--inset:0;--pf-c-tabs--m-vertical--m-box--inset:0}.pf-c-tabs.pf-m-inset-sm{--pf-c-tabs--inset:var(--pf-global--spacer--sm);--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--sm);--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--sm)}.pf-c-tabs.pf-m-inset-md{--pf-c-tabs--inset:var(--pf-global--spacer--md);--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--md);--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--md)}.pf-c-tabs.pf-m-inset-lg{--pf-c-tabs--inset:var(--pf-global--spacer--lg);--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--lg);--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--lg)}.pf-c-tabs.pf-m-inset-xl{--pf-c-tabs--inset:var(--pf-global--spacer--xl);--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--xl);--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--xl)}.pf-c-tabs.pf-m-inset-2xl{--pf-c-tabs--inset:var(--pf-global--spacer--2xl);--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--2xl);--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--2xl)}@media (min-width:576px){.pf-c-tabs.pf-m-inset-none-on-sm{--pf-c-tabs--inset:0;--pf-c-tabs--m-vertical--inset:0;--pf-c-tabs--m-vertical--m-box--inset:0}.pf-c-tabs.pf-m-inset-sm-on-sm{--pf-c-tabs--inset:var(--pf-global--spacer--sm);--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--sm);--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--sm)}.pf-c-tabs.pf-m-inset-md-on-sm{--pf-c-tabs--inset:var(--pf-global--spacer--md);--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--md);--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--md)}.pf-c-tabs.pf-m-inset-lg-on-sm{--pf-c-tabs--inset:var(--pf-global--spacer--lg);--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--lg);--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--lg)}.pf-c-tabs.pf-m-inset-xl-on-sm{--pf-c-tabs--inset:var(--pf-global--spacer--xl);--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--xl);--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--xl)}.pf-c-tabs.pf-m-inset-2xl-on-sm{--pf-c-tabs--inset:var(--pf-global--spacer--2xl);--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--2xl);--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--2xl)}}@media (min-width:768px){.pf-c-tabs.pf-m-inset-none-on-md{--pf-c-tabs--inset:0;--pf-c-tabs--m-vertical--inset:0;--pf-c-tabs--m-vertical--m-box--inset:0}.pf-c-tabs.pf-m-inset-sm-on-md{--pf-c-tabs--inset:var(--pf-global--spacer--sm);--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--sm);--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--sm)}.pf-c-tabs.pf-m-inset-md-on-md{--pf-c-tabs--inset:var(--pf-global--spacer--md);--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--md);--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--md)}.pf-c-tabs.pf-m-inset-lg-on-md{--pf-c-tabs--inset:var(--pf-global--spacer--lg);--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--lg);--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--lg)}.pf-c-tabs.pf-m-inset-xl-on-md{--pf-c-tabs--inset:var(--pf-global--spacer--xl);--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--xl);--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--xl)}.pf-c-tabs.pf-m-inset-2xl-on-md{--pf-c-tabs--inset:var(--pf-global--spacer--2xl);--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--2xl);--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--2xl)}}@media (min-width:992px){.pf-c-tabs.pf-m-inset-none-on-lg{--pf-c-tabs--inset:0;--pf-c-tabs--m-vertical--inset:0;--pf-c-tabs--m-vertical--m-box--inset:0}.pf-c-tabs.pf-m-inset-sm-on-lg{--pf-c-tabs--inset:var(--pf-global--spacer--sm);--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--sm);--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--sm)}.pf-c-tabs.pf-m-inset-md-on-lg{--pf-c-tabs--inset:var(--pf-global--spacer--md);--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--md);--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--md)}.pf-c-tabs.pf-m-inset-lg-on-lg{--pf-c-tabs--inset:var(--pf-global--spacer--lg);--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--lg);--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--lg)}.pf-c-tabs.pf-m-inset-xl-on-lg{--pf-c-tabs--inset:var(--pf-global--spacer--xl);--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--xl);--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--xl)}.pf-c-tabs.pf-m-inset-2xl-on-lg{--pf-c-tabs--inset:var(--pf-global--spacer--2xl);--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--2xl);--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--2xl)}}@media (min-width:1200px){.pf-c-tabs.pf-m-inset-none-on-xl{--pf-c-tabs--inset:0;--pf-c-tabs--m-vertical--inset:0;--pf-c-tabs--m-vertical--m-box--inset:0}.pf-c-tabs.pf-m-inset-sm-on-xl{--pf-c-tabs--inset:var(--pf-global--spacer--sm);--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--sm);--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--sm)}.pf-c-tabs.pf-m-inset-md-on-xl{--pf-c-tabs--inset:var(--pf-global--spacer--md);--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--md);--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--md)}.pf-c-tabs.pf-m-inset-lg-on-xl{--pf-c-tabs--inset:var(--pf-global--spacer--lg);--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--lg);--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--lg)}.pf-c-tabs.pf-m-inset-xl-on-xl{--pf-c-tabs--inset:var(--pf-global--spacer--xl);--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--xl);--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--xl)}.pf-c-tabs.pf-m-inset-2xl-on-xl{--pf-c-tabs--inset:var(--pf-global--spacer--2xl);--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--2xl);--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--2xl)}}@media (min-width:1450px){.pf-c-tabs.pf-m-inset-none-on-2xl{--pf-c-tabs--inset:0;--pf-c-tabs--m-vertical--inset:0;--pf-c-tabs--m-vertical--m-box--inset:0}.pf-c-tabs.pf-m-inset-sm-on-2xl{--pf-c-tabs--inset:var(--pf-global--spacer--sm);--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--sm);--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--sm)}.pf-c-tabs.pf-m-inset-md-on-2xl{--pf-c-tabs--inset:var(--pf-global--spacer--md);--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--md);--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--md)}.pf-c-tabs.pf-m-inset-lg-on-2xl{--pf-c-tabs--inset:var(--pf-global--spacer--lg);--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--lg);--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--lg)}.pf-c-tabs.pf-m-inset-xl-on-2xl{--pf-c-tabs--inset:var(--pf-global--spacer--xl);--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--xl);--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--xl)}.pf-c-tabs.pf-m-inset-2xl-on-2xl{--pf-c-tabs--inset:var(--pf-global--spacer--2xl);--pf-c-tabs--m-vertical--inset:var(--pf-global--spacer--2xl);--pf-c-tabs--m-vertical--m-box--inset:var(--pf-global--spacer--2xl)}}.pf-c-tile{--pf-c-tile--PaddingTop:var(--pf-global--spacer--lg);--pf-c-tile--PaddingRight:var(--pf-global--spacer--lg);--pf-c-tile--PaddingBottom:var(--pf-global--spacer--lg);--pf-c-tile--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-tile--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-tile--before--BorderColor:var(--pf-global--BorderColor--100);--pf-c-tile--before--BorderWidth:var(--pf-global--BorderWidth--sm);--pf-c-tile--before--BorderRadius:var(--pf-global--BorderRadius--sm);--pf-c-tile--hover--before--BorderColor:var(--pf-global--primary-color--100);--pf-c-tile--m-selected--before--BorderWidth:var(--pf-global--BorderWidth--md);--pf-c-tile--m-selected--before--BorderColor:var(--pf-global--primary-color--100);--pf-c-tile--focus--before--BorderWidth:var(--pf-global--BorderWidth--md);--pf-c-tile--focus--before--BorderColor:var(--pf-global--primary-color--100);--pf-c-tile--m-disabled--BackgroundColor:var(--pf-global--disabled-color--300);--pf-c-tile__title--Color:var(--pf-global--Color--100);--pf-c-tile--hover__title--Color:var(--pf-global--primary-color--100);--pf-c-tile--m-selected__title--Color:var(--pf-global--primary-color--100);--pf-c-tile--focus__title--Color:var(--pf-global--primary-color--100);--pf-c-tile--m-disabled__title--Color:var(--pf-global--disabled-color--100);--pf-c-tile__icon--MarginRight:var(--pf-global--spacer--sm);--pf-c-tile__icon--FontSize:var(--pf-global--icon--FontSize--md);--pf-c-tile__icon--Color:var(--pf-global--Color--100);--pf-c-tile--hover__icon--Color:var(--pf-global--primary-color--100);--pf-c-tile--m-selected__icon--Color:var(--pf-global--primary-color--100);--pf-c-tile--m-disabled__icon--Color:var(--pf-global--disabled-color--100);--pf-c-tile--focus__icon--Color:var(--pf-global--primary-color--100);--pf-c-tile__header--m-stacked__icon--MarginBottom:var(--pf-global--spacer--xs);--pf-c-tile__header--m-stacked__icon--FontSize:var(--pf-global--icon--FontSize--lg);--pf-c-tile--m-display-lg__header--m-stacked__icon--FontSize:var(--pf-global--icon--FontSize--xl);--pf-c-tile__body--Color:var(--pf-global--Color--100);--pf-c-tile__body--FontSize:var(--pf-global--FontSize--xs);--pf-c-tile--m-disabled__body--Color:var(--pf-global--disabled-color--100);position:relative;display:inline-grid;padding:var(--pf-c-tile--PaddingTop) var(--pf-c-tile--PaddingRight) var(--pf-c-tile--PaddingBottom) var(--pf-c-tile--PaddingLeft);text-align:center;cursor:pointer;background-color:var(--pf-c-tile--BackgroundColor);grid-template-rows:min-content}.pf-c-tile:before{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none;content:"";border:var(--pf-c-tile--before--BorderWidth) solid var(--pf-c-tile--before--BorderColor);border-radius:var(--pf-c-tile--before--BorderRadius)}.pf-c-tile:hover{--pf-c-tile__title--Color:var(--pf-c-tile--hover__title--Color);--pf-c-tile__icon--Color:var(--pf-c-tile--hover__icon--Color);--pf-c-tile--before--BorderColor:var(--pf-c-tile--hover--before--BorderColor)}.pf-c-tile.pf-m-selected{--pf-c-tile__title--Color:var(--pf-c-tile--m-selected__title--Color);--pf-c-tile__icon--Color:var(--pf-c-tile--m-selected__icon--Color);--pf-c-tile--before--BorderWidth:var(--pf-c-tile--m-selected--before--BorderWidth);--pf-c-tile--before--BorderColor:var(--pf-c-tile--m-selected--before--BorderColor)}.pf-c-tile:focus{--pf-c-tile__title--Color:var(--pf-c-tile--focus__title--Color);--pf-c-tile__icon--Color:var(--pf-c-tile--focus__icon--Color);--pf-c-tile--before--BorderWidth:var(--pf-c-tile--focus--before--BorderWidth);--pf-c-tile--before--BorderColor:var(--pf-c-tile--focus--before--BorderColor)}.pf-c-tile.pf-m-disabled{--pf-c-tile--BackgroundColor:var(--pf-c-tile--m-disabled--BackgroundColor);--pf-c-tile__title--Color:var(--pf-c-tile--m-disabled__title--Color);--pf-c-tile__body--Color:var(--pf-c-tile--m-disabled__body--Color);--pf-c-tile--before--BorderWidth:0;--pf-c-tile__icon--Color:var(--pf-c-tile--m-disabled__icon--Color);pointer-events:none}.pf-c-tile.pf-m-display-lg .pf-c-tile__header.pf-m-stacked{--pf-c-tile__icon--FontSize:var(--pf-c-tile--m-display-lg__header--m-stacked__icon--FontSize)}.pf-c-tile__header{display:flex;align-items:center;justify-content:center}.pf-c-tile__header.pf-m-stacked{--pf-c-tile__icon--MarginRight:0;--pf-c-tile__icon--FontSize:var(--pf-c-tile__header--m-stacked__icon--FontSize);flex-direction:column;justify-content:normal}.pf-c-tile__header.pf-m-stacked .pf-c-tile__icon{display:flex;align-items:center;justify-content:center;margin-bottom:var(--pf-c-tile__header--m-stacked__icon--MarginBottom)}.pf-c-tile__title{color:var(--pf-c-tile__title--Color)}.pf-c-tile__body{font-size:var(--pf-c-tile__body--FontSize);color:var(--pf-c-tile__body--Color)}.pf-c-tile__icon{margin-right:var(--pf-c-tile__icon--MarginRight);font-size:var(--pf-c-tile__icon--FontSize);color:var(--pf-c-tile__icon--Color)}.pf-c-title{--pf-c-title--FontFamily:var(--pf-global--FontFamily--heading--sans-serif);--pf-c-title--m-4xl--LineHeight:var(--pf-global--LineHeight--sm);--pf-c-title--m-4xl--FontSize:var(--pf-global--FontSize--4xl);--pf-c-title--m-4xl--FontWeight:var(--pf-global--FontWeight--normal);--pf-c-title--m-3xl--LineHeight:var(--pf-global--LineHeight--sm);--pf-c-title--m-3xl--FontSize:var(--pf-global--FontSize--3xl);--pf-c-title--m-3xl--FontWeight:var(--pf-global--FontWeight--normal);--pf-c-title--m-2xl--LineHeight:var(--pf-global--LineHeight--sm);--pf-c-title--m-2xl--FontSize:var(--pf-global--FontSize--2xl);--pf-c-title--m-2xl--FontWeight:var(--pf-global--FontWeight--normal);--pf-c-title--m-xl--LineHeight:var(--pf-global--LineHeight--md);--pf-c-title--m-xl--FontSize:var(--pf-global--FontSize--xl);--pf-c-title--m-xl--FontWeight:var(--pf-global--FontWeight--normal);--pf-c-title--m-lg--LineHeight:var(--pf-global--LineHeight--md);--pf-c-title--m-lg--FontSize:var(--pf-global--FontSize--lg);--pf-c-title--m-lg--FontWeight:var(--pf-global--FontWeight--normal);--pf-c-title--m-md--LineHeight:var(--pf-global--LineHeight--md);--pf-c-title--m-md--FontSize:var(--pf-global--FontSize--md);--pf-c-title--m-md--FontWeight:var(--pf-global--FontWeight--normal);font-family:var(--pf-c-title--FontFamily);word-break:break-word}.pf-c-title.pf-m-4xl{font-size:var(--pf-c-title--m-4xl--FontSize);font-weight:var(--pf-c-title--m-4xl--FontWeight);line-height:var(--pf-c-title--m-4xl--LineHeight)}.pf-c-title.pf-m-3xl{font-size:var(--pf-c-title--m-3xl--FontSize);font-weight:var(--pf-c-title--m-3xl--FontWeight);line-height:var(--pf-c-title--m-3xl--LineHeight)}.pf-c-title.pf-m-2xl{font-size:var(--pf-c-title--m-2xl--FontSize);font-weight:var(--pf-c-title--m-2xl--FontWeight);line-height:var(--pf-c-title--m-2xl--LineHeight)}.pf-c-title.pf-m-xl{font-size:var(--pf-c-title--m-xl--FontSize);font-weight:var(--pf-c-title--m-xl--FontWeight);line-height:var(--pf-c-title--m-xl--LineHeight)}.pf-c-title.pf-m-lg{font-size:var(--pf-c-title--m-lg--FontSize);font-weight:var(--pf-c-title--m-lg--FontWeight);line-height:var(--pf-c-title--m-lg--LineHeight)}.pf-c-title.pf-m-md{font-size:var(--pf-c-title--m-md--FontSize);font-weight:var(--pf-c-title--m-md--FontWeight);line-height:var(--pf-c-title--m-md--LineHeight)}.pf-m-overpass-font .pf-c-title{--pf-c-title--m-md--FontWeight:var(--pf-global--FontWeight--semi-bold);--pf-c-title--m-lg--FontWeight:var(--pf-global--FontWeight--semi-bold)}.pf-c-toggle-group{--pf-c-toggle-group__button--PaddingTop:var(--pf-global--spacer--form-element);--pf-c-toggle-group__button--PaddingRight:var(--pf-global--spacer--md);--pf-c-toggle-group__button--PaddingBottom:var(--pf-global--spacer--form-element);--pf-c-toggle-group__button--PaddingLeft:var(--pf-global--spacer--md);--pf-c-toggle-group__button--FontSize:var(--pf-global--FontSize--sm);--pf-c-toggle-group__button--LineHeight:calc(var(--pf-global--FontSize--md)*var(--pf-global--LineHeight--md));--pf-c-toggle-group__button--Color:var(--pf-global--Color--100);--pf-c-toggle-group__button--BackgroundColor:var(--pf-global--BackgroundColor--200);--pf-c-toggle-group__button--hover--BackgroundColor:var(--pf-global--disabled-color--200);--pf-c-toggle-group__button--focus--BackgroundColor:var(--pf-global--disabled-color--200);--pf-c-toggle-group__button--disabled--BackgroundColor:var(--pf-global--disabled-color--200);--pf-c-toggle-group__button--disabled--Color:var(--pf-global--disabled-color--100);--pf-c-toggle-group__item--first-child__button--BorderTopLeftRadius:var(--pf-global--BorderRadius--sm);--pf-c-toggle-group__item--first-child__button--BorderBottomLeftRadius:var(--pf-global--BorderRadius--sm);--pf-c-toggle-group__item--last-child__button--BorderTopRightRadius:var(--pf-global--BorderRadius--sm);--pf-c-toggle-group__item--last-child__button--BorderBottomRightRadius:var(--pf-global--BorderRadius--sm);--pf-c-toggle-group__icon--text--MarginLeft:var(--pf-global--spacer--sm);--pf-c-toggle-group__button--m-light--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-toggle-group__button--m-selected--BackgroundColor:var(--pf-global--primary-color--100);--pf-c-toggle-group__button--m-selected--Color:var(--pf-global--Color--light-100);display:flex}.pf-c-toggle-group__item:first-child .pf-c-toggle-group__button{border-top-left-radius:var(--pf-c-toggle-group__item--first-child__button--BorderTopLeftRadius);border-bottom-left-radius:var(--pf-c-toggle-group__item--first-child__button--BorderBottomLeftRadius)}.pf-c-toggle-group__item:last-child .pf-c-toggle-group__button{border-top-right-radius:var(--pf-c-toggle-group__item--last-child__button--BorderTopRightRadius);border-bottom-right-radius:var(--pf-c-toggle-group__item--last-child__button--BorderBottomRightRadius)}.pf-c-toggle-group__button{display:inline-flex;padding:var(--pf-c-toggle-group__button--PaddingTop) var(--pf-c-toggle-group__button--PaddingRight) var(--pf-c-toggle-group__button--PaddingBottom) var(--pf-c-toggle-group__button--PaddingLeft);font-size:var(--pf-c-toggle-group__button--FontSize);line-height:var(--pf-c-toggle-group__button--LineHeight);color:var(--pf-c-toggle-group__button--Color);background-color:var(--pf-c-toggle-group__button--BackgroundColor);border:0}.pf-c-toggle-group__button.pf-m-light{--pf-c-toggle-group__button--BackgroundColor:var(--pf-c-toggle-group__button--m-light--BackgroundColor)}.pf-c-toggle-group__button:hover{--pf-c-toggle-group__button--BackgroundColor:var(--pf-c-toggle-group__button--hover--BackgroundColor);text-decoration:none}.pf-c-toggle-group__button:focus{--pf-c-toggle-group__button--BackgroundColor:var(--pf-c-toggle-group__button--focus--BackgroundColor)}.pf-c-toggle-group__button.pf-m-selected{--pf-c-toggle-group__button--BackgroundColor:var(--pf-c-toggle-group__button--m-selected--BackgroundColor);--pf-c-toggle-group__button--Color:var(--pf-c-toggle-group__button--m-selected--Color)}.pf-c-toggle-group__button.pf-m-disabled,.pf-c-toggle-group__button:disabled{--pf-c-toggle-group__button--BackgroundColor:var(--pf-c-toggle-group__button--disabled--BackgroundColor);--pf-c-toggle-group__button--Color:var(--pf-c-toggle-group__button--disabled--Color);pointer-events:none}.pf-c-toggle-group__icon+.pf-c-toggle-group__text,.pf-c-toggle-group__text+.pf-c-toggle-group__icon{margin-left:var(--pf-c-toggle-group__icon--text--MarginLeft)}.pf-c-tooltip{--pf-c-tooltip--MaxWidth:18.75rem;--pf-c-tooltip--BoxShadow:var(--pf-global--BoxShadow--md);--pf-c-tooltip__content--PaddingTop:var(--pf-global--spacer--sm);--pf-c-tooltip__content--PaddingRight:var(--pf-global--spacer--md);--pf-c-tooltip__content--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-tooltip__content--PaddingLeft:var(--pf-global--spacer--md);--pf-c-tooltip__content--Color:var(--pf-global--Color--light-100);--pf-c-tooltip__content--BackgroundColor:var(--pf-global--BackgroundColor--dark-100);--pf-c-tooltip__content--FontSize:var(--pf-global--FontSize--sm);--pf-c-tooltip__arrow--Width:var(--pf-global--arrow--width);--pf-c-tooltip__arrow--Height:var(--pf-global--arrow--width);--pf-c-tooltip__arrow--m-top--TranslateX:-50%;--pf-c-tooltip__arrow--m-top--TranslateY:50%;--pf-c-tooltip__arrow--m-top--Rotate:45deg;--pf-c-tooltip__arrow--m-right--TranslateX:-50%;--pf-c-tooltip__arrow--m-right--TranslateY:-50%;--pf-c-tooltip__arrow--m-right--Rotate:45deg;--pf-c-tooltip__arrow--m-bottom--TranslateX:-50%;--pf-c-tooltip__arrow--m-bottom--TranslateY:-50%;--pf-c-tooltip__arrow--m-bottom--Rotate:45deg;--pf-c-tooltip__arrow--m-left--TranslateX:50%;--pf-c-tooltip__arrow--m-left--TranslateY:-50%;--pf-c-tooltip__arrow--m-left--Rotate:45deg;position:relative;max-width:var(--pf-c-tooltip--MaxWidth);box-shadow:var(--pf-c-tooltip--BoxShadow)}.pf-c-tooltip.pf-m-top .pf-c-tooltip__arrow{bottom:0;left:50%;transform:translateX(var(--pf-c-tooltip__arrow--m-top--TranslateX)) translateY(var(--pf-c-tooltip__arrow--m-top--TranslateY)) rotate(var(--pf-c-tooltip__arrow--m-top--Rotate))}.pf-c-tooltip.pf-m-bottom .pf-c-tooltip__arrow{top:0;left:50%;transform:translateX(var(--pf-c-tooltip__arrow--m-bottom--TranslateX)) translateY(var(--pf-c-tooltip__arrow--m-bottom--TranslateY)) rotate(var(--pf-c-tooltip__arrow--m-bottom--Rotate))}.pf-c-tooltip.pf-m-left .pf-c-tooltip__arrow{top:50%;right:0;transform:translateX(var(--pf-c-tooltip__arrow--m-left--TranslateX)) translateY(var(--pf-c-tooltip__arrow--m-left--TranslateY)) rotate(var(--pf-c-tooltip__arrow--m-left--Rotate))}.pf-c-tooltip.pf-m-right .pf-c-tooltip__arrow{top:50%;left:0;transform:translateX(var(--pf-c-tooltip__arrow--m-right--TranslateX)) translateY(var(--pf-c-tooltip__arrow--m-right--TranslateY)) rotate(var(--pf-c-tooltip__arrow--m-right--Rotate))}.pf-c-tooltip__content{position:relative;padding:var(--pf-c-tooltip__content--PaddingTop) var(--pf-c-tooltip__content--PaddingRight) var(--pf-c-tooltip__content--PaddingBottom) var(--pf-c-tooltip__content--PaddingLeft);font-size:var(--pf-c-tooltip__content--FontSize);color:var(--pf-c-tooltip__content--Color);text-align:center;word-break:break-word;background-color:var(--pf-c-tooltip__content--BackgroundColor)}.pf-c-tooltip__content.pf-m-text-align-left{text-align:left}.pf-c-tooltip__arrow{position:absolute;width:var(--pf-c-tooltip__arrow--Width);height:var(--pf-c-tooltip__arrow--Height);pointer-events:none;background-color:var(--pf-c-tooltip__content--BackgroundColor)}.pf-c-touchspin{--pf-c-touchspin__unit--c-input-group--MarginLeft:var(--pf-global--spacer--sm);--pf-c-touchspin__icon--FontSize:var(--pf-global--FontSize--xs);--pf-c-touchspin--c-form-control--width-base:calc(var(--pf-global--spacer--sm)*2);--pf-c-touchspin--c-form-control--width-chars:4;--pf-c-touchspin--c-form-control--Width:calc(var(--pf-c-touchspin--c-form-control--width-base) + var(--pf-c-touchspin--c-form-control--width-chars)*1ch);display:inline-flex;align-items:center}.pf-c-touchspin .pf-c-form-control{display:inline-flex;width:var(--pf-c-touchspin--c-form-control--Width);text-align:right}.pf-c-input-group+.pf-c-touchspin__unit,.pf-c-touchspin__unit+.pf-c-input-group{margin-left:var(--pf-c-touchspin__unit--c-input-group--MarginLeft)}.pf-c-touchspin__icon{font-size:var(--pf-c-touchspin__icon--FontSize)}.pf-c-tree-view{--pf-c-tree-view--PaddingTop:var(--pf-global--spacer--sm);--pf-c-tree-view--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-tree-view__node--indent--base:calc(var(--pf-global--spacer--md)*2 + var(--pf-c-tree-view__node-toggle-icon--MinWidth));--pf-c-tree-view__node--nested-indent--base:calc(var(--pf-c-tree-view__node--indent--base) - var(--pf-global--spacer--md));--pf-c-tree-view__node--PaddingTop:var(--pf-global--spacer--sm);--pf-c-tree-view__node--PaddingRight:var(--pf-global--spacer--sm);--pf-c-tree-view__node--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-tree-view__node--PaddingLeft:0;--pf-c-tree-view__node--Color:var(--pf-global--Color--100);--pf-c-tree-view__node--m-current--Color:var(--pf-global--link--Color);--pf-c-tree-view__node--m-current--FontWeight:var(--pf-global--FontWeight--bold);--pf-c-tree-view__node--hover--BackgroundColor:var(--pf-global--BackgroundColor--200);--pf-c-tree-view__node--focus--BackgroundColor:var(--pf-global--palette--black-200);--pf-c-tree-view__list-item__list-item__node-toggle--Top:var(--pf-c-tree-view__node--PaddingTop);--pf-c-tree-view__list-item__list-item__node-toggle--Left:var(--pf-c-tree-view__node--PaddingLeft);--pf-c-tree-view__list-item__list-item__node-toggle--TranslateX:-100%;--pf-c-tree-view__node-toggle-icon--MinWidth:var(--pf-global--FontSize--md);--pf-c-tree-view__node-toggle-icon--Transition:var(--pf-global--Transition);--pf-c-tree-view__node-toggle-button--PaddingTop:var(--pf-global--spacer--form-element);--pf-c-tree-view__node-toggle-button--PaddingRight:var(--pf-global--spacer--md);--pf-c-tree-view__node-toggle-button--PaddingBottom:var(--pf-global--spacer--form-element);--pf-c-tree-view__node-toggle-button--PaddingLeft:var(--pf-global--spacer--md);--pf-c-tree-view__node-toggle-button--MarginTop:calc(var(--pf-global--spacer--form-element)*-1);--pf-c-tree-view__node-toggle-button--MarginBottom:calc(var(--pf-global--spacer--form-element)*-1);--pf-c-tree-view__node-check--MarginRight:var(--pf-global--spacer--sm);--pf-c-tree-view__node-count--MarginLeft:var(--pf-global--spacer--sm);--pf-c-tree-view__node-count--c-badge--m-read--BackgroundColor:var(--pf-global--disabled-color--200);--pf-c-tree-view__search--PaddingTop:var(--pf-global--spacer--sm);--pf-c-tree-view__search--PaddingRight:var(--pf-global--spacer--sm);--pf-c-tree-view__search--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-tree-view__search--PaddingLeft:var(--pf-global--spacer--sm);--pf-c-tree-view__node-icon--PaddingRight:var(--pf-global--spacer--sm);--pf-c-tree-view__node-icon--Color:var(--pf-global--icon--Color--light);--pf-c-tree-view__list-item--m-expanded__node-toggle-icon--Rotate:90deg;--pf-c-tree-view__node-text--max-lines:1;--pf-c-tree-view__action--MarginLeft:var(--pf-global--spacer--md);--pf-c-tree-view__action--focus--BackgroundColor:var(--pf-global--BackgroundColor--200);--pf-c-tree-view__action--Color:var(--pf-global--icon--Color--light);--pf-c-tree-view__action--hover--Color:var(--pf-global--icon--Color--dark);--pf-c-tree-view__action--focus--Color:var(--pf-global--icon--Color--dark);padding-top:var(--pf-c-tree-view--PaddingTop);padding-bottom:var(--pf-c-tree-view--PaddingBottom)}.pf-c-tree-view__list-item.pf-m-expanded>.pf-c-tree-view__content>.pf-c-tree-view__node>.pf-c-tree-view__node-toggle>.pf-c-tree-view__node-toggle-icon{transform:rotate(var(--pf-c-tree-view__list-item--m-expanded__node-toggle-icon--Rotate));text-align:center}.pf-c-tree-view__node{position:relative;display:flex;flex:1 1;align-items:center;min-width:0;padding:var(--pf-c-tree-view__node--PaddingTop) var(--pf-c-tree-view__node--PaddingRight) var(--pf-c-tree-view__node--PaddingBottom) var(--pf-c-tree-view__node--PaddingLeft);color:var(--pf-c-tree-view__node--Color);text-align:left;cursor:pointer;border:0}.pf-c-tree-view__node.pf-m-current{--pf-c-tree-view__node--Color:var(--pf-c-tree-view__node--m-current--Color);font-weight:var(--pf-c-tree-view__node--m-current--FontWeight)}.pf-c-tree-view__node:focus{background-color:var(--pf-c-tree-view__node--focus--BackgroundColor)}.pf-c-tree-view__node .pf-c-tree-view__node-count{margin-left:var(--pf-c-tree-view__node-count--MarginLeft)}.pf-c-tree-view__node .pf-c-tree-view__node-count .pf-c-badge.pf-m-read{--pf-c-badge--m-read--BackgroundColor:var(--pf-c-tree-view__node-count--c-badge--m-read--BackgroundColor)}.pf-c-tree-view__node-toggle-icon{display:inline-block;min-width:var(--pf-c-tree-view__node-toggle-icon--MinWidth);transition:var(--pf-c-tree-view__node-toggle-icon--Transition)}.pf-c-tree-view__node-check{margin-right:var(--pf-c-tree-view__node-check--MarginRight)}.pf-c-tree-view__node-toggle{display:inline-flex;align-items:center;justify-content:center;padding:var(--pf-c-tree-view__node-toggle-button--PaddingTop) var(--pf-c-tree-view__node-toggle-button--PaddingRight) var(--pf-c-tree-view__node-toggle-button--PaddingBottom) var(--pf-c-tree-view__node-toggle-button--PaddingLeft);margin-top:var(--pf-c-tree-view__node-toggle-button--MarginTop);margin-bottom:var(--pf-c-tree-view__node-toggle-button--MarginBottom);border:0}.pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__node-toggle{position:absolute;top:var(--pf-c-tree-view__list-item__list-item__node-toggle--Top);left:var(--pf-c-tree-view__list-item__list-item__node-toggle--Left);transform:translateX(var(--pf-c-tree-view__list-item__list-item__node-toggle--TranslateX))}.pf-c-tree-view__node-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pf-c-tree-view__search{padding:var(--pf-c-tree-view__search--PaddingTop) var(--pf-c-tree-view__search--PaddingRight) var(--pf-c-tree-view__search--PaddingBottom) var(--pf-c-tree-view__search--PaddingLeft)}.pf-c-tree-view__node-icon{padding-right:var(--pf-c-tree-view__node-icon--PaddingRight);color:var(--pf-c-tree-view__node-icon--Color)}.pf-c-tree-view__content{display:flex;align-items:center}.pf-c-tree-view__content:focus-within,.pf-c-tree-view__content:hover{background-color:var(--pf-c-tree-view__node--hover--BackgroundColor)}.pf-c-tree-view__action{margin-left:var(--pf-c-tree-view__action--MarginLeft);color:var(--pf-c-tree-view__action--Color);border:0}.pf-c-tree-view__action:hover{--pf-c-tree-view__action--Color:var(--pf-c-tree-view__action--hover--Color)}.pf-c-tree-view__action:focus{--pf-c-tree-view__action--Color:var(--pf-c-tree-view__action--focus--Color);background-color:var(--pf-c-tree-view__action--focus--BackgroundColor)}.pf-c-tree-view__list-item .pf-c-tree-view__list-item{--pf-c-tree-view__node--PaddingLeft:calc(var(--pf-c-tree-view__node--nested-indent--base)*1 + var(--pf-c-tree-view__node--indent--base));--pf-c-tree-view__list-item__list-item__node-toggle--Left:var(--pf-c-tree-view__node--PaddingLeft)}.pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item{--pf-c-tree-view__node--PaddingLeft:calc(var(--pf-c-tree-view__node--nested-indent--base)*2 + var(--pf-c-tree-view__node--indent--base));--pf-c-tree-view__list-item__list-item__node-toggle--Left:var(--pf-c-tree-view__node--PaddingLeft)}.pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item{--pf-c-tree-view__node--PaddingLeft:calc(var(--pf-c-tree-view__node--nested-indent--base)*3 + var(--pf-c-tree-view__node--indent--base));--pf-c-tree-view__list-item__list-item__node-toggle--Left:var(--pf-c-tree-view__node--PaddingLeft)}.pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item{--pf-c-tree-view__node--PaddingLeft:calc(var(--pf-c-tree-view__node--nested-indent--base)*4 + var(--pf-c-tree-view__node--indent--base));--pf-c-tree-view__list-item__list-item__node-toggle--Left:var(--pf-c-tree-view__node--PaddingLeft)}.pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item{--pf-c-tree-view__node--PaddingLeft:calc(var(--pf-c-tree-view__node--nested-indent--base)*5 + var(--pf-c-tree-view__node--indent--base));--pf-c-tree-view__list-item__list-item__node-toggle--Left:var(--pf-c-tree-view__node--PaddingLeft)}.pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item{--pf-c-tree-view__node--PaddingLeft:calc(var(--pf-c-tree-view__node--nested-indent--base)*6 + var(--pf-c-tree-view__node--indent--base));--pf-c-tree-view__list-item__list-item__node-toggle--Left:var(--pf-c-tree-view__node--PaddingLeft)}.pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item{--pf-c-tree-view__node--PaddingLeft:calc(var(--pf-c-tree-view__node--nested-indent--base)*7 + var(--pf-c-tree-view__node--indent--base));--pf-c-tree-view__list-item__list-item__node-toggle--Left:var(--pf-c-tree-view__node--PaddingLeft)}.pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item{--pf-c-tree-view__node--PaddingLeft:calc(var(--pf-c-tree-view__node--nested-indent--base)*8 + var(--pf-c-tree-view__node--indent--base));--pf-c-tree-view__list-item__list-item__node-toggle--Left:var(--pf-c-tree-view__node--PaddingLeft)}.pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item{--pf-c-tree-view__node--PaddingLeft:calc(var(--pf-c-tree-view__node--nested-indent--base)*9 + var(--pf-c-tree-view__node--indent--base));--pf-c-tree-view__list-item__list-item__node-toggle--Left:var(--pf-c-tree-view__node--PaddingLeft)}.pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item{--pf-c-tree-view__node--PaddingLeft:calc(var(--pf-c-tree-view__node--nested-indent--base)*10 + var(--pf-c-tree-view__node--indent--base));--pf-c-tree-view__list-item__list-item__node-toggle--Left:var(--pf-c-tree-view__node--PaddingLeft)}.pf-c-wizard{--pf-c-wizard--Height:100%;--pf-c-modal-box--c-wizard--FlexBasis:47.625rem;--pf-c-wizard__header--BackgroundColor:var(--pf-global--BackgroundColor--dark-100);--pf-c-wizard__header--ZIndex:var(--pf-global--ZIndex--md);--pf-c-wizard__header--PaddingTop:var(--pf-global--spacer--lg);--pf-c-wizard__header--PaddingRight:var(--pf-global--spacer--md);--pf-c-wizard__header--PaddingBottom:var(--pf-global--spacer--lg);--pf-c-wizard__header--PaddingLeft:var(--pf-global--spacer--md);--pf-c-wizard__header--lg--PaddingRight:var(--pf-global--spacer--md);--pf-c-wizard__header--lg--PaddingLeft:var(--pf-global--spacer--md);--pf-c-wizard__header--xl--PaddingRight:var(--pf-global--spacer--lg);--pf-c-wizard__header--xl--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-wizard__close--Top:calc(var(--pf-global--spacer--lg) - var(--pf-global--spacer--form-element));--pf-c-wizard__close--Right:0;--pf-c-wizard__close--xl--Right:var(--pf-global--spacer--lg);--pf-c-wizard__close--FontSize:var(--pf-global--FontSize--xl);--pf-c-wizard__title--PaddingRight:var(--pf-global--spacer--2xl);--pf-c-wizard__description--PaddingTop:var(--pf-global--spacer--sm);--pf-c-wizard__description--Color:var(--pf-global--Color--light-200);--pf-c-wizard__nav-link--Color:var(--pf-global--Color--100);--pf-c-wizard__nav-link--TextDecoration:var(--pf-global--link--TextDecoration);--pf-c-wizard__nav-link--hover--Color:var(--pf-global--link--Color);--pf-c-wizard__nav-link--focus--Color:var(--pf-global--link--Color);--pf-c-wizard__nav-link--m-current--Color:var(--pf-global--link--Color);--pf-c-wizard__nav-link--m-current--FontWeight:var(--pf-global--FontWeight--bold);--pf-c-wizard__nav-link--m-disabled--Color:var(--pf-global--Color--dark-200);--pf-c-wizard__nav-list__nav-list__nav-link--m-current--FontWeight:var(--pf-global--FontWeight--bold);--pf-c-wizard__nav-link--before--Width:1.5rem;--pf-c-wizard__nav-link--before--Height:1.5rem;--pf-c-wizard__nav-link--before--Top:0;--pf-c-wizard__nav-link--before--BackgroundColor:var(--pf-global--BackgroundColor--200);--pf-c-wizard__nav-link--before--BorderRadius:var(--pf-global--BorderRadius--lg);--pf-c-wizard__nav-link--before--Color:var(--pf-global--Color--100);--pf-c-wizard__nav-link--before--FontSize:var(--pf-global--FontSize--sm);--pf-c-wizard__nav-link--before--TranslateX:calc(-100% - var(--pf-global--spacer--sm));--pf-c-wizard__nav-link--m-current--before--BackgroundColor:var(--pf-global--active-color--100);--pf-c-wizard__nav-link--m-current--before--Color:var(--pf-global--Color--light-100);--pf-c-wizard__nav-link--m-disabled--before--BackgroundColor:transparent;--pf-c-wizard__nav-link--m-disabled--before--Color:var(--pf-global--Color--dark-200);--pf-c-wizard__toggle--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-wizard__toggle--ZIndex:var(--pf-global--ZIndex--md);--pf-c-wizard__toggle--BoxShadow:var(--pf-global--BoxShadow--md-bottom);--pf-c-wizard__toggle--PaddingTop:var(--pf-global--spacer--lg);--pf-c-wizard__toggle--PaddingRight:var(--pf-global--spacer--md);--pf-c-wizard__toggle--PaddingBottom:var(--pf-global--spacer--lg);--pf-c-wizard__toggle--PaddingLeft:calc(var(--pf-global--spacer--md) + var(--pf-c-wizard__nav-link--before--Width) + var(--pf-global--spacer--sm));--pf-c-wizard__toggle--m-expanded--BorderBottomWidth:var(--pf-global--BorderWidth--sm);--pf-c-wizard__toggle--m-expanded--BorderBottomColor:var(--pf-global--BorderColor--100);--pf-c-wizard--m-in-page__toggle--xl--PaddingLeft:calc(var(--pf-global--spacer--xl) + var(--pf-c-wizard__nav-link--before--Width) + var(--pf-global--spacer--sm));--pf-c-wizard__toggle-num--before--Top:0;--pf-c-wizard__toggle-list-item--not-last-child--MarginRight:var(--pf-global--spacer--sm);--pf-c-wizard__toggle-list-item--MarginBottom:var(--pf-global--spacer--xs);--pf-c-wizard__toggle-list--MarginRight:var(--pf-global--spacer--sm);--pf-c-wizard__toggle-list--MarginBottom:calc(var(--pf-c-wizard__toggle-list-item--MarginBottom)*-1);--pf-c-wizard__toggle-separator--MarginLeft:var(--pf-global--spacer--sm);--pf-c-wizard__toggle-separator--Color:var(--pf-global--BorderColor--200);--pf-c-wizard__toggle-icon--LineHeight:var(--pf-global--LineHeight--md);--pf-c-wizard__toggle--m-expanded__toggle-icon--Rotate:180deg;--pf-c-wizard__nav--ZIndex:var(--pf-global--ZIndex--sm);--pf-c-wizard__nav--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-wizard__nav--BoxShadow:var(--pf-global--BoxShadow--md-bottom);--pf-c-wizard__nav--Width:100%;--pf-c-wizard__nav--lg--Width:15.625rem;--pf-c-wizard__nav--lg--BorderRightWidth:var(--pf-global--BorderWidth--sm);--pf-c-wizard__nav--lg--BorderRightColor:var(--pf-global--BorderColor--100);--pf-c-wizard__nav-list--PaddingTop:var(--pf-global--spacer--lg);--pf-c-wizard__nav-list--PaddingRight:var(--pf-global--spacer--md);--pf-c-wizard__nav-list--PaddingBottom:var(--pf-global--spacer--lg);--pf-c-wizard__nav-list--PaddingLeft:calc(var(--pf-global--spacer--md) + var(--pf-c-wizard__nav-link--before--Width) + var(--pf-global--spacer--sm));--pf-c-wizard__nav-list--lg--PaddingTop:var(--pf-global--spacer--md);--pf-c-wizard__nav-list--lg--PaddingRight:var(--pf-global--spacer--md);--pf-c-wizard__nav-list--lg--PaddingBottom:var(--pf-global--spacer--md);--pf-c-wizard__nav-list--xl--PaddingTop:var(--pf-global--spacer--lg);--pf-c-wizard__nav-list--xl--PaddingRight:var(--pf-global--spacer--lg);--pf-c-wizard__nav-list--xl--PaddingBottom:var(--pf-global--spacer--lg);--pf-c-wizard__nav-list--xl--PaddingLeft:calc(var(--pf-global--spacer--lg) + var(--pf-c-wizard__nav-link--before--Width) + var(--pf-global--spacer--sm));--pf-c-wizard__nav-list--nested--MarginLeft:var(--pf-global--spacer--md);--pf-c-wizard__nav-list--nested--MarginTop:var(--pf-global--spacer--md);--pf-c-wizard__nav-item--MarginTop:var(--pf-global--spacer--md);--pf-c-wizard__outer-wrap--BackgroundColor:var(--pf-global--BackgroundColor--100);--pf-c-wizard__outer-wrap--lg--PaddingLeft:var(--pf-c-wizard__nav--Width);--pf-c-wizard__main--ZIndex:var(--pf-global--ZIndex--xs);--pf-c-wizard__main-body--PaddingTop:var(--pf-global--spacer--md);--pf-c-wizard__main-body--PaddingRight:var(--pf-global--spacer--md);--pf-c-wizard__main-body--PaddingBottom:var(--pf-global--spacer--md);--pf-c-wizard__main-body--PaddingLeft:var(--pf-global--spacer--md);--pf-c-wizard__main-body--xl--PaddingTop:var(--pf-global--spacer--lg);--pf-c-wizard__main-body--xl--PaddingRight:var(--pf-global--spacer--lg);--pf-c-wizard__main-body--xl--PaddingBottom:var(--pf-global--spacer--lg);--pf-c-wizard__main-body--xl--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-wizard__footer--PaddingTop:var(--pf-global--spacer--md);--pf-c-wizard__footer--PaddingRight:var(--pf-global--spacer--md);--pf-c-wizard__footer--PaddingBottom:var(--pf-global--spacer--sm);--pf-c-wizard__footer--PaddingLeft:var(--pf-global--spacer--md);--pf-c-wizard__footer--xl--PaddingTop:var(--pf-global--spacer--lg);--pf-c-wizard__footer--xl--PaddingRight:var(--pf-global--spacer--lg);--pf-c-wizard__footer--xl--PaddingBottom:var(--pf-global--spacer--md);--pf-c-wizard__footer--xl--PaddingLeft:var(--pf-global--spacer--lg);--pf-c-wizard__footer--child--MarginRight:var(--pf-global--spacer--md);--pf-c-wizard__footer--child--MarginBottom:var(--pf-global--spacer--sm);position:relative;display:flex;flex-direction:column;height:var(--pf-c-wizard--Height)}@media screen and (min-width:992px){.pf-c-wizard{--pf-c-wizard__header--PaddingRight:var(--pf-c-wizard__header--lg--PaddingRight);--pf-c-wizard__header--PaddingLeft:var(--pf-c-wizard__header--lg--PaddingLeft)}}@media screen and (min-width:1200px){.pf-c-wizard{--pf-c-wizard__header--PaddingRight:var(--pf-c-wizard__header--xl--PaddingRight);--pf-c-wizard__header--PaddingLeft:var(--pf-c-wizard__header--xl--PaddingLeft);--pf-c-wizard__close--Right:var(--pf-c-wizard__close--xl--Right)}}@media screen and (min-width:992px){.pf-c-wizard{--pf-c-wizard__nav--Width:var(--pf-c-wizard__nav--lg--Width);--pf-c-wizard__nav--BoxShadow:none;--pf-c-wizard__nav-list--PaddingTop:var(--pf-c-wizard__nav-list--lg--PaddingTop);--pf-c-wizard__nav-list--PaddingRight:var(--pf-c-wizard__nav-list--lg--PaddingRight);--pf-c-wizard__nav-list--PaddingBottom:var(--pf-c-wizard__nav-list--lg--PaddingBottom)}}@media screen and (min-width:1200px){.pf-c-wizard{--pf-c-wizard__nav-list--PaddingTop:var(--pf-c-wizard__nav-list--xl--PaddingTop);--pf-c-wizard__nav-list--PaddingRight:var(--pf-c-wizard__nav-list--xl--PaddingRight);--pf-c-wizard__nav-list--PaddingBottom:var(--pf-c-wizard__nav-list--xl--PaddingBottom);--pf-c-wizard__nav-list--PaddingLeft:var(--pf-c-wizard__nav-list--xl--PaddingLeft);--pf-c-wizard__main-body--PaddingTop:var(--pf-c-wizard__main-body--xl--PaddingTop);--pf-c-wizard__main-body--PaddingRight:var(--pf-c-wizard__main-body--xl--PaddingRight);--pf-c-wizard__main-body--PaddingBottom:var(--pf-c-wizard__main-body--xl--PaddingBottom);--pf-c-wizard__main-body--PaddingLeft:var(--pf-c-wizard__main-body--xl--PaddingLeft);--pf-c-wizard__footer--PaddingTop:var(--pf-c-wizard__footer--xl--PaddingTop);--pf-c-wizard__footer--PaddingRight:var(--pf-c-wizard__footer--xl--PaddingRight);--pf-c-wizard__footer--PaddingBottom:var(--pf-c-wizard__footer--xl--PaddingBottom);--pf-c-wizard__footer--PaddingLeft:var(--pf-c-wizard__footer--xl--PaddingLeft)}}.pf-c-modal-box .pf-c-wizard{flex:1 1 var(--pf-c-modal-box--c-wizard--FlexBasis);min-height:0}.pf-c-wizard>:not(.pf-c-wizard__outer-wrap){flex-shrink:0}.pf-c-wizard.pf-m-finished{--pf-c-wizard__outer-wrap--lg--PaddingLeft:0}.pf-c-wizard.pf-m-finished .pf-c-wizard__footer,.pf-c-wizard.pf-m-finished .pf-c-wizard__nav,.pf-c-wizard.pf-m-finished .pf-c-wizard__toggle{display:none;visibility:hidden}.pf-c-wizard__header{color:var(--pf-global--Color--100);position:relative;z-index:var(--pf-c-wizard__header--ZIndex);padding:var(--pf-c-wizard__header--PaddingTop) var(--pf-c-wizard__header--PaddingRight) var(--pf-c-wizard__header--PaddingBottom) var(--pf-c-wizard__header--PaddingLeft);background-color:var(--pf-c-wizard__header--BackgroundColor)}.pf-c-wizard__header .pf-c-wizard__close{position:absolute;top:var(--pf-c-wizard__close--Top);right:var(--pf-c-wizard__close--Right);font-size:var(--pf-c-wizard__close--FontSize)}.pf-c-wizard__title{padding-right:var(--pf-c-wizard__title--PaddingRight);word-wrap:break-word}.pf-c-wizard__description{display:none;padding-top:var(--pf-c-wizard__description--PaddingTop);color:var(--pf-c-wizard__description--Color);visibility:hidden}@media screen and (min-width:992px){.pf-c-wizard__description{display:block;visibility:visible}}.pf-c-wizard__toggle{position:relative;z-index:var(--pf-c-wizard__toggle--ZIndex);display:flex;justify-content:space-between;width:100%;padding:var(--pf-c-wizard__toggle--PaddingTop) var(--pf-c-wizard__toggle--PaddingRight) var(--pf-c-wizard__toggle--PaddingBottom) var(--pf-c-wizard__toggle--PaddingLeft);background-color:var(--pf-c-wizard__toggle--BackgroundColor);border:0;box-shadow:var(--pf-c-wizard__toggle--BoxShadow)}@media screen and (min-width:992px){.pf-c-wizard__toggle{display:none;visibility:hidden}}.pf-c-wizard__toggle.pf-m-expanded{--pf-c-wizard__toggle--BoxShadow:none;border-bottom:var(--pf-c-wizard__toggle--m-expanded--BorderBottomWidth) solid var(--pf-c-wizard__toggle--m-expanded--BorderBottomColor)}.pf-c-wizard__toggle.pf-m-expanded .pf-c-wizard__toggle-icon{transform:rotate(var(--pf-c-wizard__toggle--m-expanded__toggle-icon--Rotate))}.pf-c-wizard__toggle-list{position:relative;display:flex;flex-wrap:wrap;align-items:baseline;margin-right:var(--pf-c-wizard__toggle-list--MarginRight);margin-bottom:var(--pf-c-wizard__toggle-list--MarginBottom);list-style:none}.pf-c-wizard__toggle-list-item{margin-bottom:var(--pf-c-wizard__toggle-list-item--MarginBottom);text-align:left;word-break:break-word}.pf-c-wizard__toggle-list-item:not(:last-child){margin-right:var(--pf-c-wizard__toggle-list-item--not-last-child--MarginRight)}.pf-c-wizard__toggle-num{--pf-c-wizard__nav-link--before--Top:var(--pf-c-wizard__toggle-num--before--Top)}.pf-c-wizard__toggle-separator{margin-left:var(--pf-c-wizard__toggle-separator--MarginLeft);color:var(--pf-c-wizard__toggle-separator--Color)}.pf-c-wizard__toggle-icon{line-height:var(--pf-c-wizard__toggle-icon--LineHeight)}.pf-c-wizard__outer-wrap{position:relative;display:flex;flex-direction:column;flex-grow:1;min-height:0;background-color:var(--pf-c-wizard__outer-wrap--BackgroundColor)}@media screen and (min-width:992px){.pf-c-wizard__outer-wrap{padding-left:var(--pf-c-wizard__outer-wrap--lg--PaddingLeft)}}.pf-c-wizard__inner-wrap{position:relative;display:flex;flex-direction:column;flex-grow:1;min-height:0}@media screen and (min-width:992px){.pf-c-wizard__inner-wrap{position:static}}.pf-c-wizard__nav{position:absolute;top:0;left:0;z-index:var(--pf-c-wizard__nav--ZIndex);display:none;width:var(--pf-c-wizard__nav--Width);max-height:100%;overflow-y:auto;-webkit-overflow-scrolling:touch;visibility:hidden;background-color:var(--pf-c-wizard__nav--BackgroundColor);box-shadow:var(--pf-c-wizard__nav--BoxShadow)}.pf-c-wizard__nav.pf-m-expanded{display:block;visibility:visible}@media screen and (min-width:992px){.pf-c-wizard__nav{display:block;height:100%;visibility:visible;border-right:var(--pf-c-wizard__nav--lg--BorderRightWidth) solid var(--pf-c-wizard__nav--lg--BorderRightColor)}}.pf-c-wizard__nav-list{padding:var(--pf-c-wizard__nav-list--PaddingTop) var(--pf-c-wizard__nav-list--PaddingRight) var(--pf-c-wizard__nav-list--PaddingBottom) var(--pf-c-wizard__nav-list--PaddingLeft);list-style:none;counter-reset:wizard-nav-count}.pf-c-wizard__nav-list .pf-c-wizard__nav-list{padding:0;margin-top:var(--pf-c-wizard__nav-list--nested--MarginTop);margin-left:var(--pf-c-wizard__nav-list--nested--MarginLeft)}.pf-c-wizard__nav-list .pf-c-wizard__nav-list .pf-c-wizard__nav-link:before{content:none}.pf-c-wizard__nav-list .pf-c-wizard__nav-list .pf-c-wizard__nav-link.pf-m-current{font-weight:var(--pf-c-wizard__nav-list__nav-list__nav-link--m-current--FontWeight)}.pf-c-wizard__nav-item+.pf-c-wizard__nav-item{margin-top:var(--pf-c-wizard__nav-item--MarginTop)}.pf-c-wizard__nav-link{position:relative;display:inline-block;color:var(--pf-c-wizard__nav-link--Color);text-align:left;text-decoration:var(--pf-c-wizard__nav-link--TextDecoration);word-break:break-word;border:0}.pf-c-wizard__nav-link:before,.pf-c-wizard__toggle-num{position:absolute;top:var(--pf-c-wizard__nav-link--before--Top);left:0;display:inline-flex;align-items:center;justify-content:center;width:var(--pf-c-wizard__nav-link--before--Width);height:var(--pf-c-wizard__nav-link--before--Height);font-size:var(--pf-c-wizard__nav-link--before--FontSize);line-height:1;color:var(--pf-c-wizard__nav-link--before--Color);background-color:var(--pf-c-wizard__nav-link--before--BackgroundColor);border-radius:var(--pf-c-wizard__nav-link--before--BorderRadius);transform:translateX(var(--pf-c-wizard__nav-link--before--TranslateX))}.pf-c-wizard__nav-link:before{top:0;content:counter(wizard-nav-count);counter-increment:wizard-nav-count}.pf-c-wizard__nav-link:hover{--pf-c-wizard__nav-link--Color:var(--pf-c-wizard__nav-link--hover--Color)}.pf-c-wizard__nav-link:focus{--pf-c-wizard__nav-link--Color:var(--pf-c-wizard__nav-link--focus--Color)}.pf-c-wizard__nav-link.pf-m-current{--pf-c-wizard__nav-link--Color:var(--pf-c-wizard__nav-link--m-current--Color);font-weight:var(--pf-c-wizard__nav-link--m-current--FontWeight)}.pf-c-wizard__nav-link.pf-m-current:before,.pf-c-wizard__toggle-num{--pf-c-wizard__nav-link--before--BackgroundColor:var(--pf-c-wizard__nav-link--m-current--before--BackgroundColor);--pf-c-wizard__nav-link--before--Color:var(--pf-c-wizard__nav-link--m-current--before--Color)}.pf-c-wizard__nav-link.pf-m-disabled,.pf-c-wizard__nav-link:disabled{--pf-c-wizard__nav-link--Color:var(--pf-c-wizard__nav-link--m-disabled--Color);pointer-events:none}.pf-c-wizard__nav-link.pf-m-disabled:before,.pf-c-wizard__nav-link:disabled:before{--pf-c-wizard__nav-link--before--BackgroundColor:var(--pf-c-wizard__nav-link--m-disabled--before--BackgroundColor);--pf-c-wizard__nav-link--before--Color:var(--pf-c-wizard__nav-link--m-disabled--before--Color)}.pf-c-wizard__main{z-index:var(--pf-c-wizard__main--ZIndex);flex:1 1 auto;overflow-x:hidden;overflow-y:auto;word-break:break-word}.pf-c-wizard__main-body{padding:var(--pf-c-wizard__main-body--PaddingTop) var(--pf-c-wizard__main-body--PaddingRight) var(--pf-c-wizard__main-body--PaddingBottom) var(--pf-c-wizard__main-body--PaddingLeft)}.pf-c-wizard__main-body.pf-m-no-padding{padding:0}.pf-c-wizard__footer{display:flex;flex-wrap:wrap;flex-shrink:0;padding:var(--pf-c-wizard__footer--PaddingTop) var(--pf-c-wizard__footer--PaddingRight) var(--pf-c-wizard__footer--PaddingBottom) var(--pf-c-wizard__footer--PaddingLeft)}.pf-c-wizard__footer>*{margin-bottom:var(--pf-c-wizard__footer--child--MarginBottom)}.pf-c-wizard__footer>:not(:last-child){margin-right:var(--pf-c-wizard__footer--child--MarginRight)}.pf-l-bullseye{--pf-l-bullseye--Padding:0;display:flex;align-items:center;justify-content:center;height:100%;padding:var(--pf-l-bullseye--Padding);margin:0}.pf-l-flex{--pf-l-flex--Display:flex;--pf-l-flex--FlexWrap:wrap;--pf-l-flex--AlignItems:baseline;--pf-l-flex--m-row--AlignItems:baseline;--pf-l-flex--m-row-reverse--AlignItems:baseline;--pf-l-flex--item--Order:0;--pf-l-flex--spacer-base:var(--pf-global--spacer--md);--pf-l-flex--spacer:var(--pf-l-flex--spacer-base);--pf-l-flex--spacer--none:0;--pf-l-flex--spacer--xs:var(--pf-global--spacer--xs);--pf-l-flex--spacer--sm:var(--pf-global--spacer--sm);--pf-l-flex--spacer--md:var(--pf-global--spacer--md);--pf-l-flex--spacer--lg:var(--pf-global--spacer--lg);--pf-l-flex--spacer--xl:var(--pf-global--spacer--xl);--pf-l-flex--spacer--2xl:var(--pf-global--spacer--2xl);--pf-l-flex--spacer--3xl:var(--pf-global--spacer--3xl);--pf-l-flex--spacer--4xl:var(--pf-global--spacer--4xl);display:var(--pf-l-flex--Display);flex-wrap:var(--pf-l-flex--FlexWrap);align-items:var(--pf-l-flex--AlignItems)}.pf-l-flex:last-child{--pf-l-flex--spacer:0}.pf-l-flex>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer-base);order:var(--pf-l-flex--item--Order);max-width:100%;margin-right:var(--pf-l-flex--spacer)}@media screen and (min-width:576px){.pf-l-flex>*{order:var(--pf-l-flex--item--Order-on-sm,var(--pf-l-flex--item--Order))}}@media screen and (min-width:768px){.pf-l-flex>*{order:var(--pf-l-flex--item--Order-on-md,var(--pf-l-flex--item--Order-on-sm,var(--pf-l-flex--item--Order)))}}@media screen and (min-width:992px){.pf-l-flex>*{order:var(--pf-l-flex--item--Order-on-lg,var(--pf-l-flex--item--Order-on-md,var(--pf-l-flex--item--Order-on-sm,var(--pf-l-flex--item--Order))))}}@media screen and (min-width:1200px){.pf-l-flex>*{order:var(--pf-l-flex--item--Order-on-xl,var(--pf-l-flex--item--Order-on-lg,var(--pf-l-flex--item--Order-on-md,var(--pf-l-flex--item--Order-on-sm,var(--pf-l-flex--item--Order)))))}}@media screen and (min-width:1450px){.pf-l-flex>*{order:var(--pf-l-flex--item--Order-on-2xl,var(--pf-l-flex--item--Order-on-xl,var(--pf-l-flex--item--Order-on-lg,var(--pf-l-flex--item--Order-on-md,var(--pf-l-flex--item--Order-on-sm,var(--pf-l-flex--item--Order))))))}}.pf-l-flex>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-flex{display:var(--pf-l-flex--Display)}.pf-l-flex.pf-m-inline-flex{--pf-l-flex--Display:inline-flex}.pf-l-flex.pf-m-column{flex-direction:column;align-items:normal}.pf-l-flex.pf-m-column>*{margin:0 0 var(--pf-l-flex--spacer) 0}.pf-l-flex.pf-m-column-reverse{flex-direction:column-reverse;align-items:normal}.pf-l-flex.pf-m-column-reverse>*{margin:var(--pf-l-flex--spacer) 0 0 0}.pf-l-flex.pf-m-row{flex-direction:row;align-items:var(--pf-l-flex--m-row--AlignItems)}.pf-l-flex.pf-m-row>*{margin:0 var(--pf-l-flex--spacer) 0 0}.pf-l-flex.pf-m-row-reverse{flex-direction:row-reverse;align-items:var(--pf-l-flex--m-row-reverse--AlignItems)}.pf-l-flex.pf-m-row-reverse>*{margin:0 0 0 var(--pf-l-flex--spacer)}.pf-l-flex.pf-m-wrap{flex-wrap:wrap}.pf-l-flex.pf-m-wrap-reverse{flex-wrap:wrap-reverse}.pf-l-flex.pf-m-nowrap{flex-wrap:nowrap}.pf-l-flex.pf-m-justify-content-flex-start{justify-content:flex-start}.pf-l-flex.pf-m-justify-content-flex-end{justify-content:flex-end}.pf-l-flex.pf-m-justify-content-center{justify-content:center}.pf-l-flex.pf-m-justify-content-space-between{justify-content:space-between}.pf-l-flex.pf-m-justify-content-space-around{justify-content:space-around}.pf-l-flex.pf-m-justify-content-space-evenly{justify-content:space-evenly}.pf-l-flex.pf-m-align-items-flex-start{align-items:flex-start}.pf-l-flex.pf-m-align-items-flex-end{align-items:flex-end}.pf-l-flex.pf-m-align-items-center{align-items:center}.pf-l-flex.pf-m-align-items-stretch{align-items:stretch}.pf-l-flex.pf-m-align-items-baseline{align-items:baseline}.pf-l-flex.pf-m-align-content-flex-start{align-content:flex-start}.pf-l-flex.pf-m-align-content-flex-end{align-content:flex-end}.pf-l-flex.pf-m-align-content-center{align-content:center}.pf-l-flex.pf-m-align-content-stretch{align-content:stretch}.pf-l-flex.pf-m-align-content-space-between{align-content:space-between}.pf-l-flex.pf-m-align-content-space-around{align-content:space-around}.pf-l-flex>.pf-m-align-right{margin-left:auto}.pf-l-flex>.pf-m-align-left{margin-left:0}.pf-l-flex>.pf-m-grow{flex-grow:1}.pf-l-flex>.pf-m-shrink{flex-shrink:1}.pf-l-flex>.pf-m-full-width{width:100%;margin-right:0}.pf-l-flex>.pf-m-flex-1{flex:1 0 0}.pf-l-flex>.pf-m-flex-2{flex:2 0 0}.pf-l-flex>.pf-m-flex-3{flex:3 0 0}.pf-l-flex>.pf-m-flex-4{flex:4 0 0}.pf-l-flex>.pf-m-flex-default{flex:0 1 auto}.pf-l-flex>.pf-m-flex-none{flex:none}.pf-l-flex>.pf-m-align-self-flex-start{align-self:flex-start}.pf-l-flex>.pf-m-align-self-flex-end{align-self:flex-end}.pf-l-flex>.pf-m-align-self-center{align-self:center}.pf-l-flex>.pf-m-align-self-baseline{align-self:baseline}.pf-l-flex>.pf-m-align-self-stretch{align-self:stretch}@media (min-width:576px){.pf-l-flex.pf-m-flex-on-sm{display:var(--pf-l-flex--Display)}.pf-l-flex.pf-m-inline-flex-on-sm{--pf-l-flex--Display:inline-flex}.pf-l-flex.pf-m-column-on-sm{flex-direction:column;align-items:normal}.pf-l-flex.pf-m-column-on-sm>*{margin:0 0 var(--pf-l-flex--spacer) 0}.pf-l-flex.pf-m-column-reverse-on-sm{flex-direction:column-reverse;align-items:normal}.pf-l-flex.pf-m-column-reverse-on-sm>*{margin:var(--pf-l-flex--spacer) 0 0 0}.pf-l-flex.pf-m-row-on-sm{flex-direction:row;align-items:var(--pf-l-flex--m-row--AlignItems)}.pf-l-flex.pf-m-row-on-sm>*{margin:0 var(--pf-l-flex--spacer) 0 0}.pf-l-flex.pf-m-row-reverse-on-sm{flex-direction:row-reverse;align-items:var(--pf-l-flex--m-row-reverse--AlignItems)}.pf-l-flex.pf-m-row-reverse-on-sm>*{margin:0 0 0 var(--pf-l-flex--spacer)}.pf-l-flex.pf-m-wrap-on-sm{flex-wrap:wrap}.pf-l-flex.pf-m-wrap-reverse-on-sm{flex-wrap:wrap-reverse}.pf-l-flex.pf-m-nowrap-on-sm{flex-wrap:nowrap}.pf-l-flex.pf-m-justify-content-flex-start-on-sm{justify-content:flex-start}.pf-l-flex.pf-m-justify-content-flex-end-on-sm{justify-content:flex-end}.pf-l-flex.pf-m-justify-content-center-on-sm{justify-content:center}.pf-l-flex.pf-m-justify-content-space-between-on-sm{justify-content:space-between}.pf-l-flex.pf-m-justify-content-space-around-on-sm{justify-content:space-around}.pf-l-flex.pf-m-justify-content-space-evenly-on-sm{justify-content:space-evenly}.pf-l-flex.pf-m-align-items-flex-start-on-sm{align-items:flex-start}.pf-l-flex.pf-m-align-items-flex-end-on-sm{align-items:flex-end}.pf-l-flex.pf-m-align-items-center-on-sm{align-items:center}.pf-l-flex.pf-m-align-items-stretch-on-sm{align-items:stretch}.pf-l-flex.pf-m-align-items-baseline-on-sm{align-items:baseline}.pf-l-flex.pf-m-align-content-flex-start-on-sm{align-content:flex-start}.pf-l-flex.pf-m-align-content-flex-end-on-sm{align-content:flex-end}.pf-l-flex.pf-m-align-content-center-on-sm{align-content:center}.pf-l-flex.pf-m-align-content-stretch-on-sm{align-content:stretch}.pf-l-flex.pf-m-align-content-space-between-on-sm{align-content:space-between}.pf-l-flex.pf-m-align-content-space-around-on-sm{align-content:space-around}.pf-l-flex>.pf-m-align-right-on-sm{margin-left:auto}.pf-l-flex>.pf-m-align-left-on-sm{margin-left:0}.pf-l-flex>.pf-m-grow-on-sm{flex-grow:1}.pf-l-flex>.pf-m-shrink-on-sm{flex-shrink:1}.pf-l-flex>.pf-m-full-width-on-sm{width:100%;margin-right:0}.pf-l-flex>.pf-m-flex-1-on-sm{flex:1 0 0}.pf-l-flex>.pf-m-flex-2-on-sm{flex:2 0 0}.pf-l-flex>.pf-m-flex-3-on-sm{flex:3 0 0}.pf-l-flex>.pf-m-flex-4-on-sm{flex:4 0 0}.pf-l-flex>.pf-m-flex-default-on-sm{flex:0 1 auto}.pf-l-flex>.pf-m-flex-none-on-sm{flex:none}.pf-l-flex>.pf-m-align-self-flex-start-on-sm{align-self:flex-start}.pf-l-flex>.pf-m-align-self-flex-end-on-sm{align-self:flex-end}.pf-l-flex>.pf-m-align-self-center-on-sm{align-self:center}.pf-l-flex>.pf-m-align-self-baseline-on-sm{align-self:baseline}.pf-l-flex>.pf-m-align-self-stretch-on-sm{align-self:stretch}}@media (min-width:768px){.pf-l-flex.pf-m-flex-on-md{display:var(--pf-l-flex--Display)}.pf-l-flex.pf-m-inline-flex-on-md{--pf-l-flex--Display:inline-flex}.pf-l-flex.pf-m-column-on-md{flex-direction:column;align-items:normal}.pf-l-flex.pf-m-column-on-md>*{margin:0 0 var(--pf-l-flex--spacer) 0}.pf-l-flex.pf-m-column-reverse-on-md{flex-direction:column-reverse;align-items:normal}.pf-l-flex.pf-m-column-reverse-on-md>*{margin:var(--pf-l-flex--spacer) 0 0 0}.pf-l-flex.pf-m-row-on-md{flex-direction:row;align-items:var(--pf-l-flex--m-row--AlignItems)}.pf-l-flex.pf-m-row-on-md>*{margin:0 var(--pf-l-flex--spacer) 0 0}.pf-l-flex.pf-m-row-reverse-on-md{flex-direction:row-reverse;align-items:var(--pf-l-flex--m-row-reverse--AlignItems)}.pf-l-flex.pf-m-row-reverse-on-md>*{margin:0 0 0 var(--pf-l-flex--spacer)}.pf-l-flex.pf-m-wrap-on-md{flex-wrap:wrap}.pf-l-flex.pf-m-wrap-reverse-on-md{flex-wrap:wrap-reverse}.pf-l-flex.pf-m-nowrap-on-md{flex-wrap:nowrap}.pf-l-flex.pf-m-justify-content-flex-start-on-md{justify-content:flex-start}.pf-l-flex.pf-m-justify-content-flex-end-on-md{justify-content:flex-end}.pf-l-flex.pf-m-justify-content-center-on-md{justify-content:center}.pf-l-flex.pf-m-justify-content-space-between-on-md{justify-content:space-between}.pf-l-flex.pf-m-justify-content-space-around-on-md{justify-content:space-around}.pf-l-flex.pf-m-justify-content-space-evenly-on-md{justify-content:space-evenly}.pf-l-flex.pf-m-align-items-flex-start-on-md{align-items:flex-start}.pf-l-flex.pf-m-align-items-flex-end-on-md{align-items:flex-end}.pf-l-flex.pf-m-align-items-center-on-md{align-items:center}.pf-l-flex.pf-m-align-items-stretch-on-md{align-items:stretch}.pf-l-flex.pf-m-align-items-baseline-on-md{align-items:baseline}.pf-l-flex.pf-m-align-content-flex-start-on-md{align-content:flex-start}.pf-l-flex.pf-m-align-content-flex-end-on-md{align-content:flex-end}.pf-l-flex.pf-m-align-content-center-on-md{align-content:center}.pf-l-flex.pf-m-align-content-stretch-on-md{align-content:stretch}.pf-l-flex.pf-m-align-content-space-between-on-md{align-content:space-between}.pf-l-flex.pf-m-align-content-space-around-on-md{align-content:space-around}.pf-l-flex>.pf-m-align-right-on-md{margin-left:auto}.pf-l-flex>.pf-m-align-left-on-md{margin-left:0}.pf-l-flex>.pf-m-grow-on-md{flex-grow:1}.pf-l-flex>.pf-m-shrink-on-md{flex-shrink:1}.pf-l-flex>.pf-m-full-width-on-md{width:100%;margin-right:0}.pf-l-flex>.pf-m-flex-1-on-md{flex:1 0 0}.pf-l-flex>.pf-m-flex-2-on-md{flex:2 0 0}.pf-l-flex>.pf-m-flex-3-on-md{flex:3 0 0}.pf-l-flex>.pf-m-flex-4-on-md{flex:4 0 0}.pf-l-flex>.pf-m-flex-default-on-md{flex:0 1 auto}.pf-l-flex>.pf-m-flex-none-on-md{flex:none}.pf-l-flex>.pf-m-align-self-flex-start-on-md{align-self:flex-start}.pf-l-flex>.pf-m-align-self-flex-end-on-md{align-self:flex-end}.pf-l-flex>.pf-m-align-self-center-on-md{align-self:center}.pf-l-flex>.pf-m-align-self-baseline-on-md{align-self:baseline}.pf-l-flex>.pf-m-align-self-stretch-on-md{align-self:stretch}}@media (min-width:992px){.pf-l-flex.pf-m-flex-on-lg{display:var(--pf-l-flex--Display)}.pf-l-flex.pf-m-inline-flex-on-lg{--pf-l-flex--Display:inline-flex}.pf-l-flex.pf-m-column-on-lg{flex-direction:column;align-items:normal}.pf-l-flex.pf-m-column-on-lg>*{margin:0 0 var(--pf-l-flex--spacer) 0}.pf-l-flex.pf-m-column-reverse-on-lg{flex-direction:column-reverse;align-items:normal}.pf-l-flex.pf-m-column-reverse-on-lg>*{margin:var(--pf-l-flex--spacer) 0 0 0}.pf-l-flex.pf-m-row-on-lg{flex-direction:row;align-items:var(--pf-l-flex--m-row--AlignItems)}.pf-l-flex.pf-m-row-on-lg>*{margin:0 var(--pf-l-flex--spacer) 0 0}.pf-l-flex.pf-m-row-reverse-on-lg{flex-direction:row-reverse;align-items:var(--pf-l-flex--m-row-reverse--AlignItems)}.pf-l-flex.pf-m-row-reverse-on-lg>*{margin:0 0 0 var(--pf-l-flex--spacer)}.pf-l-flex.pf-m-wrap-on-lg{flex-wrap:wrap}.pf-l-flex.pf-m-wrap-reverse-on-lg{flex-wrap:wrap-reverse}.pf-l-flex.pf-m-nowrap-on-lg{flex-wrap:nowrap}.pf-l-flex.pf-m-justify-content-flex-start-on-lg{justify-content:flex-start}.pf-l-flex.pf-m-justify-content-flex-end-on-lg{justify-content:flex-end}.pf-l-flex.pf-m-justify-content-center-on-lg{justify-content:center}.pf-l-flex.pf-m-justify-content-space-between-on-lg{justify-content:space-between}.pf-l-flex.pf-m-justify-content-space-around-on-lg{justify-content:space-around}.pf-l-flex.pf-m-justify-content-space-evenly-on-lg{justify-content:space-evenly}.pf-l-flex.pf-m-align-items-flex-start-on-lg{align-items:flex-start}.pf-l-flex.pf-m-align-items-flex-end-on-lg{align-items:flex-end}.pf-l-flex.pf-m-align-items-center-on-lg{align-items:center}.pf-l-flex.pf-m-align-items-stretch-on-lg{align-items:stretch}.pf-l-flex.pf-m-align-items-baseline-on-lg{align-items:baseline}.pf-l-flex.pf-m-align-content-flex-start-on-lg{align-content:flex-start}.pf-l-flex.pf-m-align-content-flex-end-on-lg{align-content:flex-end}.pf-l-flex.pf-m-align-content-center-on-lg{align-content:center}.pf-l-flex.pf-m-align-content-stretch-on-lg{align-content:stretch}.pf-l-flex.pf-m-align-content-space-between-on-lg{align-content:space-between}.pf-l-flex.pf-m-align-content-space-around-on-lg{align-content:space-around}.pf-l-flex>.pf-m-align-right-on-lg{margin-left:auto}.pf-l-flex>.pf-m-align-left-on-lg{margin-left:0}.pf-l-flex>.pf-m-grow-on-lg{flex-grow:1}.pf-l-flex>.pf-m-shrink-on-lg{flex-shrink:1}.pf-l-flex>.pf-m-full-width-on-lg{width:100%;margin-right:0}.pf-l-flex>.pf-m-flex-1-on-lg{flex:1 0 0}.pf-l-flex>.pf-m-flex-2-on-lg{flex:2 0 0}.pf-l-flex>.pf-m-flex-3-on-lg{flex:3 0 0}.pf-l-flex>.pf-m-flex-4-on-lg{flex:4 0 0}.pf-l-flex>.pf-m-flex-default-on-lg{flex:0 1 auto}.pf-l-flex>.pf-m-flex-none-on-lg{flex:none}.pf-l-flex>.pf-m-align-self-flex-start-on-lg{align-self:flex-start}.pf-l-flex>.pf-m-align-self-flex-end-on-lg{align-self:flex-end}.pf-l-flex>.pf-m-align-self-center-on-lg{align-self:center}.pf-l-flex>.pf-m-align-self-baseline-on-lg{align-self:baseline}.pf-l-flex>.pf-m-align-self-stretch-on-lg{align-self:stretch}}@media (min-width:1200px){.pf-l-flex.pf-m-flex-on-xl{display:var(--pf-l-flex--Display)}.pf-l-flex.pf-m-inline-flex-on-xl{--pf-l-flex--Display:inline-flex}.pf-l-flex.pf-m-column-on-xl{flex-direction:column;align-items:normal}.pf-l-flex.pf-m-column-on-xl>*{margin:0 0 var(--pf-l-flex--spacer) 0}.pf-l-flex.pf-m-column-reverse-on-xl{flex-direction:column-reverse;align-items:normal}.pf-l-flex.pf-m-column-reverse-on-xl>*{margin:var(--pf-l-flex--spacer) 0 0 0}.pf-l-flex.pf-m-row-on-xl{flex-direction:row;align-items:var(--pf-l-flex--m-row--AlignItems)}.pf-l-flex.pf-m-row-on-xl>*{margin:0 var(--pf-l-flex--spacer) 0 0}.pf-l-flex.pf-m-row-reverse-on-xl{flex-direction:row-reverse;align-items:var(--pf-l-flex--m-row-reverse--AlignItems)}.pf-l-flex.pf-m-row-reverse-on-xl>*{margin:0 0 0 var(--pf-l-flex--spacer)}.pf-l-flex.pf-m-wrap-on-xl{flex-wrap:wrap}.pf-l-flex.pf-m-wrap-reverse-on-xl{flex-wrap:wrap-reverse}.pf-l-flex.pf-m-nowrap-on-xl{flex-wrap:nowrap}.pf-l-flex.pf-m-justify-content-flex-start-on-xl{justify-content:flex-start}.pf-l-flex.pf-m-justify-content-flex-end-on-xl{justify-content:flex-end}.pf-l-flex.pf-m-justify-content-center-on-xl{justify-content:center}.pf-l-flex.pf-m-justify-content-space-between-on-xl{justify-content:space-between}.pf-l-flex.pf-m-justify-content-space-around-on-xl{justify-content:space-around}.pf-l-flex.pf-m-justify-content-space-evenly-on-xl{justify-content:space-evenly}.pf-l-flex.pf-m-align-items-flex-start-on-xl{align-items:flex-start}.pf-l-flex.pf-m-align-items-flex-end-on-xl{align-items:flex-end}.pf-l-flex.pf-m-align-items-center-on-xl{align-items:center}.pf-l-flex.pf-m-align-items-stretch-on-xl{align-items:stretch}.pf-l-flex.pf-m-align-items-baseline-on-xl{align-items:baseline}.pf-l-flex.pf-m-align-content-flex-start-on-xl{align-content:flex-start}.pf-l-flex.pf-m-align-content-flex-end-on-xl{align-content:flex-end}.pf-l-flex.pf-m-align-content-center-on-xl{align-content:center}.pf-l-flex.pf-m-align-content-stretch-on-xl{align-content:stretch}.pf-l-flex.pf-m-align-content-space-between-on-xl{align-content:space-between}.pf-l-flex.pf-m-align-content-space-around-on-xl{align-content:space-around}.pf-l-flex>.pf-m-align-right-on-xl{margin-left:auto}.pf-l-flex>.pf-m-align-left-on-xl{margin-left:0}.pf-l-flex>.pf-m-grow-on-xl{flex-grow:1}.pf-l-flex>.pf-m-shrink-on-xl{flex-shrink:1}.pf-l-flex>.pf-m-full-width-on-xl{width:100%;margin-right:0}.pf-l-flex>.pf-m-flex-1-on-xl{flex:1 0 0}.pf-l-flex>.pf-m-flex-2-on-xl{flex:2 0 0}.pf-l-flex>.pf-m-flex-3-on-xl{flex:3 0 0}.pf-l-flex>.pf-m-flex-4-on-xl{flex:4 0 0}.pf-l-flex>.pf-m-flex-default-on-xl{flex:0 1 auto}.pf-l-flex>.pf-m-flex-none-on-xl{flex:none}.pf-l-flex>.pf-m-align-self-flex-start-on-xl{align-self:flex-start}.pf-l-flex>.pf-m-align-self-flex-end-on-xl{align-self:flex-end}.pf-l-flex>.pf-m-align-self-center-on-xl{align-self:center}.pf-l-flex>.pf-m-align-self-baseline-on-xl{align-self:baseline}.pf-l-flex>.pf-m-align-self-stretch-on-xl{align-self:stretch}}@media (min-width:1450px){.pf-l-flex.pf-m-flex-on-2xl{display:var(--pf-l-flex--Display)}.pf-l-flex.pf-m-inline-flex-on-2xl{--pf-l-flex--Display:inline-flex}.pf-l-flex.pf-m-column-on-2xl{flex-direction:column;align-items:normal}.pf-l-flex.pf-m-column-on-2xl>*{margin:0 0 var(--pf-l-flex--spacer) 0}.pf-l-flex.pf-m-column-reverse-on-2xl{flex-direction:column-reverse;align-items:normal}.pf-l-flex.pf-m-column-reverse-on-2xl>*{margin:var(--pf-l-flex--spacer) 0 0 0}.pf-l-flex.pf-m-row-on-2xl{flex-direction:row;align-items:var(--pf-l-flex--m-row--AlignItems)}.pf-l-flex.pf-m-row-on-2xl>*{margin:0 var(--pf-l-flex--spacer) 0 0}.pf-l-flex.pf-m-row-reverse-on-2xl{flex-direction:row-reverse;align-items:var(--pf-l-flex--m-row-reverse--AlignItems)}.pf-l-flex.pf-m-row-reverse-on-2xl>*{margin:0 0 0 var(--pf-l-flex--spacer)}.pf-l-flex.pf-m-wrap-on-2xl{flex-wrap:wrap}.pf-l-flex.pf-m-wrap-reverse-on-2xl{flex-wrap:wrap-reverse}.pf-l-flex.pf-m-nowrap-on-2xl{flex-wrap:nowrap}.pf-l-flex.pf-m-justify-content-flex-start-on-2xl{justify-content:flex-start}.pf-l-flex.pf-m-justify-content-flex-end-on-2xl{justify-content:flex-end}.pf-l-flex.pf-m-justify-content-center-on-2xl{justify-content:center}.pf-l-flex.pf-m-justify-content-space-between-on-2xl{justify-content:space-between}.pf-l-flex.pf-m-justify-content-space-around-on-2xl{justify-content:space-around}.pf-l-flex.pf-m-justify-content-space-evenly-on-2xl{justify-content:space-evenly}.pf-l-flex.pf-m-align-items-flex-start-on-2xl{align-items:flex-start}.pf-l-flex.pf-m-align-items-flex-end-on-2xl{align-items:flex-end}.pf-l-flex.pf-m-align-items-center-on-2xl{align-items:center}.pf-l-flex.pf-m-align-items-stretch-on-2xl{align-items:stretch}.pf-l-flex.pf-m-align-items-baseline-on-2xl{align-items:baseline}.pf-l-flex.pf-m-align-content-flex-start-on-2xl{align-content:flex-start}.pf-l-flex.pf-m-align-content-flex-end-on-2xl{align-content:flex-end}.pf-l-flex.pf-m-align-content-center-on-2xl{align-content:center}.pf-l-flex.pf-m-align-content-stretch-on-2xl{align-content:stretch}.pf-l-flex.pf-m-align-content-space-between-on-2xl{align-content:space-between}.pf-l-flex.pf-m-align-content-space-around-on-2xl{align-content:space-around}.pf-l-flex>.pf-m-align-right-on-2xl{margin-left:auto}.pf-l-flex>.pf-m-align-left-on-2xl{margin-left:0}.pf-l-flex>.pf-m-grow-on-2xl{flex-grow:1}.pf-l-flex>.pf-m-shrink-on-2xl{flex-shrink:1}.pf-l-flex>.pf-m-full-width-on-2xl{width:100%;margin-right:0}.pf-l-flex>.pf-m-flex-1-on-2xl{flex:1 0 0}.pf-l-flex>.pf-m-flex-2-on-2xl{flex:2 0 0}.pf-l-flex>.pf-m-flex-3-on-2xl{flex:3 0 0}.pf-l-flex>.pf-m-flex-4-on-2xl{flex:4 0 0}.pf-l-flex>.pf-m-flex-default-on-2xl{flex:0 1 auto}.pf-l-flex>.pf-m-flex-none-on-2xl{flex:none}.pf-l-flex>.pf-m-align-self-flex-start-on-2xl{align-self:flex-start}.pf-l-flex>.pf-m-align-self-flex-end-on-2xl{align-self:flex-end}.pf-l-flex>.pf-m-align-self-center-on-2xl{align-self:center}.pf-l-flex>.pf-m-align-self-baseline-on-2xl{align-self:baseline}.pf-l-flex>.pf-m-align-self-stretch-on-2xl{align-self:stretch}}.pf-l-flex.pf-m-space-items-none>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--none)}.pf-l-flex.pf-m-space-items-none>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-xs>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--xs)}.pf-l-flex.pf-m-space-items-xs>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-sm>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--sm)}.pf-l-flex.pf-m-space-items-sm>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-md>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--md)}.pf-l-flex.pf-m-space-items-md>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-lg>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--lg)}.pf-l-flex.pf-m-space-items-lg>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-xl>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--xl)}.pf-l-flex.pf-m-space-items-xl>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-2xl>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--2xl)}.pf-l-flex.pf-m-space-items-2xl>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-3xl>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--3xl)}.pf-l-flex.pf-m-space-items-3xl>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-4xl>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--4xl)}.pf-l-flex.pf-m-space-items-4xl>:last-child{--pf-l-flex--spacer:0}@media (min-width:576px){.pf-l-flex.pf-m-space-items-none-on-sm>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--none)}.pf-l-flex.pf-m-space-items-none-on-sm>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-xs-on-sm>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--xs)}.pf-l-flex.pf-m-space-items-xs-on-sm>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-sm-on-sm>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--sm)}.pf-l-flex.pf-m-space-items-sm-on-sm>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-md-on-sm>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--md)}.pf-l-flex.pf-m-space-items-md-on-sm>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-lg-on-sm>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--lg)}.pf-l-flex.pf-m-space-items-lg-on-sm>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-xl-on-sm>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--xl)}.pf-l-flex.pf-m-space-items-xl-on-sm>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-2xl-on-sm>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--2xl)}.pf-l-flex.pf-m-space-items-2xl-on-sm>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-3xl-on-sm>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--3xl)}.pf-l-flex.pf-m-space-items-3xl-on-sm>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-4xl-on-sm>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--4xl)}.pf-l-flex.pf-m-space-items-4xl-on-sm>:last-child{--pf-l-flex--spacer:0}}@media (min-width:768px){.pf-l-flex.pf-m-space-items-none-on-md>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--none)}.pf-l-flex.pf-m-space-items-none-on-md>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-xs-on-md>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--xs)}.pf-l-flex.pf-m-space-items-xs-on-md>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-sm-on-md>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--sm)}.pf-l-flex.pf-m-space-items-sm-on-md>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-md-on-md>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--md)}.pf-l-flex.pf-m-space-items-md-on-md>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-lg-on-md>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--lg)}.pf-l-flex.pf-m-space-items-lg-on-md>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-xl-on-md>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--xl)}.pf-l-flex.pf-m-space-items-xl-on-md>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-2xl-on-md>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--2xl)}.pf-l-flex.pf-m-space-items-2xl-on-md>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-3xl-on-md>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--3xl)}.pf-l-flex.pf-m-space-items-3xl-on-md>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-4xl-on-md>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--4xl)}.pf-l-flex.pf-m-space-items-4xl-on-md>:last-child{--pf-l-flex--spacer:0}}@media (min-width:992px){.pf-l-flex.pf-m-space-items-none-on-lg>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--none)}.pf-l-flex.pf-m-space-items-none-on-lg>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-xs-on-lg>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--xs)}.pf-l-flex.pf-m-space-items-xs-on-lg>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-sm-on-lg>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--sm)}.pf-l-flex.pf-m-space-items-sm-on-lg>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-md-on-lg>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--md)}.pf-l-flex.pf-m-space-items-md-on-lg>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-lg-on-lg>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--lg)}.pf-l-flex.pf-m-space-items-lg-on-lg>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-xl-on-lg>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--xl)}.pf-l-flex.pf-m-space-items-xl-on-lg>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-2xl-on-lg>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--2xl)}.pf-l-flex.pf-m-space-items-2xl-on-lg>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-3xl-on-lg>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--3xl)}.pf-l-flex.pf-m-space-items-3xl-on-lg>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-4xl-on-lg>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--4xl)}.pf-l-flex.pf-m-space-items-4xl-on-lg>:last-child{--pf-l-flex--spacer:0}}@media (min-width:1200px){.pf-l-flex.pf-m-space-items-none-on-xl>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--none)}.pf-l-flex.pf-m-space-items-none-on-xl>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-xs-on-xl>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--xs)}.pf-l-flex.pf-m-space-items-xs-on-xl>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-sm-on-xl>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--sm)}.pf-l-flex.pf-m-space-items-sm-on-xl>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-md-on-xl>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--md)}.pf-l-flex.pf-m-space-items-md-on-xl>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-lg-on-xl>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--lg)}.pf-l-flex.pf-m-space-items-lg-on-xl>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-xl-on-xl>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--xl)}.pf-l-flex.pf-m-space-items-xl-on-xl>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-2xl-on-xl>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--2xl)}.pf-l-flex.pf-m-space-items-2xl-on-xl>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-3xl-on-xl>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--3xl)}.pf-l-flex.pf-m-space-items-3xl-on-xl>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-4xl-on-xl>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--4xl)}.pf-l-flex.pf-m-space-items-4xl-on-xl>:last-child{--pf-l-flex--spacer:0}}@media (min-width:1450px){.pf-l-flex.pf-m-space-items-none-on-2xl>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--none)}.pf-l-flex.pf-m-space-items-none-on-2xl>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-xs-on-2xl>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--xs)}.pf-l-flex.pf-m-space-items-xs-on-2xl>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-sm-on-2xl>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--sm)}.pf-l-flex.pf-m-space-items-sm-on-2xl>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-md-on-2xl>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--md)}.pf-l-flex.pf-m-space-items-md-on-2xl>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-lg-on-2xl>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--lg)}.pf-l-flex.pf-m-space-items-lg-on-2xl>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-xl-on-2xl>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--xl)}.pf-l-flex.pf-m-space-items-xl-on-2xl>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-2xl-on-2xl>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--2xl)}.pf-l-flex.pf-m-space-items-2xl-on-2xl>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-3xl-on-2xl>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--3xl)}.pf-l-flex.pf-m-space-items-3xl-on-2xl>:last-child{--pf-l-flex--spacer:0}.pf-l-flex.pf-m-space-items-4xl-on-2xl>*{--pf-l-flex--spacer:var(--pf-l-flex--spacer--4xl)}.pf-l-flex.pf-m-space-items-4xl-on-2xl>:last-child{--pf-l-flex--spacer:0}}.pf-l-flex .pf-m-spacer-none,.pf-l-flex .pf-m-spacer-none:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--none)}.pf-l-flex .pf-m-spacer-xs,.pf-l-flex .pf-m-spacer-xs:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--xs)}.pf-l-flex .pf-m-spacer-sm,.pf-l-flex .pf-m-spacer-sm:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--sm)}.pf-l-flex .pf-m-spacer-md,.pf-l-flex .pf-m-spacer-md:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--md)}.pf-l-flex .pf-m-spacer-lg,.pf-l-flex .pf-m-spacer-lg:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--lg)}.pf-l-flex .pf-m-spacer-xl,.pf-l-flex .pf-m-spacer-xl:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--xl)}.pf-l-flex .pf-m-spacer-2xl,.pf-l-flex .pf-m-spacer-2xl:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--2xl)}.pf-l-flex .pf-m-spacer-3xl,.pf-l-flex .pf-m-spacer-3xl:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--3xl)}.pf-l-flex .pf-m-spacer-4xl,.pf-l-flex .pf-m-spacer-4xl:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--4xl)}@media (min-width:576px){.pf-l-flex .pf-m-spacer-none-on-sm,.pf-l-flex .pf-m-spacer-none-on-sm:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--none)}.pf-l-flex .pf-m-spacer-xs-on-sm,.pf-l-flex .pf-m-spacer-xs-on-sm:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--xs)}.pf-l-flex .pf-m-spacer-sm-on-sm,.pf-l-flex .pf-m-spacer-sm-on-sm:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--sm)}.pf-l-flex .pf-m-spacer-md-on-sm,.pf-l-flex .pf-m-spacer-md-on-sm:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--md)}.pf-l-flex .pf-m-spacer-lg-on-sm,.pf-l-flex .pf-m-spacer-lg-on-sm:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--lg)}.pf-l-flex .pf-m-spacer-xl-on-sm,.pf-l-flex .pf-m-spacer-xl-on-sm:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--xl)}.pf-l-flex .pf-m-spacer-2xl-on-sm,.pf-l-flex .pf-m-spacer-2xl-on-sm:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--2xl)}.pf-l-flex .pf-m-spacer-3xl-on-sm,.pf-l-flex .pf-m-spacer-3xl-on-sm:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--3xl)}.pf-l-flex .pf-m-spacer-4xl-on-sm,.pf-l-flex .pf-m-spacer-4xl-on-sm:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--4xl)}}@media (min-width:768px){.pf-l-flex .pf-m-spacer-none-on-md,.pf-l-flex .pf-m-spacer-none-on-md:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--none)}.pf-l-flex .pf-m-spacer-xs-on-md,.pf-l-flex .pf-m-spacer-xs-on-md:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--xs)}.pf-l-flex .pf-m-spacer-sm-on-md,.pf-l-flex .pf-m-spacer-sm-on-md:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--sm)}.pf-l-flex .pf-m-spacer-md-on-md,.pf-l-flex .pf-m-spacer-md-on-md:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--md)}.pf-l-flex .pf-m-spacer-lg-on-md,.pf-l-flex .pf-m-spacer-lg-on-md:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--lg)}.pf-l-flex .pf-m-spacer-xl-on-md,.pf-l-flex .pf-m-spacer-xl-on-md:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--xl)}.pf-l-flex .pf-m-spacer-2xl-on-md,.pf-l-flex .pf-m-spacer-2xl-on-md:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--2xl)}.pf-l-flex .pf-m-spacer-3xl-on-md,.pf-l-flex .pf-m-spacer-3xl-on-md:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--3xl)}.pf-l-flex .pf-m-spacer-4xl-on-md,.pf-l-flex .pf-m-spacer-4xl-on-md:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--4xl)}}@media (min-width:992px){.pf-l-flex .pf-m-spacer-none-on-lg,.pf-l-flex .pf-m-spacer-none-on-lg:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--none)}.pf-l-flex .pf-m-spacer-xs-on-lg,.pf-l-flex .pf-m-spacer-xs-on-lg:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--xs)}.pf-l-flex .pf-m-spacer-sm-on-lg,.pf-l-flex .pf-m-spacer-sm-on-lg:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--sm)}.pf-l-flex .pf-m-spacer-md-on-lg,.pf-l-flex .pf-m-spacer-md-on-lg:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--md)}.pf-l-flex .pf-m-spacer-lg-on-lg,.pf-l-flex .pf-m-spacer-lg-on-lg:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--lg)}.pf-l-flex .pf-m-spacer-xl-on-lg,.pf-l-flex .pf-m-spacer-xl-on-lg:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--xl)}.pf-l-flex .pf-m-spacer-2xl-on-lg,.pf-l-flex .pf-m-spacer-2xl-on-lg:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--2xl)}.pf-l-flex .pf-m-spacer-3xl-on-lg,.pf-l-flex .pf-m-spacer-3xl-on-lg:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--3xl)}.pf-l-flex .pf-m-spacer-4xl-on-lg,.pf-l-flex .pf-m-spacer-4xl-on-lg:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--4xl)}}@media (min-width:1200px){.pf-l-flex .pf-m-spacer-none-on-xl,.pf-l-flex .pf-m-spacer-none-on-xl:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--none)}.pf-l-flex .pf-m-spacer-xs-on-xl,.pf-l-flex .pf-m-spacer-xs-on-xl:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--xs)}.pf-l-flex .pf-m-spacer-sm-on-xl,.pf-l-flex .pf-m-spacer-sm-on-xl:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--sm)}.pf-l-flex .pf-m-spacer-md-on-xl,.pf-l-flex .pf-m-spacer-md-on-xl:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--md)}.pf-l-flex .pf-m-spacer-lg-on-xl,.pf-l-flex .pf-m-spacer-lg-on-xl:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--lg)}.pf-l-flex .pf-m-spacer-xl-on-xl,.pf-l-flex .pf-m-spacer-xl-on-xl:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--xl)}.pf-l-flex .pf-m-spacer-2xl-on-xl,.pf-l-flex .pf-m-spacer-2xl-on-xl:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--2xl)}.pf-l-flex .pf-m-spacer-3xl-on-xl,.pf-l-flex .pf-m-spacer-3xl-on-xl:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--3xl)}.pf-l-flex .pf-m-spacer-4xl-on-xl,.pf-l-flex .pf-m-spacer-4xl-on-xl:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--4xl)}}@media (min-width:1450px){.pf-l-flex .pf-m-spacer-none-on-2xl,.pf-l-flex .pf-m-spacer-none-on-2xl:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--none)}.pf-l-flex .pf-m-spacer-xs-on-2xl,.pf-l-flex .pf-m-spacer-xs-on-2xl:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--xs)}.pf-l-flex .pf-m-spacer-sm-on-2xl,.pf-l-flex .pf-m-spacer-sm-on-2xl:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--sm)}.pf-l-flex .pf-m-spacer-md-on-2xl,.pf-l-flex .pf-m-spacer-md-on-2xl:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--md)}.pf-l-flex .pf-m-spacer-lg-on-2xl,.pf-l-flex .pf-m-spacer-lg-on-2xl:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--lg)}.pf-l-flex .pf-m-spacer-xl-on-2xl,.pf-l-flex .pf-m-spacer-xl-on-2xl:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--xl)}.pf-l-flex .pf-m-spacer-2xl-on-2xl,.pf-l-flex .pf-m-spacer-2xl-on-2xl:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--2xl)}.pf-l-flex .pf-m-spacer-3xl-on-2xl,.pf-l-flex .pf-m-spacer-3xl-on-2xl:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--3xl)}.pf-l-flex .pf-m-spacer-4xl-on-2xl,.pf-l-flex .pf-m-spacer-4xl-on-2xl:last-child{--pf-l-flex--spacer:var(--pf-l-flex--spacer--4xl)}}.pf-l-gallery{--pf-l-gallery--m-gutter--GridGap:var(--pf-global--gutter);--pf-l-gallery--GridTemplateColumns--min:250px;--pf-l-gallery--GridTemplateColumns--max:1fr;--pf-l-gallery--GridTemplateColumns:repeat(auto-fill,minmax(var(--pf-l-gallery--GridTemplateColumns--minmax--min),var(--pf-l-gallery--GridTemplateColumns--minmax--max)));--pf-l-gallery--GridTemplateRows:auto;display:grid;grid-template-columns:var(--pf-l-gallery--GridTemplateColumns);grid-template-rows:var(--pf-l-gallery--GridTemplateRows);--pf-l-gallery--GridTemplateColumns--minmax--min:var(--pf-l-gallery--GridTemplateColumns--min);--pf-l-gallery--GridTemplateColumns--minmax--max:var(--pf-l-gallery--GridTemplateColumns--max)}.pf-l-gallery.pf-m-gutter{grid-gap:var(--pf-l-gallery--m-gutter--GridGap)}@media (min-width:576px){.pf-l-gallery{--pf-l-gallery--GridTemplateColumns--minmax--min:var(--pf-l-gallery--GridTemplateColumns--min-on-sm,var(--pf-l-gallery--GridTemplateColumns--min))}}@media (min-width:768px){.pf-l-gallery{--pf-l-gallery--GridTemplateColumns--minmax--min:var(--pf-l-gallery--GridTemplateColumns--min-on-md,var(--pf-l-gallery--GridTemplateColumns--min-on-sm,var(--pf-l-gallery--GridTemplateColumns--min)))}}@media (min-width:992px){.pf-l-gallery{--pf-l-gallery--GridTemplateColumns--minmax--min:var(--pf-l-gallery--GridTemplateColumns--min-on-lg,var(--pf-l-gallery--GridTemplateColumns--min-on-md,var(--pf-l-gallery--GridTemplateColumns--min-on-sm,var(--pf-l-gallery--GridTemplateColumns--min))))}}@media (min-width:1200px){.pf-l-gallery{--pf-l-gallery--GridTemplateColumns--minmax--min:var(--pf-l-gallery--GridTemplateColumns--min-on-xl,var(--pf-l-gallery--GridTemplateColumns--min-on-lg,var(--pf-l-gallery--GridTemplateColumns--min-on-md,var(--pf-l-gallery--GridTemplateColumns--min-on-sm,var(--pf-l-gallery--GridTemplateColumns--min)))))}}@media (min-width:1450px){.pf-l-gallery{--pf-l-gallery--GridTemplateColumns--minmax--min:var(--pf-l-gallery--GridTemplateColumns--min-on-2xl,var(--pf-l-gallery--GridTemplateColumns--min-on-xl,var(--pf-l-gallery--GridTemplateColumns--min-on-lg,var(--pf-l-gallery--GridTemplateColumns--min-on-md,var(--pf-l-gallery--GridTemplateColumns--min-on-sm,var(--pf-l-gallery--GridTemplateColumns--min))))))}}@media (min-width:576px){.pf-l-gallery{--pf-l-gallery--GridTemplateColumns--minmax--max:var(--pf-l-gallery--GridTemplateColumns--max-on-sm,var(--pf-l-gallery--GridTemplateColumns--max))}}@media (min-width:768px){.pf-l-gallery{--pf-l-gallery--GridTemplateColumns--minmax--max:var(--pf-l-gallery--GridTemplateColumns--max-on-md,var(--pf-l-gallery--GridTemplateColumns--max-on-sm,var(--pf-l-gallery--GridTemplateColumns--max)))}}@media (min-width:992px){.pf-l-gallery{--pf-l-gallery--GridTemplateColumns--minmax--max:var(--pf-l-gallery--GridTemplateColumns--max-on-lg,var(--pf-l-gallery--GridTemplateColumns--max-on-md,var(--pf-l-gallery--GridTemplateColumns--max-on-sm,var(--pf-l-gallery--GridTemplateColumns--max))))}}@media (min-width:1200px){.pf-l-gallery{--pf-l-gallery--GridTemplateColumns--minmax--max:var(--pf-l-gallery--GridTemplateColumns--max-on-xl,var(--pf-l-gallery--GridTemplateColumns--max-on-lg,var(--pf-l-gallery--GridTemplateColumns--max-on-md,var(--pf-l-gallery--GridTemplateColumns--max-on-sm,var(--pf-l-gallery--GridTemplateColumns--max)))))}}@media (min-width:1450px){.pf-l-gallery{--pf-l-gallery--GridTemplateColumns--minmax--max:var(--pf-l-gallery--GridTemplateColumns--max-on-2xl,var(--pf-l-gallery--GridTemplateColumns--max-on-xl,var(--pf-l-gallery--GridTemplateColumns--max-on-lg,var(--pf-l-gallery--GridTemplateColumns--max-on-md,var(--pf-l-gallery--GridTemplateColumns--max-on-sm,var(--pf-l-gallery--GridTemplateColumns--max))))))}}.pf-l-grid{--pf-l-grid--m-gutter--GridGap:var(--pf-global--gutter);--pf-l-grid__item--GridColumnStart:auto;--pf-l-grid__item--GridColumnEnd:span 12;--pf-l-grid--item--Order:0;display:grid;grid-template-columns:repeat(12,[col-start] 1fr)}.pf-l-grid .pf-l-grid__item,.pf-l-grid>*{min-width:0;min-height:0;grid-column-start:var(--pf-l-grid__item--GridColumnStart);grid-column-end:var(--pf-l-grid__item--GridColumnEnd);order:var(--pf-l-grid--item--Order)}@media (min-width:576px){.pf-l-grid .pf-l-grid__item,.pf-l-grid>*{order:var(--pf-l-grid--item--Order-on-sm,var(--pf-l-grid--item--Order))}}@media (min-width:768px){.pf-l-grid .pf-l-grid__item,.pf-l-grid>*{order:var(--pf-l-grid--item--Order-on-md,var(--pf-l-grid--item--Order-on-sm,var(--pf-l-grid--item--Order)))}}@media (min-width:992px){.pf-l-grid .pf-l-grid__item,.pf-l-grid>*{order:var(--pf-l-grid--item--Order-on-lg,var(--pf-l-grid--item--Order-on-md,var(--pf-l-grid--item--Order-on-sm,var(--pf-l-grid--item--Order))))}}@media (min-width:1200px){.pf-l-grid .pf-l-grid__item,.pf-l-grid>*{order:var(--pf-l-grid--item--Order-on-xl,var(--pf-l-grid--item--Order-on-lg,var(--pf-l-grid--item--Order-on-md,var(--pf-l-grid--item--Order-on-sm,var(--pf-l-grid--item--Order)))))}}@media (min-width:1450px){.pf-l-grid .pf-l-grid__item,.pf-l-grid>*{order:var(--pf-l-grid--item--Order-on-2xl,var(--pf-l-grid--item--Order-on-xl,var(--pf-l-grid--item--Order-on-lg,var(--pf-l-grid--item--Order-on-md,var(--pf-l-grid--item--Order-on-sm,var(--pf-l-grid--item--Order))))))}}.pf-l-grid.pf-m-all-1-col>*{--pf-l-grid__item--GridColumnEnd:span 1}.pf-l-grid.pf-m-all-2-col>*{--pf-l-grid__item--GridColumnEnd:span 2}.pf-l-grid.pf-m-all-3-col>*{--pf-l-grid__item--GridColumnEnd:span 3}.pf-l-grid.pf-m-all-4-col>*{--pf-l-grid__item--GridColumnEnd:span 4}.pf-l-grid.pf-m-all-5-col>*{--pf-l-grid__item--GridColumnEnd:span 5}.pf-l-grid.pf-m-all-6-col>*{--pf-l-grid__item--GridColumnEnd:span 6}.pf-l-grid.pf-m-all-7-col>*{--pf-l-grid__item--GridColumnEnd:span 7}.pf-l-grid.pf-m-all-8-col>*{--pf-l-grid__item--GridColumnEnd:span 8}.pf-l-grid.pf-m-all-9-col>*{--pf-l-grid__item--GridColumnEnd:span 9}.pf-l-grid.pf-m-all-10-col>*{--pf-l-grid__item--GridColumnEnd:span 10}.pf-l-grid.pf-m-all-11-col>*{--pf-l-grid__item--GridColumnEnd:span 11}.pf-l-grid.pf-m-all-12-col>*{--pf-l-grid__item--GridColumnEnd:span 12}@media screen and (min-width:576px){.pf-l-grid.pf-m-all-1-col-on-sm>*{--pf-l-grid__item--GridColumnEnd:span 1}.pf-l-grid.pf-m-all-2-col-on-sm>*{--pf-l-grid__item--GridColumnEnd:span 2}.pf-l-grid.pf-m-all-3-col-on-sm>*{--pf-l-grid__item--GridColumnEnd:span 3}.pf-l-grid.pf-m-all-4-col-on-sm>*{--pf-l-grid__item--GridColumnEnd:span 4}.pf-l-grid.pf-m-all-5-col-on-sm>*{--pf-l-grid__item--GridColumnEnd:span 5}.pf-l-grid.pf-m-all-6-col-on-sm>*{--pf-l-grid__item--GridColumnEnd:span 6}.pf-l-grid.pf-m-all-7-col-on-sm>*{--pf-l-grid__item--GridColumnEnd:span 7}.pf-l-grid.pf-m-all-8-col-on-sm>*{--pf-l-grid__item--GridColumnEnd:span 8}.pf-l-grid.pf-m-all-9-col-on-sm>*{--pf-l-grid__item--GridColumnEnd:span 9}.pf-l-grid.pf-m-all-10-col-on-sm>*{--pf-l-grid__item--GridColumnEnd:span 10}.pf-l-grid.pf-m-all-11-col-on-sm>*{--pf-l-grid__item--GridColumnEnd:span 11}.pf-l-grid.pf-m-all-12-col-on-sm>*{--pf-l-grid__item--GridColumnEnd:span 12}}@media screen and (min-width:768px){.pf-l-grid.pf-m-all-1-col-on-md>*{--pf-l-grid__item--GridColumnEnd:span 1}.pf-l-grid.pf-m-all-2-col-on-md>*{--pf-l-grid__item--GridColumnEnd:span 2}.pf-l-grid.pf-m-all-3-col-on-md>*{--pf-l-grid__item--GridColumnEnd:span 3}.pf-l-grid.pf-m-all-4-col-on-md>*{--pf-l-grid__item--GridColumnEnd:span 4}.pf-l-grid.pf-m-all-5-col-on-md>*{--pf-l-grid__item--GridColumnEnd:span 5}.pf-l-grid.pf-m-all-6-col-on-md>*{--pf-l-grid__item--GridColumnEnd:span 6}.pf-l-grid.pf-m-all-7-col-on-md>*{--pf-l-grid__item--GridColumnEnd:span 7}.pf-l-grid.pf-m-all-8-col-on-md>*{--pf-l-grid__item--GridColumnEnd:span 8}.pf-l-grid.pf-m-all-9-col-on-md>*{--pf-l-grid__item--GridColumnEnd:span 9}.pf-l-grid.pf-m-all-10-col-on-md>*{--pf-l-grid__item--GridColumnEnd:span 10}.pf-l-grid.pf-m-all-11-col-on-md>*{--pf-l-grid__item--GridColumnEnd:span 11}.pf-l-grid.pf-m-all-12-col-on-md>*{--pf-l-grid__item--GridColumnEnd:span 12}}@media screen and (min-width:992px){.pf-l-grid.pf-m-all-1-col-on-lg>*{--pf-l-grid__item--GridColumnEnd:span 1}.pf-l-grid.pf-m-all-2-col-on-lg>*{--pf-l-grid__item--GridColumnEnd:span 2}.pf-l-grid.pf-m-all-3-col-on-lg>*{--pf-l-grid__item--GridColumnEnd:span 3}.pf-l-grid.pf-m-all-4-col-on-lg>*{--pf-l-grid__item--GridColumnEnd:span 4}.pf-l-grid.pf-m-all-5-col-on-lg>*{--pf-l-grid__item--GridColumnEnd:span 5}.pf-l-grid.pf-m-all-6-col-on-lg>*{--pf-l-grid__item--GridColumnEnd:span 6}.pf-l-grid.pf-m-all-7-col-on-lg>*{--pf-l-grid__item--GridColumnEnd:span 7}.pf-l-grid.pf-m-all-8-col-on-lg>*{--pf-l-grid__item--GridColumnEnd:span 8}.pf-l-grid.pf-m-all-9-col-on-lg>*{--pf-l-grid__item--GridColumnEnd:span 9}.pf-l-grid.pf-m-all-10-col-on-lg>*{--pf-l-grid__item--GridColumnEnd:span 10}.pf-l-grid.pf-m-all-11-col-on-lg>*{--pf-l-grid__item--GridColumnEnd:span 11}.pf-l-grid.pf-m-all-12-col-on-lg>*{--pf-l-grid__item--GridColumnEnd:span 12}}@media screen and (min-width:1200px){.pf-l-grid.pf-m-all-1-col-on-xl>*{--pf-l-grid__item--GridColumnEnd:span 1}.pf-l-grid.pf-m-all-2-col-on-xl>*{--pf-l-grid__item--GridColumnEnd:span 2}.pf-l-grid.pf-m-all-3-col-on-xl>*{--pf-l-grid__item--GridColumnEnd:span 3}.pf-l-grid.pf-m-all-4-col-on-xl>*{--pf-l-grid__item--GridColumnEnd:span 4}.pf-l-grid.pf-m-all-5-col-on-xl>*{--pf-l-grid__item--GridColumnEnd:span 5}.pf-l-grid.pf-m-all-6-col-on-xl>*{--pf-l-grid__item--GridColumnEnd:span 6}.pf-l-grid.pf-m-all-7-col-on-xl>*{--pf-l-grid__item--GridColumnEnd:span 7}.pf-l-grid.pf-m-all-8-col-on-xl>*{--pf-l-grid__item--GridColumnEnd:span 8}.pf-l-grid.pf-m-all-9-col-on-xl>*{--pf-l-grid__item--GridColumnEnd:span 9}.pf-l-grid.pf-m-all-10-col-on-xl>*{--pf-l-grid__item--GridColumnEnd:span 10}.pf-l-grid.pf-m-all-11-col-on-xl>*{--pf-l-grid__item--GridColumnEnd:span 11}.pf-l-grid.pf-m-all-12-col-on-xl>*{--pf-l-grid__item--GridColumnEnd:span 12}}@media screen and (min-width:1450px){.pf-l-grid.pf-m-all-1-col-on-2xl>*{--pf-l-grid__item--GridColumnEnd:span 1}.pf-l-grid.pf-m-all-2-col-on-2xl>*{--pf-l-grid__item--GridColumnEnd:span 2}.pf-l-grid.pf-m-all-3-col-on-2xl>*{--pf-l-grid__item--GridColumnEnd:span 3}.pf-l-grid.pf-m-all-4-col-on-2xl>*{--pf-l-grid__item--GridColumnEnd:span 4}.pf-l-grid.pf-m-all-5-col-on-2xl>*{--pf-l-grid__item--GridColumnEnd:span 5}.pf-l-grid.pf-m-all-6-col-on-2xl>*{--pf-l-grid__item--GridColumnEnd:span 6}.pf-l-grid.pf-m-all-7-col-on-2xl>*{--pf-l-grid__item--GridColumnEnd:span 7}.pf-l-grid.pf-m-all-8-col-on-2xl>*{--pf-l-grid__item--GridColumnEnd:span 8}.pf-l-grid.pf-m-all-9-col-on-2xl>*{--pf-l-grid__item--GridColumnEnd:span 9}.pf-l-grid.pf-m-all-10-col-on-2xl>*{--pf-l-grid__item--GridColumnEnd:span 10}.pf-l-grid.pf-m-all-11-col-on-2xl>*{--pf-l-grid__item--GridColumnEnd:span 11}.pf-l-grid.pf-m-all-12-col-on-2xl>*{--pf-l-grid__item--GridColumnEnd:span 12}}.pf-l-grid>.pf-m-1-col{--pf-l-grid__item--GridColumnEnd:span 1}.pf-l-grid>.pf-m-2-col{--pf-l-grid__item--GridColumnEnd:span 2}.pf-l-grid>.pf-m-3-col{--pf-l-grid__item--GridColumnEnd:span 3}.pf-l-grid>.pf-m-4-col{--pf-l-grid__item--GridColumnEnd:span 4}.pf-l-grid>.pf-m-5-col{--pf-l-grid__item--GridColumnEnd:span 5}.pf-l-grid>.pf-m-6-col{--pf-l-grid__item--GridColumnEnd:span 6}.pf-l-grid>.pf-m-7-col{--pf-l-grid__item--GridColumnEnd:span 7}.pf-l-grid>.pf-m-8-col{--pf-l-grid__item--GridColumnEnd:span 8}.pf-l-grid>.pf-m-9-col{--pf-l-grid__item--GridColumnEnd:span 9}.pf-l-grid>.pf-m-10-col{--pf-l-grid__item--GridColumnEnd:span 10}.pf-l-grid>.pf-m-11-col{--pf-l-grid__item--GridColumnEnd:span 11}.pf-l-grid>.pf-m-12-col{--pf-l-grid__item--GridColumnEnd:span 12}.pf-l-grid>.pf-m-offset-1-col{--pf-l-grid__item--GridColumnStart:col-start 2}.pf-l-grid>.pf-m-offset-2-col{--pf-l-grid__item--GridColumnStart:col-start 3}.pf-l-grid>.pf-m-offset-3-col{--pf-l-grid__item--GridColumnStart:col-start 4}.pf-l-grid>.pf-m-offset-4-col{--pf-l-grid__item--GridColumnStart:col-start 5}.pf-l-grid>.pf-m-offset-5-col{--pf-l-grid__item--GridColumnStart:col-start 6}.pf-l-grid>.pf-m-offset-6-col{--pf-l-grid__item--GridColumnStart:col-start 7}.pf-l-grid>.pf-m-offset-7-col{--pf-l-grid__item--GridColumnStart:col-start 8}.pf-l-grid>.pf-m-offset-8-col{--pf-l-grid__item--GridColumnStart:col-start 9}.pf-l-grid>.pf-m-offset-9-col{--pf-l-grid__item--GridColumnStart:col-start 10}.pf-l-grid>.pf-m-offset-10-col{--pf-l-grid__item--GridColumnStart:col-start 11}.pf-l-grid>.pf-m-offset-11-col{--pf-l-grid__item--GridColumnStart:col-start 12}.pf-l-grid>.pf-m-offset-12-col{--pf-l-grid__item--GridColumnStart:col-start 13}.pf-l-grid>.pf-m-1-row{grid-row:span 1}.pf-l-grid>.pf-m-2-row{grid-row:span 2}.pf-l-grid>.pf-m-3-row{grid-row:span 3}.pf-l-grid>.pf-m-4-row{grid-row:span 4}.pf-l-grid>.pf-m-5-row{grid-row:span 5}.pf-l-grid>.pf-m-6-row{grid-row:span 6}.pf-l-grid>.pf-m-7-row{grid-row:span 7}.pf-l-grid>.pf-m-8-row{grid-row:span 8}.pf-l-grid>.pf-m-9-row{grid-row:span 9}.pf-l-grid>.pf-m-10-row{grid-row:span 10}.pf-l-grid>.pf-m-11-row{grid-row:span 11}.pf-l-grid>.pf-m-12-row{grid-row:span 12}@media screen and (min-width:576px){.pf-l-grid>.pf-m-1-col-on-sm{--pf-l-grid__item--GridColumnEnd:span 1}.pf-l-grid>.pf-m-2-col-on-sm{--pf-l-grid__item--GridColumnEnd:span 2}.pf-l-grid>.pf-m-3-col-on-sm{--pf-l-grid__item--GridColumnEnd:span 3}.pf-l-grid>.pf-m-4-col-on-sm{--pf-l-grid__item--GridColumnEnd:span 4}.pf-l-grid>.pf-m-5-col-on-sm{--pf-l-grid__item--GridColumnEnd:span 5}.pf-l-grid>.pf-m-6-col-on-sm{--pf-l-grid__item--GridColumnEnd:span 6}.pf-l-grid>.pf-m-7-col-on-sm{--pf-l-grid__item--GridColumnEnd:span 7}.pf-l-grid>.pf-m-8-col-on-sm{--pf-l-grid__item--GridColumnEnd:span 8}.pf-l-grid>.pf-m-9-col-on-sm{--pf-l-grid__item--GridColumnEnd:span 9}.pf-l-grid>.pf-m-10-col-on-sm{--pf-l-grid__item--GridColumnEnd:span 10}.pf-l-grid>.pf-m-11-col-on-sm{--pf-l-grid__item--GridColumnEnd:span 11}.pf-l-grid>.pf-m-12-col-on-sm{--pf-l-grid__item--GridColumnEnd:span 12}.pf-l-grid>.pf-m-offset-1-col-on-sm{--pf-l-grid__item--GridColumnStart:col-start 2}.pf-l-grid>.pf-m-offset-2-col-on-sm{--pf-l-grid__item--GridColumnStart:col-start 3}.pf-l-grid>.pf-m-offset-3-col-on-sm{--pf-l-grid__item--GridColumnStart:col-start 4}.pf-l-grid>.pf-m-offset-4-col-on-sm{--pf-l-grid__item--GridColumnStart:col-start 5}.pf-l-grid>.pf-m-offset-5-col-on-sm{--pf-l-grid__item--GridColumnStart:col-start 6}.pf-l-grid>.pf-m-offset-6-col-on-sm{--pf-l-grid__item--GridColumnStart:col-start 7}.pf-l-grid>.pf-m-offset-7-col-on-sm{--pf-l-grid__item--GridColumnStart:col-start 8}.pf-l-grid>.pf-m-offset-8-col-on-sm{--pf-l-grid__item--GridColumnStart:col-start 9}.pf-l-grid>.pf-m-offset-9-col-on-sm{--pf-l-grid__item--GridColumnStart:col-start 10}.pf-l-grid>.pf-m-offset-10-col-on-sm{--pf-l-grid__item--GridColumnStart:col-start 11}.pf-l-grid>.pf-m-offset-11-col-on-sm{--pf-l-grid__item--GridColumnStart:col-start 12}.pf-l-grid>.pf-m-offset-12-col-on-sm{--pf-l-grid__item--GridColumnStart:col-start 13}.pf-l-grid>.pf-m-1-row-on-sm{grid-row:span 1}.pf-l-grid>.pf-m-2-row-on-sm{grid-row:span 2}.pf-l-grid>.pf-m-3-row-on-sm{grid-row:span 3}.pf-l-grid>.pf-m-4-row-on-sm{grid-row:span 4}.pf-l-grid>.pf-m-5-row-on-sm{grid-row:span 5}.pf-l-grid>.pf-m-6-row-on-sm{grid-row:span 6}.pf-l-grid>.pf-m-7-row-on-sm{grid-row:span 7}.pf-l-grid>.pf-m-8-row-on-sm{grid-row:span 8}.pf-l-grid>.pf-m-9-row-on-sm{grid-row:span 9}.pf-l-grid>.pf-m-10-row-on-sm{grid-row:span 10}.pf-l-grid>.pf-m-11-row-on-sm{grid-row:span 11}.pf-l-grid>.pf-m-12-row-on-sm{grid-row:span 12}}@media screen and (min-width:768px){.pf-l-grid>.pf-m-1-col-on-md{--pf-l-grid__item--GridColumnEnd:span 1}.pf-l-grid>.pf-m-2-col-on-md{--pf-l-grid__item--GridColumnEnd:span 2}.pf-l-grid>.pf-m-3-col-on-md{--pf-l-grid__item--GridColumnEnd:span 3}.pf-l-grid>.pf-m-4-col-on-md{--pf-l-grid__item--GridColumnEnd:span 4}.pf-l-grid>.pf-m-5-col-on-md{--pf-l-grid__item--GridColumnEnd:span 5}.pf-l-grid>.pf-m-6-col-on-md{--pf-l-grid__item--GridColumnEnd:span 6}.pf-l-grid>.pf-m-7-col-on-md{--pf-l-grid__item--GridColumnEnd:span 7}.pf-l-grid>.pf-m-8-col-on-md{--pf-l-grid__item--GridColumnEnd:span 8}.pf-l-grid>.pf-m-9-col-on-md{--pf-l-grid__item--GridColumnEnd:span 9}.pf-l-grid>.pf-m-10-col-on-md{--pf-l-grid__item--GridColumnEnd:span 10}.pf-l-grid>.pf-m-11-col-on-md{--pf-l-grid__item--GridColumnEnd:span 11}.pf-l-grid>.pf-m-12-col-on-md{--pf-l-grid__item--GridColumnEnd:span 12}.pf-l-grid>.pf-m-offset-1-col-on-md{--pf-l-grid__item--GridColumnStart:col-start 2}.pf-l-grid>.pf-m-offset-2-col-on-md{--pf-l-grid__item--GridColumnStart:col-start 3}.pf-l-grid>.pf-m-offset-3-col-on-md{--pf-l-grid__item--GridColumnStart:col-start 4}.pf-l-grid>.pf-m-offset-4-col-on-md{--pf-l-grid__item--GridColumnStart:col-start 5}.pf-l-grid>.pf-m-offset-5-col-on-md{--pf-l-grid__item--GridColumnStart:col-start 6}.pf-l-grid>.pf-m-offset-6-col-on-md{--pf-l-grid__item--GridColumnStart:col-start 7}.pf-l-grid>.pf-m-offset-7-col-on-md{--pf-l-grid__item--GridColumnStart:col-start 8}.pf-l-grid>.pf-m-offset-8-col-on-md{--pf-l-grid__item--GridColumnStart:col-start 9}.pf-l-grid>.pf-m-offset-9-col-on-md{--pf-l-grid__item--GridColumnStart:col-start 10}.pf-l-grid>.pf-m-offset-10-col-on-md{--pf-l-grid__item--GridColumnStart:col-start 11}.pf-l-grid>.pf-m-offset-11-col-on-md{--pf-l-grid__item--GridColumnStart:col-start 12}.pf-l-grid>.pf-m-offset-12-col-on-md{--pf-l-grid__item--GridColumnStart:col-start 13}.pf-l-grid>.pf-m-1-row-on-md{grid-row:span 1}.pf-l-grid>.pf-m-2-row-on-md{grid-row:span 2}.pf-l-grid>.pf-m-3-row-on-md{grid-row:span 3}.pf-l-grid>.pf-m-4-row-on-md{grid-row:span 4}.pf-l-grid>.pf-m-5-row-on-md{grid-row:span 5}.pf-l-grid>.pf-m-6-row-on-md{grid-row:span 6}.pf-l-grid>.pf-m-7-row-on-md{grid-row:span 7}.pf-l-grid>.pf-m-8-row-on-md{grid-row:span 8}.pf-l-grid>.pf-m-9-row-on-md{grid-row:span 9}.pf-l-grid>.pf-m-10-row-on-md{grid-row:span 10}.pf-l-grid>.pf-m-11-row-on-md{grid-row:span 11}.pf-l-grid>.pf-m-12-row-on-md{grid-row:span 12}}@media screen and (min-width:992px){.pf-l-grid>.pf-m-1-col-on-lg{--pf-l-grid__item--GridColumnEnd:span 1}.pf-l-grid>.pf-m-2-col-on-lg{--pf-l-grid__item--GridColumnEnd:span 2}.pf-l-grid>.pf-m-3-col-on-lg{--pf-l-grid__item--GridColumnEnd:span 3}.pf-l-grid>.pf-m-4-col-on-lg{--pf-l-grid__item--GridColumnEnd:span 4}.pf-l-grid>.pf-m-5-col-on-lg{--pf-l-grid__item--GridColumnEnd:span 5}.pf-l-grid>.pf-m-6-col-on-lg{--pf-l-grid__item--GridColumnEnd:span 6}.pf-l-grid>.pf-m-7-col-on-lg{--pf-l-grid__item--GridColumnEnd:span 7}.pf-l-grid>.pf-m-8-col-on-lg{--pf-l-grid__item--GridColumnEnd:span 8}.pf-l-grid>.pf-m-9-col-on-lg{--pf-l-grid__item--GridColumnEnd:span 9}.pf-l-grid>.pf-m-10-col-on-lg{--pf-l-grid__item--GridColumnEnd:span 10}.pf-l-grid>.pf-m-11-col-on-lg{--pf-l-grid__item--GridColumnEnd:span 11}.pf-l-grid>.pf-m-12-col-on-lg{--pf-l-grid__item--GridColumnEnd:span 12}.pf-l-grid>.pf-m-offset-1-col-on-lg{--pf-l-grid__item--GridColumnStart:col-start 2}.pf-l-grid>.pf-m-offset-2-col-on-lg{--pf-l-grid__item--GridColumnStart:col-start 3}.pf-l-grid>.pf-m-offset-3-col-on-lg{--pf-l-grid__item--GridColumnStart:col-start 4}.pf-l-grid>.pf-m-offset-4-col-on-lg{--pf-l-grid__item--GridColumnStart:col-start 5}.pf-l-grid>.pf-m-offset-5-col-on-lg{--pf-l-grid__item--GridColumnStart:col-start 6}.pf-l-grid>.pf-m-offset-6-col-on-lg{--pf-l-grid__item--GridColumnStart:col-start 7}.pf-l-grid>.pf-m-offset-7-col-on-lg{--pf-l-grid__item--GridColumnStart:col-start 8}.pf-l-grid>.pf-m-offset-8-col-on-lg{--pf-l-grid__item--GridColumnStart:col-start 9}.pf-l-grid>.pf-m-offset-9-col-on-lg{--pf-l-grid__item--GridColumnStart:col-start 10}.pf-l-grid>.pf-m-offset-10-col-on-lg{--pf-l-grid__item--GridColumnStart:col-start 11}.pf-l-grid>.pf-m-offset-11-col-on-lg{--pf-l-grid__item--GridColumnStart:col-start 12}.pf-l-grid>.pf-m-offset-12-col-on-lg{--pf-l-grid__item--GridColumnStart:col-start 13}.pf-l-grid>.pf-m-1-row-on-lg{grid-row:span 1}.pf-l-grid>.pf-m-2-row-on-lg{grid-row:span 2}.pf-l-grid>.pf-m-3-row-on-lg{grid-row:span 3}.pf-l-grid>.pf-m-4-row-on-lg{grid-row:span 4}.pf-l-grid>.pf-m-5-row-on-lg{grid-row:span 5}.pf-l-grid>.pf-m-6-row-on-lg{grid-row:span 6}.pf-l-grid>.pf-m-7-row-on-lg{grid-row:span 7}.pf-l-grid>.pf-m-8-row-on-lg{grid-row:span 8}.pf-l-grid>.pf-m-9-row-on-lg{grid-row:span 9}.pf-l-grid>.pf-m-10-row-on-lg{grid-row:span 10}.pf-l-grid>.pf-m-11-row-on-lg{grid-row:span 11}.pf-l-grid>.pf-m-12-row-on-lg{grid-row:span 12}}@media screen and (min-width:1200px){.pf-l-grid>.pf-m-1-col-on-xl{--pf-l-grid__item--GridColumnEnd:span 1}.pf-l-grid>.pf-m-2-col-on-xl{--pf-l-grid__item--GridColumnEnd:span 2}.pf-l-grid>.pf-m-3-col-on-xl{--pf-l-grid__item--GridColumnEnd:span 3}.pf-l-grid>.pf-m-4-col-on-xl{--pf-l-grid__item--GridColumnEnd:span 4}.pf-l-grid>.pf-m-5-col-on-xl{--pf-l-grid__item--GridColumnEnd:span 5}.pf-l-grid>.pf-m-6-col-on-xl{--pf-l-grid__item--GridColumnEnd:span 6}.pf-l-grid>.pf-m-7-col-on-xl{--pf-l-grid__item--GridColumnEnd:span 7}.pf-l-grid>.pf-m-8-col-on-xl{--pf-l-grid__item--GridColumnEnd:span 8}.pf-l-grid>.pf-m-9-col-on-xl{--pf-l-grid__item--GridColumnEnd:span 9}.pf-l-grid>.pf-m-10-col-on-xl{--pf-l-grid__item--GridColumnEnd:span 10}.pf-l-grid>.pf-m-11-col-on-xl{--pf-l-grid__item--GridColumnEnd:span 11}.pf-l-grid>.pf-m-12-col-on-xl{--pf-l-grid__item--GridColumnEnd:span 12}.pf-l-grid>.pf-m-offset-1-col-on-xl{--pf-l-grid__item--GridColumnStart:col-start 2}.pf-l-grid>.pf-m-offset-2-col-on-xl{--pf-l-grid__item--GridColumnStart:col-start 3}.pf-l-grid>.pf-m-offset-3-col-on-xl{--pf-l-grid__item--GridColumnStart:col-start 4}.pf-l-grid>.pf-m-offset-4-col-on-xl{--pf-l-grid__item--GridColumnStart:col-start 5}.pf-l-grid>.pf-m-offset-5-col-on-xl{--pf-l-grid__item--GridColumnStart:col-start 6}.pf-l-grid>.pf-m-offset-6-col-on-xl{--pf-l-grid__item--GridColumnStart:col-start 7}.pf-l-grid>.pf-m-offset-7-col-on-xl{--pf-l-grid__item--GridColumnStart:col-start 8}.pf-l-grid>.pf-m-offset-8-col-on-xl{--pf-l-grid__item--GridColumnStart:col-start 9}.pf-l-grid>.pf-m-offset-9-col-on-xl{--pf-l-grid__item--GridColumnStart:col-start 10}.pf-l-grid>.pf-m-offset-10-col-on-xl{--pf-l-grid__item--GridColumnStart:col-start 11}.pf-l-grid>.pf-m-offset-11-col-on-xl{--pf-l-grid__item--GridColumnStart:col-start 12}.pf-l-grid>.pf-m-offset-12-col-on-xl{--pf-l-grid__item--GridColumnStart:col-start 13}.pf-l-grid>.pf-m-1-row-on-xl{grid-row:span 1}.pf-l-grid>.pf-m-2-row-on-xl{grid-row:span 2}.pf-l-grid>.pf-m-3-row-on-xl{grid-row:span 3}.pf-l-grid>.pf-m-4-row-on-xl{grid-row:span 4}.pf-l-grid>.pf-m-5-row-on-xl{grid-row:span 5}.pf-l-grid>.pf-m-6-row-on-xl{grid-row:span 6}.pf-l-grid>.pf-m-7-row-on-xl{grid-row:span 7}.pf-l-grid>.pf-m-8-row-on-xl{grid-row:span 8}.pf-l-grid>.pf-m-9-row-on-xl{grid-row:span 9}.pf-l-grid>.pf-m-10-row-on-xl{grid-row:span 10}.pf-l-grid>.pf-m-11-row-on-xl{grid-row:span 11}.pf-l-grid>.pf-m-12-row-on-xl{grid-row:span 12}}@media screen and (min-width:1450px){.pf-l-grid>.pf-m-1-col-on-2xl{--pf-l-grid__item--GridColumnEnd:span 1}.pf-l-grid>.pf-m-2-col-on-2xl{--pf-l-grid__item--GridColumnEnd:span 2}.pf-l-grid>.pf-m-3-col-on-2xl{--pf-l-grid__item--GridColumnEnd:span 3}.pf-l-grid>.pf-m-4-col-on-2xl{--pf-l-grid__item--GridColumnEnd:span 4}.pf-l-grid>.pf-m-5-col-on-2xl{--pf-l-grid__item--GridColumnEnd:span 5}.pf-l-grid>.pf-m-6-col-on-2xl{--pf-l-grid__item--GridColumnEnd:span 6}.pf-l-grid>.pf-m-7-col-on-2xl{--pf-l-grid__item--GridColumnEnd:span 7}.pf-l-grid>.pf-m-8-col-on-2xl{--pf-l-grid__item--GridColumnEnd:span 8}.pf-l-grid>.pf-m-9-col-on-2xl{--pf-l-grid__item--GridColumnEnd:span 9}.pf-l-grid>.pf-m-10-col-on-2xl{--pf-l-grid__item--GridColumnEnd:span 10}.pf-l-grid>.pf-m-11-col-on-2xl{--pf-l-grid__item--GridColumnEnd:span 11}.pf-l-grid>.pf-m-12-col-on-2xl{--pf-l-grid__item--GridColumnEnd:span 12}.pf-l-grid>.pf-m-offset-1-col-on-2xl{--pf-l-grid__item--GridColumnStart:col-start 2}.pf-l-grid>.pf-m-offset-2-col-on-2xl{--pf-l-grid__item--GridColumnStart:col-start 3}.pf-l-grid>.pf-m-offset-3-col-on-2xl{--pf-l-grid__item--GridColumnStart:col-start 4}.pf-l-grid>.pf-m-offset-4-col-on-2xl{--pf-l-grid__item--GridColumnStart:col-start 5}.pf-l-grid>.pf-m-offset-5-col-on-2xl{--pf-l-grid__item--GridColumnStart:col-start 6}.pf-l-grid>.pf-m-offset-6-col-on-2xl{--pf-l-grid__item--GridColumnStart:col-start 7}.pf-l-grid>.pf-m-offset-7-col-on-2xl{--pf-l-grid__item--GridColumnStart:col-start 8}.pf-l-grid>.pf-m-offset-8-col-on-2xl{--pf-l-grid__item--GridColumnStart:col-start 9}.pf-l-grid>.pf-m-offset-9-col-on-2xl{--pf-l-grid__item--GridColumnStart:col-start 10}.pf-l-grid>.pf-m-offset-10-col-on-2xl{--pf-l-grid__item--GridColumnStart:col-start 11}.pf-l-grid>.pf-m-offset-11-col-on-2xl{--pf-l-grid__item--GridColumnStart:col-start 12}.pf-l-grid>.pf-m-offset-12-col-on-2xl{--pf-l-grid__item--GridColumnStart:col-start 13}.pf-l-grid>.pf-m-1-row-on-2xl{grid-row:span 1}.pf-l-grid>.pf-m-2-row-on-2xl{grid-row:span 2}.pf-l-grid>.pf-m-3-row-on-2xl{grid-row:span 3}.pf-l-grid>.pf-m-4-row-on-2xl{grid-row:span 4}.pf-l-grid>.pf-m-5-row-on-2xl{grid-row:span 5}.pf-l-grid>.pf-m-6-row-on-2xl{grid-row:span 6}.pf-l-grid>.pf-m-7-row-on-2xl{grid-row:span 7}.pf-l-grid>.pf-m-8-row-on-2xl{grid-row:span 8}.pf-l-grid>.pf-m-9-row-on-2xl{grid-row:span 9}.pf-l-grid>.pf-m-10-row-on-2xl{grid-row:span 10}.pf-l-grid>.pf-m-11-row-on-2xl{grid-row:span 11}.pf-l-grid>.pf-m-12-row-on-2xl{grid-row:span 12}}.pf-l-grid.pf-m-gutter{grid-gap:var(--pf-l-grid--m-gutter--GridGap)}.pf-l-level{--pf-l-level--m-gutter--MarginRight:var(--pf-global--gutter);display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between}.pf-l-level.pf-m-gutter>:not(:last-child){margin-right:var(--pf-l-level--m-gutter--MarginRight)}.pf-l-split{--pf-l-split--m-gutter--MarginRight:var(--pf-global--gutter);display:flex;flex-wrap:nowrap;padding:0;margin:0}.pf-l-split__item.pf-m-fill{flex-grow:1}.pf-l-split.pf-m-gutter>:not(:last-child){margin-right:var(--pf-l-split--m-gutter--MarginRight)}.pf-l-stack{--pf-l-stack--m-gutter--MarginBottom:var(--pf-global--gutter);display:flex;flex-direction:column;height:100%}.pf-l-stack__item.pf-m-fill{flex-grow:1}.pf-l-stack.pf-m-gutter>:not(:last-child){margin-bottom:var(--pf-l-stack--m-gutter--MarginBottom)} -/*# sourceMappingURL=patternfly.min.css.map */ diff --git a/awx/ui/public/static/css/patternfly.min.css.map b/awx/ui/public/static/css/patternfly.min.css.map deleted file mode 100644 index 32fc2565bf5c..000000000000 --- a/awx/ui/public/static/css/patternfly.min.css.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["patternfly.min.css"],"names":[],"mappings":"AA6vJA,gBACgB,CA7vJhB,+RACE,yDAA0D,CAC1D,yDAA0D,CAC1D,qEAAsE,CACtE,yEAA0E,CAC1E,4DAA6D,CAC7D,0EAA2E,CAC3E,8EAAiF,CAEnF,0KACE,0DAA2D,CAC3D,0DAA2D,CAC3D,sEAAuE,CACvE,0EAA2E,CAC3E,6DAA8D,CAC9D,oEAAqE,CACrE,6EAAgF,CAChF,kQACE,oFAAuF,CACzF,kRACE,yEAA0E,CAC1E,gFAAiF,CACjF,gFAAiF,CACjF,iFAAkF,CAClF,sFAAuF,CACvF,6FAA8F,CAC9F,6FAA8F,CAC9F,8FAA+F,CAC/F,oEAAqE,CACrE,2EAA4E,CAC5E,2EAA4E,CAC5E,4EAA6E,CAC7E,0EAA2E,CAC3E,iFAAkF,CAClF,iFAAkF,CAClF,kFAAqF,CAEzF,2GACE,gDAAiD,CACjD,yCAA0C,CAC1C,8CAA+C,CAC/C,uEAAwE,CACxE,6EAA8E,CAC9E,yCAA0C,CAC1C,+CAAkD,CAClD,0JACE,sEAAuE,CACvE,4EAA+E,CACjF,oCACE,kLACE,sEAAuE,CACvE,4EAA+E,CACjF,sLACE,uEAAwE,CACxE,6EAAgF,CAAE,CACtF,oCACE,kLACE,sEAAuE,CACvE,4EAA+E,CACjF,sLACE,uEAAwE,CACxE,6EAAgF,CAAE,CACtF,oCACE,kLACE,sEAAuE,CACvE,4EAA+E,CACjF,sLACE,uEAAwE,CACxE,6EAAgF,CAAE,CACtF,qCACE,kLACE,sEAAuE,CACvE,4EAA+E,CACjF,sLACE,uEAAwE,CACxE,6EAAgF,CAAE,CACtF,qCACE,sLACE,sEAAuE,CACvE,4EAA+E,CACjF,0LACE,uEAAwE,CACxE,6EAAgF,CAAE,CAExF,MACE,uCAAwC,CACxC,uCAAwC,CACxC,uCAAwC,CACxC,uCAAwC,CACxC,uCAAwC,CACxC,uCAAwC,CACxC,uCAAwC,CACxC,uCAAwC,CACxC,uCAAwC,CACxC,uCAAwC,CACxC,uCAAwC,CACxC,wCAAyC,CACzC,qCAAsC,CACtC,sCAAuC,CACvC,sCAAuC,CACvC,sCAAuC,CACvC,mCAAoC,CACpC,sCAAuC,CACvC,sCAAuC,CACvC,sCAAuC,CACvC,qCAAsC,CACtC,sCAAuC,CACvC,sCAAuC,CACvC,sCAAuC,CACvC,sCAAuC,CACvC,sCAAuC,CACvC,sCAAuC,CACvC,sCAAuC,CACvC,qCAAsC,CACtC,sCAAuC,CACvC,sCAAuC,CACvC,sCAAuC,CACvC,sCAAuC,CACvC,sCAAuC,CACvC,sCAAuC,CACvC,sCAAuC,CACvC,sCAAuC,CACvC,uCAAwC,CACxC,uCAAwC,CACxC,uCAAwC,CACxC,uCAAwC,CACxC,uCAAwC,CACxC,uCAAwC,CACxC,uCAAwC,CACxC,4CAA6C,CAC7C,4CAA6C,CAC7C,4CAA6C,CAC7C,4CAA6C,CAC7C,4CAA6C,CAC7C,4CAA6C,CAC7C,4CAA6C,CAC7C,6CAA8C,CAC9C,6CAA8C,CAC9C,6CAA8C,CAC9C,6CAA8C,CAC9C,6CAA8C,CAC9C,6CAA8C,CAC9C,6CAA8C,CAC9C,wCAAyC,CACzC,wCAAyC,CACzC,wCAAyC,CACzC,wCAAyC,CACzC,wCAAyC,CACzC,wCAAyC,CACzC,wCAAyC,CACzC,uCAAwC,CACxC,wCAAyC,CACzC,wCAAyC,CACzC,wCAAyC,CACzC,wCAAyC,CACzC,wCAAyC,CACzC,wCAAyC,CACzC,wCAAyC,CACzC,oCAAqC,CACrC,qCAAsC,CACtC,qCAAsC,CACtC,qCAAsC,CACtC,qCAAsC,CACtC,qCAAsC,CACtC,gCAAiC,CACjC,sCAAuC,CACvC,yCAA0C,CAC1C,4CAA6C,CAC7C,+CAAgD,CAChD,+CAAgD,CAChD,8CAA+C,CAC/C,8CAA+C,CAC/C,8CAA+C,CAC/C,8CAA+C,CAC/C,mEAAuE,CACvE,mEAAuE,CACvE,+BAAgC,CAChC,+BAAgC,CAChC,+BAAgC,CAChC,+BAAgC,CAChC,kCAAmC,CACnC,qCAAsC,CACtC,qCAAsC,CACtC,oCAAqC,CACrC,oCAAqC,CACrC,mCAAoC,CACpC,sCAAuC,CACvC,sCAAuC,CACvC,sCAAuC,CACvC,wCAAyC,CACzC,wCAAyC,CACzC,wCAAyC,CACzC,oCAAqC,CACrC,uCAAwC,CACxC,6CAA8C,CAC9C,yCAA0C,CAC1C,yCAA0C,CAC1C,uCAAwC,CACxC,uCAAwC,CACxC,uCAAwC,CACxC,uCAAwC,CACxC,uCAAwC,CACxC,oCAAqC,CACrC,oCAAqC,CACrC,uCAAwC,CACxC,uCAAwC,CACxC,sCAAuC,CACvC,sCAAuC,CACvC,sCAAuC,CACvC,kGAA0G,CAC1G,8EAAkF,CAClF,+EAAmF,CACnF,gFAAoF,CACpF,+EAAmF,CACnF,gGAAwG,CACxG,0EAA8E,CAC9E,2EAA+E,CAC/E,4EAAgF,CAChF,2EAA+E,CAC/E,2FAAmG,CACnG,0EAA8E,CAC9E,2EAA+E,CAC/E,4EAAgF,CAChF,2EAA+E,CAC/E,sFAA8F,CAC9F,mEAAuE,CACvE,oEAAwE,CACxE,qEAAyE,CACzE,oEAAwE,CACxE,mEAAuE,CACvE,uCAAwC,CACxC,4CAA6C,CAC7C,+BAAgC,CAChC,8BAA+B,CAC/B,4BAA6B,CAC7B,8BAA+B,CAC/B,4BAA6B,CAC7B,6BAA8B,CAC9B,6BAA8B,CAC9B,6BAA8B,CAC9B,0CAA2C,CAC3C,wBAAyB,CACzB,8BAA+B,CAC/B,2BAA4B,CAC5B,2BAA4B,CAC5B,2BAA4B,CAC5B,2BAA4B,CAC5B,2BAA4B,CAC5B,4BAA6B,CAC7B,6BAA8B,CAC9B,iCAAkC,CAClC,iCAAkC,CAClC,iCAAkC,CAClC,kCAAmC,CACnC,mCAAoC,CACpC,6BAA8B,CAC9B,uCAAwC,CACxC,uCAAwC,CACxC,8CAA+C,CAC/C,mCAAoC,CACpC,6CAA8C,CAC9C,sCAAuC,CACvC,kDAAmD,CACnD,gCAAiC,CACjC,gCAAiC,CACjC,gCAAiC,CACjC,gCAAiC,CACjC,qCAAsC,CACtC,qCAAsC,CACtC,qCAAsC,CACtC,0CAA2C,CAC3C,2CAA4C,CAC5C,iCAAkC,CAClC,kCAAmC,CACnC,uCAAwC,CACxC,sCAAuC,CACvC,wCAAyC,CACzC,wCAAyC,CACzC,sCAAuC,CACvC,wCAAyC,CACzC,+FAAqG,CACrG,2GAAiH,CACjH,mHAA0H,CAC1H,yNAAsO,CACtO,2JAAoK,CACpK,kCAAmC,CACnC,kCAAmC,CACnC,iCAAkC,CAClC,iCAAkC,CAClC,kCAAmC,CACnC,8BAA+B,CAC/B,kCAAmC,CACnC,iCAAkC,CAClC,kCAAmC,CACnC,mCAAoC,CACpC,sCAAuC,CACvC,gDAAiD,CACjD,iCAAkC,CAClC,2CAA4C,CAC5C,+BAAgC,CAChC,+BAAgC,CAChC,mCAAoC,CACpC,6CAAiE,CACjE,6DAAiE,CACjE,qCAAsC,CACtC,mCAAoC,CACpC,sCAAuC,CACvC,uCAAwC,CACxC,wCAA2C,CAE7C,oBACE,sFAAuF,CACvF,qFAAsF,CACtF,oFAAqF,CACrF,oFAAqF,CACrF,0EAA6E,CAE/E,WACE,yBAA4B,CAC5B,6DAAkE,CAClE,0KAAoL,CACpL,iBAAkB,CAClB,eAAgB,CAChB,iCAAoC,CAEtC,WACE,yBAA4B,CAC5B,4DAAiE,CACjE,wKAAkL,CAClL,iBAAkB,CAClB,eAAgB,CAChB,iCAAoC,CAEtC,WACE,yBAA4B,CAC5B,0DAA+D,CAC/D,oKAA8K,CAC9K,iBAAkB,CAClB,eAAgB,CAChB,iCAAoC,CAEtC,WACE,sBAAyB,CACzB,uDAA4D,CAC5D,8JAAwK,CACxK,iBAAkB,CAClB,eAAgB,CAChB,iCAAoC,CAEtC,WACE,sBAAyB,CACzB,sDAA2D,CAC3D,4JAAsK,CACtK,iBAAkB,CAClB,eAAgB,CAChB,iCAAoC,CAEtC,WACE,oBAAuB,CACvB,iBAAkB,CAClB,eAAgB,CAChB,wDAA6D,CAC7D,+SAAqU,CAEvU,WACE,oBAAuB,CACvB,iBAAkB,CAClB,eAAgB,CAChB,+DAAoE,CACpE,2UAAiW,CAEnW,WACE,oBAAuB,CACvB,iBAAkB,CAClB,eAAgB,CAChB,8DAAmE,CACnE,uUAA6V,CAE/V,WACE,oBAAuB,CACvB,iBAAkB,CAClB,eAAgB,CAChB,qEAA0E,CAC1E,mWAAyX,CAE3X,WACE,oBAAuB,CACvB,iBAAkB,CAClB,eAAgB,CAChB,yDAA8D,CAC9D,mTAAyU,CAE3U,WACE,oBAAuB,CACvB,iBAAkB,CAClB,eAAgB,CAChB,gEAAqE,CACrE,+UAAqW,CAEvW,WACE,oBAAuB,CACvB,iBAAkB,CAClB,eAAgB,CAChB,2DAAgE,CAChE,2TAAiV,CAEnV,WACE,oBAAuB,CACvB,iBAAkB,CAClB,eAAgB,CAChB,0DAA+D,CAC/D,uTAA6U,CAE/U,WACE,oBAAuB,CACvB,iBAAkB,CAClB,eAAgB,CAChB,4DAAiE,CACjE,+TAAqV,CAEvV,WACE,oBAAuB,CACvB,iBAAkB,CAClB,eAAgB,CAChB,mEAAwE,CACxE,2VAAiX,CAEnX,WACE,oBAAuB,CACvB,iBAAkB,CAClB,eAAgB,CAChB,wDAA6D,CAC7D,+SAAqU,CAEvU,WACE,oBAAuB,CACvB,iBAAkB,CAClB,eAAgB,CAChB,+DAAoE,CACpE,2UAAiW,CAEnW,WACE,oBAAuB,CACvB,iBAAkB,CAClB,eAAgB,CAChB,6DAAkE,CAClE,mUAAyV,CAE3V,WACE,oBAAuB,CACvB,iBAAkB,CAClB,eAAgB,CAChB,oEAAyE,CACzE,+VAAqX,CAEvX,WACE,oBAAuB,CACvB,iBAAkB,CAClB,eAAgB,CAChB,yDAA8D,CAC9D,mTAAyU,CAE3U,WACE,oBAAuB,CACvB,iBAAkB,CAClB,eAAgB,CAChB,gEAAqE,CACrE,+UAAqW,CAEvW,WACE,yBAA4B,CAC5B,iBAAkB,CAClB,eAAgB,CAChB,mEAAwE,CACxE,2VAAiX,CAEnX,WACE,yBAA4B,CAC5B,iBAAkB,CAClB,eAAgB,CAChB,qEAA0E,CAC1E,mWAAyX,CAE3X,WACE,yBAA4B,CAC5B,iBAAkB,CAClB,eAAgB,CAChB,sEAA2E,CAC3E,uWAA6X,CAE/X,WACE,yBAA4B,CAC5B,iBAAkB,CAClB,eAAgB,CAChB,kEAAuE,CACvE,uVAA6W,CAE/W,0DACE,SAAU,CACV,QAAS,CACT,4BAA+B,CAEjC,KACE,yBAA6B,CAE/B,kBACE,cAAe,CACf,KAAM,CACN,MAAO,CACP,eAAgB,CAChB,kBAAsB,CACtB,kBAAmB,CACnB,QAAW,CAEb,yGAuBE,SAAU,CACV,QAAW,CAEb,UAEE,WAAc,CAEhB,kBAME,cAAe,CACf,gDAAmD,CAErD,GACE,eAAkB,CAEpB,sCAKE,QAAS,CACT,mBAAoB,CACpB,cAAe,CACf,4CAA6C,CAC7C,kCAAqC,CAEvC,oCAME,cAAe,CACf,WAAc,CAEhB,OACE,QAAW,CAEb,MACE,gBAAiB,CACjB,wBAA2B,CAE7B,MAEE,SAAU,CACV,eAAkB,CAEpB,iBAGE,qBAAwB,CAE1B,KACE,sBAAuB,CACvB,gBAAmB,CAErB,KACE,oDAAqD,CACrD,wCAAyC,CACzC,gDAAiD,CACjD,4CAA6C,CAC7C,eAAgB,CAChB,uDAA0D,CAE5D,EACE,8CAA+C,CAC/C,mCAAoC,CACpC,sDAAyD,CACzD,QACE,6DAA8D,CAC9D,+EAAkF,CAEtF,SAEE,cAAiB,CAEnB,wHAIE,SAAU,CACV,iBAAoB,CAEtB,4GAIE,6BAAgC,CAElC,sBACE,mDAAsD,CAExD,4BACE,4BAA+B,CAEjC,gCACE,gCAAuC,CAEzC,gCACE,+BAAsC,CAExC,2BACE,wBAA2B,CAE7B,2BACE,wBAA2B,CAE7B,6BACE,4BAA+B,CAEjC,4BACE,qBAAwB,CAE1B,4BACE,wBAA2B,CAE7B,4BACE,wBAA2B,CAE7B,kCAKE,iCAAkC,CAClC,kCAAmC,CACnC,oBAAqB,CACrB,iBAAkB,CAClB,mBAAoB,CACpB,mBAAoB,CACpB,aAAgB,CAElB,SACE,mBAAoB,CACpB,iBAAmB,CACnB,uBAA0B,CAE5B,SACE,eAAkB,CAEpB,SACE,gBAAmB,CAErB,SACE,aAAgB,CAElB,SACE,aAAgB,CAElB,SACE,aAAgB,CAElB,SACE,aAAgB,CAElB,SACE,aAAgB,CAElB,SACE,aAAgB,CAElB,SACE,aAAgB,CAElB,SACE,aAAgB,CAElB,SACE,aAAgB,CAElB,UACE,cAAiB,CAEnB,SACE,iBAAkB,CAClB,YAAe,CAEjB,SACE,oBAAqB,CACrB,iBAAkB,CAClB,cAAiB,CACjB,YACE,iBAAoB,CAExB,SACE,SAAU,CACV,iBAAkB,CAClB,iBAAkB,CAClB,SAAU,CACV,mBAAsB,CAExB,aACE,uBAAyB,CACzB,kBAAmB,CACnB,wBAA2B,CAE7B,gBACE,UAAa,CAEf,iBACE,WAAc,CAEhB,mGAKE,iBAAoB,CAEtB,wGAKE,gBAAmB,CAErB,WACE,oCAAuC,CAEzC,YACE,sCAAyC,CAE3C,mBACE,GACE,sBAAyB,CAC3B,GACE,uBAA2B,CAAE,CAEjC,gBACE,qEAAsE,CACtE,uBAA0B,CAE5B,iBACE,qEAAsE,CACtE,wBAA2B,CAE7B,iBACE,qEAAsE,CACtE,wBAA2B,CAE7B,sBACE,+EAAgF,CAChF,oBAAyB,CAE3B,oBAEE,oBAAyB,CAE3B,2DAHE,+EAK0B,CAF5B,uCAEE,mBAA0B,CAE5B,0HAKE,WAAc,CAEhB,YACE,oBAAqB,CACrB,UAAW,CACX,eAAgB,CAChB,iBAAkB,CAClB,qBAAsB,CACtB,WAAc,CAEhB,8BAEE,MAAO,CACP,iBAAkB,CAClB,iBAAkB,CAClB,UAAa,CAEf,eACE,mBAAsB,CAGxB,eACE,aAAgB,CAElB,cACE,UAAa,CAEf,mBACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,uCACE,eAAkB,CAEpB,gBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,iDACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,+BACE,eAAkB,CAEpB,+BACE,eAAkB,CAEpB,gCACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,mCACE,eAAkB,CAEpB,mCACE,eAAkB,CAEpB,oCACE,eAAkB,CAEpB,iCACE,eAAkB,CAEpB,+BACE,eAAkB,CAEpB,+BACE,eAAkB,CAEpB,gCACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,yCACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,gBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,+BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,oCACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,+BACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,8BACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,iCACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,+BACE,eAAkB,CAEpB,+BACE,eAAkB,CAEpB,gCACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,gCACE,eAAkB,CAEpB,8BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,iCACE,eAAkB,CAEpB,iCACE,eAAkB,CAEpB,kCACE,eAAkB,CAEpB,+BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,+BACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,gCACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,iCACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,8BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,iCACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,8BACE,eAAkB,CAEpB,iCACE,eAAkB,CAEpB,iCACE,eAAkB,CAEpB,oCACE,eAAkB,CAEpB,oCACE,eAAkB,CAEpB,iCACE,eAAkB,CAEpB,iCACE,eAAkB,CAEpB,qCACE,eAAkB,CAEpB,oCACE,eAAkB,CAEpB,iCACE,eAAkB,CAEpB,uCACE,eAAkB,CAEpB,4CACE,eAAkB,CAEpB,oCACE,eAAkB,CAEpB,mCACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,gCACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,8BACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,gCACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,gCACE,eAAkB,CAEpB,kCACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,+BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,+BACE,eAAkB,CAEpB,sCACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,gCACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,kCACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,iCACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,8BACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,+BACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,+BACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,8BACE,eAAkB,CAEpB,+BACE,eAAkB,CAEpB,oCACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,8BACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,+BACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,gBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,+BACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,gCACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,gCACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,+BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,gCACE,eAAkB,CAEpB,8BACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,iCACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,gCACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,gCACE,eAAkB,CAEpB,8BACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,8BACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,+BACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,gBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,iCACE,eAAkB,CAEpB,iCACE,eAAkB,CAEpB,kCACE,eAAkB,CAEpB,+BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,8BACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,kCACE,eAAkB,CAEpB,8BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,iCACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,kCACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,gBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,+BACE,eAAkB,CAEpB,8BACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,8BACE,eAAkB,CAEpB,8BACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,iCACE,eAAkB,CAEpB,qCACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,gBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,8BACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,8BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,8BACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,8BACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,+BACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,+BACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,gCACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,8BACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,8BACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,gBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,+BACE,eAAkB,CAEpB,8BACE,eAAkB,CAEpB,8BACE,eAAkB,CAEpB,iCACE,eAAkB,CAEpB,wCACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,8BACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,gBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,8BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,2BACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,gBACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,6BACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,iBACE,eAAkB,CAEpB,kCACE,eAAkB,CAEpB,iCACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,uBACE,eAAkB,CAEpB,8BACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,wBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,yBACE,eAAkB,CAEpB,0BACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,oBACE,eAAkB,CAEpB,kCACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,kBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,sBACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,qBACE,eAAkB,CAEpB,4BACE,eAAkB,CAEpB,mBACE,eAAkB,CAEpB,WACE,QAAS,CACT,kBAAsB,CACtB,UAAW,CACX,WAAY,CACZ,eAAgB,CAChB,SAAU,CACV,iBAAkB,CAClB,SAAY,CAEd,uDACE,SAAU,CACV,WAAY,CACZ,QAAS,CACT,gBAAiB,CACjB,eAAgB,CAChB,UAAa,CAEf,WACE,gCAAkC,CAClC,iBAAkB,CAClB,eAAgB,CAChB,+CAAoD,CACpD,iVAA4W,CAE9W,SAEE,gCAAkC,CAClC,eAAkB,CAEpB,WACE,kBAAqB,CACrB,iCAAsC,CACtC,wPAAmR,CAErR,smGACE,kBAAqB,CACrB,kCAAmC,CACnC,iCAAkC,CAClC,iBAAkB,CAClB,mBAAoB,CACpB,eAAmB,CACnB,oBAAqB,CACrB,mBAAsB,CAExB,4BACE,WAAc,CAEhB,6BACE,WAAc,CAEhB,8BACE,WAAc,CAEhB,6BACE,WAAc,CAEhB,sBACE,WAAc,CAEhB,uBACE,WAAc,CAEhB,+BACE,WAAc,CAEhB,2BACE,WAAc,CAEhB,qBACE,WAAc,CAEhB,0BACE,WAAc,CAEhB,sBACE,WAAc,CAEhB,8BACE,WAAc,CAEhB,uBACE,WAAc,CAEhB,wBACE,WAAc,CAEhB,qBACE,WAAc,CAEhB,sBACE,WAAc,CAEhB,+BACE,WAAc,CAEhB,6BACE,WAAc,CAEhB,wBACE,WAAc,CAEhB,0BACE,WAAc,CAEhB,+BACE,WAAc,CAEhB,oBACE,WAAc,CAEhB,yBACE,WAAc,CAEhB,6BACE,WAAc,CAEhB,uBACE,WAAc,CAEhB,qBACE,WAAc,CAEhB,4BACE,WAAc,CAEhB,2BACE,WAAc,CAEhB,0BACE,WAAc,CAEhB,+BACE,WAAc,CAEhB,uBACE,WAAc,CAEhB,uBACE,WAAc,CAEhB,uBACE,WAAc,CAEhB,6BACE,WAAc,CAEhB,4BACE,WAAc,CAEhB,4BACE,WAAc,CAEhB,qBACE,WAAc,CAEhB,wBACE,WAAc,CAEhB,qBACE,WAAc,CAEhB,uBACE,WAAc,CAEhB,4BACE,WAAc,CAEhB,qBACE,WAAc,CAEhB,+BACE,WAAc,CAEhB,4BACE,WAAc,CAEhB,oBACE,WAAc,CAEhB,uBACE,WAAc,CAEhB,4BACE,WAAc,CAEhB,uBACE,WAAc,CAEhB,yBACE,WAAc,CAEhB,2BACE,WAAc,CAEhB,0BACE,WAAc,CAEhB,uBACE,WAAc,CAEhB,2BACE,WAAc,CAEhB,2BACE,WAAc,CAEhB,wBACE,WAAc,CAEhB,4BACE,WAAc,CAEhB,4BACE,WAAc,CAEhB,oBACE,WAAc,CAEhB,mBACE,WAAc,CAEhB,2BACE,WAAc,CAEhB,mBACE,WAAc,CAEhB,0BACE,WAAc,CAEhB,0BACE,WAAc,CAEhB,yBACE,WAAc,CAEhB,uBACE,WAAc,CAEhB,yBACE,WAAc,CAEhB,wBACE,WAAc,CAEhB,uBACE,WAAc,CAEhB,wBACE,WAAc,CAEhB,gCACE,WAAc,CAEhB,+BACE,WAAc,CAEhB,qCACE,WAAc,CAEhB,iCACE,WAAc,CAEhB,uCACE,WAAc,CAEhB,wCACE,WAAc,CAEhB,gCACE,WAAc,CAEhB,+BACE,WAAc,CAEhB,wBACE,WAAc,CAEhB,qBACE,WAAc,CAEhB,sBACE,WAAc,CAEhB,wBACE,WAAc,CAEhB,mCACE,WAAc,CAEhB,wBACE,WAAc,CAEhB,0BACE,WAAc,CAEhB,0BACE,WAAc,CAEhB,wBACE,WAAc,CAEhB,yBACE,WAAc,CAEhB,wBACE,WAAc,CAEhB,2BACE,WAAc,CAEhB,2BACE,WAAc,CAEhB,8BACE,WAAc,CAEhB,uCACE,WAAc,CAEhB,sCACE,WAAc,CAEhB,gCACE,WAAc,CAEhB,+BACE,WAAc,CAEhB,wBACE,WAAc,CAEhB,qBACE,WAAc,CAEhB,uBACE,WAAc,CAEhB,yBACE,WAAc,CAEhB,6BACE,WAAc,CAEhB,uBACE,WAAc,CAEhB,gCACE,WAAc,CAEhB,wBACE,WAAc,CAEhB,yBACE,WAAc,CAEhB,wBACE,WAAc,CAEhB,yBACE,WAAc,CAEhB,+BACE,WAAc,CAEhB,uBACE,WAAc,CAEhB,2BACE,WAAc,CAEhB,yBACE,WAAc,CAEhB,2BACE,WAAc,CAEhB,yBACE,WAAc,CAEhB,wBACE,WAAc,CAEhB,yBACE,WAAc,CAEhB,0BACE,WAAc,CAEhB,qBACE,WAAc,CAEhB,sBACE,WAAc,CAEhB,gCACE,WAAc,CAEhB,uBACE,WAAc,CAEhB,iCACE,WAAc,CAEhB,qBACE,WAAc,CAEhB,sBACE,6EAA8E,CAC9E,kEAAuE,CACvE,2DAA4D,CAC5D,mCAAoC,CACpC,4CAA6C,CAC7C,+EAAgF,CAChF,mCAAoC,CACpC,8EAAmF,CACnF,0CAA2C,CAC3C,+DAAgE,CAChE,iEAAkE,CAClE,kEAAmE,CACnE,gEAAiE,CACjE,oEAAqE,CACrE,sEAAuE,CACvE,uEAAwE,CACxE,qEAAsE,CACtE,yDAA0D,CAC1D,0DAA2D,CAC3D,uEAAwE,CACxE,wEAAyE,CACzE,uEAAwE,CACxE,yEAA0E,CAC1E,6EAA8E,CAC9E,4EAA6E,CAC7E,8EAA+E,CAC/E,mEAAoE,CACpE,uEAAwE,CACxE,wEAAyE,CACzE,yEAA0E,CAC1E,8EAA+E,CAC/E,iDAAkD,CAClD,6EAA8E,CAC9E,2EAA4E,CAC5E,gFAAiF,CACjF,wFAAyF,CACzF,6GAAgH,CAChH,8GAAiH,CACjH,8FAA+F,CAC/F,+EAAmF,CACnF,oFAAyF,CACzF,6DAA8D,CAC9D,sDAAuD,CACvD,kDAAmD,CACnD,yEAA0E,CAC1E,0EAA2E,CAC3E,wEAAyE,CACzE,8EAA+E,CAC/E,6EAA8E,CAC9E,0EAA2E,CAC3E,0EAA2E,CAC3E,+EAAgF,CAChF,uEAAwE,CACxE,yEAA0E,CAC1E,0EAA2E,CAC3E,wEAAyE,CACzE,4EAA6E,CAC7E,8EAA+E,CAC/E,+EAAgF,CAChF,6EAA8E,CAC9E,kCAAmC,CACnC,iBAAkB,CAClB,2CAA4C,CAC5C,YAAa,CACb,+CAAgD,CAChD,mEAAoE,CACpE,wCAAyC,CACzC,0CAA2C,CAC3C,iBAAkB,CAClB,eAAgB,CAChB,6DAA8D,CAC9D,iDAAoD,CACpD,oCACE,sBACE,8EAA+E,CAC/E,kFAAmF,CACnF,oFAAqF,CACrF,gFAAiF,CAGjF,gGAAiG,CACjG,8FAA+F,CAC/F,kGALmF,CAAE,CAMzF,yCACE,sBACE,gGAAiG,CACjG,kGAAqG,CAAE,CAC3G,yCACE,sBACE,gGAAmG,CAAE,CACzG,yCACE,sBACE,kGAAmG,CACnG,gGAAiG,CAGjG,oGAAqG,CAGrG,8FAA+F,CAC/F,kGAAmG,CACnG,oGAAqG,CACrG,gGAAiG,CAGjG,4EAA6E,CAC7E,qFAbmG,CAAE,CAczG,yCACE,sBACE,sEAAuE,CACvE,oEAAqE,CACrE,4EAA6E,CAC7E,+CAAgD,CAChD,mDAAoD,CACpD,qDAAwD,CAAE,CAEhE,6BACE,eAAgB,CAChB,YAAa,CACb,yMAA4M,CAE9M,mCACE,uDAA0D,CAE5D,8BACE,gBAAiB,CACjB,YAAa,CACb,qBAAsB,CACtB,+DAAgE,CAChE,iEAAkE,CAClE,6DAAgE,CAElE,iCACE,8DAA+D,CAC/D,eAAgB,CAChB,0DAA6D,CAE/D,+BACE,YAAa,CACb,qBAAsB,CACtB,iBAAkB,CAClB,4MAA6M,CAC7M,iBAAkB,CAClB,eAAgB,CAChB,2BAA4B,CAC5B,gCAAiC,CACjC,qBAAwB,CACxB,oCACE,+BACE,gBAAiB,CACjB,wBAA2B,CAAE,CAEnC,6BACE,eAAgB,CAChB,eAAgB,CAChB,KAAM,CACN,YAAa,CACb,sBAAuB,CACvB,wBAAyB,CACzB,0DAA2D,CAC3D,8DAA+D,CAC/D,gEAAmE,CACnE,yCACE,6BACE,aAAgB,CAChB,sBAAyB,CAAE,CAC/B,yCACE,6BACE,wBAA2B,CAAE,CACjC,qDACE,YAAa,CACb,kBAAmB,CACnB,sBAAuB,CACvB,yDAA0D,CAC1D,2DAA4D,CAC5D,gEAAiE,CACjE,yDAA0D,CAC1D,8EAA+E,CAC/E,wEAA2E,CAC3E,2DACE,6HAAgI,CAEtI,4BACE,YAAa,CACb,iBAAoB,CACpB,yCACE,4BACE,aAAc,CACd,kBAAmB,CACnB,uEAAwE,CACxE,2BAA4B,CAC5B,2BAA4B,CAC5B,6EAA8E,CAC9E,qEAAsE,CACtE,cAAiB,CAAE,CAEzB,gBACE,wEAAyE,CACzE,iEAAkE,CAClE,mEAAoE,CACpE,oEAAqE,CACrE,kEAAmE,CACnE,6DAA8D,CAC9D,uFAAwF,CACxF,uFAAwF,CACxF,wFAAyF,CACzF,yEAA0E,CAC1E,kGAAmG,CACnG,iFAAkF,CAClF,iFAAkF,CAClF,kFAAmF,CACnF,iGAAkG,CAClG,iFAAkF,CAClF,gGAAiG,CACjG,sFAAuF,CACvF,qGAAsG,CACtG,wDAAyD,CACzD,+DAAgE,CAChE,gFAAiF,CACjF,kFAAmF,CACnF,mFAAoF,CACpF,iFAAkF,CAClF,sEAAuE,CACvE,2EAA4E,CAC5E,4EAA6E,CAC7E,wFAAyF,CACzF,mIAAoI,CACpI,+DAAgE,CAChE,kCAAmC,CACnC,uDAA0D,CAE5D,wBACE,iBAAkB,CAClB,YAAa,CACb,kBAAmB,CACnB,6BAA8B,CAC9B,UAAW,CACX,qLAAsL,CACtL,QAAW,CACX,+BACE,iBAAkB,CAClB,KAAM,CACN,QAAS,CACT,MAAO,CACP,kDAAmD,CACnD,UAAW,CACX,uEAA0E,CAC5E,sCACE,oHAAuH,CACvH,mEACE,8EAA+E,CAC/E,mEAAsE,CACxE,mEACE,gFAAmF,CACvF,8BACE,sEAAyE,CACzE,2DACE,8DAAiE,CACrE,8BACE,sEAAyE,CACzE,2DACE,yEAA0E,CAC1E,8DAAiE,CACrE,+BACE,uEAA0E,CAC1E,4DACE,0EAA2E,CAC3E,+DAAkE,CAExE,6BACE,eAAgB,CAChB,sBAAuB,CACvB,kBAAmB,CACnB,sDAAyD,CAE3D,6BACE,yDAA4D,CAE9D,kCACE,2DAA4D,CAC5D,oDAAuD,CACvD,6CACE,sEAAuE,CACvE,eAAkB,CACpB,gDACE,oKAAuK,CAE3K,uCACE,iBAAkB,CAClB,iPAAoP,CACpP,8CACE,iBAAkB,CAClB,KAAM,CACN,QAAS,CACT,MAAO,CACP,iEAAkE,CAClE,UAAW,CACX,sFAAyF,CAE7F,kBACE,oCAAqC,CACrC,mEAAoE,CACpE,oEAAuE,CAEzE,2CAEE,6EAA8E,CAC9E,6EAA8E,CAC9E,YAAa,CACb,kBAAqB,CACrB,mDAEE,kDAAqD,CACvD,kMAIE,kDAAqD,CACvD,iEAEE,yEAA4E,CAEhF,YACE,uDAAwD,CACxD,oEAAqE,CACrE,6DAA8D,CAC9D,8DAA+D,CAC/D,iEAAkE,CAClE,qDAAsD,CACtD,uDAAwD,CACxD,wDAAyD,CACzD,sDAAuD,CACvD,qDAAsD,CACtD,8DAA+D,CAC/D,uCAAwC,CACxC,4DAA6D,CAC7D,iEAAkE,CAClE,kEAAmE,CACnE,+DAAgE,CAChE,gCAAiC,CACjC,+EAAkF,CAClF,kFAAqF,CACrF,yCAA0C,CAC1C,uEAA0E,CAC1E,kEAAmE,CACnE,mEAAoE,CACpE,gFAAiF,CACjF,8FAA+F,CAC/F,4EAA6E,CAC7E,yEAA0E,CAC1E,0EAA2E,CAC3E,0EAA2E,CAC3E,uEAAwE,CACxE,wEAAyE,CACzE,4EAA6E,CAC7E,yEAA0E,CAC1E,0EAA2E,CAC3E,sEAAuE,CACvE,mEAAoE,CACpE,oEAAqE,CACrE,sCAAuC,CACvC,0EAA2E,CAC3E,sFAAuF,CACvF,mFAAoF,CACpF,qFAAsF,CACtF,kFAAmF,CACnF,kCAAmC,CACnC,iBAAkB,CAClB,YAAa,CACb,qIAAsI,CACtI,qCAAsC,CACtC,mDAAoD,CACpD,oFAAqF,CACrF,uCAAwC,CACxC,4DAA6D,CAC7D,+FAAkG,CAClG,yBACE,yEAA0E,CAC1E,mEAAoE,CACpE,qEAAsE,CACtE,+FAAkG,CACpG,wBACE,wEAAyE,CACzE,kEAAmE,CACnE,oEAAqE,CACrE,8FAAiG,CACnG,yBACE,yEAA0E,CAC1E,mEAAoE,CACpE,qEAAsE,CACtE,+FAAkG,CACpG,sBACE,sEAAuE,CACvE,gEAAiE,CACjE,kEAAmE,CACnE,4FAA+F,CACjG,wBACE,8DAA+D,CAC/D,0EAA6E,CAEjF,kBACE,cAAe,CACf,YAAa,CACb,6CAA8C,CAC9C,iDAAkD,CAClD,2CAA4C,CAC5C,oCAAuC,CAEzC,mBACE,eAAgB,CAChB,gDAAiD,CACjD,qCAAsC,CACtC,qBAAwB,CACxB,iCACE,mBAAoB,CACpB,2BAA4B,CAC5B,sDAAuD,CACvD,eAAkB,CAEtB,yBACE,qBAAsB,CACtB,sDAAuD,CACvD,qBAAwB,CACxB,mDACE,+FAAkG,CAEtG,oBACE,gBAAiB,CACjB,+CAAgD,CAChD,mDAAoD,CACpD,qDAAsD,CACtD,2DAA8D,CAC9D,iCACE,2BAA8B,CAElC,0BACE,qBAAsB,CACtB,uDAA0D,CAC1D,uCACE,2DAA8D,CAC9D,wDACE,mFAAsF,CAE5F,uCACE,oEAAuE,CAEzE,kBACE,gEAAiE,CACjE,8DAA+D,CAC/D,+DAAgE,CAChE,6CAA8C,CAC9C,iEAAoE,CACpE,sBACE,mDAAsD,CACxD,6BACE,cAAe,CACf,yCAA0C,CAC1C,6CAA8C,CAC9C,gDAAiD,CACjD,4DAAqE,CACrE,oDAAuD,CAE3D,mBACE,uFAAwF,CACxF,oEAAqE,CACrE,kEAAmE,CACnE,qEAAsE,CACtE,wEAAyE,CACzE,8DAA+D,CAC/D,uCAAwC,CACxC,uFAAwF,CACxF,8EAA+E,CAC/E,sEAAuE,CACvE,iFAAkF,CAClF,qEAAsE,CACtE,+DAAgE,CAChE,sEAAuE,CACvE,uEAAwE,CACxE,sEAAuE,CACvE,kFAAmF,CACnF,2EAA4E,CAC5E,yEAA0E,CAC1E,2EAA4E,CAC5E,4EAA6E,CAC7E,0EAA2E,CAC3E,sFAAuF,CACvF,qFAAsF,CACtF,2EAA4E,CAC5E,uEAAwE,CACxE,yEAA0E,CAC1E,0EAA2E,CAC3E,wEAAyE,CACzE,uEAAwE,CACxE,+EAAgF,CAChF,0CAA2C,CAC3C,iFAAkF,CAClF,mGAAoG,CACpG,sDAAuD,CACvD,0EAA2E,CAC3E,qFAAsF,CACtF,oDAAqD,CACrD,uFAAwF,CACxF,4EAA6E,CAC7E,8FAA+F,CAC/F,mFAAoF,CACpF,0GAA2G,CAC3G,6EAA8E,CAC9E,+EAAgF,CAChF,gFAAiF,CACjF,iFAAkF,CAClF,sFAAuF,CACvF,mEAAoE,CACpE,2FAA4F,CAC5F,0EAA2E,CAC3E,yEAA0E,CAC1E,gGAAiG,CACjG,kGAAmG,CACnG,8FAA+F,CAC/F,yEAA0E,CAC1E,oFAAqF,CACrF,yEAA0E,CAC1E,sEAAuE,CACvE,yEAA0E,CAC1E,iBAAkB,CAClB,oBAAqB,CACrB,cAAiB,CACjB,4DACE,yDAA4D,CAC9D,iCACE,yDAA0D,CAC1D,+DAAkE,CAClE,4CACE,8CAAiD,CAEvD,2BACE,iMAAkM,CAClM,6CAA8C,CAC9C,WAAc,CACd,iCACE,iFAAoF,CACtF,yEACE,kFAAqF,CACvF,iCACE,iFAAoF,CACtF,oCACE,oFAAqF,CACrF,mBAAsB,CAE1B,yBACE,iBAAkB,CAClB,uCAAwC,CACxC,8CAA+C,CAC/C,cAAe,CACf,sDAAuD,CACvD,4DAA6D,CAC7D,gEAAiE,CACjE,2BAA4B,CAC5B,oDAAuD,CACvD,0CACE,OAAU,CACZ,qDACE,yEAA0E,CAC1E,uEAA0E,CAE9E,gCACE,qNAAsN,CACtN,iEAAkE,CAClE,qIAAwI,CAE1I,iCACE,YAAe,CACf,+CACE,2HAA8H,CAElI,8BACE,YAAa,CACb,kBAAmB,CACnB,gDAAiD,CACjD,6MAA8M,CAC9M,2DAA4D,CAC5D,gDAAiD,CACjD,kBAAmB,CACnB,QAAW,CACX,wEACE,sHAAuH,CACvH,oBAAuB,CACzB,yMAGE,4EAA+E,CACjF,mFACE,0FAA2F,CAC3F,mBAAsB,CACxB,4KACE,4BAA+B,CACjC,8XACE,SAAY,CACd,wCACE,sGAAuG,CACvG,0HAA6H,CAC/H,0CACE,0FAA2F,CAC3F,0FAA2F,CAC3F,4HAA6H,CAC7H,iEAAoE,CACpE,gGACE,2GAA8G,CAEpH,mCACE,mBAAoB,CACpB,kBAAmB,CACnB,sBAAuB,CACvB,qDAAsD,CACtD,uDAAwD,CACxD,kEAAqE,CACrE,qCACE,cAAe,CACf,eAAkB,CAEtB,4CACE,2EAA4E,CAC5E,gBAAiB,CACjB,qEAAsE,CACtE,8DAA+D,CAC/D,SAAU,CACV,mFAAsF,CAExF,oDACE,8DAAiE,CAEnE,gCAIE,qNAAgE,CAChE,yDAA0D,CAC1D,6DAA8D,CAC9D,kDAAqD,CAEvD,aACE,8DAA+D,CAC/D,4BAA6B,CAC7B,6BAA8B,CAC9B,+BAAgC,CAChC,iCAAkC,CAClC,8CAAiD,CAEnD,eACE,oDAAqD,CACrD,wFAAyF,CACzF,cAAe,CACf,KAAM,CACN,MAAO,CACP,oCAAqC,CACrC,UAAW,CACX,WAAY,CACZ,sDAAyD,CAE3D,qBACE,eAAkB,CAEpB,uBACE,oFAAqF,CACrF,wEAA6E,CAC7E,8EAAmF,CACnF,4EAAiF,CACjF,kFAAuF,CACvF,6EAAkF,CAClF,mDAAwD,CACxD,8BACE,cAAe,CACf,KAAM,CACN,MAAO,CACP,UAAW,CACX,UAAW,CACX,WAAY,CACZ,UAAW,CACX,8DAA+D,CAC/D,8DAA+D,CAC/D,2CAA4C,CAC5C,2BAA4B,CAC5B,qBAAwB,CACxB,kEACE,8BACE,yFAA4F,CAAE,CAClG,yBACE,8BACE,0FAA6F,CAAE,CACnG,8GACE,8BACE,6FAAgG,CAAE,CACtG,yBACE,8BACE,0FAA6F,CAAE,CAEvG,+BACE,aAAgB,CAElB,YACE,6DAA8D,CAC9D,qDAAsD,CACtD,2DAA4D,CAC5D,uDAAwD,CACxD,sDAAuD,CACvD,qDAAsD,CACtD,mDAAoD,CACpD,4EAA6E,CAC7E,6DAA8D,CAC9D,4EAA6E,CAC7E,gEAAiE,CACjE,oBAAqB,CACrB,qCAAsC,CACtC,6CAA8C,CAC9C,2CAA4C,CAC5C,qCAAsC,CACtC,yCAA0C,CAC1C,8BAA+B,CAC/B,iBAAkB,CAClB,mDAAoD,CACpD,6CAAgD,CAChD,sBACE,oDAAqD,CACrD,wEAA2E,CAC7E,wBACE,sDAAuD,CACvD,0EAA6E,CAEjF,aACE,sDAAuD,CACvD,wDAAyD,CACzD,4DAA6D,CAC7D,yDAA0D,CAC1D,uDAAwD,CACxD,2DAA4D,CAC5D,sDAAuD,CACvD,iDAAkD,CAClD,0EAA2E,CAC3E,0EAA2E,CAC3E,4EAA6E,CAC7E,8EAA+E,CAC/E,8EAA+E,CAC/E,4DAA6D,CAC7D,yEAA0E,CAC1E,kCAAmC,CACnC,eAAgB,CAChB,sBAAuB,CAEvB,yIAA0I,CAC1I,aAAc,CACd,sCAAuC,CACvC,+BAAgC,CAChC,kBAAmB,CACnB,oDAAuD,CACvD,yBACE,aACE,gEAAiE,CACjE,8DAAiE,CAAE,CACvE,uBACE,kCAAmC,CACnC,0EAA6E,CAC/E,yBACE,4EAA+E,CACjF,0BACE,6EAAgF,CAClF,0BACE,kCAAmC,CACnC,6EAAgF,CAClF,yBACE,eAAgB,CAChB,KAAM,CACN,4CAA6C,CAC7C,kDAAqD,CAEzD,iBACE,gEAAiE,CACjE,oEAAqE,CACrE,iEAAkE,CAClE,yEAA0E,CAC1E,yEAA0E,CAC1E,wEAAyE,CACzE,sEAAuE,CACvE,mEAAoE,CACpE,mBAAsB,CAExB,uBACE,YAAa,CACb,cAAe,CACf,kBAAqB,CAEvB,uBACE,YAAa,CACb,oBAAqB,CACrB,gDAAiD,CACjD,oDAAqD,CACrD,oDAAqD,CACrD,kBAAmB,CACnB,eAAkB,CAClB,wCACE,sDAAyD,CAE7D,+BACE,8DAA+D,CAC/D,wDAAyD,CACzD,aAAc,CACd,iDAAoD,CAEtD,uBACE,iBAAkB,CAClB,oDAAqD,CACrD,mBAAoB,CACpB,qBAAwB,CACxB,oCACE,cAAiB,CACjB,8EACE,oDAAqD,CACrD,oBAAuB,CAE7B,0BACE,cAAe,CACf,mDAAsD,CAExD,iDAEE,kBAAqB,CAEvB,sFAEE,mDAAsD,CAExD,mEACE,YAAa,CACb,iBAAoB,CAEtB,aACE,gEAAiE,CACjE,wDAAyD,CACzD,mEAAoE,CACpE,uDAAwD,CACxD,0DAA2D,CAC3D,8DAA+D,CAC/D,sDAAuD,CACvD,8DAA+D,CAC/D,qEAAsE,CACtE,6CAA8C,CAC9C,mEAAoE,CACpE,0EAA2E,CAC3E,0EAA2E,CAC3E,2EAA4E,CAC5E,oEAAqE,CACrE,8EAA+E,CAC/E,uDAAwD,CACxD,8EAA+E,CAC/E,kEAAmE,CACnE,qFAAsF,CACtF,yEAA0E,CAC1E,qFAAsF,CACtF,yEAA0E,CAC1E,sFAAuF,CACvF,0EAA2E,CAC3E,uDAAwD,CACxD,mFAAoF,CACpF,sEAAuE,CACvE,8DAA+D,CAC/D,0FAA2F,CAC3F,6EAA8E,CAC9E,8DAA+D,CAC/D,0FAA2F,CAC3F,6EAA8E,CAC9E,+DAAgE,CAChE,2FAA4F,CAC5F,8EAA+E,CAC/E,sDAAuD,CACvD,0EAA2E,CAC3E,6DAA8D,CAC9D,6DAA8D,CAC9D,iFAAkF,CAClF,oEAAqE,CACrE,6DAA8D,CAC9D,iFAAkF,CAClF,oEAAqE,CACrE,8DAA+D,CAC/D,kFAAmF,CACnF,qEAAsE,CACtE,8EAA+E,CAC/E,iEAAkE,CAClE,oFAAqF,CACrF,wEAAyE,CACzE,oFAAqF,CACrF,wEAAyE,CACzE,qFAAsF,CACtF,yEAA0E,CAC1E,4EAA6E,CAC7E,iEAAkE,CAClE,mFAAoF,CACpF,wEAAyE,CACzE,mFAAoF,CACpF,wEAAyE,CACzE,oFAAqF,CACrF,yEAA0E,CAC1E,kDAAmD,CACnD,0DAA2D,CAC3D,yDAA0D,CAC1D,wEAAyE,CACzE,yDAA0D,CAC1D,wEAAyE,CACzE,0DAA2D,CAC3D,yEAA0E,CAC1E,4DAA6D,CAC7D,iDAAkD,CAClD,oGAAqG,CACrG,kFAAmF,CACnF,mDAAoD,CACpD,0DAA2D,CAC3D,0DAA2D,CAC3D,iEAAkE,CAClE,0DAA2D,CAC3D,iEAAkE,CAClE,2DAA4D,CAC5D,kEAAmE,CACnE,6EAA8E,CAC9E,6DAA8D,CAC9D,gFAAiF,CACjF,4DAA6D,CAC7D,wCAAyC,CACzC,8EAA+E,CAC/E,kFAAmF,CACnF,oFAAqF,CACrF,qFAAsF,CACtF,mFAAoF,CACpF,yFAA0F,CAC1F,uFAAwF,CACxF,mEAAoE,CACpE,2FAA4F,CAC5F,6FAA8F,CAC9F,wFAAyF,CACzF,oEAAqE,CACrE,4FAA6F,CAC7F,8FAA+F,CAC/F,uFAAwF,CACxF,mEAAoE,CACpE,2FAA4F,CAC5F,6FAA8F,CAC9F,4FAA6F,CAC7F,wEAAyE,CACzE,gGAAiG,CACjG,kGAAmG,CACnG,+DAAgE,CAChE,oEAAqE,CACrE,sEAAuE,CACvE,uEAAwE,CACxE,qEAAsE,CACtE,0EAA2E,CAC3E,4EAA6E,CAC7E,sEAAuE,CACvE,mEAAoE,CACpE,wGAAyG,CACzG,kCAAmC,CACnC,wCAAyC,CACzC,gCAAiC,CACjC,0DAA2D,CAC3D,qDAAsD,CACtD,kFAAmF,CACnF,kHAAqH,CACrH,iHAAoH,CACpH,uEAAwE,CACxE,kHAAmH,CACnH,iBAAkB,CAClB,oBAAqB,CACrB,yIAA0I,CAC1I,sCAAuC,CACvC,0CAA2C,CAC3C,0CAA2C,CAC3C,iBAAkB,CAClB,kBAAmB,CACnB,gBAAiB,CACjB,QAAS,CACT,8CAAiD,CACjD,mBACE,iBAAkB,CAClB,KAAM,CACN,OAAQ,CACR,QAAS,CACT,MAAO,CACP,mBAAoB,CACpB,UAAW,CACX,mDAAoD,CACpD,mDAAoD,CACpD,qDAAwD,CAC1D,mBACE,+EAAgF,CAChF,oBAAuB,CACzB,mBACE,+EAAkF,CACpF,6CACE,gFAAmF,CACrF,wBACE,aAAc,CACd,UAAa,CACf,wBACE,6DAAgE,CAClE,wKACE,sEAAuE,CACvE,0EAA2E,CAC3E,4EAA6E,CAC7E,wEAAyE,CACzE,sEAAyE,CAC3E,0BACE,0CAA2C,CAC3C,+DAAkE,CAClE,gCACE,2EAA4E,CAC5E,+FAAkG,CACpG,gCACE,2EAA4E,CAC5E,+FAAkG,CACpG,uEACE,4EAA6E,CAC7E,gGAAmG,CACvG,4BACE,qFAAsF,CACtF,4CAA6C,CAC7C,iEAAoE,CACpE,kCACE,+EAAgF,CAChF,mGAAoG,CACpG,4FAA+F,CACjG,kCACE,+EAAgF,CAChF,mGAAoG,CACpG,4FAA+F,CACjG,2EACE,gFAAiF,CACjF,oGAAqG,CACrG,6FAAgG,CACpG,2BACE,oFAAqF,CACrF,2CAA4C,CAC5C,gEAAmE,CACnE,iCACE,6EAA8E,CAC9E,iGAAkG,CAClG,2FAA8F,CAChG,iCACE,6EAA8E,CAC9E,iGAAkG,CAClG,2FAA8F,CAChG,yEACE,8EAA+E,CAC/E,kGAAmG,CACnG,4FAA+F,CACnG,yBACE,yCAA0C,CAC1C,8DAAiE,CACjE,+BACE,yEAA0E,CAC1E,6FAAgG,CAClG,+BACE,yEAA0E,CAC1E,6FAAgG,CAClG,qEACE,0EAA2E,CAC3E,8FAAiG,CACrG,0BACE,0CAA2C,CAC3C,+DAAkE,CAClE,gCACE,2EAA4E,CAC5E,+FAAkG,CACpG,gCACE,2EAA4E,CAC5E,+FAAkG,CACpG,uEACE,4EAA6E,CAC7E,gGAAmG,CACvG,uBACE,8FAA+F,CAC/F,uCAAwC,CACxC,4DAA+D,CAC/D,+CACE,qEAAsE,CACtE,yFAA4F,CAC9F,+CACE,qEAAsE,CACtE,yFAA4F,CAC9F,qGACE,sEAAuE,CACvE,0FAA6F,CAC/F,mCACE,sEAAuE,CACvE,cAAe,CACf,SAAU,CACV,eAAgB,CAChB,kBAAmB,CACnB,cAAiB,CACjB,yCACE,+EAAgF,CAChF,2EAA8E,CAClF,uCACE,0EAA6E,CACjF,0BACE,uEAAwE,CACxE,iGAAkG,CAClG,mFAAoF,CACpF,2PAA4P,CAC5P,0CAA2C,CAC3C,+DAAkE,CAClE,gCACE,qBAAwB,CAC1B,gCACE,2EAA4E,CAC5E,+FAAgG,CAChG,iHAAoH,CACpH,sCACE,kFAAqF,CACzF,uEACE,4EAA6E,CAC7E,gGAAiG,CACjG,kHAAqH,CACrH,mFACE,mFAAsF,CAC1F,gCACE,2EAA4E,CAC5E,+FAAgG,CAChG,iHAAoH,CACpH,sCACE,kFAAqF,CACzF,wCACE,gFAAiF,CACjF,oGAAqG,CACrG,sHAAyH,CACzH,8CACE,uFAA0F,CAChG,wBACE,2EAA4E,CAC5E,+FAAgG,CAChG,wCAAyC,CACzC,6DAAgE,CAChE,8BACE,uEAAwE,CACxE,2FAA8F,CAChG,mEACE,wEAAyE,CACzE,4FAA+F,CACjG,8BACE,uEAAwE,CACxE,2FAA8F,CAClG,iDACE,mBAAsB,CACxB,iFACE,kFAAmF,CACnF,yCAA0C,CAC1C,8DAAiE,CACnE,gCACE,mCAAoC,CACpC,2DAA4D,CAC5D,cAAiB,CACnB,2BACE,wEAAyE,CACzE,sEAAuE,CACvE,gHAAmH,CACrH,8BACE,2EAA4E,CAC5E,yEAA4E,CAEhF,8BACE,2DAA8D,CAEhE,4BACE,uDAA0D,CAE5D,uBACE,iBAAkB,CAClB,qCAAsC,CACtC,uCAAwC,CACxC,aAAc,CACd,8DAAiE,CACjE,qCACE,kCAAqC,CAEzC,iCACE,iEAAoE,CAEtE,qBACE,6EAA8E,CAC9E,8DAA+D,CAC/D,gEAAiE,CACjE,iEAAkE,CAClE,+DAAgE,CAChE,8DAA+D,CAC/D,wEAAyE,CACzE,6CAA8C,CAC9C,wDAAyD,CACzD,uDAAwD,CACxD,iGAAkG,CAClG,yGAA4G,CAC5G,0GAA6G,CAC7G,gGAAiG,CACjG,gFAAiF,CACjF,iFAAkF,CAClF,sEAAuE,CACvE,2EAA4E,CAC5E,sDAAuD,CACvD,wDAAyD,CACzD,yDAA0D,CAC1D,uDAAwD,CACxD,kGAAmG,CACnG,0GAA2G,CAC3G,wGAAyG,CACzG,+GAAgH,CAChH,gHAAiH,CACjH,mHAAoH,CACpH,uHAAwH,CACxH,6FAA8F,CAC9F,sEAAuE,CACvE,gDAAiD,CACjD,kDAAmD,CACnD,uGAAwG,CACxG,iDAAkD,CAClD,yGAA0G,CAC1G,8EAA+E,CAC/E,6EAA8E,CAC9E,+GAAgH,CAChH,+GAAgH,CAChH,sGAAuG,CACvG,sCAAuC,CACvC,uCAAwC,CACxC,4EAA6E,CAC7E,+DAAgE,CAChE,wDAAyD,CACzD,kFAAmF,CACnF,iFAAkF,CAClF,2DAA4D,CAC5D,sFAAuF,CACvF,sFAAuF,CACvF,0FAA2F,CAC3F,kDAAmD,CACnD,kCAAmC,CACnC,mBAAoB,CACpB,qBAAsB,CACtB,yKAA0K,CAC1K,8CAA+C,CAC/C,4DAA+D,CAEjE,6BACE,YAAa,CACb,8DAAiE,CAEnE,yCACE,wEAAyE,CACzE,sEAAyE,CACzE,yDACE,gIAAiI,CACjI,8HAAiI,CACnI,yDACE,gIAAiI,CACjI,8HAAiI,CAErI,mCACE,WAAc,CAEhB,kCACE,oDAAuD,CAEzD,+BACE,kBAAqB,CAEvB,2BACE,2HAA8H,CAEhI,0BACE,6DAA8D,CAC9D,uDAAwD,CACxD,iBAAoB,CAEtB,4CACE,wHAA2H,CAE7H,iCACE,iGAAkG,CAClG,iBAAkB,CAClB,yNAA0N,CAC1N,iBAAoB,CACpB,wCACE,iBAAkB,CAClB,uDAAwD,CACxD,2DAA4D,CAC5D,6DAA8D,CAC9D,yDAA0D,CAC1D,UAAW,CACX,gFAAmF,CACrF,8CACE,qHAAwH,CAC1H,+CACE,sIAAuI,CACvI,oIAAqI,CACrI,oIAAuI,CACzI,kDACE,+HAAkI,CACpI,gDACE,+HAAkI,CACpI,qDACE,wGAA2G,CAC7G,+CACE,sHAAuH,CACvH,oIAAqI,CACrI,oIAAqI,CACrI,0IAA2I,CAC3I,uHAAwH,CACxH,kGAAqG,CACvG,+CACE,sEAAuE,CACvE,wDAA2D,CAE/D,2BACE,iBAAkB,CAClB,mBAAoB,CACpB,kBAAmB,CACnB,sBAAuB,CACvB,6CAA8C,CAC9C,+CAAgD,CAChD,aAAc,CACd,6CAA8C,CAC9C,kEAAmE,CACnE,QAAW,CACX,iCACE,iBAAkB,CAClB,KAAM,CACN,OAAQ,CACR,QAAS,CACT,MAAO,CACP,UAAW,CACX,sHAAyH,CAC3H,4DACE,4DAA+D,CACjE,uEACE,qGAAwG,CAC1G,uEACE,qGAAsG,CACtG,2GAA4G,CAC5G,SAAU,CACV,6DAAgE,CAClE,oCACE,mBAAoB,CACpB,oFAAqF,CACrF,kEAAqE,CAEzE,WACE,mEAAoE,CACpE,sDAAuD,CACvD,0EAA2E,CAC3E,2EAA4E,CAC5E,2EAA4E,CAC5E,4EAA6E,CAC7E,gFAAiF,CACjF,uFAAwF,CACxF,kGAAmG,CACnG,qEAAsE,CACtE,uEAAwE,CACxE,4EAA6E,CAC7E,wEAAyE,CACzE,yEAA0E,CAC1E,uEAAwE,CACxE,iFAAkF,CAClF,0FAA2F,CAC3F,kEAAmE,CACnE,mEAAoE,CACpE,iEAAkE,CAClE,6DAA8D,CAC9D,8DAA+D,CAC/D,4DAA6D,CAC7D,sEAAuE,CACvE,qFAAwF,CACxF,oEAAqE,CACrE,wFAA2F,CAC3F,4EAA+E,CAC/E,wEAAyE,CACzE,yDAA0D,CAC1D,2DAA4D,CAC5D,iEAAkE,CAClE,+EAAgF,CAChF,0DAA2D,CAC3D,4DAA6D,CAC7D,8DAA+D,CAC/D,oEAAqE,CACrE,YAAa,CACb,qBAAsB,CACtB,kDAAmD,CACnD,sCAAyC,CACzC,gCACE,0DAA6D,CAC/D,2BACE,iBAAkB,CAClB,cAAiB,CACjB,iCACE,2DAA8D,CAChE,iCACE,2DAA8D,CAChE,kCACE,4DAA+D,CACjE,yCACE,gEAAmE,CACnE,gDACE,iBAAkB,CAClB,KAAM,CACN,OAAQ,CACR,MAAO,CACP,iEAAkE,CAClE,UAAW,CACX,oFAAuF,CAC7F,wBACE,uEAAwE,CACxE,2EAA4E,CAC5E,yFAA0F,CAC1F,iFAAkF,CAClF,mFAAoF,CACpF,+EAAgF,CAChF,mGAAoG,CACpG,qHAAwH,CAC1H,qBACE,2BAA4B,CAC5B,wFAA2F,CAC7F,wDACE,0EAA6E,CAC/E,6KAIE,0DAA6D,CAEjE,mBACE,YAAa,CACb,kBAAmB,CACnB,kBAAqB,CACrB,qCACE,SAAY,CAEhB,0BACE,qBAAsB,CACtB,wLAA2L,CAE7L,+BACE,oBAAqB,CACrB,2DAA8D,CAEhE,kBACE,+CAAgD,CAChD,+CAAkD,CAEpD,oBACE,YAAa,CACb,kBAAmB,CACnB,qBAAsB,CACtB,OAAQ,CACR,mDAAoD,CACpD,iJAAoJ,CACpJ,wBACE,wDAA2D,CAC7D,kHAGE,SAAY,CAEhB,yEAIE,mDAAoD,CACpD,qDAAsD,CACtD,iDAAoD,CACpD,yHAIE,qDAAwD,CAE5D,uEAEE,sEAAyE,CAE3E,+BACE,sCAAyC,CAE3C,oCACE,aAAgB,CAElB,iBACE,0CAA6C,CAE/C,mBACE,4CAA+C,CAEjD,iDACE,gDAAmD,CAErD,YACE,+EAAgF,CAChF,0EAA2E,CAC3E,uDAAwD,CACxD,oEAAqE,CACrE,4DAA6D,CAC7D,gEAAiE,CACjE,yCAA0C,CAC1C,kEAAmE,CACnE,6DAA8D,CAC9D,YAAa,CACb,8BAA+B,CAC/B,mCAAoC,CACpC,kBAAmB,CACnB,mBAAsB,CAExB,mBACE,4CAA6C,CAC7C,gDAAiD,CACjD,gDAAiD,CACjD,qCAAwC,CAE1C,mBACE,8CAAiD,CAEnD,yBACE,aAAc,CACd,kDAAmD,CACnD,2CAA8C,CAEhD,uDAEE,cAAiB,CAEnB,0HAGE,oEAAqE,CACrE,kBAAqB,CAEvB,WACE,oDAAqD,CACrD,sDAAuD,CACvD,uDAAwD,CACxD,qDAAsD,CACtD,+DAAgE,CAChE,4DAA6D,CAC7D,mEAAoE,CACpE,kEAAmE,CACnE,gEAAiE,CACjE,yEAA0E,CAC1E,gFAAiF,CACjF,mEAAoE,CACpE,6EAA8E,CAC9E,0DAA2D,CAC3D,qDAAsD,CACtD,gCAAiC,CACjC,8DAA+D,CAC/D,gEAAiE,CACjE,iEAAkE,CAClE,+DAAgE,CAChE,sEAAyE,CACzE,4EAAiF,CACjF,4EAA+E,CAC/E,8DAA+D,CAC/D,6DAA8D,CAC9D,0DAA2D,CAC3D,kCAAmC,CACnC,iBAAkB,CAClB,mBAAoB,CACpB,kBAAmB,CACnB,iIAAkI,CAClI,eAAgB,CAChB,kDAAmD,CACnD,4CAA+C,CAC/C,kBACE,iBAAkB,CAClB,KAAM,CACN,OAAQ,CACR,QAAS,CACT,MAAO,CACP,UAAW,CACX,wFAAyF,CACzF,oDAAuD,CACzD,yBACE,QAAW,CACX,0CACE,+CAAkD,CACtD,0BACE,2EAA4E,CAC5E,mDAAsD,CACtD,2CACE,uDAA0D,CAC9D,wBACE,gEAAiE,CACjE,oEAAqE,CACrE,sEAAuE,CACvE,kEAAmE,CACnE,4DAA6D,CAC7D,gDAAiD,CACjD,oDAAqD,CACrD,sDAAyD,CAC3D,uBACE,iDAAoD,CAExD,iBACE,eAAgB,CAChB,sBAAuB,CACvB,kBAAmB,CACnB,iBAAkB,CAClB,0CAA2C,CAC3C,0CAA2C,CAC3C,mCAAsC,CAExC,oEAEE,8CAAiD,CAEnD,iBACE,kCAAmC,CACnC,2EAA8E,CAC9E,0EAA6E,CAC7E,sEAAuE,CACvE,wEAAyE,CACzE,yEAA0E,CAC1E,uEAAwE,CACxE,8EAA+E,CAC/E,qFAAsF,CACtF,kEAAmE,CACnE,iEAAkE,CAClE,uCAAwC,CACxC,yEAA4E,CAC5E,4EAA+E,CAC/E,sEAAuE,CACvE,uEAA0E,CAC1E,+BAIE,yMAA6D,CAC7D,oEAAqE,CACrE,8DAAiE,CAErE,uBACE,YAAa,CACb,MAAO,CACP,cAAe,CACf,oBAAuB,CAEzB,uBACE,sDAAuD,CACvD,wDAA2D,CAE7D,wCAEE,mBAAoB,CACpB,cAAe,CACf,kBAAqB,CAEvB,4BACE,mBAAoB,CACpB,2DAA4D,CAC5D,6DAAgE,CAElE,wBACE,eAAgB,CAChB,sBAAuB,CACvB,kBAAmB,CACnB,iDAAkD,CAClD,uDAAwD,CACxD,iDAAoD,CAEtD,wBACE,YAAa,CACb,qBAAsB,CACtB,mDAAoD,CACpD,yDAA4D,CAE9D,qBACE,6DAA8D,CAC9D,4DAA6D,CAC7D,kFAAmF,CACnF,oFAAqF,CACrF,qFAAsF,CACtF,mFAAoF,CACpF,uGAAwG,CACxG,2DAA4D,CAC5D,6FAA8F,CAC9F,8FAA+F,CAC/F,4FAA6F,CAC7F,yFAA0F,CAC1F,8FAAmG,CACnG,qEACE,6EAAgF,CAEpF,4BACE,YAAe,CACf,gCACE,gBAAmB,CAEvB,kCACE,8DAAiE,CAEnE,yCACE,yPAA0P,CAC1P,oBAAqB,CACrB,gFAAiF,CACjF,2BAA4B,CAC5B,wEAAyE,CACzE,8QAA+Q,CAC/Q,oEAAuE,CACvE,6CACE,oBAAuB,CAE3B,kBACE,qFAAsF,CACtF,4FAA6F,CAC7F,4FAA6F,CAC7F,wHAAyH,CACzH,uFAAwF,CACxF,wFAAyF,CACzF,wEAAyE,CACzE,uEAAwE,CACxE,gFAAiF,CACjF,4FAA6F,CAC7F,6FAA8F,CAC9F,gGAAiG,CACjG,mGAAoG,CACpG,yDAA0D,CAC1D,iEAAkE,CAClE,mEAAoE,CACpE,oEAAqE,CACrE,kEAAmE,CACnE,qEAAsE,CACtE,gFAAiF,CACjF,+EAAgF,CAChF,2DAA4D,CAC5D,0EAA2E,CAC3E,kEAAmE,CACnE,6EAA8E,CAC9E,iEAAkE,CAClE,yEAA0E,CAC1E,2EAA4E,CAC5E,4CAA6C,CAC7C,0EAA2E,CAC3E,uEAAwE,CACxE,2EAA8E,CAC9E,iCACE,qGAAwG,CAE5G,0BACE,iBAAkB,CAClB,YAAa,CACb,oBAAuB,CACvB,iCACE,iBAAkB,CAClB,OAAQ,CACR,QAAS,CACT,MAAO,CACP,mBAAoB,CACpB,UAAW,CACX,yIAA4I,CAEhJ,4BACE,YAAe,CACf,sDACE,6FAAgG,CAChG,4DACE,6HAAgI,CAClI,4DACE,6HAAgI,CAClI,qEACE,8GAAiH,CAEvH,wBACE,iBAAkB,CAClB,+DAAgE,CAChE,uDAAwD,CACxD,uDAA0D,CAC1D,8CACE,iBAAkB,CAClB,KAAM,CACN,OAAQ,CACR,QAAS,CACT,MAAO,CACP,UAAW,CACX,oFAAqF,CACrF,mEAAsE,CACxE,+CACE,iBAAkB,CAClB,KAAM,CACN,OAAQ,CACR,QAAS,CACT,MAAO,CACP,UAAW,CACX,8IAAiJ,CACnJ,uCACE,+DAAkE,CAEtE,kDACE,kBAAqB,CAEvB,wBACE,iBAAkB,CAClB,qLAAwL,CACxL,oDACE,yDAA0D,CAC1D,qDAAsD,CACtD,oBAAuB,CAE3B,uBACE,iBAAkB,CAClB,YAAa,CACb,kBAAmB,CACnB,iLAAkL,CAClL,gBAAiB,CACjB,yCAA0C,CAC1C,8DAA+D,CAG/D,yGAAuM,CAAvM,6GAAuM,CAAvM,2GAAuM,CAAvM,uGAAyM,CAE3M,wDACE,+DAAkE,CAEpE,cACE,yDAA0D,CAC1D,2DAA4D,CAC5D,uDAAwD,CACxD,+DAAgE,CAChE,kDAAmD,CACnD,qFAAsF,CACtF,0DAA2D,CAC3D,6DAA8D,CAC9D,+DAAgE,CAChE,4DAA6D,CAC7D,mEAAoE,CACpE,0DAA2D,CAC3D,6DAA8D,CAC9D,+DAAgE,CAChE,2DAA4D,CAC5D,mEAAoE,CACpE,0DAA2D,CAC3D,6DAA8D,CAC9D,+DAAgE,CAChE,2DAA4D,CAC5D,mEAAoE,CACpE,0DAA2D,CAC3D,6DAA8D,CAC9D,+DAAgE,CAChE,2DAA4D,CAC5D,mEAAoE,CACpE,0DAA2D,CAC3D,6DAA8D,CAC9D,+DAAgE,CAChE,2DAA4D,CAC5D,mEAAoE,CACpE,0DAA2D,CAC3D,6DAA8D,CAC9D,+DAAgE,CAChE,2DAA4D,CAC5D,mEAAoE,CACpE,gEAAiE,CACjE,kEAAmE,CACnE,8DAA+D,CAC/D,yDAA0D,CAC1D,sDAAuD,CACvD,wEAAyE,CACzE,oEAAqE,CACrE,sFAAuF,CACvF,mEAAoE,CACpE,qEAAsE,CACtE,sEAAuE,CACvE,oEAAqE,CACrE,8DAA+D,CAC/D,8EAA+E,CAC/E,6EAA8E,CAC9E,4DAA6D,CAC7D,2DAA4D,CAC5D,kEAAmE,CACnE,mEAAoE,CACpE,4DAA6D,CAC7D,2DAA4D,CAC5D,kEAAmE,CACnE,mEAAoE,CACpE,yDAA0D,CAC1D,0DAA2D,CAC3D,2DAA4D,CAC5D,uDAAwD,CACxD,sEAAuE,CACvE,0DAA2D,CAC3D,mCAAoC,CACpC,4DAA6D,CAC7D,sEAAuE,CACvE,uCAAwC,CACxC,2CAA4C,CAC5C,gCAAmC,CACnC,gBACE,mCAAoC,CACpC,sDAAyD,CACzD,sBACE,6DAA8D,CAC9D,+EAAkF,CACtF,oBACE,6CAAgD,CAClD,gUASE,+CAAkD,CACpD,sGAME,QAAS,CACT,oDAAuD,CACvD,8KAME,YAAe,CACjB,wKAME,eAAkB,CACtB,kCAEE,QAAW,CACb,iBACE,6CAA8C,CAC9C,mDAAoD,CACpD,2CAA4C,CAC5C,+CAAgD,CAChD,+CAAkD,CACpD,iBACE,6CAA8C,CAC9C,mDAAoD,CACpD,2CAA4C,CAC5C,+CAAgD,CAChD,+CAAkD,CACpD,iBACE,6CAA8C,CAC9C,mDAAoD,CACpD,2CAA4C,CAC5C,+CAAgD,CAChD,+CAAkD,CACpD,iBACE,6CAA8C,CAC9C,mDAAoD,CACpD,2CAA4C,CAC5C,+CAAgD,CAChD,+CAAkD,CACpD,iBACE,6CAA8C,CAC9C,mDAAoD,CACpD,2CAA4C,CAC5C,+CAAgD,CAChD,+CAAkD,CACpD,iBACE,6CAA8C,CAC9C,mDAAoD,CACpD,2CAA4C,CAC5C,+CAAgD,CAChD,+CAAkD,CACpD,oBACE,aAAc,CACd,8CAA+C,CAC/C,kDAAmD,CACnD,uCAA0C,CAC1C,qCACE,sDAAyD,CAC7D,yBACE,6LAA8L,CAC9L,4CAA6C,CAC7C,mHAAsH,CACxH,iBACE,sCAAuC,CACvC,yDAA0D,CAC1D,WAAc,CAChB,iBACE,iDAAkD,CAClD,+CAAkD,CAClD,oBACE,qDAAsD,CACtD,0EAA6E,CAC/E,oBACE,qDAAsD,CACtD,0EAA6E,CACjF,iBACE,iDAAkD,CAClD,+CAAgD,CAChD,6CAAgD,CAChD,oBACE,qDAAsD,CACtD,0EAA6E,CAC/E,oBACE,qDAAsD,CACtD,0EAA6E,CACjF,iBACE,YAAa,CACb,yBAA4B,CAC5B,oCACE,iBACE,2BAA8B,CAC9B,kDAAmD,CACnD,4CAA+C,CAAE,CACvD,iBACE,+CAAkD,CAClD,mCACE,6CAAgD,CAChD,oCACE,mCACE,oEAAuE,CAAE,CAC/E,oCACE,iBACE,aAAgB,CAAE,CACxB,oCACE,iBACE,aAAgB,CAAE,CAExB,kCACE,+DAAgE,CAChE,sEAAuE,CACvE,sEAAuE,CACvE,sEAAyE,CACzE,6CACE,+CAAkD,CAEtD,uBACE,wCAAyC,CACzC,kFAAmF,CACnF,0EAA2E,CAC3E,qFAAsF,CACtF,yEAA0E,CAC1E,8EAA+E,CAC/E,kFAAmF,CACnF,oFAAqF,CACrF,qFAAsF,CACtF,mFAAoF,CACpF,mEAAoE,CACpE,6FAA8F,CAC9F,4FAA6F,CAC7F,8FAA+F,CAC/F,8FAA+F,CAC/F,gGAAiG,CACjG,6EAA8E,CAC9E,qFAAsF,CACtF,iFAAkF,CAClF,8EAA+E,CAC/E,6EAA8E,CAC9E,4EAA6E,CAC7E,kEAAmE,CACnE,sEAAuE,CACvE,2FAA4F,CAC5F,wEAAyE,CACzE,6EAA8E,CAC9E,+EAAgF,CAChF,gFAAiF,CACjF,8EAA+E,CAC/E,0FAA2F,CAC3F,yFAA0F,CAC1F,mFAAoF,CACpF,6EAA8E,CAC9E,+EAAgF,CAChF,gFAAiF,CACjF,8EAA+E,CAC/E,qDAAsD,CACtD,gFAAiF,CACjF,kFAAmF,CACnF,mFAAoF,CACpF,iFAAkF,CAClF,4GAA6G,CAC7G,0FAA2F,CAC3F,iBAAkB,CAClB,oBAAqB,CACrB,yCAA0C,CAC1C,cAAiB,CAEnB,+BACE,iBAAkB,CAClB,YAAa,CACb,kBAAmB,CACnB,6BAA8B,CAC9B,UAAW,CACX,iNAAkN,CAClN,iDAAkD,CAClD,kBAAmB,CACnB,cAAe,CACf,WAAc,CACd,sCACE,iBAAkB,CAClB,KAAM,CACN,OAAQ,CACR,QAAS,CACT,MAAO,CACP,UAAW,CACX,8DAA+D,CAC/D,sOAAyO,CAC3O,4CACE,iHAAoH,CACtH,kJACE,kHAAmH,CACnH,mFAAsF,CACxF,qDACE,oHAAqH,CACrH,qFAAwF,CAC1F,mEACE,mEAAoE,CACpE,iEAAoE,CACtE,mEACE,eAAgB,CAChB,sBAAuB,CACvB,kBAAmB,CACnB,6DAA8D,CAC9D,iEAAkE,CAClE,iEAAoE,CAExE,6BACE,kCAAmC,CACnC,iBAAkB,CAClB,2CAA4C,CAC5C,kDAAmD,CACnD,cAAe,CACf,0DAA2D,CAC3D,oEAAqE,CACrE,2BAA4B,CAC5B,wDAA2D,CAE7D,oCACE,iBAAkB,CAClB,qOAAsO,CACtO,6IAAgJ,CAElJ,oCACE,qOAAsO,CACtO,gBAAiB,CACjB,+DAAkE,CAEpE,kCACE,6DAA8D,CAC9D,iBAAoB,CAEtB,uCACE,YAAa,CACb,kBAAmB,CACnB,UAAW,CACX,iPAAkP,CAClP,kBAAmB,CACnB,WAAc,CACd,0FACE,oBAAqB,CACrB,qFAAwF,CAC1F,gDACE,mEAAoE,CACpE,mBAAsB,CAE1B,oCACE,wCACE,0FAA2F,CAC3F,oFAAqF,CACrF,gGAAiG,CACjG,4FAA6F,CAC7F,oHAAqH,CACrH,0HAA2H,CAC3H,0GAA2G,CAC3G,8GAAiH,CAAE,CACrH,2DACE,wCACE,0FAA2F,CAC3F,wFAAyF,CACzF,wHAAyH,CACzH,sHAAyH,CAAE,CAEjI,oCACI,sEACE,YAAa,CACb,cAAe,CACf,WAAY,CACZ,qEAAwE,CAC1E,+FACE,qDAAwD,CAC1D,oFACE,MAAO,CACP,OAAgB,CAClB,+EACE,gBAAmB,CACrB,2EACE,WAAc,CAChB,0EACE,WAAc,CAChB,0EACE,WAAc,CAChB,0EACE,WAAc,CAChB,0EACE,WAAc,CAChB,4EACE,eAAmB,CACnB,kBAAqB,CAAE,CAE7B,gCACE,+BACE,0FAA2F,CAC3F,oFAAqF,CACrF,gGAAiG,CACjG,4FAA6F,CAC7F,oHAAqH,CACrH,0HAA2H,CAC3H,0GAA2G,CAC3G,8GAAiH,CAAE,CACrH,uDACE,+BACE,0FAA2F,CAC3F,wFAAyF,CACzF,wHAAyH,CACzH,sHAAyH,CAAE,CAEjI,gCACI,6DACE,YAAa,CACb,cAAe,CACf,WAAY,CACZ,qEAAwE,CAC1E,sFACE,qDAAwD,CAC1D,2EACE,MAAO,CACP,OAAgB,CAClB,sEACE,gBAAmB,CACrB,kEACE,WAAc,CAChB,iEACE,WAAc,CAChB,iEACE,WAAc,CAChB,iEACE,WAAc,CAChB,iEACE,WAAc,CAChB,mEACE,eAAmB,CACnB,kBAAqB,CAAE,CAE7B,oCACE,6BACE,0FAA2F,CAC3F,oFAAqF,CACrF,gGAAiG,CACjG,4FAA6F,CAC7F,oHAAqH,CACrH,0HAA2H,CAC3H,0GAA2G,CAC3G,8GAAiH,CAAE,CACrH,2DACE,6BACE,0FAA2F,CAC3F,wFAAyF,CACzF,wHAAyH,CACzH,sHAAyH,CAAE,CAEjI,oCACI,2DACE,YAAa,CACb,cAAe,CACf,WAAY,CACZ,qEAAwE,CAC1E,oFACE,qDAAwD,CAC1D,yEACE,MAAO,CACP,OAAgB,CAClB,oEACE,gBAAmB,CACrB,gEACE,WAAc,CAChB,+DACE,WAAc,CAChB,+DACE,WAAc,CAChB,+DACE,WAAc,CAChB,+DACE,WAAc,CAChB,iEACE,eAAmB,CACnB,kBAAqB,CAAE,CAE7B,oCACE,6BACE,0FAA2F,CAC3F,oFAAqF,CACrF,gGAAiG,CACjG,4FAA6F,CAC7F,oHAAqH,CACrH,0HAA2H,CAC3H,0GAA2G,CAC3G,8GAAiH,CAAE,CACrH,2DACE,6BACE,0FAA2F,CAC3F,wFAAyF,CACzF,wHAAyH,CACzH,sHAAyH,CAAE,CAEjI,oCACI,2DACE,YAAa,CACb,cAAe,CACf,WAAY,CACZ,qEAAwE,CAC1E,oFACE,qDAAwD,CAC1D,yEACE,MAAO,CACP,OAAgB,CAClB,oEACE,gBAAmB,CACrB,gEACE,WAAc,CAChB,+DACE,WAAc,CAChB,+DACE,WAAc,CAChB,+DACE,WAAc,CAChB,+DACE,WAAc,CAChB,iEACE,eAAmB,CACnB,kBAAqB,CAAE,CAE7B,oCACE,6BACE,0FAA2F,CAC3F,oFAAqF,CACrF,gGAAiG,CACjG,4FAA6F,CAC7F,oHAAqH,CACrH,0HAA2H,CAC3H,0GAA2G,CAC3G,8GAAiH,CAAE,CACrH,2DACE,6BACE,0FAA2F,CAC3F,wFAAyF,CACzF,wHAAyH,CACzH,sHAAyH,CAAE,CAEjI,oCACI,2DACE,YAAa,CACb,cAAe,CACf,WAAY,CACZ,qEAAwE,CAC1E,oFACE,qDAAwD,CAC1D,yEACE,MAAO,CACP,OAAgB,CAClB,oEACE,gBAAmB,CACrB,gEACE,WAAc,CAChB,+DACE,WAAc,CAChB,+DACE,WAAc,CAChB,+DACE,WAAc,CAChB,+DACE,WAAc,CAChB,iEACE,eAAmB,CACnB,kBAAqB,CAAE,CAE7B,qCACE,6BACE,0FAA2F,CAC3F,oFAAqF,CACrF,gGAAiG,CACjG,4FAA6F,CAC7F,oHAAqH,CACrH,0HAA2H,CAC3H,0GAA2G,CAC3G,8GAAiH,CAAE,CACrH,4DACE,6BACE,0FAA2F,CAC3F,wFAAyF,CACzF,wHAAyH,CACzH,sHAAyH,CAAE,CAEjI,qCACI,2DACE,YAAa,CACb,cAAe,CACf,WAAY,CACZ,qEAAwE,CAC1E,oFACE,qDAAwD,CAC1D,yEACE,MAAO,CACP,OAAgB,CAClB,oEACE,gBAAmB,CACrB,gEACE,WAAc,CAChB,+DACE,WAAc,CAChB,+DACE,WAAc,CAChB,+DACE,WAAc,CAChB,+DACE,WAAc,CAChB,iEACE,eAAmB,CACnB,kBAAqB,CAAE,CAE7B,qCACE,8BACE,0FAA2F,CAC3F,oFAAqF,CACrF,gGAAiG,CACjG,4FAA6F,CAC7F,oHAAqH,CACrH,0HAA2H,CAC3H,0GAA2G,CAC3G,8GAAiH,CAAE,CACrH,4DACE,8BACE,0FAA2F,CAC3F,wFAAyF,CACzF,wHAAyH,CACzH,sHAAyH,CAAE,CAEjI,qCACI,4DACE,YAAa,CACb,cAAe,CACf,WAAY,CACZ,qEAAwE,CAC1E,qFACE,qDAAwD,CAC1D,0EACE,MAAO,CACP,OAAgB,CAClB,qEACE,gBAAmB,CACrB,iEACE,WAAc,CAChB,gEACE,WAAc,CAChB,gEACE,WAAc,CAChB,gEACE,WAAc,CAChB,gEACE,WAAc,CAChB,kEACE,eAAmB,CACnB,kBAAqB,CAAE,CAE7B,gBACE,mEAAoE,CACpE,6DAA8D,CAC9D,sEAAuE,CACvE,uEAAwE,CACxE,8EAA+E,CAC/E,uEAAwE,CACxE,+FAAgG,CAChG,+FAAgG,CAChG,wHAA0H,CAC1H,yFAA4F,CAC5F,6GAA8G,CAC9G,iIAAmI,CACnI,iIAAmI,CACnI,kIAAoI,CACpI,6GAA8G,CAC9G,4EAA6E,CAC7E,gDAAiD,CACjD,gHAAiH,CACjH,gHAAiH,CACjH,+EAAgF,CAChF,gFAAiF,CACjF,2DAA4D,CAC5D,uEAAwE,CACxE,uEAAwE,CACxE,qCAAsC,CACtC,+FAAkG,CAClG,qEAAsE,CACtE,oEAAqE,CACrE,yEAA0E,CAC1E,wEAAyE,CACzE,8EAA+E,CAC/E,+DAAgE,CAChE,kEAAmE,CACnE,gEAAiE,CACjE,2CAA4C,CAC5C,wEAAyE,CACzE,0CAA2C,CAC3C,yEAA0E,CAC1E,6EAA8E,CAC9E,wCAAyC,CACzC,wCAAyC,CACzC,yCAA0C,CAC1C,yCAA0C,CAC1C,wCAAyC,CACzC,gDAAiD,CACjD,0EAA6E,CAC7E,mFAAsF,CACtF,wDAAyD,CACzD,6DAA8D,CAC9D,iFAAkF,CAClF,kFAAmF,CACnF,wFAA2F,CAC3F,yFAA4F,CAC5F,wFAAyF,CACzF,gHAAiH,CACjH,yGAA0G,CAC1G,yGAA0G,CAC1G,kGAAmG,CACnG,sDAAuD,CACvD,uEAAwE,CACxE,0EAA2E,CAC3E,wEAAyE,CACzE,4EAA6E,CAC7E,wFAAyF,CACzF,2CAA4C,CAC5C,sEAAuE,CACvE,yEAA0E,CAC1E,sEAAuE,CACvE,0EAA2E,CAC3E,uFAAwF,CACxF,mFAAsF,CACtF,sFAAuF,CACvF,uFAAwF,CACxF,uHAA0H,CAC1H,qHAAwH,CACxH,uDAAwD,CACxD,yGAA4G,CAC5G,kFAAmF,CACnF,oFAAqF,CACrF,qFAAsF,CACtF,mFAAoF,CACpF,sFAAuF,CACvF,wFAAyF,CACzF,yFAA0F,CAC1F,uFAAwF,CACxF,oEAAqE,CACrE,2EAA4E,CAC5E,0EAA2E,CAC3E,6EAA8E,CAC9E,sDAAuD,CACvD,oDAAqD,CACrD,mFAAoF,CACpF,iFAAkF,CAClF,kFAAmF,CACnF,0DAA2D,CAC3D,mFAAoF,CACpF,iFAAkF,CAClF,oFAAqF,CACrF,iFAAkF,CAClF,qFAAsF,CACtF,kCAAmC,CACnC,wBAAyB,CACzB,oBAAqB,CACrB,4FAA+F,CAC/F,oCACE,gBACE,0EAA2E,CAC3E,0EAA2E,CAG3E,4FAA6F,CAC7F,4FAJ6E,CAAE,CAKnF,yBACE,gBACE,gFAAmF,CAAE,CACzF,6BACE,oDAAqD,CACrD,mGAAoG,CACpG,mGAAoG,CACpG,yGAA0G,CAC1G,uGAAwG,CACxG,qGAAsG,CACtG,2GAA4G,CAC5G,+GAAkH,CAClH,mDACE,qFAAsF,CACtF,2FAA4F,CAC5F,6FAA8F,CAC9F,gGAAmG,CACrG,oDACE,2DAA8D,CAClE,+BACE,oBAAuB,CAE3B,8IAIE,kFAAmF,CACnF,uCAAwC,CACxC,6CAA8C,CAC9C,yCAA4C,CAE9C,sJAIE,4CAA+C,CAEjD,sIAIE,yCAA4C,CAE9C,sBACE,iBAAkB,CAClB,YAAa,CACb,qBAAsB,CACtB,6DAA8D,CAC9D,iHAAoH,CACpH,6BACE,iBAAkB,CAClB,4CAA6C,CAC7C,QAAS,CACT,MAAO,CACP,gDAAiD,CACjD,UAAW,CACX,qEAAsE,CACtE,0DAA6D,CAC/D,sCACE,cAAe,CACf,uEAA0E,CAC1E,wFACE,iBAAkB,CAClB,gEAAmE,CACnE,kKACE,2CAA8C,CAC9C,8MACE,8JAAiK,CACvK,4CACE,sEAAyE,CAC3E,4CACE,sEAAyE,CAC3E,6CACE,uEAA0E,CAC9E,oCACE,gHAAiH,CACjH,iBAAkB,CAClB,uDAAwD,CACxD,6DAAgE,CAClE,2CACE,iBAAkB,CAClB,KAAM,CACN,OAAQ,CACR,QAAS,CACT,MAAO,CACP,UAAW,CACX,iFAAkF,CAClF,gEAAmE,CACrE,oCACE,gHAAmH,CACnH,wEACE,8HAAiI,CAEvI,0BACE,YAAa,CACb,gBAAiB,CACjB,2DAA4D,CAC5D,yDAA4D,CAE9D,8BACE,YAAa,CACb,gBAAiB,CACjB,2DAA4D,CAC5D,iEAAkE,CAClE,6DAAgE,CAChE,gDACE,6EAAgF,CAEpF,uCACE,wEAAyE,CACzE,sEAAuE,CACvE,kEAAmE,CACnE,oEAAqE,CACrE,QAAW,CACX,6CACE,8HAA+H,CAC/H,WAAc,CAChB,6CACE,8HAAiI,CACnI,8CACE,eAAkB,CACpB,qDACE,mIAAoI,CACpI,mBAAoB,CACpB,WAAc,CAChB,4EACE,8DAAiE,CAErE,6BACE,iFAAkF,CAClF,sBAAuB,CACvB,wBAAyB,CACzB,0DAA2D,CAC3D,gEAAiE,CACjE,0DAA6D,CAC7D,+CACE,4EAA+E,CACjF,qDACE,mDAAsD,CAE1D,wBACE,mDAAoD,CACpD,qDAAwD,CAE1D,6BACE,mBAAoB,CACpB,yDAA4D,CAC5D,iEACE,8EAAiF,CAErF,8BACE,YAAa,CACb,UAAW,CACX,8BAAiC,CAEnC,sBACE,MAAO,CACP,gBAAmB,CACnB,mDAAoD,CACpD,yDAA4D,CAC5D,4CACE,aAAc,CACd,OAAQ,CACR,yDAA4D,CAC9D,gCACE,WAAY,CACZ,6DAA8D,CAC9D,eAAoB,CACtB,sDACE,eAAkB,CAClB,iEAAoE,CACtE,uCACE,aAAgB,CAEpB,sBACE,oBAAuB,CAEzB,4CAEE,+CAAgD,CAChD,cAAe,CACf,8CAA+C,CAC/C,uDAAwD,CACxD,iDAAkD,CAClD,mDAAsD,CAExD,oCACE,+DAAgE,CAChE,eAAgB,CAChB,oIAAuI,CACvI,6EACE,yPAA4P,CAC5P,6FACE,SAAY,CAElB,uBACE,4DAA6D,CAC7D,+DAAgE,CAChE,qDAAsD,CACtD,uDAAwD,CACxD,sKAAwK,CACxK,mEAAoE,CACpE,sEAAuE,CACvE,wDAAyD,CACzD,+CAAgD,CAChD,4EAA6E,CAC7E,sEAAuE,CACvE,uDAAwD,CACxD,2EAA6E,CAC7E,0KAA2K,CAC3K,8DAA+D,CAC/D,uEAAwE,CACxE,wIAAyI,CACzI,YAAa,CACb,oBAAqB,CACrB,4CAA6C,CAC7C,kDAAmD,CACnD,uEAA0E,CAC1E,oCACE,uBACE,8DAA+D,CAC/D,8DAAiE,CAAE,CACvE,uCACE,0HAA2H,CAC3H,4FAA+F,CAC/F,yBACE,uCACE,0JAA8J,CAAE,CACpK,yBACE,uCACE,wNAA6N,CAAE,CACnO,0BACE,uCACE,sRAA4R,CAAE,CAClS,0BACE,uCACE,qVAA4V,CAAE,CACpW,wCACE,mBAAsB,CACxB,+CACE,2EAA+E,CACjF,qCACE,6HAAgI,CAChI,gHAAmH,CACnH,yBACE,qCACE,6KAAiL,CAAE,CACvL,yBACE,qCACE,0OAA+O,CAAE,CACrP,0BACE,qCACE,uSAA6S,CAAE,CACnT,0BACE,qCACE,qWAA4W,CAAE,CAEtX,8BACE,YAAa,CACb,2DAA4D,CAC5D,mDAAoD,CACpD,yDAA0D,CAC1D,8EAA+E,CAC/E,oBAAuB,CAEzB,iEAEE,eAAkB,CAEpB,6BACE,sDAAuD,CACvD,0DAA6D,CAC7D,0DACE,cAAiB,CAErB,kCACE,qHAAwH,CAE1H,kCACE,qHAAwH,CAE1H,kCACE,qHAAwH,CAE1H,yBACE,wCACE,qHAAwH,CAC1H,wCACE,qHAAwH,CAC1H,wCACE,qHAAwH,CAAE,CAE9H,yBACE,wCACE,qHAAwH,CAC1H,wCACE,qHAAwH,CAC1H,wCACE,qHAAwH,CAAE,CAE9H,0BACE,wCACE,qHAAwH,CAC1H,wCACE,qHAAwH,CAC1H,wCACE,qHAAwH,CAAE,CAE9H,0BACE,yCACE,qHAAwH,CAC1H,yCACE,qHAAwH,CAC1H,yCACE,qHAAwH,CAAE,CAE9H,yBACE,uDAAwD,CACxD,qDAAsD,CACtD,uDAAwD,CACxD,mDAAoD,CACpD,sDAAuD,CACvD,mEAAoE,CACpE,iEAAkE,CAClE,mEAAoE,CACpE,+DAAgE,CAChE,yEAA0E,CAC1E,2EAA4E,CAC5E,4EAA6E,CAC7E,oFAAqF,CACrF,2EAA4E,CAC5E,+FAAgG,CAChG,8EAA+E,CAC/E,+EAAgF,CAChF,kDAAmD,CACnD,gDAAiD,CACjD,wEAAyE,CACzE,0EAA2E,CAC3E,2EAA4E,CAC5E,yEAA0E,CAC1E,wEAAyE,CACzE,4DAA6D,CAC7D,oGAAqG,CACrG,2GAA4G,CAC5G,yGAA0G,CAC1G,4DAA6D,CAC7D,gKAAiK,CACjK,4IAA6I,CAC7I,wEAAyE,CACzE,4FAA6F,CAC7F,gGAAiG,CACjG,4EAA6E,CAC7E,+EAAgF,CAChF,0EAA2E,CAC3E,8EAA+E,CAC/E,6EAA8E,CAC9E,+EAAgF,CAChF,iFAAkF,CAClF,kFAAmF,CACnF,gFAAiF,CACjF,uFAA0F,CAC1F,0FAA6F,CAC7F,0DAA2D,CAC3D,oEAAqE,CACrE,+EAAgF,CAChF,8EAA+E,CAC/E,uGAAwG,CACxG,qDAAsD,CACtD,gFAAiF,CACjF,oFAAqF,CACrF,oGAAqG,CACrG,YAAa,CACb,4IAA6I,CAC7I,6UAAgV,CAChV,sCAA0C,CAE5C,+BACE,gBAAmB,CACnB,2CACE,sGAAuG,CACvG,oGAAqG,CACrG,sGAAuG,CACvG,kGAAqG,CAEzG,iCACE,0DAA2D,CAC3D,kEAAqE,CAEvE,qCACE,kEAAqE,CAEvE,gCACE,YAAa,CACb,yDAA0D,CAC1D,iEAAoE,CAEtE,uCACE,WAAc,CAEhB,wCACE,YAAe,CACf,+EACE,mFAAsF,CAE1F,iCACE,YAAa,CACb,0DAA2D,CAC3D,kEAAqE,CAEvE,sCACE,WAAY,CACZ,+DAAgE,CAChE,wDAA2D,CAE7D,+BACE,wDAAyD,CACzD,0DAA2D,CAC3D,0DAA2D,CAC3D,aAAc,CACd,gHAAmH,CAErH,+BACE,YAAa,CACb,qBAAwB,CACxB,8DACE,mDAAoD,CACpD,sDAAyD,CACzD,oGACE,iBAAkB,CAClB,KAAM,CACN,kEAAmE,CACnE,yFAA4F,CAElG,oDACE,4GAA+G,CAEjH,iFACE,mIAAsI,CAExI,8DAEE,YAAe,CAEjB,mEAEE,eAAkB,CAEpB,+BACE,iBAAkB,CAClB,UAAW,CACX,iNAAkN,CAClN,wDAAyD,CACzD,eAAgB,CAChB,cAAe,CACf,sEAAuE,CACvE,QAAW,CACX,qCACE,6GAAgH,CAClH,4CACE,oHAAuH,CACzH,6CACE,kHAAqH,CACrH,iFACE,yGAA0G,CAC1G,8EAAiF,CACrF,0CACE,wEAA2E,CAC7E,oEACE,kEAAqE,CACrE,0FACE,4GAA+G,CAErH,oCACE,eAAgB,CAChB,sBAAuB,CACvB,kBAAmB,CACnB,WAAY,CACZ,sDAAyD,CAE3D,mCACE,4DAA6D,CAC7D,iBAAkB,CAClB,oEAAqE,CACrE,kEAAqE,CAEvE,oCACE,YAAa,CACb,WAAc,CAEhB,sCACE,6OAA8O,CAC9O,iEAAkE,CAClE,uEAA0E,CAE5E,qCACE,YAAa,CACb,kBAAmB,CACnB,oEAAuE,CAEzE,2CACE,oBAAqB,CACrB,oEAAqE,CACrE,iBAAkB,CAClB,uEAAwE,CACxE,0EAA6E,CAE/E,wEACE,mKAAsK,CACtK,0GAA6G,CAE/G,4GACE,mKAAsK,CACtK,0GAA6G,CAE/G,gJACE,mKAAsK,CACtK,0GAA6G,CAE/G,oLACE,mKAAsK,CACtK,0GAA6G,CAE/G,wNACE,mKAAsK,CACtK,0GAA6G,CAE/G,4PACE,mKAAsK,CACtK,0GAA6G,CAE/G,gSACE,mKAAsK,CACtK,0GAA6G,CAE/G,oUACE,mKAAsK,CACtK,0GAA6G,CAE/G,wWACE,mKAAsK,CACtK,0GAA6G,CAE/G,4YACE,oKAAuK,CACvK,0GAA6G,CAE/G,cACE,sEAAuE,CACvE,mDAAoD,CACpD,uDAAwD,CACxD,0DAA2D,CAC3D,kEAAmE,CACnE,iEAAkE,CAClE,iEAAkE,CAClE,qEAAsE,CACtE,0EAA2E,CAC3E,2FAA4F,CAC5F,8EAA+E,CAC/E,yFAA0F,CAC1F,sDAAuD,CACvD,uDAAwD,CACxD,qDAAsD,CACtD,uEAAwE,CACxE,oFAAqF,CACrF,wFAAyF,CACzF,uFAAwF,CACxF,wFAA2F,CAC3F,qFAAsF,CACtF,yDAA0D,CAC1D,8DAA+D,CAC/D,+DAAgE,CAChE,0EAA2E,CAC3E,wFAAyF,CACzF,qFAAsF,CACtF,yDAA0D,CAC1D,gFAAiF,CACjF,+EAAgF,CAChF,gFAAiF,CACjF,oDAAqD,CACrD,+EAAgF,CAChF,wEAAyE,CACzE,yCAA0C,CAC1C,wEAAyE,CACzE,6EAA8E,CAC9E,0EAA2E,CAC3E,uEAAwE,CACxE,uEAAwE,CACxE,4EAA6E,CAC7E,yFAA0F,CAC1F,+EAAgF,CAChF,iBAAkB,CAClB,mCAAoC,CACpC,YAAa,CACb,2CAA4C,CAC5C,iDAAkD,CAClD,qDAAwD,CACxD,oCACE,cACE,0GAA2G,CAC3G,4GAA6G,CAC7G,wGAA2G,CAAE,CACjH,qCACE,cACE,kFAAqF,CAAE,CAC3F,+BACE,+EAAgF,CAChF,8EAAiF,CAErF,gFAEE,yEAA4E,CAE9E,4GAEE,wCAA2C,CAC3C,kIAEE,wBAA2B,CAE/B,qBACE,yDAA0D,CAC1D,YAAa,CACb,kBAAmB,CACnB,wCAA2C,CAC3C,uCACE,yEAA4E,CAC5E,yCACE,8EAAiF,CACrF,4CACE,8EAAiF,CACjF,8CACE,mFAAsF,CAC1F,uCACE,yEAA4E,CAC5E,yCACE,8EAAiF,CACnF,2CACE,gBAAmB,CACvB,uCACE,yEAA4E,CAC5E,uHAEE,YAAa,CACb,iBAAoB,CACtB,6DACE,oBAAqB,CACrB,kBAAqB,CACzB,gCACE,wBAA2B,CAE/B,oBACE,wDAAyD,CACzD,wCAA2C,CAC3C,uCACE,yEAA4E,CAC9E,qCACE,uEAA0E,CAC5E,kDACE,oHAAuH,CACzH,uCACE,yEAA4E,CAC9E,oCACE,sEAAyE,CAC3E,+BACE,iEAAkE,CAClE,0DAA6D,CAC/D,oCACE,gBAAmB,CACnB,qDACE,gBAAmB,CACvB,+BACE,wBAA2B,CAE/B,+BACE,oBAAqB,CACrB,2DAA4D,CAC5D,8DAAiE,CAEnE,sDAEE,YAAa,CACb,cAAe,CACf,kBAAqB,CAEvB,uBACE,iBAAkB,CAClB,wDAAyD,CACzD,sDAAyD,CAE3D,+BACE,UAAa,CAEf,kCACE,iBAAkB,CAClB,QAAS,CACT,OAAQ,CACR,MAAO,CACP,uDAAwD,CACxD,YAAa,CACb,UAAW,CACX,6NAA8N,CAC9N,iBAAkB,CAClB,yEAA0E,CAC1E,6DAAgE,CAChE,oCACE,kCACE,eAAgB,CAChB,eAAkB,CAAE,CACxB,gDACE,YAAa,CACb,4EAA6E,CAC7E,kBAAqB,CACvB,6GAEE,wBAA2B,CAC7B,uDACE,YAAa,CACb,4EAA+E,CACjF,8CACE,YAAa,CACb,iBAAoB,CAExB,oFAEE,YAAa,CACb,cAAe,CACf,oBAAqB,CACrB,kEAAmE,CACnE,cAAiB,CACjB,4HAEE,wDAAyD,CACzD,wEAA2E,CAC7E,8HAEE,yDAA0D,CAC1D,YAAa,CACb,cAAe,CACf,cAAiB,CACnB,sSAIE,wBAA2B,CAE/B,0CACE,gCAAmC,CAErC,6CACE,+CAAkD,CAEpD,4DACE,uEAA0E,CAE5E,6BACE,iFAAoF,CACpF,mGAEE,YAAa,CACb,aAAc,CACd,kBAAqB,CACvB,mDACE,YAAa,CACb,iBAAoB,CAExB,yBACE,mCACE,iFAAoF,CACpF,+GAEE,YAAa,CACb,aAAc,CACd,kBAAqB,CACvB,yDACE,YAAa,CACb,iBAAoB,CAAE,CAE5B,yBACE,mCACE,iFAAoF,CACpF,+GAEE,YAAa,CACb,aAAc,CACd,kBAAqB,CACvB,yDACE,YAAa,CACb,iBAAoB,CAAE,CAE5B,yBACE,mCACE,iFAAoF,CACpF,+GAEE,YAAa,CACb,aAAc,CACd,kBAAqB,CACvB,yDACE,YAAa,CACb,iBAAoB,CAAE,CAE5B,0BACE,mCACE,iFAAoF,CACpF,+GAEE,YAAa,CACb,aAAc,CACd,kBAAqB,CACvB,yDACE,YAAa,CACb,iBAAoB,CAAE,CAE5B,0BACE,oCACE,iFAAoF,CACpF,iHAEE,YAAa,CACb,aAAc,CACd,kBAAqB,CACvB,0DACE,YAAa,CACb,iBAAoB,CAAE,CAE5B,uGAEE,gBAAmB,CAKrB,8OAEE,aAAgB,CAChB,uIAEE,gBAAmB,CAEvB,2BACE,YAAa,CACb,iBAAoB,CAEtB,4BACE,YAAa,CACb,kBAAqB,CAEvB,wGAEE,gBAAmB,CAErB,oGAEE,cAAiB,CAEnB,yBACE,mHAEE,gBAAmB,CAIrB,sQAEE,aAAgB,CAChB,mJAEE,gBAAmB,CACvB,iCACE,YAAa,CACb,iBAAoB,CACtB,kCACE,YAAa,CACb,kBAAqB,CACvB,oHAEE,gBAAmB,CACrB,gHAEE,cAAiB,CAAE,CAEvB,yBACE,mHAEE,gBAAmB,CAIrB,sQAEE,aAAgB,CAChB,mJAEE,gBAAmB,CACvB,iCACE,YAAa,CACb,iBAAoB,CACtB,kCACE,YAAa,CACb,kBAAqB,CACvB,oHAEE,gBAAmB,CACrB,gHAEE,cAAiB,CAAE,CAEvB,yBACE,mHAEE,gBAAmB,CAIrB,sQAEE,aAAgB,CAChB,mJAEE,gBAAmB,CACvB,iCACE,YAAa,CACb,iBAAoB,CACtB,kCACE,YAAa,CACb,kBAAqB,CACvB,oHAEE,gBAAmB,CACrB,gHAEE,cAAiB,CAAE,CAEvB,0BACE,mHAEE,gBAAmB,CAIrB,sQAEE,aAAgB,CAChB,mJAEE,gBAAmB,CACvB,iCACE,YAAa,CACb,iBAAoB,CACtB,kCACE,YAAa,CACb,kBAAqB,CACvB,oHAEE,gBAAmB,CACrB,gHAEE,cAAiB,CAAE,CAEvB,0BACE,qHAEE,gBAAmB,CAIrB,0QAEE,aAAgB,CAChB,qJAEE,gBAAmB,CACvB,kCACE,YAAa,CACb,iBAAoB,CACtB,mCACE,YAAa,CACb,kBAAqB,CACvB,sHAEE,gBAAmB,CACrB,kHAEE,cAAiB,CAAE,CAKvB,wFACE,wBAA2B,CAE7B,qCACE,mDAAsD,CAExD,+CACE,wBAA2B,CAE7B,qCACE,mDAAsD,CAExD,+CACE,wBAA2B,CAE7B,qCACE,mDAAsD,CAExD,+CACE,wBAA2B,CAE7B,yBAGE,oGACE,wBAA2B,CAC7B,2CACE,mDAAsD,CACxD,qDACE,wBAA2B,CAC7B,2CACE,mDAAsD,CACxD,qDACE,wBAA2B,CAC7B,2CACE,mDAAsD,CACxD,qDACE,wBAA2B,CAAE,CAEjC,yBAGE,oGACE,wBAA2B,CAC7B,2CACE,mDAAsD,CACxD,qDACE,wBAA2B,CAC7B,2CACE,mDAAsD,CACxD,qDACE,wBAA2B,CAC7B,2CACE,mDAAsD,CACxD,qDACE,wBAA2B,CAAE,CAEjC,yBAGE,oGACE,wBAA2B,CAC7B,2CACE,mDAAsD,CACxD,qDACE,wBAA2B,CAC7B,2CACE,mDAAsD,CACxD,qDACE,wBAA2B,CAC7B,2CACE,mDAAsD,CACxD,qDACE,wBAA2B,CAAE,CAEjC,0BAGE,oGACE,wBAA2B,CAC7B,2CACE,mDAAsD,CACxD,qDACE,wBAA2B,CAC7B,2CACE,mDAAsD,CACxD,qDACE,wBAA2B,CAC7B,2CACE,mDAAsD,CACxD,qDACE,wBAA2B,CAAE,CAEjC,0BAGE,sGACE,wBAA2B,CAC7B,4CACE,mDAAsD,CACxD,sDACE,wBAA2B,CAC7B,4CACE,mDAAsD,CACxD,sDACE,wBAA2B,CAC7B,4CACE,mDAAsD,CACxD,sDACE,wBAA2B,CAAE,CAI/B,2EACE,wBAA2B,CAI7B,uEACE,mDAAsD,CAIxD,uEACE,mDAAsD,CAIxD,uEACE,mDAAsD,CAE1D,yBAGI,uFACE,wBAA2B,CAG7B,mFACE,mDAAsD,CAGxD,mFACE,mDAAsD,CAGxD,mFACE,mDAAsD,CAAE,CAE9D,yBAGI,uFACE,wBAA2B,CAG7B,mFACE,mDAAsD,CAGxD,mFACE,mDAAsD,CAGxD,mFACE,mDAAsD,CAAE,CAE9D,yBAGI,uFACE,wBAA2B,CAG7B,mFACE,mDAAsD,CAGxD,mFACE,mDAAsD,CAGxD,mFACE,mDAAsD,CAAE,CAE9D,0BAGI,uFACE,wBAA2B,CAG7B,mFACE,mDAAsD,CAGxD,mFACE,mDAAsD,CAGxD,mFACE,mDAAsD,CAAE,CAE9D,0BAGI,yFACE,wBAA2B,CAG7B,qFACE,mDAAsD,CAGxD,qFACE,mDAAsD,CAGxD,qFACE,mDAAsD,CAAE,CAE9D,8BACE,uBAEkE,CAEpE,0DAHE,gEAAiE,CACjE,+DAKkE,CAHpE,4BACE,kDAEkE,CAEpE,4BACE,kDAEkE,CAEpE,wDAHE,gEAAiE,CACjE,+DAKkE,CAHpE,4BACE,kDAEkE,CAEpE,4BACE,kDAEkE,CAEpE,yDAHE,gEAAiE,CACjE,+DAKkE,CAHpE,6BACE,mDAEkE,CAEpE,yBACE,oCACE,uBAEkE,CACpE,sEAFE,gEAAiE,CACjE,+DAIkE,CAHpE,kCACE,kDAEkE,CACpE,kCACE,kDAEkE,CACpE,oEAFE,gEAAiE,CACjE,+DAIkE,CAHpE,kCACE,kDAEkE,CACpE,kCACE,kDAEkE,CACpE,qEAFE,gEAAiE,CACjE,+DAIkE,CAHpE,mCACE,mDAEkE,CAAE,CAExE,yBACE,oCACE,uBAEkE,CACpE,sEAFE,gEAAiE,CACjE,+DAIkE,CAHpE,kCACE,kDAEkE,CACpE,kCACE,kDAEkE,CACpE,oEAFE,gEAAiE,CACjE,+DAIkE,CAHpE,kCACE,kDAEkE,CACpE,kCACE,kDAEkE,CACpE,qEAFE,gEAAiE,CACjE,+DAIkE,CAHpE,mCACE,mDAEkE,CAAE,CAExE,yBACE,oCACE,uBAEkE,CACpE,sEAFE,gEAAiE,CACjE,+DAIkE,CAHpE,kCACE,kDAEkE,CACpE,kCACE,kDAEkE,CACpE,oEAFE,gEAAiE,CACjE,+DAIkE,CAHpE,kCACE,kDAEkE,CACpE,kCACE,kDAEkE,CACpE,qEAFE,gEAAiE,CACjE,+DAIkE,CAHpE,mCACE,mDAEkE,CAAE,CAExE,0BACE,oCACE,uBAEkE,CACpE,sEAFE,gEAAiE,CACjE,+DAIkE,CAHpE,kCACE,kDAEkE,CACpE,kCACE,kDAEkE,CACpE,oEAFE,gEAAiE,CACjE,+DAIkE,CAHpE,kCACE,kDAEkE,CACpE,kCACE,kDAEkE,CACpE,qEAFE,gEAAiE,CACjE,+DAIkE,CAHpE,mCACE,mDAEkE,CAAE,CAExE,0BACE,qCACE,uBAEkE,CACpE,wEAFE,gEAAiE,CACjE,+DAIkE,CAHpE,mCACE,kDAEkE,CACpE,mCACE,kDAEkE,CACpE,sEAFE,gEAAiE,CACjE,+DAIkE,CAHpE,mCACE,kDAEkE,CACpE,mCACE,kDAEkE,CACpE,uEAFE,gEAAiE,CACjE,+DAIkE,CAHpE,oCACE,mDAEkE,CAAE,CAExE,2CACE,wBAA2B,CAE7B,kBACE,0CAA2C,CAC3C,0FAA2F,CAC3F,uEAAwE,CACxE,wEAAyE,CACzE,mEAAoE,CACpE,mFAAoF,CACpF,mLAAsL,CACtL,uHAAwH,CACxH,yDAA0D,CAC1D,0FAA2F,CAC3F,uEAAwE,CACxE,iEAAkE,CAClE,2EAA4E,CAC5E,wCAAyC,CACzC,oCAAqC,CACrC,oDAAqD,CACrD,sDAAuD,CACvD,iBAAkB,CAClB,oBAAuB,CAEzB,+BACE,0DAA2D,CAC3D,wDAAyD,CACzD,iDAAoD,CACpD,0CACE,2FAA8F,CAElG,4CACE,2DAA8D,CAEhE,4BACE,iBAAkB,CAClB,0CAA2C,CAC3C,8CAA+C,CAC/C,4CAA6C,CAC7C,iDAAkD,CAClD,mEAAoE,CACpE,uDAA0D,CAC1D,6CACE,2FAA4F,CAC5F,yFAA4F,CAC9F,uDACE,+EAAgF,CAChF,0EAA6E,CAEjF,cACE,wDAAyD,CACzD,kEAAmE,CACnE,yDAA0D,CAC1D,2EAA4E,CAC5E,qCAAsC,CACtC,+BAAgC,CAChC,iDAAkD,CAClD,0EAA2E,CAC3E,YAAa,CACb,kBAAmB,CACnB,kBAAmB,CACnB,sBAAuB,CACvB,UAAW,CACX,QAAW,CACX,oBACE,4FAAqG,CACrG,kBAAmB,CACnB,yCAA0C,CAC1C,UAAW,CACX,4DAA6D,CAC7D,mBAAsB,CACxB,4BACE,mBAAoB,CACpB,qBAAsB,CACtB,UAAW,CACX,cAAe,CACf,eAAgB,CAChB,eAAkB,CAClB,kCACE,sGAAuG,CACvG,mDAAsD,CAC1D,8BACE,+BAAkC,CACpC,4BACE,yDAA4D,CAC9D,4BACE,yDAA4D,CAC9D,4BACE,yDAA4D,CAC9D,4BACE,yDAA4D,CAC9D,4BACE,yDAA4D,CAC9D,6BACE,0DAA6D,CAC/D,6BACE,0DAA6D,CAC/D,yBACE,oCACE,+BAAkC,CACpC,kCACE,yDAA4D,CAC9D,kCACE,yDAA4D,CAC9D,kCACE,yDAA4D,CAC9D,kCACE,yDAA4D,CAC9D,kCACE,yDAA4D,CAC9D,mCACE,0DAA6D,CAC/D,mCACE,0DAA6D,CAAE,CACnE,yBACE,oCACE,+BAAkC,CACpC,kCACE,yDAA4D,CAC9D,kCACE,yDAA4D,CAC9D,kCACE,yDAA4D,CAC9D,kCACE,yDAA4D,CAC9D,kCACE,yDAA4D,CAC9D,mCACE,0DAA6D,CAC/D,mCACE,0DAA6D,CAAE,CACnE,yBACE,oCACE,+BAAkC,CACpC,kCACE,yDAA4D,CAC9D,kCACE,yDAA4D,CAC9D,kCACE,yDAA4D,CAC9D,kCACE,yDAA4D,CAC9D,kCACE,yDAA4D,CAC9D,mCACE,0DAA6D,CAC/D,mCACE,0DAA6D,CAAE,CACnE,0BACE,oCACE,+BAAkC,CACpC,kCACE,yDAA4D,CAC9D,kCACE,yDAA4D,CAC9D,kCACE,yDAA4D,CAC9D,kCACE,yDAA4D,CAC9D,kCACE,yDAA4D,CAC9D,mCACE,0DAA6D,CAC/D,mCACE,0DAA6D,CAAE,CACnE,0BACE,qCACE,+BAAkC,CACpC,mCACE,yDAA4D,CAC9D,mCACE,yDAA4D,CAC9D,mCACE,yDAA4D,CAC9D,mCACE,yDAA4D,CAC9D,mCACE,yDAA4D,CAC9D,oCACE,0DAA6D,CAC/D,oCACE,0DAA6D,CAAE,CAErE,aACE,8EAA+E,CAC/E,sCAAuC,CACvC,8EAA+E,CAC/E,2DAA4D,CAC5D,oCAAqC,CACrC,uCAAwC,CACxC,kCAAmC,CACnC,oCAAqC,CACrC,uDAAwD,CACxD,4CAA6C,CAC7C,6CAA8C,CAC9C,4DAA6D,CAC7D,4DAA6D,CAC7D,yDAA0D,CAC1D,4EAA6E,CAC7E,6EAA8E,CAC9E,+EAAmF,CACnF,8FAA+F,CAC/F,6GAA8G,CAC9G,kGAAmG,CACnG,6DAA8D,CAC9D,+DAAgE,CAChE,gEAAiE,CACjE,8DAA+D,CAC/D,iEAAkE,CAClE,mEAAoE,CACpE,oEAAqE,CACrE,kEAAmE,CACnE,wEAAyE,CACzE,0EAA2E,CAC3E,2EAA4E,CAC5E,yEAA0E,CAC1E,4EAA6E,CAC7E,8EAA+E,CAC/E,+EAAgF,CAChF,6EAA8E,CAC9E,2CAA4C,CAC5C,6CAA8C,CAC9C,8CAA+C,CAC/C,4CAA6C,CAC7C,8BAA+B,CAC/B,mCAAoC,CACpC,iCAAkC,CAClC,+BAAgC,CAChC,yCAA0C,CAC1C,mCAAoC,CACpC,+EAAgF,CAChF,0CAA2C,CAC3C,gDAAiD,CACjD,oDAAqD,CACrD,sDAAuD,CACvD,kEAAmE,CACnE,8EAA+E,CAC/E,oFAAqF,CACrF,gDAAiD,CACjD,wGAAyG,CACzG,mDAAoD,CACpD,iDAAkD,CAClD,qHAAsH,CACtH,yHAA0H,CAC1H,6DAA8D,CAC9D,kDAAmD,CACnD,kHAAmH,CACnH,iHAAkH,CAClH,kEAAmE,CACnE,iEAAkE,CAClE,gIAAiI,CACjI,uCAAwC,CACxC,wGAAyG,CACzG,sDAAuD,CACvD,uHAAwH,CACxH,+EAAgF,CAChF,uFAAwF,CACxF,yDAA0D,CAC1D,0FAA2F,CAC3F,wDAAyD,CACzD,gGAAiG,CACjG,gGAAiG,CACjG,6EAA8E,CAC9E,+GAAgH,CAChH,gFAAiF,CACjF,8GAA+G,CAC/G,oDAAqD,CACrD,qDAAsD,CACtD,0EAA2E,CAC3E,2EAA4E,CAC5E,+EAAkF,CAClF,iFAAoF,CACpF,oCAAqC,CACrC,gFAAiF,CACjF,+FAAgG,CAChG,+FAAgG,CAChG,oEAAqE,CACrE,qFAAsF,CACtF,wDAAyD,CACzD,qGAAsG,CACtG,mFAAoF,CACpF,kGAAmG,CACnG,kGAAmG,CACnG,YAAa,CACb,qBAAsB,CACtB,WAAY,CACZ,iBAAoB,CACpB,oCACE,aACE,wEAAyE,CACzE,0EAA2E,CAC3E,8EAA+E,CAC/E,gFAAiF,CACjF,4EAA6E,CAC7E,gGAAiG,CACjG,oGAAqG,CACrG,sGAAuG,CACvG,kGAAqG,CAAE,CAC3G,qCACE,aACE,wEAAyE,CACzE,sEAAyE,CACzE,+BACE,mCAAoC,CACpC,wFAAyF,CACzF,wFAA2F,CAAE,CACnG,gIACE,6DAAgE,CAClE,oEACE,OAAQ,CACR,0DAA6D,CAC7D,2BAA8B,CAChC,sEACE,OAAU,CACZ,kDACE,qBAAwB,CAC1B,kEACE,2BAA8B,CAChC,kFACE,uBAA0B,CAC5B,oFACE,2BAAgC,CAEpC,sBACE,WAAY,CACZ,6DAAgE,CAChE,yCACE,4BAA+B,CAEnC,mBACE,YAAa,CACb,WAAY,CACZ,eAAkB,CAEpB,0CAEE,YAAa,CACb,qBAAsB,CACtB,aAAc,CACd,aAAgB,CAElB,sBACE,2CAA4C,CAC5C,iDAAkD,CAClD,OAAQ,CACR,6DAAgE,CAChE,yCACE,yMAA4M,CAC9M,yCACE,4BAA+B,CAEnC,oBACE,iBAAkB,CAClB,yCAA0C,CAC1C,+CAAgD,CAChD,OAAQ,CACR,+CAAgD,CAChD,aAAc,CACd,2DAA4D,CAC5D,+CAAgD,CAChD,iEAAkE,CAClE,iEAAkE,CAClE,gCAAmC,CACnC,0BACE,iBAAkB,CAClB,KAAM,CACN,MAAO,CACP,6CAA8C,CAC9C,WAAY,CACZ,UAAW,CACX,kEAAqE,CACvE,uCACE,4BAA+B,CAEnC,+BACE,GACE,iBAAoB,CAAE,CAE1B,4BACE,kCAAmC,CACnC,6DAA8D,CAC9D,4BAA+B,CAEjC,mBACE,YAAa,CACb,0BAA2B,CAC3B,6BAAgC,CAChC,qBACE,aAAgB,CAEpB,sBACE,aAAc,CACd,UAAW,CACX,YAAa,CACb,mBAAoB,CACpB,iDAAkD,CAClD,qDAAwD,CAE1D,mBACE,YAAa,CACb,qKAAwK,CACxK,mCACE,SAAY,CACZ,qIAEE,YAAa,CACb,cAAiB,CACrB,gCACE,iNAAoN,CACtN,2CACE,aAAgB,CAClB,8BACE,QAAW,CAEf,oCACE,eAAkB,CAEpB,uBACE,iBAAkB,CAClB,qCAAsC,CACtC,yCAA0C,CAC1C,2CAA4C,CAC5C,uCAAwC,CACxC,YAAa,CACb,yCAA0C,CAC1C,2CAA4C,CAC5C,2CAA4C,CAC5C,iBAAkB,CAClB,8DAAiE,CACjE,qCACE,gFAAiF,CACjF,8EAA+E,CAC/E,gFAAiF,CACjF,oHAAqH,CACrH,sHAAuH,CACvH,sIAAuI,CACvI,0IAA2I,CAC3I,4IAA6I,CAC7I,wIAA2I,CAC7I,6BACE,2HAA8H,CAChI,6BACE,2HAA8H,CAChI,6BACE,iBAAkB,CAClB,KAAM,CACN,OAAQ,CACR,QAAS,CACT,MAAO,CACP,UAAW,CACX,6DAA8D,CAC9D,kOAAqO,CAEzO,8BACE,iBAAkB,CAClB,4CAA6C,CAC7C,8CAA+C,CAC/C,8BAAkC,CAClC,oCACE,aAAc,CACd,uDAAwD,CACxD,yDAA0D,CAC1D,UAAW,CAGX,qIAA+P,CAA/P,yIAA+P,CAA/P,uIAA+P,CAA/P,mIAAiQ,CAErQ,oCACE,aACE,6CAAgD,CAChD,kEACE,2DAA8D,CAChE,mEACE,gEAAmE,CACnE,yEACE,OAAQ,CACR,QAAW,CACjB,6BACE,0GAA6G,CAC7G,gKACE,6EAA8E,CAC9E,cAAiB,CACnB,kFACE,uBAA0B,CAC5B,0EACE,OAAQ,CACR,SAAY,CACd,mFACE,gFAAiF,CACjF,cAAiB,CACjB,0GACE,gCAAiC,CACjC,kCAAmC,CACnC,4FAA6F,CAC7F,kDAAmD,CACnD,kHAAqH,CAC3H,+BACE,4GAA6G,CAC7G,oCAAqC,CACrC,cAAe,CACf,mEAAsE,CACtE,oKACE,2EAA4E,CAC5E,cAAiB,CACnB,4EACE,KAAM,CACN,SAAU,CACV,UAAW,CACX,+DAAkE,CACpE,qFACE,8EAA+E,CAC/E,cAAiB,CACjB,4GACE,8BAA+B,CAC/B,gCAAiC,CACjC,oCAAqC,CACrC,4FAA6F,CAC7F,kDAAmD,CACnD,wHAA2H,CACjI,sGACE,oGAAqG,CACrG,wFAAyF,CACzF,gHAAiH,CACjH,8GAA+G,CAC/G,2EAA8E,CAChF,wHACE,8FAA+F,CAC/F,sGAAuG,CACvG,4HAA6H,CAC7H,kDAAmD,CACnD,iDAAoD,CACtD,sJAEE,gDAAmD,CACrD,uBACE,aAAc,CACd,kBAAqB,CAAE,CAE3B,yBACE,kCACE,mCAAsC,CACxC,kCACE,mCAAsC,CACxC,kCACE,mCAAsC,CACxC,kCACE,mCAAsC,CACxC,kCACE,mCAAsC,CACxC,mCACE,oCAAuC,CAAE,CAE7C,yBACE,wCACE,mCAAsC,CACxC,wCACE,mCAAsC,CACxC,wCACE,mCAAsC,CACxC,wCACE,mCAAsC,CACxC,wCACE,mCAAsC,CACxC,yCACE,oCAAuC,CAAE,CAE7C,0BACE,wCACE,mCAAsC,CACxC,wCACE,mCAAsC,CACxC,wCACE,mCAAsC,CACxC,wCACE,mCAAsC,CACxC,wCACE,mCAAsC,CACxC,yCACE,oCAAuC,CAAE,CAE7C,0BACE,yCACE,mCAAsC,CACxC,yCACE,mCAAsC,CACxC,yCACE,mCAAsC,CACxC,yCACE,mCAAsC,CACxC,yCACE,mCAAsC,CACxC,0CACE,oCAAuC,CAAE,CAE7C,yBACE,oIAEE,aAAgB,CAClB,gIAEE,gDAAmD,CACnD,sLAEE,wFAA2F,CAC/F,kEACE,eAAkB,CACpB,gEACE,yDAA4D,CAC5D,0BAA6B,CAC/B,8EACE,aAAc,CACd,uBAA0B,CAC5B,0HACE,aAAc,CACd,kBAAqB,CACvB,gFACE,0DAA6D,CAC7D,aAAc,CACd,2BAA8B,CAChC,8FACE,cAAe,CACf,uBAA0B,CAC5B,0IACE,aAAc,CACd,kBAAqB,CACvB,gEACE,uBAA0B,CAC5B,gFACE,cAAe,CACf,uBAA0B,CAC5B,kFACE,uBAA0B,CAC5B,0HACE,YAAa,CACb,iBAAoB,CAAE,CAE1B,yBACE,gJAEE,aAAgB,CAClB,4IAEE,gDAAmD,CACnD,kMAEE,wFAA2F,CAC/F,wEACE,eAAkB,CACpB,sEACE,yDAA4D,CAC5D,0BAA6B,CAC/B,oFACE,aAAc,CACd,uBAA0B,CAC5B,gIACE,aAAc,CACd,kBAAqB,CACvB,sFACE,0DAA6D,CAC7D,aAAc,CACd,2BAA8B,CAChC,oGACE,cAAe,CACf,uBAA0B,CAC5B,gJACE,aAAc,CACd,kBAAqB,CACvB,sEACE,uBAA0B,CAC5B,sFACE,cAAe,CACf,uBAA0B,CAC5B,wFACE,uBAA0B,CAC5B,gIACE,YAAa,CACb,iBAAoB,CAAE,CAE1B,0BACE,gJAEE,aAAgB,CAClB,4IAEE,gDAAmD,CACnD,kMAEE,wFAA2F,CAC/F,wEACE,eAAkB,CACpB,sEACE,yDAA4D,CAC5D,0BAA6B,CAC/B,oFACE,aAAc,CACd,uBAA0B,CAC5B,gIACE,aAAc,CACd,kBAAqB,CACvB,sFACE,0DAA6D,CAC7D,aAAc,CACd,2BAA8B,CAChC,oGACE,cAAe,CACf,uBAA0B,CAC5B,gJACE,aAAc,CACd,kBAAqB,CACvB,sEACE,uBAA0B,CAC5B,sFACE,cAAe,CACf,uBAA0B,CAC5B,wFACE,uBAA0B,CAC5B,gIACE,YAAa,CACb,iBAAoB,CAAE,CAE1B,0BACE,kJAEE,aAAgB,CAClB,8IAEE,gDAAmD,CACnD,oMAEE,wFAA2F,CAC/F,yEACE,eAAkB,CACpB,uEACE,yDAA4D,CAC5D,0BAA6B,CAC/B,qFACE,aAAc,CACd,uBAA0B,CAC5B,iIACE,aAAc,CACd,kBAAqB,CACvB,uFACE,0DAA6D,CAC7D,aAAc,CACd,2BAA8B,CAChC,qGACE,cAAe,CACf,uBAA0B,CAC5B,iJACE,aAAc,CACd,kBAAqB,CACvB,uEACE,uBAA0B,CAC5B,uFACE,cAAe,CACf,uBAA0B,CAC5B,yFACE,uBAA0B,CAC5B,iIACE,YAAa,CACb,iBAAoB,CAAE,CAE1B,eACE,0EAA2E,CAC3E,kEAAmE,CACnE,6EAA8E,CAC9E,iEAAkE,CAClE,yEAA0E,CAC1E,gEAAiE,CACjE,wEAAyE,CACzE,2DAA4D,CAC5D,oEAAqE,CACrE,oDAAqD,CACrD,8EAA+E,CAC/E,kFAAmF,CACnF,oFAAqF,CACrF,qFAAsF,CACtF,mFAAoF,CACpF,6FAA8F,CAC9F,4FAA6F,CAC7F,8FAA+F,CAC/F,2FAA4F,CAC5F,6FAA8F,CAC9F,gGAAiG,CACjG,kGAAmG,CACnG,wFAAyF,CACzF,oEAAqE,CACrE,2EAA4E,CAC5E,uFAAwF,CACxF,0DAA2D,CAC3D,4EAA6E,CAC7E,mFAAoF,CACpF,wFAAyF,CACzF,+FAAgG,CAChG,gGAAiG,CACjG,+FAAgG,CAChG,oGAAqG,CACrG,kEAAmE,CACnE,iGAAkG,CAClG,yFAA0F,CAC1F,oGAAqG,CACrG,wFAAyF,CACzF,2EAA4E,CAC5E,8FAA+F,CAC/F,8FAA+F,CAC/F,kGAAmG,CACnG,mGAAoG,CACpG,wHAA2H,CAC3H,mFAAoF,CACpF,6FAA8F,CAC9F,yEAA0E,CAC1E,sEAAuE,CACvE,qEAAsE,CACtE,8DAA+D,CAC/D,mFAAoF,CACpF,gEAAiE,CACjE,8DAA+D,CAC/D,iEAAkE,CAClE,oEAAqE,CACrE,0DAA2D,CAC3D,mCAAoC,CACpC,mFAAoF,CACpF,uDAAwD,CACxD,mEAAoE,CACpE,qEAAsE,CACtE,sEAAuE,CACvE,oEAAqE,CACrE,mEAAoE,CACpE,2EAA4E,CAC5E,uEAAwE,CACxE,mEAAoE,CACpE,0EAA2E,CAC3E,6EAA8E,CAC9E,+FAAgG,CAChG,iEAAkE,CAClE,2EAA4E,CAC5E,yEAA0E,CAC1E,2EAA4E,CAC5E,4EAA6E,CAC7E,+EAAgF,CAChF,+EAAgF,CAChF,sEAAuE,CACvE,qEAAsE,CACtE,wFAAyF,CACzF,0FAA2F,CAC3F,sFAAuF,CACvF,qEAAsE,CACtE,gFAAiF,CACjF,qEAAsE,CACtE,qEAAsE,CACtE,wEAAyE,CACzE,uEAAwE,CACxE,kEAAmE,CACnE,qEAAsE,CACtE,iBAAkB,CAClB,oBAAqB,CACrB,cAAiB,CACjB,6BACE,qDAAsD,CACtD,2DAA8D,CAC9D,wCACE,0CAA6C,CAEnD,uBACE,iBAAkB,CAClB,YAAa,CACb,kBAAmB,CACnB,6BAA8B,CAC9B,gDAAiD,CACjD,cAAe,CACf,iLAAkL,CAClL,gDAAiD,CACjD,oDAAqD,CACrD,oDAAqD,CACrD,yCAA0C,CAC1C,8DAA+D,CAC/D,WAAc,CACd,sGAEE,iBAAkB,CAClB,KAAM,CACN,OAAQ,CACR,QAAS,CACT,MAAO,CACP,UAAW,CACX,8DAA+D,CAC/D,sOAAyO,CAC3O,qEACE,mBAAsB,CACtB,uGACE,gGAAmG,CACnG,qHACE,QAAW,CACjB,yCACE,SAAY,CACZ,2CACE,iBAAkB,CAIlB,6QAA8E,CAC9E,qFAAwF,CACxF,sDACE,kIAAqI,CACvI,qDACE,mIAAsI,CAC1I,qDACE,wIAAyI,CACzI,sIAAyI,CACzI,mFACE,+FAAkG,CAClG,0FACE,aAAgB,CAClB,8FACE,+EAAkF,CACxF,sEACE,YAAa,CACb,kBAAmB,CACnB,cAAiB,CACjB,4EACE,mGAAsG,CAC1G,uEACE,gDAAiD,CACjD,QAAW,CACb,qEACE,iFAAoF,CACxF,oIAEE,iHAAoH,CACtH,kMAEE,kHAAmH,CACnH,mFAAsF,CACxF,oIAEE,iHAAkH,CAClH,kFAAqF,CACvF,sJAEE,sHAAuH,CACvH,uFAA0F,CAC5F,kCACE,oBAAqB,CACrB,kDAAqD,CACrD,oCACE,oEAAuE,CACzE,yCACE,QAAW,CACb,wNAEE,2FAA8F,CAChG,2FACE,8FAAiG,CACrG,oCACE,6EAA8E,CAC9E,iGAAkG,CAClG,mEAAsE,CACtE,2CACE,QAAW,CACb,0CACE,wGAA2G,CAC7G,2FACE,yGAA4G,CAC9G,0CACE,wGAA2G,CAC7G,mDACE,6GAAgH,CACpH,mDACE,eAAgB,CAChB,sBAAuB,CACvB,kBAAqB,CAEzB,4BACE,2DAA4D,CAC5D,yDAA0D,CAC1D,yDAA4D,CAC5D,kEACE,8EAAiF,CAErF,6BACE,mBAAoB,CACpB,wDAAyD,CACzD,4DAA6D,CAC7D,8DAAiE,CACjE,wCACE,4CAA+C,CAEnD,qBACE,iBAAkB,CAClB,mCAAoC,CACpC,0CAA2C,CAC3C,cAAe,CACf,kDAAmD,CACnD,wDAAyD,CACzD,sDAAuD,CACvD,2BAA4B,CAC5B,gDAAmD,CACnD,sCACE,OAAU,CACZ,6CACE,iEAAkE,CAClE,mEAAsE,CAE1E,0BACE,aAAc,CACd,UAAW,CACX,6LAA8L,CAC9L,mDAAoD,CACpD,uDAAwD,CACxD,uDAAwD,CACxD,4CAA6C,CAC7C,eAAgB,CAChB,kBAAmB,CACnB,iEAAkE,CAClE,WAAc,CACd,gEACE,+EAAgF,CAChF,mGAAoG,CACpG,oBAAuB,CACzB,2EACE,kFAAmF,CACnF,sGAAuG,CACvG,mBAAsB,CACxB,oCACE,YAAa,CACb,kBAAqB,CACrB,qDACE,qBAAsB,CACtB,iBAAoB,CACtB,mEACE,YAAa,CACb,kBAAqB,CACzB,oCACE,gFAAmF,CACnF,oFACE,uDAA0D,CAEhE,+BACE,mBAAoB,CACpB,kBAAmB,CACnB,sBAAuB,CACvB,iDAAkD,CAClD,mDAAoD,CACpD,8DAAiE,CACjE,iCACE,cAAe,CACf,eAAkB,CAEtB,sCACE,+DAAgE,CAChE,wDAA2D,CAE7D,4CACE,0DAA6D,CAE/D,4BAIE,qMAA4D,CAC5D,qDAAsD,CACtD,yDAA0D,CAC1D,8CAAiD,CAEnD,kBACE,2DAA4D,CAC5D,6DAA8D,CAC9D,8DAA+D,CAC/D,4DAA6D,CAC7D,0CAA2C,CAC3C,mEAAoE,CACpE,uEAAwE,CACxE,oEAAqE,CACrE,mFAAoF,CACpF,gEAAiE,CACjE,4DAA6D,CAC7D,mEAAoE,CACpE,8EAA+E,CAC/E,qEAAsE,CACtE,iFAAoF,CACpF,sFAAyF,CACzF,+EAAgF,CAChF,qFAAwF,CACxF,qDAAsD,CACtD,uEAAwE,CACxE,yEAA0E,CAC1E,iEAAkE,CAClE,mEAAoE,CACpE,oEAAqE,CACrE,kEAAmE,CACnE,yEAA0E,CAC1E,sEAAuE,CACvE,yEAA0E,CAC1E,2EAA4E,CAC5E,iDAAkD,CAClD,mDAAoD,CACpD,uEAAwE,CACxE,sEAAuE,CACvE,yEAA0E,CAC1E,gDAAiD,CACjD,qFAAsF,CACtF,YAAa,CACb,kBAAmB,CACnB,sBAAuB,CACvB,6JAA8J,CAC9J,iBAAoB,CACpB,0BACE,wEAAyE,CACzE,4EAA6E,CAC7E,8EAA+E,CAC/E,0EAA2E,CAC3E,sFAAuF,CACvF,wFAAyF,CACzF,kFAAmF,CACnF,wFAAyF,CACzF,4FAA+F,CAC/F,kDACE,uDAA0D,CAC5D,uCACE,uEAA0E,CAC9E,0BACE,sFAAyF,CAC3F,0BACE,sFAAyF,CAC3F,0BACE,kFAAmF,CACnF,wFAAyF,CACzF,gFAAiF,CACjF,gHAAmH,CACnH,kDACE,uDAA0D,CAC9D,mCACE,WAAc,CAElB,2BACE,oDAAuD,CACvD,+CACE,mEAAsE,CAE1E,wBACE,yDAA0D,CAC1D,iDAAkD,CAClD,0CAA6C,CAE/C,wBACE,mDAAoD,CACpD,0CAA6C,CAE/C,gFAEE,sDAAyD,CACzD,0IAEE,iEAAoE,CAExE,6BACE,YAAa,CACb,cAAe,CACf,sBAAuB,CACvB,wDAAyD,CACzD,8DAAiE,CACjE,+BACE,mEAAoE,CACpE,qEAAsE,CACtE,iEAAoE,CAExE,qFACE,wCAA2C,CAE7C,yBACE,oFAAqF,CACrF,4EAA6E,CAC7E,uFAAwF,CACxF,gDAAiD,CACjD,sEAAuE,CACvE,oFAAqF,CACrF,qFAAsF,CACtF,oFAAqF,CACrF,yFAA0F,CAC1F,0EAA2E,CAC3E,iEAAkE,CAClE,gDAAiD,CACjD,gEAAiE,CACjE,oHAAqH,CACrH,0EAA6E,CAC7E,uCACE,kGAAmG,CACnG,8GAAiH,CAErH,iCACE,YAAa,CACb,yNAA0N,CAC1N,mDAAoD,CACpD,WAAc,CACd,uCACE,6FAAgG,CAClG,qFACE,8FAAiG,CACnG,uCACE,6FAAgG,CAEpG,sCACE,wDAAyD,CACzD,kEAAmE,CACnE,qEAAwE,CAE1E,sCACE,mEAAsE,CAExE,kCACE,6DAAgE,CAElE,qDACE,mDAAsD,CAExD,kBACE,2GAA4G,CAC5G,2FAA4F,CAC5F,4FAA6F,CAC7F,6FAA8F,CAC9F,uFAAwF,CACxF,0FAA2F,CAC3F,6EAA8E,CAC9E,6FAA8F,CAC9F,mDAAoD,CACpD,iGAAoG,CACpG,yGAA4G,CAC5G,iBAAkB,CAClB,YAAa,CACb,qBAAwB,CACxB,yCACE,iBAAkB,CAClB,KAAM,CACN,OAAQ,CACR,QAAS,CACT,MAAO,CACP,6DAA8D,CAC9D,UAAW,CACX,kIAAqI,CACvI,wCACE,iBAAkB,CAClB,KAAM,CACN,OAAQ,CACR,QAAS,CACT,MAAO,CACP,UAAW,CACX,8EAA+E,CAC/E,6DAAgE,CAClE,+DACE,iBAAoB,CACpB,sEACE,iBAAkB,CAClB,KAAM,CACN,oEAAqE,CACrE,qEAAsE,CACtE,mEAAoE,CACpE,UAAW,CACX,0FAA6F,CAEnG,yDACE,uFAA0F,CAE5F,gCACE,iBAAkB,CAClB,YAAe,CACf,mDACE,aAAc,CACd,2EAA4E,CAC5E,YAAe,CAEnB,wCACE,iBAAkB,CAClB,OAAQ,CACR,QAAS,CACT,8BAAkC,CAEpC,WACE,iDAAkD,CAClD,oEAAqE,CACrE,oEAAqE,CACrE,sFAAuF,CACvF,iEAAkE,CAClE,6CAA8C,CAC9C,mFAAoF,CACpF,oEAAqE,CACrE,2DAA4D,CAC5D,+DAAgE,CAChE,2EAA4E,CAC5E,sEAAuE,CACvE,oEAAqE,CACrE,oEAAqE,CACrE,sEAAuE,CACvE,sEAAuE,CACvE,wEAAyE,CACzE,yEAA0E,CAC1E,uEAAwE,CACxE,gGAAmG,CACnG,oGAAuG,CACvG,sGAAyG,CACzG,iIAAoI,CACpI,sEAAuE,CACvE,kDAAmD,CACnD,qFAAsF,CACtF,kFAAmF,CACnF,mEAAoE,CACpE,qEAAsE,CACtE,sEAAuE,CACvE,oEAAqE,CACrE,oFAAuF,CACvF,wFAA2F,CAC3F,0FAA6F,CAC7F,sFAAyF,CACzF,gEAAiE,CACjE,iEAAkE,CAClE,4DAA6D,CAC7D,sEAAuE,CACvE,uEAAwE,CACxE,+EAAgF,CAChF,+EAAgF,CAChF,4EAA6E,CAC7E,4DAA6D,CAC7D,sDAAuD,CACvD,6EAA8E,CAC9E,yFAA0F,CAC1F,2EAA4E,CAC5E,4FAA6F,CAC7F,8EAA+E,CAC/E,mFAAsF,CACtF,+KAAkL,CAClL,wEAAyE,CACzE,0EAA2E,CAC3E,kGAAmG,CACnG,2FAA4F,CAC5F,4JAA6J,CAC7J,iGAAoG,CACpG,oGAAuG,CACvG,6EAA8E,CAC9E,6EAA8E,CAC9E,8CAA+C,CAC/C,+DAAgE,CAChE,wEAAyE,CACzE,2EAA4E,CAC5E,+CAAkD,CAClD,kGAAmG,CACnG,qGAAsG,CACtG,mEAAsE,CACtE,4JAA6J,CAC7J,mFAAoF,CACpF,+EAAgF,CAChF,kGAAqG,CACrG,qGAAwG,CACxG,gFAAiF,CACjF,sEAAuE,CACvE,yEAA0E,CAC1E,4DAA6D,CAC7D,6CAAgD,CAChD,uEAA0E,CAC1E,2FAA8F,CAC9F,2HAA8H,CAC9H,yHAA4H,CAC5H,+HAAkI,CAClI,YAAa,CACb,kCAAqC,CACrC,2BACE,yCAA4C,CAC5C,8DACE,gBAAmB,CACrB,yBACE,6CACE,YAAa,CACb,8EAA+E,CAC/E,yJAA4J,CAC9J,mDACE,uEAA0E,CAC1E,uEACE,wDAA2D,CAC/D,qDACE,aAAgB,CAAE,CACxB,4BACE,mDAAsD,CAE1D,8BACE,uDAAwD,CACxD,eAAkB,CAEpB,oBACE,YAAa,CACb,kCAAqC,CACrC,8FACE,+CAAkD,CAEtD,wBACE,qCAAsC,CACtC,2DAA8D,CAEhE,kBACE,2CAA4C,CAC5C,+CAAkD,CAClD,6BACE,qBAAwB,CAC1B,4CACE,cAAiB,CACnB,gCACE,gDAAmD,CACrD,sCACE,kBAAqB,CAEzB,uBACE,oDAAuD,CAEzD,2BACE,wDAAyD,CACzD,oDAAqD,CACrD,6CAAgD,CAElD,6BAIE,yMAA6D,CAI7D,oMAA2D,CAC3D,sDAAuD,CACvD,aAAc,CACd,QAAS,CACT,oEAAuE,CAEzE,sCACE,YAAa,CACb,kBAAqB,CACrB,wCACE,0EAA6E,CAEjF,8DACE,qCAAsC,CACtC,wEAA2E,CAE7E,wBACE,mDAAoD,CACpD,iDAAkD,CAClD,0CAA6C,CAC7C,mCACE,6EAAgF,CAClF,qCACE,+EAAkF,CACpF,qCACE,+EAAkF,CACpF,sCACE,YAAa,CACb,iBAAoB,CACtB,oCACE,iBAAkB,CAClB,SAAY,CAEhB,6BACE,4DAA6D,CAC7D,sDAAyD,CAE3D,qBACE,QAAW,CAEb,oBACE,YAAa,CACb,cAAe,CAIf,gKAAoD,CACpD,sBAIE,4LAA2D,CAE/D,wBAEE,yFAA0F,CAC1F,YAAa,CACb,wGAA0G,CAC1G,4GAA6G,CAC7G,qHAAwH,CACxH,mCACE,6CAAgD,CAClD,oFACE,0CAA6C,CAC/C,gDACE,gEAAmE,CACrE,gDACE,kHAAmH,CACnH,sHAAuH,CACvH,sHAAuH,CACvH,4HAA6H,CAC7H,2CAA8C,CAC9C,4GACE,sIAAyI,CAC7I,qEACE,2GAA8G,CAElH,+BACE,eAAkB,CAClB,YAAe,CACf,4DAA6D,CAC7D,gEAAmE,CACnE,8DACE,gHAAmH,CAEvH,sCACE,iEAAkE,CAClE,uEAA0E,CAE5E,oCACE,oBAAqB,CACrB,6DAA8D,CAC9D,iBAAkB,CAClB,gEAAiE,CACjE,mEAAsE,CAExE,+BACE,4DAA6D,CAC7D,YAAe,CACf,YAAa,CACb,sBAAuB,CACvB,4DAA6D,CAC7D,kEAAqE,CAEvE,oCACE,YAAa,CACb,qBAAsB,CACtB,WAAc,CAEhB,qCACE,YAAe,CAEjB,0CACE,WAAc,CAEhB,2CACE,sEAAuE,CACvE,6DAAgE,CAElE,uCACE,kEAAmE,CACnE,wEAAyE,CACzE,oEAAqE,CACrE,kBAAqB,CAEvB,6BACE,0DAA2D,CAC3D,YAAa,CACb,2CAA4C,CAC5C,0DAA2D,CAC3D,gEAAmE,CACnE,iEACE,6CAA8C,CAC9C,6CAAgD,CAClD,gEACE,uFAA0F,CAE9F,mBACE,4DAA6D,CAC7D,gEAAiE,CACjE,kEAAmE,CACnE,sEAAuE,CACvE,wEAAyE,CACzE,yEAA0E,CAC1E,uEAAwE,CACxE,mCAAoC,CACpC,2EAA4E,CAC5E,oOAAyO,CACzO,6DAA8D,CAC9D,gHAAiH,CACjH,mHAAoH,CACpH,uEAAwE,CACxE,sEAAuE,CACvE,kFAAmF,CACnF,+EAAgF,CAChF,2IAA4I,CAC5I,kFAAmF,CACnF,oFAAqF,CACrF,gJAAiJ,CACjJ,uFAAwF,CACxF,yEAA0E,CAC1E,0EAA2E,CAC3E,oFAAqF,CACrF,sDAAuD,CACvD,oFAAqF,CACrF,0FAA2F,CAC3F,oIAAqI,CACrI,yFAA0F,CAC1F,0FAA2F,CAC3F,iFAAkF,CAClF,+IAAgJ,CAChJ,oFAAqF,CACrF,uEAAwE,CACxE,oGAAqG,CACrG,wDAAyD,CACzD,8JAA+J,CAC/J,gFAAiF,CACjF,gFAAiF,CACjF,kJAAmJ,CACnJ,oiBAAqiB,CACriB,mFAAoF,CACpF,mJAAoJ,CACpJ,sFAAuF,CACvF,yEAA0E,CAC1E,kHAAyH,CACzH,0DAA2D,CAC3D,oKAAqK,CACrK,uDAAwD,CACxD,kFAAmF,CACnF,wJAAyJ,CACzJ,koBAAmoB,CACnoB,iFAAkF,CAClF,+IAAgJ,CAChJ,mFAAoF,CACpF,uEAAwE,CACxE,oGAAqG,CACrG,wDAAyD,CACzD,8JAA+J,CAC/J,gFAAiF,CACjF,gFAAiF,CACjF,kJAAmJ,CACnJ,8jBAA+jB,CAC/jB,wNAA2N,CAC3N,6IAA8I,CAC9I,uEAAwE,CACxE,wFAAyF,CACzF,mHAAoH,CACpH,0hBAA2hB,CAC3hB,0LAA2L,CAC3L,+CAAgD,CAChD,mGAAoG,CACpG,uDAAwD,CACxD,+EAAgF,CAChF,+EAAgF,CAChF,sEAAuE,CACvE,sSAAuS,CACvS,wNAAyN,CACzN,oJAAsJ,CACtJ,gOAAkO,CAClO,0MAA4M,CAC5M,oJAAsJ,CACtJ,gOAAkO,CAClO,0MAA4M,CAC5M,wJAA0J,CAC1J,oOAAsO,CACtO,8MAAgN,CAChN,2/BAA4/B,CAC5/B,ogBAAqgB,CACrgB,sEAAuE,CACvE,2TAA4T,CAC5T,kDAAmD,CACnD,gGAAiG,CACjG,uDAAwD,CACxD,2JAA4J,CAC5J,gFAAiF,CACjF,mJAAoJ,CACpJ,kFAAmF,CACnF,iKAAkK,CAClK,gFAAiF,CACjF,mJAAoJ,CACpJ,iGAAkG,CAClG,mGAAoG,CACpG,iGAAkG,CAClG,kCAAmC,CACnC,UAAW,CACX,iKAAkK,CAClK,4CAA6C,CAC7C,gDAAiD,CACjD,0DAA2D,CAC3D,2BAA4B,CAC5B,kDAAmD,CACnD,sLAAuL,CACvL,oDAAqD,CACrD,oBAAqB,CACrB,uBAA0B,CAC1B,gCACE,kDAAqD,CACvD,iCACE,uCAAwC,CACxC,sBAAyB,CAC3B,6BACE,oEAAuE,CACvE,+EACE,mGAAsG,CACxG,+EACE,kGAAmG,CACnG,0GAA2G,CAC3G,0GAA6G,CACjH,yBACE,yFAA4F,CAC9F,yBACE,yFAA0F,CAC1F,6DAA8D,CAC9D,sEAAyE,CAC3E,iCACE,8FAA+F,CAC/F,kEAAmE,CACnE,2EAA8E,CAChF,4BACE,oEAAqE,CACrE,wFAAyF,CACzF,kBAAmB,CACnB,4DAA+D,CACjE,sCACE,iFAAkF,CAClF,2FAA4F,CAC5F,+DAAgE,CAChE,iEAAkE,CAClE,yEAA0E,CAC1E,iEAAkE,CAClE,wEAA2E,CAC3E,gDACE,sFAAuF,CACvF,yEAA0E,CAC1E,iFAAkF,CAClF,yEAA4E,CAChF,gCACE,iFAAkF,CAClF,2FAA4F,CAC5F,+DAAgE,CAChE,iEAAkE,CAClE,yEAA0E,CAC1E,iEAAkE,CAClE,wEAA2E,CAC3E,0CACE,sFAAuF,CACvF,yEAA0E,CAC1E,iFAAkF,CAClF,yEAA4E,CAChF,gCACE,mFAAoF,CACpF,6FAA8F,CAC9F,iEAAkE,CAClE,mEAAoE,CACpE,2EAA4E,CAC5E,mEAAoE,CACpE,0EAA6E,CAC7E,0CACE,sFAAuF,CACvF,2EAA4E,CAC5E,mFAAoF,CACpF,2EAA8E,CAClF,+BACE,gFAAiF,CACjF,kEAAmE,CACnE,0EAA2E,CAC3E,kEAAqE,CACvE,6BACE,gFAAiF,CACjF,gEAAiE,CACjE,+HAAgI,CAChI,mHAAsH,CACtH,2CACE,8FAAiG,CACnG,wCACE,2FAA8F,CAClG,yBACE,gFAAiF,CACjF,gEAAiE,CACjE,wEAAyE,CACzE,gEAAmE,CACnE,4CACE,yFAA0F,CAC1F,8GAA+G,CAC/G,iHAAmH,CACnH,8HAAgI,CAChI,kHAAsH,CACxH,sCACE,yFAA0F,CAC1F,8GAA+G,CAC/G,iHAAmH,CACnH,8HAAgI,CAChI,kHAAsH,CACxH,sCACE,2FAA4F,CAC5F,mHAAqH,CACrH,wIAA0I,CAC1I,oHAAwH,CAC5H,2BACE,kHAAmH,CACnH,kHAAmH,CACnH,sHAAyH,CAC3H,wCACE,eAAkB,CACpB,0CACE,iBAAoB,CAExB,WACE,oDAAqD,CACrD,oDAAqD,CACrD,sDAAuD,CACvD,uDAAwD,CACxD,qDAAsD,CACtD,+DAAgE,CAChE,4DAA6D,CAC7D,0DAA2D,CAC3D,sDAAuD,CACvD,+CAAgD,CAChD,2DAA4D,CAC5D,0DAA2D,CAC3D,oEAAqE,CACrE,8DAA+D,CAC/D,2FAA8F,CAC9F,YAAa,CACb,8BAA+B,CAC/B,yCAA0C,CAC1C,iIAAkI,CAClI,6BAA8B,CAC9B,kDAAmD,CACnD,wEAAyE,CACzE,sCAAyC,CACzC,8CACE,eAAgB,CAChB,kBAAqB,CAEzB,oBACE,mBAAoB,CACpB,qBAAsB,CACtB,iDAAkD,CAClD,gBAAiB,CACjB,aAAc,CACd,UAAa,CACb,qEACE,2DAA8D,CAChE,qCACE,aAAgB,CAEpB,kBACE,2CAA8C,CAEhD,iBACE,gBAAmB,CACnB,0CAA6C,CAE/C,mBACE,gBAAqB,CACrB,qCACE,yDAA4D,CAEhE,kBACE,yEAA0E,CAC1E,2FAA4F,CAC5F,yGAA0G,CAC1G,6DAA8D,CAC9D,2EAA4E,CAC5E,qFAAwF,CAE1F,yBACE,YAAa,CACb,oBAAuB,CACvB,2BACE,8DAAiE,CACnE,yCACE,6GAAgH,CAClH,qCACE,8DAAiE,CACnE,qCAEE,qBAAwB,CAC1B,0EAFE,8CAGiD,CAErD,yBACE,MAAS,CAEX,6DACE,gGAAmG,CACnG,mEACE,uGAA0G,CAE9G,8FAGE,YAAa,CACb,iBAAoB,CAEtB,+CACE,oBAAqB,CACrB,kBAAqB,CAEvB,yaAME,kBAAqB,CAEvB,iIAEE,aAAgB,CAElB,mIAEE,oBAAuB,CAEzB,qKAEE,mBAAsB,CAExB,8SAIE,YAAa,CACb,iBAAoB,CAEtB,4EACE,kDAAqD,CACrD,wDAA6D,CAE/D,mCACE,8DAAiE,CAEnE,kBACE,0EAA2E,CAC3E,iEAAkE,CAClE,mEAAoE,CACpE,kEAAmE,CACnE,iEAAkE,CAClE,uEAAwE,CACxE,2EAA4E,CAC5E,6EAA8E,CAC9E,8EAA+E,CAC/E,4EAA6E,CAC7E,gFAAiF,CACjF,oEAAqE,CACrE,gFAAiF,CACjF,iDAAkD,CAClD,kCAAmC,CACnC,YAAa,CACb,UAAW,CACX,yDAA4D,CAC5D,sBACE,gBAAmB,CACrB,yEACE,iEAAoE,CACtE,0FAEE,MAAO,CACP,WAAc,CAChB,2BACE,uDAA0D,CAE9D,wBACE,YAAa,CACb,kBAAmB,CACnB,yDAA0D,CAC1D,uDAAwD,CACxD,iDAAkD,CAClD,0CAA2C,CAC3C,iBAAkB,CAClB,+DAAgE,CAChE,uDAAwD,CACxD,0MAA6M,CAC7M,6BACE,cAAiB,CACnB,mCACE,uCAAwC,CACxC,aAAgB,CAEpB,iBACE,qCAAsC,CACtC,kEAAmE,CACnE,wCAAyC,CACzC,iEAAkE,CAClE,4EAA6E,CAC7E,mDAAoD,CACpD,+EAAgF,CAChF,kDAAmD,CACnD,0CAA2C,CAC3C,yDAA0D,CAC1D,+EAAgF,CAChF,iFAAkF,CAClF,mDAAoD,CACpD,oDAAqD,CACrD,kDAAmD,CACnD,8FAA+F,CAC/F,6DAA8D,CAC9D,8EAAiF,CACjF,gEAAiE,CACjE,kEAAmE,CACnE,mEAAoE,CACpE,iEAAkE,CAClE,4EAA6E,CAC7E,6EAA8E,CAC9E,+EAAgF,CAChF,4EAA+E,CAC/E,iDAAkD,CAClD,mDAAoD,CACpD,oDAAqD,CACrD,kDAAmD,CACnD,wDAAyD,CACzD,wFAAyF,CACzF,yDAA0D,CAC1D,wFAAyF,CACzF,kGAAmG,CACnG,mEAAoE,CACpE,kGAAmG,CACnG,oEAAqE,CACrE,qGAAsG,CACtG,8EAA+E,CAC/E,+GAAgH,CAChH,gEAAiE,CACjE,6EAA8E,CAC9E,6EAA8E,CAC9E,iFAAkF,CAClF,mEAAoE,CACpE,YAAe,CACf,6BACE,sBAAyB,CACzB,oDACE,kBAAqB,CACzB,+BACE,wFAAyF,CACzF,4FAA6F,CAC7F,8FAA+F,CAC/F,0FAA2F,CAC3F,gHAAiH,CACjH,kHAAmH,CACnH,8HAA+H,CAC/H,gIAAiI,CACjI,kJAAmJ,CACnJ,oJAAqJ,CACrJ,8FAA+F,CAC/F,qBAAwB,CAE5B,uBACE,iBAAkB,CAClB,YAAa,CACb,0DAA2D,CAI3D,iLAAyD,CACzD,8BACE,iBAAkB,CAClB,KAAM,CACN,OAAQ,CACR,QAAS,CACT,MAAO,CACP,mBAAoB,CACpB,UAAW,CACX,8DAA+D,CAC/D,sOAAyO,CAC3O,8CACE,qCAAsC,CACtC,wCAAyC,CACzC,wFAAyF,CACzF,8FAA+F,CAC/F,0FAA2F,CAC3F,wDAA2D,CAE/D,uBACE,iBAAkB,CAClB,YAAa,CACb,MAAO,CAIP,iLAAuD,CACvD,oBAAqB,CACrB,0DAA6D,CAC7D,6BACE,yFAA4F,CAC9F,6BACE,yFAA0F,CAC1F,2GAA4G,CAC5G,6GAA8G,CAC9G,qGAAwG,CAC1G,8BACE,iBAAkB,CAClB,KAAM,CACN,OAAQ,CACR,QAAS,CACT,MAAO,CACP,mBAAoB,CACpB,UAAW,CAGX,yHAAuO,CAAvO,6HAAuO,CAAvO,2HAAuO,CAAvO,uHAAyO,CAE7O,uBACE,wDAA2D,CAC3D,2DACE,qHAAsH,CACtH,uHAAwH,CACxH,+GAAgH,CAChH,6FAAgG,CAEpG,4BACE,8CAAiD,CAEnD,wBACE,yDAA4D,CAE9D,uBACE,YAAa,CACb,qBAAwB,CAE1B,YACE,qDAAsD,CACtD,uDAAwD,CACxD,wDAAyD,CACzD,sDAAuD,CACvD,6DAA8D,CAC9D,oEAAqE,CACrE,gDAAiD,CACjD,qDAAsD,CACtD,4CAA6C,CAC7C,sDAAuD,CACvD,+EAAgF,CAChF,uFAAwF,CACxF,wFAAyF,CACzF,yFAA0F,CAC1F,yFAA0F,CAC1F,0FAA2F,CAC3F,0FAA2F,CAC3F,oGAAqG,CACrG,oGAAqG,CACrG,qGAAsG,CACtG,qGAAsG,CACtG,wEAAyE,CACzE,sEAAuE,CACvE,sEAAuE,CACvE,oGAAqG,CACrG,oGAAqG,CACrG,iGAAkG,CAClG,8GAA+G,CAC/G,8GAA+G,CAC/G,0EAA2E,CAC3E,0EAA2E,CAC3E,uEAAwE,CACxE,qGAAsG,CACtG,qGAAsG,CACtG,mGAAoG,CACpG,gHAAiH,CACjH,gHAAiH,CACjH,0EAA2E,CAC3E,0EAA2E,CAC3E,yEAA0E,CAC1E,uGAAwG,CACxG,uGAAwG,CACxG,mGAAoG,CACpG,gHAAiH,CACjH,gHAAiH,CACjH,sEAAuE,CACvE,sEAAuE,CACvE,oEAAqE,CACrE,kGAAmG,CACnG,kGAAmG,CACnG,gGAAiG,CACjG,6GAA8G,CAC9G,6GAA8G,CAC9G,4EAA6E,CAC7E,4EAA6E,CAC7E,yEAA0E,CAC1E,uGAAwG,CACxG,uGAAwG,CACxG,qGAAsG,CACtG,kHAAmH,CACnH,kHAAmH,CACnH,wEAAyE,CACzE,yEAA0E,CAC1E,sEAAuE,CACvE,oGAAqG,CACrG,oGAAqG,CACrG,iGAAkG,CAClG,8GAA+G,CAC/G,8GAA+G,CAC/G,sEAAuE,CACvE,yFAA0F,CAC1F,wFAAyF,CACzF,yFAA0F,CAC1F,qGAAsG,CACtG,sGAAuG,CACvG,qGAAsG,CACtG,sGAAuG,CACvG,yDAA0D,CAC1D,iCAAkC,CAClC,sDAAuD,CACvD,4DAA6D,CAC7D,+DAAgE,CAChE,iFAAoF,CACpF,mFAAsF,CACtF,oFAAuF,CACvF,+DAAgE,CAChE,+DAAgE,CAChE,iEAAkE,CAClE,kEAAmE,CACnE,gEAAiE,CACjE,iBAAkB,CAClB,qIAAsI,CACtI,qCAAsC,CACtC,8BAA+B,CAC/B,kBAAmB,CACnB,mDAAoD,CACpD,QAAS,CACT,6CAAgD,CAChD,sBACE,wEAAyE,CACzE,sEAAuE,CACvE,gEAAiE,CACjE,wHAAyH,CACzH,4HAA6H,CAC7H,4HAA6H,CAC7H,kJAAmJ,CACnJ,kJAAqJ,CACvJ,uBACE,yEAA0E,CAC1E,uEAAwE,CACxE,iEAAkE,CAClE,yHAA0H,CAC1H,6HAA8H,CAC9H,6HAA8H,CAC9H,mJAAoJ,CACpJ,mJAAsJ,CACxJ,wBACE,0EAA2E,CAC3E,wEAAyE,CACzE,kEAAmE,CACnE,0HAA2H,CAC3H,8HAA+H,CAC/H,8HAA+H,CAC/H,oJAAqJ,CACrJ,oJAAuJ,CACzJ,qBACE,uEAAwE,CACxE,qEAAsE,CACtE,+DAAgE,CAChE,uHAAwH,CACxH,2HAA4H,CAC5H,2HAA4H,CAC5H,iJAAkJ,CAClJ,iJAAoJ,CACtJ,wBACE,0EAA2E,CAC3E,wEAAyE,CACzE,kEAAmE,CACnE,0HAA2H,CAC3H,8HAA+H,CAC/H,8HAA+H,CAC/H,oJAAqJ,CACrJ,oJAAuJ,CACzJ,sBACE,wEAAyE,CACzE,sEAAuE,CACvE,gEAAiE,CACjE,wHAAyH,CACzH,4HAA6H,CAC7H,4HAA6H,CAC7H,kJAAmJ,CACnJ,kJAAqJ,CACvJ,yBACE,qGAAsG,CACtG,qGAAsG,CACtG,2EAA8E,CAC9E,+IAEE,kHAAmH,CACnH,kHAAqH,CACvH,+IAEE,kHAAmH,CACnH,kHAAqH,CACzH,yBACE,6DAA8D,CAC9D,iEAAkE,CAClE,qEAAsE,CACtE,uEAAwE,CACxE,mEAAoE,CAIpE,wKAAsD,CACxD,0BACE,0EAA2E,CAC3E,qFAAsF,CACtF,sGAAuG,CACvG,sGAAuG,CACvG,gIAAiI,CACjI,gIAAiI,CACjI,gIAAiI,CACjI,gIAAmI,CAEvI,iCAEE,mBAAoB,CACpB,kBAAqB,CAEvB,kBACE,eAAgB,CAChB,sBAAuB,CACvB,kBAAmB,CACnB,2CAA8C,CAEhD,qBACE,uCAAwC,CACxC,QAAW,CACX,4BACE,iBAAkB,CAClB,KAAM,CACN,OAAQ,CACR,QAAS,CACT,MAAO,CACP,UAAW,CACX,4GAA6G,CAC7G,6CAAgD,CAClD,iDAEE,cAAe,CACf,WAAc,CACd,2KAIE,oBAAuB,CACzB,6DAEE,uGAAwG,CACxG,uGAA0G,CAC5G,6DAEE,uGAAwG,CACxG,uGAA0G,CAEhH,kBACE,iDAAkD,CAClD,oCAAuC,CAEzC,kBACE,4EAA+E,CAC/E,2EAA8E,CAC9E,uEAAwE,CACxE,yEAA0E,CAC1E,0EAA2E,CAC3E,wEAAyE,CACzE,qFAAsF,CACtF,+EAAgF,CAChF,6EAA8E,CAC9E,8EAA+E,CAC/E,sFAAuF,CACvF,mEAAoE,CACpE,yCAA0C,CAC1C,gFAAiF,CACjF,kEAAmE,CACnE,wCAAyC,CACzC,0EAA6E,CAC7E,6EAAgF,CAChF,gGAAmG,CACnG,kGAAqG,CACrG,8EAA+E,CAC/E,0FAA2F,CAC3F,yFAA0F,CAC1F,uEAAwE,CACxE,wEAAyE,CACzE,mBAAsB,CACtB,gCAIE,6MAA8D,CAC9D,qEAAsE,CACtE,8GAA+G,CAC/G,+DAAkE,CACpE,gCACE,uCAAwC,CACxC,wCAAyC,CACzC,4CAA6C,CAC7C,wCAAyC,CACzC,gGAAiG,CACjG,0FAA2F,CAC3F,4FAA6F,CAC7F,yCAA0C,CAC1C,8FAA+F,CAC/F,0GAA6G,CAC7G,iDACE,sBAAyB,CAC3B,wDACE,qBAAsB,CACtB,sBAAyB,CAC3B,wDACE,qBAAwB,CAC1B,wEACE,6CAAgD,CAClD,sEACE,4FAA6F,CAC7F,8FAAiG,CAEvG,wBACE,YAAa,CACb,MAAO,CACP,cAAe,CACf,oBAAuB,CAEzB,wBACE,mBAAoB,CACpB,cAAe,CACf,uDAAwD,CACxD,yDAA4D,CAE9D,6BACE,mBAAoB,CACpB,4DAA6D,CAC7D,8DAAiE,CAEnE,yBACE,eAAgB,CAChB,sBAAuB,CACvB,kBAAmB,CACnB,kDAAmD,CACnD,wDAAyD,CACzD,0DAA2D,CAC3D,kDAAqD,CAEvD,yBAIE,oLAAyD,CAE3D,WACE,qDAAsD,CACtD,2DAA4D,CAC5D,4DAA6D,CAC7D,sDAAuD,CACvD,uDAAwD,CACxD,mEAAoE,CACpE,0CAA6C,CAC7C,4BAEE,8CAA+C,CAC/C,gDAAmD,CACrD,iBACE,0CAA6C,CAC/C,+BACE,0CAA6C,CAC/C,uBACE,0BAA2B,CAC3B,YAAa,CACb,cAAiB,CACjB,0BACE,4BAA+B,CAC/B,2CACE,wDAA2D,CAEnE,YACE,qDAAsD,CACtD,wDAAyD,CACzD,sCAAuC,CACvC,wEAAyE,CACzE,0CAA2C,CAC3C,0CAA2C,CAC3C,6CAA8C,CAC9C,8CAA+C,CAC/C,yEAA2E,CAC3E,+DAAgE,CAChE,8DAA+D,CAC/D,+DAAgE,CAChE,oEAAqE,CACrE,iEAAkE,CAClE,wEAAyE,CACzE,6EAA8E,CAC9E,gFAAiF,CACjF,6DAA8D,CAC9D,mEAAoE,CACpE,oEAAqE,CACrE,qEAAsE,CACtE,mEAAoE,CACpE,yEAA0E,CAC1E,wEAAyE,CACzE,iEAAkE,CAClE,8DAA+D,CAC/D,yEAA0E,CAC1E,kDAAmD,CACnD,uEAAwE,CACxE,kEAAmE,CACnE,mEAAoE,CACpE,iEAAkE,CAClE,uEAAwE,CACxE,sEAAuE,CACvE,sEAAuE,CACvE,6EAA8E,CAC9E,wEAAyE,CACzE,2EAA4E,CAC5E,2EAA4E,CAC5E,0EAA2E,CAC3E,+EAAgF,CAChF,8EAA+E,CAC/E,+EAAgF,CAChF,wFAAyF,CACzF,yFAA0F,CAC1F,0FAA2F,CAC3F,8FAA+F,CAC/F,uEAAwE,CACxE,yEAA0E,CAC1E,0EAA2E,CAC3E,wEAAyE,CACzE,sFAAuF,CACvF,4EAA6E,CAC7E,8DAA+D,CAC/D,+DAAgE,CAChE,qEAAsE,CACtE,0EAA2E,CAC3E,YAAa,CACb,sBAAuB,CACvB,gBAAiB,CACjB,yCAA0C,CAC1C,+CAAkD,CAClD,0BACE,YACE,4EAA+E,CAAE,CACrF,yBACE,YACE,oCAAqC,CACrC,mCAAsC,CAAE,CAC5C,0BACE,YACE,8EAA+E,CAC/E,gGAAiG,CAGjG,kCAHmG,CAAE,CAIzG,yBACE,YACE,wFAAyF,CACzF,sFAAuF,CACvF,kGAAmG,CAGnG,oFAAqF,CACrF,kFAJqG,CAAE,CAK3G,yBACE,YACE,oCAAqC,CACrC,mCAAsC,CAAE,CAC5C,0BACE,YACE,0FAA2F,CAG3F,uDAH6F,CAAE,CAInG,yBACE,YACE,kBAAqB,CAAE,CAE7B,uBACE,UAAW,CACX,gDAAmD,CACnD,0BACE,uBACE,YAAa,CACb,sBAAuB,CACvB,+DAAgE,CAChE,2EAA4E,CAC5E,wDAAyD,CACzD,wDAAyD,CACzD,sDAAyD,CAAE,CAEjE,oBACE,kCAAmC,CACnC,gBAAiB,CACjB,qDAAsD,CACtD,mDAAsD,CACtD,0BACE,oBACE,mDAAsD,CAAE,CAC5D,gCACE,8DAAiE,CAErE,kBACE,mDAAoD,CACpD,yDAA0D,CAC1D,cAAiB,CACjB,6DACE,sDAAyD,CAC3D,4DACE,4DAA+D,CAEnE,yBACE,YAAa,CACb,0BAA2B,CAC3B,oDAAqD,CACrD,8CAA+C,CAC/C,kBAAmB,CACnB,yLAA4L,CAC5L,yBACE,yBACE,8BAAiC,CAAE,CACvC,wCACE,gBAAiB,CACjB,aAAgB,CAChB,yBACE,wCACE,eAAkB,CAClB,UAAa,CAAE,CAEvB,8BACE,+DAAgE,CAChE,uDAAwD,CACxD,gBAAqB,CAEvB,uBACE,wDAAyD,CACzD,0DAA2D,CAC3D,sDAAyD,CAE3D,yBACE,YAAa,CACb,cAAiB,CACjB,qCACE,mEAAoE,CACpE,iBAAoB,CACtB,2BACE,eAAkB,CAEtB,+BACE,YAAa,CACb,cAAe,CACf,sBAAuB,CACvB,iNAAoN,CAEtN,oCACE,qEAAsE,CACtE,mEAAoE,CACpE,qEAAwE,CAE1E,6CACE,6DAA8D,CAC9D,UAAW,CACX,mEAAoE,CACpE,WAAY,CACZ,qEAAwE,CAE1E,mDACE,oEAAuE,CAEzE,8BACE,6MAA8M,CAC9M,iBAAkB,CAClB,qEAAwE,CACxE,kCACE,gEAAmE,CAEvE,oBACE,kCAAmC,CACnC,gBAAiB,CACjB,qDAAsD,CACtD,mDAAsD,CACtD,iCACE,WAAc,CAChB,gDACE,yDAA4D,CAEhE,WACE,kCAAmC,CACnC,yEAA0E,CAC1E,sDAAuD,CACvD,oDAAqD,CACrD,uDAAwD,CACxD,sEAAyE,CACzE,8DAA+D,CAC/D,iEAAkE,CAClE,4DAA6D,CAC7D,8DAA+D,CAC/D,+DAAgE,CAChE,6DAA8D,CAC9D,0DAA2D,CAC3D,iEAAkE,CAClE,mDAAoD,CACpD,2FAA4F,CAC5F,0DAA2D,CAC3D,4DAA6D,CAC7D,6DAA8D,CAC9D,2DAA4D,CAC5D,0CAAqD,CACrD,0DAA2D,CAC3D,kEAAmE,CACnE,8DAA+D,CAC/D,oEAAqE,CACrE,uEAAwE,CACxE,2EAA4E,CAC5E,6EAA8E,CAC9E,yEAA0E,CAC1E,iEAAkE,CAClE,4EAA6E,CAC7E,iEAAkE,CAClE,sEAAuE,CACvE,iEAAkE,CAClE,gEAAiE,CACjE,wEAAyE,CACzE,uEAAwE,CACxE,iFAAkF,CAClF,iFAAkF,CAClF,sEAAuE,CACvE,wEAAyE,CACzE,4EAA6E,CAC7E,8EAA+E,CAC/E,0EAA2E,CAC3E,oFAAqF,CACrF,iEAAkE,CAClE,mEAAoE,CACpE,oEAAqE,CACrE,kEAAmE,CACnE,sEAAuE,CACvE,+GAAkH,CAClH,8EAA+E,CAC/E,uFAAwF,CACxF,yFAA0F,CAC1F,kGAAmG,CACnG,oCAAqC,CACrC,qCAAsC,CACtC,4FAA6F,CAC7F,yFAA0F,CAC1F,4KAA8K,CAC9K,2EAA8E,CAC9E,oGAAqG,CACrG,qGAAsG,CACtG,4MAA8M,CAC9M,kGAAmG,CACnG,uHAAwH,CACxH,0GAA2G,CAC3G,wCAAyC,CACzC,8CAA+C,CAC/C,kDAAmD,CACnD,sCAAyC,CACzC,kCACE,iBAAkB,CAClB,yCAA0C,CAC1C,SAAY,CACd,6CACE,iBAAoB,CACtB,0BACE,0CAA2C,CAC3C,4CAA6C,CAC7C,eAAgB,CAChB,oDAAuD,CACvD,0IAEE,2BAA8B,CAChC,qCACE,2BAA4B,CAC5B,iBAAkB,CAClB,8CAA+C,CAC/C,SAAU,CACV,UAAW,CACX,4DAA+D,CAC/D,qDACE,2BAA8B,CAClC,2CACE,iBAAkB,CAClB,0DAA6D,CAC/D,6EACE,yFAA4F,CAC9F,mFACE,iBAAoB,CACtB,2CACE,oDAAuD,CAC3D,yBACE,iDAAkD,CAClD,uDAA0D,CAE9D,mBAIE,iKAAqD,CAEvD,sBACE,YAAa,CACb,wCAAyC,CACzC,6DAAgE,CAChE,uGACE,uEAAwE,CACxE,2FAA8F,CAC9F,qKACE,SAAY,CAChB,qDACE,gEAAiE,CACjE,mBAAsB,CAE1B,iBACE,YAAa,CACb,eAAgB,CAChB,qBAAsB,CACtB,WAAY,CAIZ,yJAAiD,CACjD,0CAA2C,CAC3C,8CAA+C,CAC/C,8CAA+C,CAC/C,mCAAoC,CACpC,eAAgB,CAChB,wDAAyD,CACzD,WAAc,CACd,uBACE,oBAAuB,CACzB,0BACE,gEAAiE,CACjE,mBAAsB,CACxB,4DACE,SAAY,CAEhB,sBACE,YAAa,CACb,kBAAmB,CACnB,UAAa,CACb,qDACE,kEAAmE,CACnE,8DAA+D,CAC/D,uDAAwD,CACxD,SAAY,CAEhB,sBACE,eAAgB,CAChB,sBAAuB,CACvB,kBAAmB,CACnB,WAAc,CAEhB,wBAIE,qLAAwD,CACxD,iDAAkD,CAClD,qDAAsD,CACtD,0CAA6C,CAE/C,6BACE,sDAAuD,CACvD,+CAAgD,CAChD,oBAAuB,CAEzB,sBACE,qDAAwD,CAE1D,6BACE,8DAA+D,CAC/D,4DAA+D,CAEjE,mDACE,qEAAwE,CAE1E,mDACE,qEAAwE,CAE1E,6BACE,0DAA2D,CAC3D,sDAAuD,CACvD,+CAAgD,CAChD,SAAY,CAEd,wBACE,YAAa,CAIb,qLAAwD,CACxD,WAAc,CACd,4DACE,sFAAyF,CAC3F,sCACE,2FAA8F,CAC9F,qDACE,wGAA2G,CAC7G,mEACE,mEAAsE,CAE5E,6BACE,YAAa,CACb,kBAAmB,CACnB,iDAAkD,CAClD,+CAAkD,CAEpD,gBACE,wEAAyE,CACzE,2DAA4D,CAC5D,qDAAsD,CACtD,4BAA6B,CAC7B,oEAAqE,CACrE,0CAA2C,CAC3C,qCAAsC,CACtC,0CAA2C,CAC3C,sEAAuE,CACvE,kEAAmE,CACnE,sEAAuE,CACvE,mFAAoF,CACpF,iLAAkL,CAClL,sIAAuI,CACvI,iFAAkF,CAClF,mFAAoF,CACpF,mFAAoF,CACpF,6EAA8E,CAC9E,mFAAoF,CACpF,iEAAkE,CAClE,mEAAoE,CACpE,kEAAmE,CACnE,gFAAiF,CACjF,oEAAqE,CACrE,qFAAsF,CACtF,iEAAkE,CAClE,sEAAuE,CACvE,gEAAiE,CACjE,sEAAuE,CACvE,uGAA0G,CAC1G,+DAAgE,CAChE,iEAAkE,CAClE,gEAAiE,CACjE,8EAA+E,CAC/E,uEAAwE,CACxE,4DAAmE,CACnE,8DAA+D,CAC/D,kHAAmH,CACnH,iEAAkE,CAClE,mEAAoE,CACpE,oEAAqE,CACrE,kEAAmE,CACnE,4EAA6E,CAC7E,gHAAmH,CACnH,iBAAkB,CAClB,qCAAsC,CACtC,YAAa,CACb,qBAAsB,CACtB,kCAAmC,CACnC,yCAA0C,CAC1C,2CAA4C,CAC5C,uDAAwD,CACxD,2CAA8C,CAC9C,0BACE,gBACE,oFAAuF,CAAE,CAC7F,wBACE,iEAAoE,CACtE,wBACE,0DAA6D,CAC/D,wBACE,iEAAoE,CACtE,+BACE,iDAAkD,CAClD,qBAAsB,CACtB,sDAAuD,CACvD,wDAA2D,CAC7D,4BACE,sFAAyF,CAC3F,6BACE,uFAA0F,CAC5F,6BACE,uFAA0F,CAC5F,6BACE,uFAA0F,CAC5F,0BACE,oFAAuF,CACzF,6BACE,iBAAkB,CAClB,wCAAyC,CACzC,4CAA+C,CAC/C,+BACE,kEAAqE,CAE3E,wBACE,YAAa,CACb,qBAAsB,CACtB,qDAAsD,CACtD,yDAA0D,CAC1D,uDAA0D,CAC1D,kCACE,YAAa,CACb,kBAAqB,CACvB,mCACE,uEAA0E,CAC5E,8CACE,kFAAqF,CAEzF,6BACE,WAAY,CACZ,WAAc,CAEhB,mDAEE,eAAgB,CAChB,sBAAuB,CACvB,kBAAqB,CAEvB,uBACE,aAAc,CACd,oDAAqD,CACrD,gDAAiD,CACjD,oDAAuD,CACvD,iCACE,YAAe,CAEnB,4BACE,2DAA4D,CAC5D,8CAAiD,CAEnD,6BACE,0DAA6D,CAE/D,sBACE,aAAc,CACd,iDAAkD,CAClD,mDAAoD,CACpD,uDAAwD,CACxD,qDAAsD,CACtD,iBAAkB,CAClB,eAAgB,CAChB,2BAA4B,CAC5B,qBAAsB,CACtB,gCAAmC,CACnC,iCACE,qEAAwE,CAE5E,wBACE,YAAa,CACb,aAAc,CACd,kBAAmB,CAInB,qLAA0D,CAC1D,sDACE,iEAAoE,CACpE,oCACE,sDACE,wGAA2G,CAAE,CAErH,UACE,mDAAoD,CACpD,uDAAwD,CACxD,iFAAkF,CAClF,yHAA0H,CAC1H,kEAAmE,CACnE,yEAA0E,CAC1E,yEAA0E,CAC1E,0EAA2E,CAC3E,6EAA8E,CAC9E,8FAA+F,CAC/F,8FAA+F,CAC/F,+FAAgG,CAChG,kGAAmG,CACnG,iFAAkF,CAClF,iFAAkF,CAClF,4FAA6F,CAC7F,2EAA4E,CAC5E,wFAAyF,CACzF,kFAAmF,CACnF,oGAAqG,CACrG,oGAAqG,CACrG,qGAAsG,CACtG,oGAAqG,CACrG,6BAA8B,CAC9B,+GAAgH,CAChH,wGAAyG,CACzG,iFAAkF,CAClF,uEAAwE,CACxE,yDAA0D,CAC1D,iEAAkE,CAClE,yDAA0D,CAC1D,2DAA4D,CAC5D,4DAA6D,CAC7D,0DAA2D,CAC3D,+DAAgE,CAChE,8DAA+D,CAC/D,0DAA2D,CAC3D,iEAAkE,CAClE,iEAAkE,CAClE,kEAAmE,CACnE,qEAAsE,CACtE,6CAA8C,CAC9C,oFAAqF,CACrF,oFAAqF,CACrF,qFAAsF,CACtF,wFAAyF,CACzF,qEAAwE,CACxE,iFAAkF,CAClF,6EAA8E,CAC9E,oDAAqD,CACrD,oDAAqD,CACrD,qDAAsD,CACtD,wDAAyD,CACzD,wEAAyE,CACzE,+EAAgF,CAChF,+EAAgF,CAChF,gFAAiF,CACjF,mFAAoF,CACpF,0CAA2C,CAC3C,iDAAkD,CAClD,iDAAkD,CAClD,kDAAmD,CACnD,qFAAsF,CACtF,uEAAwE,CACxE,yEAA0E,CAC1E,0EAA2E,CAC3E,wEAAyE,CACzE,2EAA4E,CAC5E,8EAA+E,CAC/E,kEAAmE,CACnE,iEAAkE,CAClE,wEAAyE,CACzE,gFAAiF,CACjF,gFAAiF,CACjF,iFAAkF,CAClF,oFAAqF,CACrF,2DAA4D,CAC5D,kEAAmE,CACnE,kEAAmE,CACnE,mEAAoE,CACpE,sEAAuE,CACvE,uFAAwF,CACxF,qDAAsD,CACtD,4FAA6F,CAC7F,4FAA6F,CAC7F,6FAA8F,CAC9F,gGAAiG,CACjG,qEAAsE,CACtE,uEAAwE,CACxE,wEAAyE,CACzE,sEAAuE,CACvE,gEAAiE,CACjE,+DAAgE,CAChE,qEAAsE,CACtE,8EAA+E,CAC/E,8EAA+E,CAC/E,+EAAgF,CAChF,kFAAmF,CACnF,yDAA0D,CAC1D,gEAAiE,CACjE,gEAAiE,CACjE,iEAAkE,CAClE,oEAAqE,CACrE,qFAAsF,CACtF,mDAAoD,CACpD,0FAA2F,CAC3F,0FAA2F,CAC3F,2FAA4F,CAC5F,8FAA+F,CAC/F,8EAA+E,CAC/E,uFAAwF,CACxF,uFAAwF,CACxF,wFAAyF,CACzF,4FAA6F,CAC7F,6FAA8F,CAC9F,0GAA2G,CAC3G,8DAA+D,CAC/D,sEAAuE,CACvE,qCAAsC,CACtC,iEAAkE,CAClE,mEAAoE,CACpE,oEAAqE,CACrE,kEAAmE,CACnE,iEAAkE,CAClE,sFAAuF,CACvF,sFAAuF,CACvF,uFAAwF,CACxF,2FAA4F,CAC5F,qFAAsF,CACtF,qFAAsF,CACtF,sFAAuF,CACvF,yFAA0F,CAC1F,+BAAgC,CAChC,oDAAqD,CACrD,wEAAyE,CACzE,uEAAwE,CACxE,2DAA4D,CAC5D,iEAAkE,CAClE,kEAAmE,CACnE,oEAAqE,CACrE,qEAAsE,CACtE,mEAAoE,CACpE,wEAAyE,CACzE,uEAAwE,CACxE,kEAAmE,CACnE,sDAAuD,CACvD,gEAAiE,CACjE,gEAAiE,CACjE,iEAAkE,CAClE,4FAA6F,CAC7F,sDAAuD,CACvD,sDAAuD,CACvD,uDAAwD,CACxD,0FAA2F,CAC3F,oEAAqE,CACrE,kEAAmE,CACnE,oEAAqE,CACrE,qEAAsE,CACtE,mEAAoE,CACpE,wEAAyE,CACzE,uEAAwE,CACxE,kEAAmE,CACnE,mEAAoE,CACpE,wFAAyF,CACzF,8EAA+E,CAC/E,mEAAoE,CACpE,2EAA4E,CAC5E,2EAA4E,CAC5E,4EAA6E,CAC7E,gFAAiF,CACjF,sDAAuD,CACvD,wEAAyE,CACzE,8EAAiF,CACjF,gFAAmF,CACnF,0FAA2F,CAC3F,gFAAiF,CACjF,qDAAsD,CACtD,oDAAqD,CACrD,oEAAqE,CACrE,6DAA8D,CAC9D,4DAA6D,CAC7D,iEAAkE,CAClE,wEAAyE,CACzE,6DAA8D,CAC9D,gEAAiE,CACjE,qCAAsC,CACtC,oCAAqC,CACrC,kFAAqF,CACrF,qCACE,UACE,sEAAuE,CACvE,oEAAqE,CACrE,wFAAyF,CACzF,sFAAuF,CACvF,wFAAyF,CACzF,sFAAuF,CACvF,wEAA2E,CAAE,CACjF,kDACE,eAAkB,CAClB,oIAGE,iBAAkB,CAClB,YAAe,CACjB,kFACE,MAAO,CACP,cAAe,CACf,eAAgB,CAChB,kBAAmB,CACnB,gCAAiC,CACjC,oBAAqB,CACrB,2CAA8C,CAC9C,wHACE,YAAe,CACnB,kFACE,YAAe,CACjB,kFACE,kBAAmB,CACnB,kBAAmB,CACnB,kBAAqB,CACrB,gGACE,QAAS,CACT,QAAW,CACb,8FACE,YAAe,CACrB,iDACE,gDAAiD,CACjD,8CAAiD,CACnD,+CACE,8CAA+C,CAC/C,4CAA+C,CACjD,qBACE,yFAA0F,CAC1F,qJAAsJ,CACtJ,6DAA8D,CAC9D,2EAA4E,CAC5E,2EAA4E,CAC5E,6EAA8E,CAC9E,mFAAoF,CACpF,+FAAgG,CAChG,+FAAgG,CAChG,iGAAkG,CAClG,uGAAwG,CACxG,yFAA0F,CAC1F,uFAAwF,CACxF,6GAA8G,CAC9G,qHAAsH,CACtH,qHAAsH,CACtH,uHAAwH,CACxH,6HAA8H,CAC9H,+EAAgF,CAChF,uGAA0G,CAC1G,mCACE,2FAA8F,CAClG,0BACE,4EAA6E,CAC7E,gFAAiF,CACjF,kFAAmF,CACnF,8EAA+E,CAC/E,kEAAmE,CACnE,gEAAiE,CACjE,kEAAmE,CACnE,gFAAiF,CACjF,kFAAmF,CACnF,gFAAiF,CACjF,wFAAyF,CACzF,sFAAuF,CACvF,oGAAqG,CACrG,oGAAqG,CACrG,sGAAuG,CACvG,4GAA6G,CAC7G,8FAA+F,CAC/F,oGAAqG,CACrG,kHAAmH,CACnH,kHAAmH,CACnH,oHAAqH,CACrH,0HAA6H,CAC/H,wBACE,0EAA2E,CAC3E,8EAA+E,CAC/E,gFAAiF,CACjF,4EAA6E,CAC7E,gEAAiE,CACjE,8DAA+D,CAC/D,gEAAiE,CACjE,8EAA+E,CAC/E,gFAAiF,CACjF,8EAA+E,CAC/E,sFAAuF,CACvF,oFAAqF,CACrF,kGAAmG,CACnG,kGAAmG,CACnG,oGAAqG,CACrG,0GAA2G,CAC3G,4FAA6F,CAC7F,kGAAmG,CACnG,gHAAiH,CACjH,gHAAiH,CACjH,kHAAmH,CACnH,wHAAyH,CACzH,kFAAmF,CACnF,gGAAiG,CACjG,gGAAiG,CACjG,kGAAmG,CACnG,sGAAuG,CACvG,8GAA+G,CAC/G,kIAAqI,CACvI,wBACE,kFAAmF,CACnF,sDAAuD,CACvD,oDAAqD,CACrD,gDAAiD,CACjD,sDAAyD,CAC3D,mDACE,SAAY,CACd,iEACE,cAAe,CACf,uBAA0B,CAC5B,kEACE,aAAc,CACd,uBAA0B,CAE9B,gBACE,aAAgB,CAElB,gBACE,iBAAkB,CAClB,2CAA8C,CAC9C,gCACE,6CAAgD,CAChD,uCACE,iBAAkB,CAClB,OAAQ,CACR,0DAA6D,CAC7D,MAAO,CACP,UAAW,CACX,yGAA4G,CAElH,gBACE,iBAAkB,CAClB,YAAa,CACb,oBAAqB,CACrB,qJAAsJ,CACtJ,yCAA0C,CAC1C,6CAA8C,CAC9C,kCAAmC,CACnC,uDAAwD,CACxD,mDAAsD,CACtD,6CACE,iBAAkB,CAClB,UAAW,CACX,cAAiB,CACnB,uBACE,OAAQ,CACR,gEAAmE,CACnE,MAAO,CACP,uDAAwD,CACxD,oEAAuE,CACzE,sBACE,KAAM,CACN,QAAS,CACT,MAAO,CAGP,cAAgE,CAAhE,sDAAgE,CAAhE,yGAAkE,CACpE,sBACE,yCAA0C,CAC1C,8DAAiE,CACjE,6BACE,2EAA8E,CAChF,4BACE,6DAA8D,CAC9D,sEAAyE,CAC7E,sBACE,yCAA0C,CAC1C,8DAAiE,CACjE,6BACE,2EAA8E,CAChF,4BACE,6DAA8D,CAC9D,sEAAyE,CAC7E,uBACE,0CAA2C,CAC3C,+DAAkE,CAClE,8BACE,4EAA+E,CACjF,6BACE,8DAA+D,CAC/D,uEAA0E,CAC9E,iIAEE,6CAA8C,CAC9C,kEAAqE,CACrE,sJAEE,+EAAkF,CACpF,mJAEE,iEAAkE,CAClE,0EAA6E,CACjF,mFACE,UAAW,CACX,oBAAqB,CACrB,WAAc,CAElB,kBACE,sEAAuE,CACvE,0EAA2E,CAC3E,4EAA6E,CAC7E,wEAAyE,CACzE,kEAAmE,CACnE,oGAAqG,CACrG,oGAAqG,CACrG,sGAAuG,CACvG,4GAA6G,CAC7G,wGAAyG,CACzG,wGAAyG,CACzG,0GAA2G,CAC3G,gHAAiH,CACjH,oFAAqF,CACrF,kFAAmF,CACnF,6CAA8C,CAC9C,qDAAsD,CACtD,iDAAkD,CAClD,sCAAuC,CACvC,oBAAqB,CACrB,2CAA8C,CAC9C,gDACE,kFAAmF,CACnF,eAAgB,CAChB,SAAY,CACd,qCACE,YAAe,CAEnB,kBACE,SAAU,CACV,mDAAoD,CACpD,iDAAkD,CAClD,gBAAiB,CACjB,2CAA4C,CAC5C,aAAgB,CAElB,uBACE,oBAAqB,CACrB,mDAAsD,CACtD,qDACE,wEAA2E,CAE/E,mBACE,qEAAsE,CACtE,uEAAwE,CACxE,2EAA4E,CAC5E,6EAA8E,CAC9E,yEAA0E,CAC1E,mEAAoE,CACpE,qGAAsG,CACtG,qGAAsG,CACtG,qGAAsG,CACtG,uGAAwG,CACxG,6GAA8G,CAC9G,yGAA0G,CAC1G,yGAA0G,CAC1G,2GAA4G,CAC5G,iHAAkH,CAClH,8CAA+C,CAC/C,qCAAwC,CACxC,sCACE,2EAA8E,CAElF,yBACE,yLAA0L,CAC1L,kDAAmD,CACnD,2CAA4C,CAC5C,uHAA0H,CAE5H,yBACE,SAAU,CACV,2CAA4C,CAC5C,2CAA4C,CAC5C,gEAAiE,CACjE,QAAS,CACT,4DAA6D,CAC7D,SAAU,CACV,qDAAwD,CACxD,gCACE,iBAAkB,CAClB,KAAM,CACN,QAAS,CACT,UAAW,CACX,gEAAiE,CACjE,yEAAkI,CAAlI,qBAAkI,CAAlI,2EAAkI,CAAlI,kBAAoI,CACtI,+BACE,kDAAqD,CACvD,+BACE,kDAAqD,CACvD,gCACE,mDAAsD,CACxD,kCACE,qDAAsD,CACtD,0EAA6E,CAC/E,uCACE,uGAAwG,CACxG,2DAA8D,CAC9D,2BAA8B,CAC9B,8CACE,OAAU,CACd,wCACE,sGAAuG,CACvG,0DAA6D,CAC7D,0BAA6B,CAC7B,+CACE,MAAS,CAEf,yBACE,4EAA6E,CAC7E,oEAAqE,CACrE,+EAAgF,CAChF,mEAAoE,CACpE,oFAAuF,CACvF,4EAA+E,CAC/E,uFAA0F,CAC1F,2EAA8E,CAC9E,yDAA0D,CAC1D,iFAAkF,CAClF,+CAAgD,CAChD,uCAAwC,CACxC,yCAA0C,CAC1C,4CAA6C,CAC7C,6CAA8C,CAC9C,6DAA8D,CAC9D,8CAA+C,CAC/C,8CAA+C,CAC/C,wCAAyC,CACzC,yCAA0C,CAC1C,iEAAkE,CAClE,qEAAsE,CACtE,6EAA8E,CAC9E,+FAAgG,CAChG,uGAAwG,CACxG,gFAAiF,CACjF,kGAAmG,CACnG,yGAA0G,CAC1G,yEAA0E,CAC1E,8FAA+F,CAC/F,iBAAkB,CAClB,oBAAqB,CACrB,yLAA0L,CAC1L,oLAAqL,CACrL,uEAAwE,CACxE,iEAAoE,CACpE,gCACE,iBAAkB,CAClB,8CAA+C,CAC/C,kDAAmD,CACnD,QAAS,CACT,MAAO,CACP,kDAAmD,CACnD,oDAAqD,CACrD,UAAW,CACX,kHAAmH,CACnH,iEAAkE,CAClE,wHAA4H,CAC9H,2BACE,8CAA+C,CAC/C,gDAAmD,CACrD,2BACE,iBAAoB,CACtB,wFAEE,oBAAqB,CACrB,8EAAiF,CACjF,sGAEE,qBAAwB,CAC5B,mCACE,gHAAiH,CACjH,wGAA2G,CAC7G,qCACE,kHAAmH,CACnH,qDAAwD,CACxD,2CACE,yHAA4H,CAChI,wCACE,qHAAsH,CACtH,wDAA2D,CAC3D,8CACE,4HAA+H,CAErI,gCACE,6DAAgE,CAElE,0BACE,kFAAmF,CACnF,2EAA4E,CAC5E,6EAA8E,CAC9E,8EAA+E,CAC/E,4EAA6E,CAC7E,0FAA2F,CAC3F,oFAAqF,CACrF,uEAAwE,CACxE,iFAAkF,CAClF,kFAAmF,CACnF,qEAAsE,CACtE,8EAA+E,CAC/E,gFAAiF,CACjF,iFAAkF,CAClF,+EAAgF,CAChF,6FAA8F,CAC9F,6FAA8F,CAC9F,0FAA2F,CAC3F,oEAAqE,CACrE,6DAA8D,CAC9D,sFAAuF,CACvF,oDAAqD,CACrD,4HAA+H,CAC/H,6GAA8G,CAC9G,mHAAoH,CACpH,mHAAoH,CACpH,yHAA0H,CAC1H,iHAAkH,CAClH,uHAAwH,CACxH,mHAAoH,CACpH,yHAA0H,CAC1H,mHAAoH,CACpH,yHAA0H,CAC1H,qGAAsG,CACtG,mGAAoG,CACpG,iIAAoI,CACpI,+DAAgE,CAChE,kFAAmF,CACnF,uEAAwE,CACxE,gHAAiH,CACjH,8FAA+F,CAC/F,+IAAiJ,CACjJ,uFAAwF,CACxF,gEAAiE,CACjE,2FAA4F,CAC5F,iGAAkG,CAClG,+DAAgE,CAChE,sHAAuH,CACvH,4FAA6F,CAC7F,mFAAoF,CACpF,wFAAyF,CACzF,sGAAuG,CACvG,uGAAwG,CACxG,0DAA2D,CAC3D,iFAAkF,CAClF,mFAAoF,CACpF,oFAAqF,CACrF,kFAAmF,CACnF,gGAAiG,CACjG,wFAAyF,CACzF,6FAA8F,CAC9F,gEAAiE,CACjE,wFAAyF,CACzF,2DAA4D,CAC5D,wFAAyF,CACzF,uFAAwF,CACxF,iFAAkF,CAClF,wEAAyE,CACzE,8EAA+E,CAC/E,YAAa,CACb,qBAAsB,CACtB,WAAY,CACZ,iEAAoE,CAEtE,kCACE,iBAAkB,CAClB,uDAAwD,CACxD,YAAa,CACb,aAAc,CACd,oBAAqB,CACrB,6NAA8N,CAC9N,yEAA0E,CAC1E,6DAAgE,CAElE,wCACE,iEAAoE,CAEtE,yCACE,sEAAyE,CAE3E,yCACE,YAAa,CACb,kBAAmB,CACnB,gBAAmB,CAErB,gCACE,eAAgB,CAChB,wDAA2D,CAE7D,qCACE,iBAAkB,CAClB,YAAa,CACb,8BAA+B,CAC/B,yOAA0O,CAC1O,4EAA6E,CAC7E,+IAAgJ,CAChJ,wEAAyE,CACzE,gEAAmE,CACnE,gGACE,qDAAwD,CAC1D,oGACE,yHAA0H,CAC1H,6HAAgI,CAClI,4CACE,iBAAkB,CAClB,2DAA4D,CAC5D,iEAAkE,CAClE,+DAAgE,CAChE,UAAW,CACX,oFAAuF,CACzF,+CACE,qJAAsJ,CACtJ,yIAA4I,CAC9I,kDACE,wJAAyJ,CACzJ,4IAA+I,CACjJ,iDACE,uJAAwJ,CACxJ,2IAA8I,CAChJ,kDACE,wJAAyJ,CACzJ,4IAA+I,CACjJ,kDACE,wJAAyJ,CACzJ,4IAA+I,CACjJ,+CACE,8HAA+H,CAC/H,0HAA2H,CAC3H,kHAAmH,CACnH,wHAAyH,CACzH,0IAA2I,CAC3I,qJAAsJ,CACtJ,iBAAoB,CACtB,oDACE,cAAiB,CACjB,0DACE,8EAA+E,CAC/E,oFAAuF,CAE7F,4CACE,YAAa,CACb,oBAAqB,CACrB,eAAkB,CAClB,YAAe,CACf,6EAAgF,CAElF,iDACE,gFAAiF,CACjF,mEAAsE,CAExE,kDACE,+EAAgF,CAChF,qBAAwB,CACxB,gEACE,mBAAoB,CACpB,2BAA4B,CAC5B,qFAAsF,CACtF,eAAkB,CAEtB,4CACE,eAAkB,CAClB,YAAiB,CAEnB,iDACE,YAAe,CACf,eAAkB,CAClB,kFAAmF,CACnF,qBAAwB,CAE1B,+CACE,YAAe,CACf,eAAkB,CAClB,wEAAyE,CACzE,iEAAoE,CAEtE,sCACE,YAAa,CACb,qBAAwB,CAE1B,+CACE,wEAA2E,CAC3E,gFACE,oKAAuK,CAE3K,iFACE,0DAA2D,CAC3D,uDAA0D,CAE5D,wCACE,YAAa,CACb,oBAAqB,CACrB,UAAW,CACX,qPAAsP,CACtP,+EAAgF,CAChF,uEAAwE,CACxE,mBAAoF,CAApF,oFAAoF,CAApF,oBAAoF,CAApF,kBAAoF,CACpF,2EAA8E,CAEhF,8CACE,mBAAoB,CACpB,2BAA4B,CAC5B,iFAAkF,CAClF,eAAgB,CAChB,6EAA8E,CAC9E,eAAgB,CAChB,qBAAwB,CAE1B,8CACE,6EAA8E,CAC9E,gBAAmB,CAErB,6CACE,4EAA6E,CAC7E,+DAAgE,CAChE,yEAA4E,CAC5E,4FACE,+FAAkG,CAEtG,mBACE,wDAAyD,CACzD,8EAA+E,CAC/E,sEAAuE,CACvE,iFAAkF,CAClF,qEAAsE,CACtE,6EAA8E,CAC9E,wEAAyE,CACzE,0EAA2E,CAC3E,8EAA+E,CAC/E,gFAAiF,CACjF,iFAAkF,CAClF,+EAAgF,CAChF,+DAAgE,CAChE,yFAA0F,CAC1F,wFAAyF,CACzF,0FAA2F,CAC3F,uFAAwF,CACxF,yFAA0F,CAC1F,0FAA2F,CAC3F,4FAA6F,CAC7F,4FAA6F,CAC7F,wEAAyE,CACzE,+EAAgF,CAChF,2FAA4F,CAC5F,0EAA2E,CAC3E,yEAA0E,CAC1E,kEAAmE,CACnE,+DAAgE,CAChE,qFAAsF,CACtF,6EAA8E,CAC9E,wFAAyF,CACzF,4EAA6E,CAC7E,uFAAwF,CACxF,oEAAqE,CACrE,kEAAmE,CACnE,qEAAsE,CACtE,wEAAyE,CACzE,8DAA+D,CAC/D,uCAAwC,CACxC,uFAAwF,CACxF,2DAA4D,CAC5D,kEAAmE,CACnE,uEAAwE,CACxE,uEAAwE,CACxE,yEAA0E,CAC1E,0EAA2E,CAC3E,wEAAyE,CACzE,iFAAkF,CAClF,mGAAoG,CACpG,qEAAsE,CACtE,8EAA+E,CAC/E,kFAAmF,CACnF,6EAA8E,CAC9E,0EAA2E,CAC3E,yEAA0E,CAC1E,gGAAiG,CACjG,kGAAmG,CACnG,8FAA+F,CAC/F,yEAA0E,CAC1E,oFAAqF,CACrF,yEAA0E,CAC1E,sEAAuE,CACvE,yEAA0E,CAC1E,iBAAkB,CAClB,oBAAqB,CACrB,cAAiB,CACjB,iCACE,yDAA0D,CAC1D,+DAAkE,CAClE,4CACE,8CAAiD,CAEvD,0IAEE,iBAAkB,CAClB,KAAM,CACN,OAAQ,CACR,QAAS,CACT,MAAO,CACP,UAAW,CACX,0DAA2D,CAC3D,sNAAyN,CAE3N,sJAEE,yGAA4G,CAE9G,0TAGE,0GAA2G,CAC3G,+EAAkF,CAEpF,sJAEE,yGAA0G,CAC1G,8EAAiF,CAEnF,2BACE,iBAAkB,CAClB,YAAa,CACb,kBAAmB,CACnB,6BAA8B,CAC9B,oDAAqD,CACrD,cAAe,CACf,0DAA2D,CAC3D,wDAAyD,CACzD,6CAA8C,CAC9C,kEAAmE,CACnE,WAAc,CACd,2CACE,wDAAyD,CACzD,4DAA6D,CAC7D,8DAAiE,CACnE,mEACE,4GAA6G,CAC7G,iFAAoF,CACtF,sDACE,sBAAuB,CACvB,sDAAyD,CAC3D,6EACE,wDAA2D,CAC7D,8PAEE,mGAAsG,CACxG,mGACE,sGAAyG,CAC3G,6EACE,mBAAsB,CACtB,gNACE,wGAA2G,CAC7G,2FACE,QAAW,CAEjB,uCACE,iBAAoB,CAEtB,kCACE,6NAA8N,CAC9N,yEAA0E,CAC1E,QAAW,CAEb,gCACE,eAAgB,CAChB,sBAAuB,CACvB,kBAAqB,CAEvB,gCACE,+DAAgE,CAChE,6DAAgE,CAChE,0EACE,kFAAqF,CAEzF,yBACE,iBAAkB,CAClB,uCAAwC,CACxC,8CAA+C,CAC/C,cAAe,CACf,sDAAuD,CACvD,4DAA6D,CAC7D,gEAAiE,CACjE,2BAA4B,CAC5B,oDAAuD,CACvD,0CACE,OAAU,CACZ,qDACE,yEAA0E,CAC1E,uEAA0E,CAE9E,8BACE,YAAa,CACb,oBAAqB,CACrB,UAAW,CACX,6MAA8M,CAC9M,uDAAwD,CACxD,gDAAiD,CACjD,kBAAmB,CACnB,qEAAsE,CACtE,WAAc,CACd,wEACE,oBAAqB,CACrB,4EAA+E,CACjF,mFACE,0DAA2D,CAC3D,mBAAoB,CACpB,+EAAkF,CAEtF,mCACE,iBAAkB,CAClB,UAAW,CACX,kEAAmE,CACnE,gBAAiB,CACjB,4DAA6D,CAC7D,qDAAwD,CAE1D,oDACE,8DAAiE,CAEnE,gCAIE,qNAAgE,CAChE,yDAA0D,CAC1D,6DAA8D,CAC9D,kDAAqD,CAEvD,oBACE,+DAAgE,CAChE,yDAA0D,CAC1D,2EAA4E,CAC5E,0EAA2E,CAC3E,2FAA4F,CAC5F,2FAA4F,CAC5F,qFAAsF,CACtF,gGAAiG,CACjG,+DAAgE,CAChE,mBAAoB,CACpB,kBAAqB,CAMvB,wDAHE,YAAa,CACb,kBAKqB,CAHvB,2BACE,qEAEqB,CACrB,6CACE,qFAAwF,CACxF,+CACE,0FAA6F,CACjG,kDACE,0FAA6F,CAC7F,oDACE,+FAAkG,CAExG,0BACE,oEAAuE,CAEzE,+GAIE,8CAAiD,CACjD,2JAIE,8BAAiC,CAErC,2EAEE,qFAAwF,CAE1F,uGAEE,8CAAiD,CACjD,6HAEE,8BAAiC,CAErC,WACE,yEAA0E,CAC1E,gFAAiF,CACjF,wDAAyD,CACzD,sCAAuC,CACvC,mEAAoE,CACpE,wEAAyE,CACzE,uEAAwE,CACxE,qFAAsF,CACtF,uFAAwF,CACxF,wFAAyF,CACzF,sFAAuF,CACvF,sFAAuF,CACvF,gIAAmI,CACnI,sFAAuF,CACvF,0DAA2D,CAC3D,oFAAqF,CACrF,wDAAyD,CACzD,sEAAuE,CACvE,qEAAsE,CACtE,mEAAoE,CACpE,uEAAwE,CACxE,4EAA6E,CAC7E,wEAAyE,CACzE,6CAA8C,CAC9C,6CAA8C,CAC9C,wHAAyH,CACzH,8HAA+H,CAC/H,gIAAiI,CACjI,0IAA2I,CAC3I,4IAA6I,CAC7I,mEAAoE,CACpE,oEAAqE,CACrE,oHAAqH,CACrH,wGAAyG,CACzG,+GAAgH,CAChH,yDAA0D,CAC1D,+BAAgC,CAChC,qCAAsC,CACtC,iFAAkF,CAClF,2FAA4F,CAC5F,qEAAsE,CACtE,6DAA8D,CAC9D,sCAAuC,CACvC,kCAAmC,CACnC,8CAA+C,CAC/C,sCAAuC,CACvC,kEAAmE,CACnE,qEAAsE,CACtE,sDAAuD,CACvD,kEAAmE,CACnE,oEAAqE,CACrE,qEAAsE,CACtE,mEAAoE,CACpE,sEAAuE,CACvE,wEAAyE,CACzE,yEAA0E,CAC1E,uEAAwE,CACxE,mFAAoF,CACpF,uFAAwF,CACxF,gGAAiG,CACjG,8GAA+G,CAC/G,8GAA+G,CAC/G,6FAA8F,CAC9F,uEAAwE,CACxE,oFAAqF,CACrF,0EAA2E,CAC3E,oFAAqF,CACrF,uFAAwF,CACxF,0EAA2E,CAC3E,iFAAkF,CAClF,uEAAwE,CACxE,mFAAoF,CACpF,8DAA+D,CAC/D,qCAAsC,CACtC,oCAAqC,CACrC,+EAAgF,CAChF,oEAAqE,CACrE,mEAAoE,CACpE,0FAA2F,CAC3F,qEAAsE,CACtE,uEAAwE,CACxE,6CAA8C,CAC9C,sEAAuE,CACvE,sFAAuF,CACvF,2EAA4E,CAC5E,0EAA2E,CAC3E,sFAAuF,CACvF,2EAA4E,CAC5E,0EAA2E,CAC3E,YAAa,CACb,WAAY,CACZ,yBAA0B,CAC1B,kCAAmC,CACnC,mCAAoC,CACpC,kDAAqD,CACrD,0BACE,WACE,sFAAyF,CAAE,CAC/F,qCACE,WACE,0FAA2F,CAC3F,oFAAqF,CACrF,kFAAmF,CAGnF,sFAAuF,CAGvF,0EAA2E,CAG3E,oFAAqF,CACrF,wFAAyF,CACzF,0FAA2F,CAC3F,sFAAuF,CAGvF,gFAAiF,CACjF,8EAA+E,CAG/E,8FAA+F,CAC/F,4FApBqF,CAAE,CAqB3F,0BACE,WACE,qCAAsC,CACtC,8CAAiD,CAAE,CAEzD,mBACE,kCAAmC,CACnC,wCAAyC,CACzC,+BAAgC,CAChC,YAAa,CACb,gBAAiB,CACjB,kBAAmB,CACnB,WAAY,CACZ,8CAA+C,CAC/C,0DAA6D,CAC7D,qBACE,YAAa,CACb,kBAAqB,CACvB,oCACE,mBACE,mCAAsC,CAAE,CAE9C,yBACE,eAAkB,CAClB,wDAA2D,CAC3D,0BACE,yBACE,8DAAiE,CAAE,CAEzE,8BACE,YAAa,CACb,MAAO,CACP,kBAAqB,CACrB,0CACE,kEAAqE,CAEzE,6CACE,qQAAsQ,CACtQ,2EAA4E,CAC5E,yEAA0E,CAC1E,qEAAsE,CACtE,aAAgB,CAElB,uBACE,kBAAmB,CACnB,WAAY,CACZ,wDAAyD,CACzD,sDAAuD,CACvD,8DAA+D,CAC/D,gBAAmB,CACnB,YAAiB,CACjB,qCACE,uBACE,eAAkB,CAClB,YAAiB,CAAE,CACvB,iCACE,kBAAqB,CAEzB,yBACE,eAAkB,CAClB,wDAAyD,CACzD,gBAAmB,CACnB,sCACE,gEAAmE,CACrE,oCACE,yBACE,eAAoB,CAAE,CAE5B,+BACE,mFAAoF,CACpF,kBAAqB,CACrB,8DACE,4DAA+D,CAEnE,8BACE,kFAAqF,CACrF,uEACE,mIAAsI,CACxI,yDACE,8FAA+F,CAC/F,wFAA2F,CAC3F,gEACE,iBAAkB,CAClB,KAAM,CACN,OAAQ,CACR,QAAS,CACT,MAAO,CACP,yEAA0E,CAC1E,2EAA4E,CAC5E,UAAa,CACf,8FACE,4JAA+J,CAC/J,oGACE,qHAAwH,CAC5H,iGACE,qFAAwF,CAC5F,sFACE,gJAAmJ,CACrJ,yFACE,mJAAsJ,CAE1J,oBACE,aAAc,CACd,gBAAiB,CACjB,mBAAoB,CACpB,yCAA0C,CAC1C,sCAAuC,CACvC,iBAAkB,CAClB,eAAgB,CAChB,gCAAiC,CACjC,2DAA4D,CAC5D,gDAAiD,CACjD,6GAAgH,CAChH,qCACE,oBACE,+CAAkD,CAAE,CACxD,kCACE,kFAAmF,CACnF,+CAAkD,CACpD,mCACE,WAAY,CACZ,eAAkB,CACpB,+BACE,kCAAmC,CACnC,yFAA4F,CAEhG,yBACE,sDAAuD,CACvD,4DAA+D,CAEjE,sKAIE,YAAa,CACb,qBAAsB,CACtB,SAAY,CACZ,8PAIE,MAAO,CACP,4DAA+D,CAEnE,yHAKE,aAAgB,CAChB,yMAKE,eAAgB,CAChB,KAAM,CACN,uDAAwD,CACxD,6DAAgE,CAClE,wNAKE,eAAgB,CAChB,QAAS,CACT,0DAA2D,CAC3D,gEAAmE,CACrE,kOAKE,iBAAkB,CAClB,aAAc,CACd,aAAgB,CAClB,wNAKE,0DAA2D,CAC3D,gEAAmE,CACrE,yMAKE,uDAAwD,CACxD,6DAAgE,CAEpE,oCAEE,cAAe,CACf,sCAAuC,CACvC,iBAAkB,CAClB,eAAgB,CAChB,gCAAmC,CACnC,gDAEE,SAAY,CAEhB,gEAGE,YAAa,CACb,qBAAwB,CAE1B,qBACE,kDAAmD,CACnD,sDAAuD,CACvD,oDAAqD,CACrD,4DAA+D,CAC/D,4GAEE,sEAAyE,CAE7E,4BACE,qMAAsM,CACtM,mEAAsE,CACtE,qDACE,iGAAoG,CACtG,0HAEE,0GAA6G,CAEjH,wTAOE,WAAc,CAEhB,+GAGE,WAAc,CAEhB,yBACE,yLAA0L,CAC1L,gEAAmE,CACnE,oCACE,mGAAsG,CACxG,4CACE,kCAAqC,CACvC,uCACE,sGAAyG,CAC3G,uCACE,sGAAyG,CAC3G,sCACE,yLAA4L,CAC9L,yCACE,uCAAwC,CACxC,yCAA0C,CAC1C,0CAA2C,CAC3C,wCAA2C,CAC7C,yBACE,4CACE,yLAA4L,CAC9L,+CACE,uCAAwC,CACxC,yCAA0C,CAC1C,0CAA2C,CAC3C,wCAA2C,CAAE,CACjD,yBACE,4CACE,yLAA4L,CAC9L,+CACE,uCAAwC,CACxC,yCAA0C,CAC1C,0CAA2C,CAC3C,wCAA2C,CAAE,CACjD,yBACE,4CACE,yLAA4L,CAC9L,+CACE,uCAAwC,CACxC,yCAA0C,CAC1C,0CAA2C,CAC3C,wCAA2C,CAAE,CACjD,0BACE,4CACE,yLAA4L,CAC9L,+CACE,uCAAwC,CACxC,yCAA0C,CAC1C,0CAA2C,CAC3C,wCAA2C,CAAE,CACjD,0BACE,6CACE,yLAA4L,CAC9L,gDACE,uCAAwC,CACxC,yCAA0C,CAC1C,0CAA2C,CAC3C,wCAA2C,CAAE,CAEnD,wBACE,WAAY,CACZ,+DAAgE,CAChE,4GAA+G,CAEjH,uBACE,aAAgB,CAElB,2CACE,kDAAmD,CACnD,sDAAuD,CACvD,oDAAuD,CAEzD,kDACE,qMAAwM,CAE1M,+CACE,yLAA4L,CAE9L,mBACE,cAAiB,CACjB,gCACE,aAAgB,CAEpB,iBACE,kEAAmE,CACnE,iDAAkD,CAClD,gFAAiF,CACjF,6EAA8E,CAC9E,kFAAmF,CACnF,oCAAqC,CACrC,yCAA0C,CAC1C,uDAAwD,CACxD,4DAA6D,CAC7D,2DAA4D,CAC5D,0DAA2D,CAC3D,mFAAoF,CACpF,kFAAmF,CACnF,iFAAkF,CAClF,uGAA0G,CAC1G,2FAA4F,CAC5F,8FAA+F,CAE/F,6FAA8F,CAC9F,yGAA0G,CAC1G,iGAAkG,CAClG,4GAA6G,CAC7G,gGAAiG,CACjG,+FAAgG,CAChG,2EAA4E,CAC5E,4EAA6E,CAC7E,6EAA8E,CAC9E,mFAAoF,CACpF,oEAAqE,CACrE,iEAAkE,CAClE,8MAAmN,CACnN,6CAA8C,CAC9C,kDAAmD,CACnD,gEAAiE,CACjE,qEAAsE,CACtE,4DAA6D,CAC7D,iEAAkE,CAClE,mFAAoF,CACpF,6EAA8E,CAC9E,wEAAyE,CACzE,0EAA2E,CAC3E,2EAA4E,CAC5E,yEAA0E,CAC1E,gEAAiE,CACjE,kCAAmC,CACnC,mFAAoF,CACpF,0EAA2E,CAC3E,qCAAsC,CACtC,wEAAyE,CACzE,0EAA2E,CAC3E,2EAA4E,CAC5E,yEAA0E,CAC1E,0EAA2E,CAC3E,yEAA0E,CAC1E,oFAAqF,CACrF,+CAAgD,CAChD,oDAAqD,CACrD,kEAAmE,CACnE,uEAAwE,CACxE,sEAAuE,CACvE,qEAAsE,CACtE,YAAa,CACb,cAAe,CACf,kBAAmB,CACnB,wBAA2B,CAC3B,oCACE,iBACE,sIAAuI,CACvI,0IAA2I,CAC3I,4IAA6I,CAC7I,wIAAyI,CACzI,wGAAyG,CACzG,mEAAoE,CACpE,2CAA4C,CAC5C,sDAAuD,CACvD,qDAAsD,CACtD,2CAA4C,CAC5C,0CAA2C,CAC3C,4CAA6C,CAC7C,iDAAoD,CAAE,CAC1D,qCACE,iBACE,gGAAiG,CACjG,8FAAiG,CAAE,CACvG,sEACE,uDAA0D,CAC5D,oCACE,uDAAwD,CACxD,6DAAgE,CAClE,6BACE,0FAA2F,CAC3F,4HAA6H,CAC7H,2HAA4H,CAC5H,4FAA6F,CAC7F,qCAAsC,CACtC,eAAgB,CAChB,+CAAgD,CAChD,sBAAuB,CACvB,kEAAmE,CACnE,sDAAyD,CACzD,wEACE,6FAA8F,CAC9F,mGAAoG,CACpG,qFAAwF,CAC1F,yCACE,wCAAyC,CACzC,6CAA8C,CAC9C,iBAAkB,CAClB,eAAkB,CACpB,0MAGE,YAAa,CACb,iBAAoB,CACtB,gDACE,iBAAkB,CAClB,aAAc,CACd,kBAAqB,CACvB,mDACE,YAAa,CACb,eAAgB,CAChB,6BAA8B,CAC9B,kBAAqB,CACvB,oCACE,6BACE,6CAA8C,CAC9C,wCAAyC,CACzC,wCAAyC,CACzC,iBAAkB,CAClB,wBAAyB,CACzB,iNAAoN,CACpN,0MAGE,aAAc,CACd,kBAAqB,CACvB,gDACE,iBAAoB,CACtB,mDACE,mBAAoB,CACpB,eAAkB,CAAE,CAC5B,6BACE,qCAAsC,CACtC,eAAgB,CAChB,yCAA0C,CAC1C,gDAAiD,CAIjD,iMAA2D,CAC3D,kEAAmE,CACnE,sDAAyD,CACzD,oCACE,6BACE,iNAAoN,CAAE,CAC5N,4CACE,kEAAqE,CACvE,8BACE,2FAA8F,CAElG,sBACE,4CAA6C,CAC7C,wBAAyB,CACzB,kDAAqD,CAEvD,2CACE,yEAA0E,CAC1E,uEAAwE,CACxE,iEAAoE,CAEtE,0FACE,mFAAsF,CAExF,kCACE,YAAa,CACb,kBAAmB,CACnB,mEAAoE,CACpE,iEAAoE,CACpE,oCACE,2DAA4D,CAC5D,kBAAqB,CACrB,oDACE,wEAA2E,CAC/E,qDACE,oEAAuE,CAE3E,8BACE,oDAAqD,CACrD,0DAA6D,CAE/D,sCACE,uFAAwF,CACxF,6FAA8F,CAC9F,6GAA8G,CAC9G,mHAAoH,CACpH,uGAAwG,CACxG,6GAAgH,CAElH,mCACE,oFAAqF,CACrF,0FAA2F,CAC3F,0GAA2G,CAC3G,gHAAiH,CACjH,oGAAqG,CACrG,0GAA6G,CAE/G,yBACE,4CACE,uFAAwF,CACxF,6FAA8F,CAC9F,6GAA8G,CAC9G,mHAAoH,CACpH,uGAAwG,CACxG,6GAAgH,CAClH,yCACE,oFAAqF,CACrF,0FAA2F,CAC3F,0GAA2G,CAC3G,gHAAiH,CACjH,oGAAqG,CACrG,0GAA6G,CAAE,CAEnH,yBACE,4CACE,uFAAwF,CACxF,6FAA8F,CAC9F,6GAA8G,CAC9G,mHAAoH,CACpH,uGAAwG,CACxG,6GAAgH,CAClH,yCACE,oFAAqF,CACrF,0FAA2F,CAC3F,0GAA2G,CAC3G,gHAAiH,CACjH,oGAAqG,CACrG,0GAA6G,CAAE,CAEnH,yBACE,4CACE,uFAAwF,CACxF,6FAA8F,CAC9F,6GAA8G,CAC9G,mHAAoH,CACpH,uGAAwG,CACxG,6GAAgH,CAClH,yCACE,oFAAqF,CACrF,0FAA2F,CAC3F,0GAA2G,CAC3G,gHAAiH,CACjH,oGAAqG,CACrG,0GAA6G,CAAE,CAEnH,0BACE,4CACE,uFAAwF,CACxF,6FAA8F,CAC9F,6GAA8G,CAC9G,mHAAoH,CACpH,uGAAwG,CACxG,6GAAgH,CAClH,yCACE,oFAAqF,CACrF,0FAA2F,CAC3F,0GAA2G,CAC3G,gHAAiH,CACjH,oGAAqG,CACrG,0GAA6G,CAAE,CAEnH,0BACE,6CACE,uFAAwF,CACxF,6FAA8F,CAC9F,6GAA8G,CAC9G,mHAAoH,CACpH,uGAAwG,CACxG,6GAAgH,CAClH,0CACE,oFAAqF,CACrF,0FAA2F,CAC3F,0GAA2G,CAC3G,gHAAiH,CACjH,oGAAqG,CACrG,0GAA6G,CAAE,CAEnH,cACE,uDAAwD,CACxD,gIAAiI,CACjI,gIAAiI,CACjI,yDAA0D,CAC1D,+EAAgF,CAChF,gEAAiE,CACjE,kEAAmE,CACnE,mEAAoE,CACpE,iEAAkE,CAClE,8DAA+D,CAC/D,+DAAgE,CAChE,gEAAiE,CACjE,6EAA8E,CAC9E,6CAA8C,CAC9C,4CAA6C,CAC7C,0CAA2C,CAC3C,+CAAgD,CAChD,+CAAgD,CAChD,4CAA6C,CAC7C,gDAAiD,CACjD,gDAAiD,CACjD,6CAA8C,CAC9C,6CAA8C,CAC9C,8CAA+C,CAC/C,2CAA4C,CAC5C,iEAAkE,CAClE,qHAAsH,CACtH,4DAA6D,CAC7D,6EAA8E,CAC9E,kEAAmE,CACnE,8DAA+D,CAC/D,iBAAkB,CAClB,uCAAwC,CACxC,uCAAwC,CACxC,uCAAwC,CACxC,yCAA4C,CAC5C,8BACE,uCAAwC,CACxC,yCAA0C,CAC1C,0CAA2C,CAC3C,wCAA2C,CAC7C,8BACE,6BAA8B,CAC9B,6BAAgC,CAClC,4CACE,QAAS,CACT,QAAS,CACT,+KAAkL,CACpL,+CACE,KAAM,CACN,QAAS,CACT,wLAA2L,CAC7L,6CACE,OAAQ,CACR,OAAQ,CACR,kLAAqL,CACvL,8CACE,OAAQ,CACR,MAAO,CACP,qLAAwL,CAE5L,uBACE,iBAAkB,CAClB,iLAAkL,CAClL,8DAAiE,CACjE,mCACE,wDAA2D,CAC7D,oCACE,iBAAkB,CAClB,sCAAuC,CACvC,0CAA6C,CAC7C,sCACE,kEAAqE,CAE3E,qBACE,iBAAkB,CAClB,uCAAwC,CACxC,yCAA0C,CAC1C,mBAAoB,CACpB,4DAA6D,CAC7D,gDAAmD,CAErD,oBACE,oBAAuB,CAEzB,sBACE,iDAAoD,CAEtD,eACE,qDAAsD,CACtD,kFAAmF,CACnF,yDAA0D,CAC1D,kFAAmF,CACnF,wDAAyD,CACzD,gEAAiE,CACjE,qEAAsE,CACtE,wCAAyC,CACzC,oEAAqE,CACrE,8FAA+F,CAC/F,qFAAsF,CACtF,qFAAsF,CACtF,mFAAoF,CACpF,mFAAoF,CACpF,mFAAoF,CACpF,iFAAkF,CAClF,2EAA4E,CAC5E,4EAA6E,CAC7E,uFAAwF,CACxF,sFAAuF,CACvF,2EAA4E,CAC5E,4EAA6E,CAC7E,+DAAgE,CAChE,2EAA4E,CAC5E,uEAAwE,CACxE,+DAAgE,CAChE,YAAa,CACb,eAAgB,CAChB,sCAAuC,CACvC,+BAAgC,CAChC,2BAA8B,CAC9B,uBACE,oEAAuE,CACvE,mDACE,2DAA8D,CAChE,+CACE,uDAA0D,CAC9D,uBACE,oEAAuE,CACzE,qDACE,YAAa,CACb,kBAAmB,CACnB,sBAAuB,CACvB,6DAAgE,CAClE,mDACE,2DAA4D,CAC5D,oDAAqD,CACrD,iBAAoB,CACtB,wDACE,eAAoB,CACtB,mDACE,eAAkB,CAClB,YAAe,CACf,iBAAoB,CACtB,oDACE,oBAAqB,CACrB,4DAA+D,CAC/D,sEACE,iEAAkE,CAClE,eAAkB,CACtB,sGAEE,eAAoB,CACtB,+BACE,sBAAyB,CACzB,2DACE,YAAa,CACb,iBAAoB,CACtB,mDACE,YAAe,CACf,eAAoB,CACtB,sDACE,YAAe,CACf,eAAoB,CACxB,2DACE,0CAA6C,CAC/C,4BACE,mGAAoG,CACpG,uFAAwF,CACxF,mGAAsG,CACxG,4BACE,mGAAoG,CACpG,uFAAwF,CACxF,mGAAsG,CACxG,2BACE,kGAAmG,CACnG,sFAAyF,CAE7F,4BACE,qBAAsB,CACtB,eAAoB,CACpB,0CACE,eAAgB,CAChB,sBAAuB,CACvB,kBAAqB,CAEzB,uBACE,eAAkB,CAClB,YAAe,CACf,gBAAiB,CACjB,qBAAwB,CAE1B,4BACE,yDAA0D,CAC1D,8CAAiD,CAEnD,oBACE,iBAAkB,CAClB,eAAkB,CAClB,YAAe,CACf,iBAAkB,CAClB,wCAAyC,CACzC,2DAA8D,CAC9D,2BACE,iBAAkB,CAClB,KAAM,CACN,MAAO,CACP,UAAW,CACX,WAAY,CACZ,UAAW,CACX,mEAAoE,CACpE,kDAAqD,CAEzD,0BACE,iBAAkB,CAClB,KAAM,CACN,MAAO,CACP,8CAA+C,CAC/C,iEAAoE,CAEtE,YACE,+EAAgF,CAChF,0EAA2E,CAC3E,uDAAwD,CACxD,oEAAqE,CACrE,4DAA6D,CAC7D,gEAAiE,CACjE,yCAA0C,CAC1C,sDAAuD,CACvD,sDAAuD,CACvD,kEAAmE,CACnE,6DAA8D,CAC9D,YAAa,CACb,8BAA+B,CAC/B,mCAAoC,CACpC,kBAAmB,CACnB,mBAAsB,CAExB,mBACE,4CAA6C,CAC7C,gDAAiD,CACjD,gDAAiD,CACjD,qCAAwC,CAE1C,mBACE,8CAAiD,CACjD,+BACE,6DAAgE,CAClE,8BACE,8DAAiE,CAErE,yBACE,aAAc,CACd,kDAAmD,CACnD,2CAA8C,CAEhD,uDAEE,cAAiB,CAEnB,0HAGE,oEAAqE,CACrE,kBAAqB,CAEvB,mBACE,gFAAiF,CACjF,iFAAkF,CAClF,qFAAsF,CACtF,sFAAuF,CACvF,+FAAgG,CAChG,mGAAoG,CACpG,sGAAuG,CACvG,kFAAmF,CACnF,0EAA2E,CAC3E,qFAAsF,CACtF,yEAA0E,CAC1E,6CAA8C,CAC9C,4DAA6D,CAC7D,6DAA8D,CAC9D,0EAA2E,CAC3E,0CAA2C,CAC3C,wEAAyE,CACzE,uEAAwE,CACxE,8EAA+E,CAC/E,mFAAoF,CACpF,kFAAmF,CACnF,iBAAkB,CAClB,YAAa,CACb,iKAAoK,CACpK,yBACE,mHAAsH,CAE1H,yBACE,MAAS,CACT,+DACE,iBAAkB,CAClB,KAAM,CACN,OAAQ,CACR,QAAS,CACT,MAAO,CACP,mBAAoB,CACpB,UAAa,CACf,gCACE,oHAAuH,CACzH,+BACE,qIAAwI,CAC1I,qEACE,mFAAsF,CACxF,sCACE,0HAA2H,CAC3H,0HAA6H,CAEjI,yBACE,iBAAkB,CAClB,OAAQ,CACR,yCAA0C,CAC1C,2CAA4C,CAC5C,gEAAmE,CAErE,+BACE,eAAgB,CAChB,sBAAuB,CACvB,kBAAmB,CACnB,iBAAkB,CAClB,UAAW,CACX,wDAAyD,CACzD,iNAAkN,CAClN,QAAW,CAEb,8BACE,YAAa,CACb,6DAA8D,CAC9D,2DAA8D,CAC9D,kCACE,kEAAqE,CACvE,2CACE,uFAAwF,CACxF,qFAAwF,CAE5F,wBACE,YAAe,CAEjB,0BACE,YAAa,CACb,kBAAqB,CAEvB,aACE,kCAAmC,CACnC,wEAAyE,CACzE,gEAAiE,CACjE,2EAA4E,CAC5E,+DAAgE,CAChE,uEAAwE,CACxE,8DAA+D,CAC/D,sEAAuE,CACvE,kEAAmE,CACnE,6EAA8E,CAC9E,4EAA6E,CAC7E,gFAAiF,CACjF,kFAAmF,CACnF,mFAAoF,CACpF,iFAAkF,CAClF,yDAA0D,CAC1D,2FAA4F,CAC5F,2FAA4F,CAC5F,4FAA6F,CAC7F,gGAAiG,CACjG,yFAA0F,CAC1F,0FAA2F,CAC3F,8FAA+F,CAC/F,sFAAuF,CACvF,+DAAgE,CAChE,uFAAwF,CACxF,iFAAkF,CAClF,gEAAiE,CACjE,mEAAoE,CACpE,+CAAgD,CAChD,4DAA6D,CAC7D,+CAAgD,CAChD,iDAAkD,CAClD,gDAAiD,CACjD,gDAAiD,CACjD,sIAAuI,CACvI,gFAAiF,CACjF,qEAAsE,CACtE,oEAAqE,CACrE,qEAAsE,CACtE,gFAAiF,CACjF,2EAA4E,CAC5E,sEAAuE,CACvE,qEAAsE,CACtE,oFAAqF,CACrF,gEAAiE,CACjE,iFAAkF,CAClF,8DAA+D,CAC/D,4DAA6D,CAC7D,+DAAgE,CAChE,kEAAmE,CACnE,wDAAyD,CACzD,iFAAkF,CAClF,iEAAkE,CAClE,mEAAoE,CACpE,gFAAiF,CACjF,oEAAqE,CACrE,kEAAmE,CACnE,iEAAkE,CAClE,yEAA0E,CAC1E,qEAAsE,CACtE,iEAAkE,CAClE,oCAAqC,CACrC,2EAA4E,CAC5E,6FAA8F,CAC9F,6FAA8F,CAC9F,+DAAgE,CAChE,4CAA6C,CAC7C,oEAAqE,CACrE,oEAAqE,CACrE,+EAAgF,CAChF,8CAA+C,CAC/C,iFAAkF,CAClF,sEAAuE,CACvE,sEAAuE,CACvE,wFAAyF,CACzF,6EAA8E,CAC9E,6EAA8E,CAC9E,gHAAiH,CACjH,wEAAyE,CACzE,4EAA6E,CAC7E,iEAAkE,CAClE,sCAAuC,CACvC,8CAA+C,CAC/C,uIAA0I,CAC1I,8EAA+E,CAC/E,mEAAoE,CACpE,oFAAqF,CACrF,sEAAuE,CACvE,kFAAmF,CACnF,8EAA+E,CAC/E,qFAAsF,CACtF,yFAA0F,CAC1F,2FAA4F,CAC5F,uFAAwF,CACxF,wEAAyE,CACzE,mFAAoF,CACpF,wEAAyE,CACzE,6EAA8E,CAC9E,wEAAyE,CACzE,8FAA+F,CAC/F,uFAAwF,CACxF,0HAA2H,CAC3H,qEAAsE,CACtE,wEAAyE,CACzE,iBAAkB,CAClB,oBAAqB,CACrB,UAAa,CACb,2BACE,wDAAyD,CACzD,8DAAiE,CACjE,sCACE,6CAAgD,CAEtD,wCACE,0CAA6C,CAE/C,qBACE,iBAAkB,CAClB,YAAa,CACb,kBAAmB,CACnB,6BAA8B,CAC9B,UAAW,CACX,8CAA+C,CAC/C,yKAA0K,CAC1K,8CAA+C,CAC/C,kDAAmD,CACnD,kDAAmD,CACnD,uCAAwC,CACxC,kBAAmB,CACnB,cAAe,CACf,4DAA6D,CAC7D,WAAc,CACd,iEACE,4FAA6F,CAC7F,mBAAsB,CACtB,+EACE,QAAW,CACf,4BACE,iBAAkB,CAClB,KAAM,CACN,OAAQ,CACR,QAAS,CACT,MAAO,CACP,UAAW,CACX,4DAA6D,CAC7D,8NAAiO,CACnO,kCACE,6GAAgH,CAClH,2EACE,6GAA8G,CAC9G,gFAAmF,CACrF,2EACE,8GAA+G,CAC/G,iFAAoF,CACtF,2CACE,kHAAmH,CACnH,qFAAwF,CAC1F,uCACE,qEAAwE,CAC1E,oCACE,mCAAoC,CACpC,qCAAsC,CACtC,sCAAyC,CACzC,uDACE,eAAgB,CAChB,sBAAuB,CACvB,kBAAmB,CACnB,iBAAkB,CAClB,WAAc,CAClB,gDACE,4DAA6D,CAC7D,0DAA2D,CAC3D,gBAAmB,CACrB,iDACE,8CAAiD,CACnD,4EACE,yEAA4E,CAEhF,6BACE,0DAA2D,CAC3D,wDAA2D,CAE7D,+DACE,2FAA8F,CAEhG,0BACE,eAAgB,CAChB,sBAAuB,CACvB,kBAAqB,CAEvB,6BACE,YAAa,CACb,MAAO,CACP,cAAe,CACf,kBAAmB,CACnB,0BAA2B,CAC3B,WAAY,CACZ,sDAAuD,CACvD,kBAAqB,CACrB,+CACE,4EAA+E,CACjF,gDACE,+EAAoF,CACtF,8CACE,sEAAuE,CACvE,4EAA+E,CACjF,wEACE,4DAAiE,CAErE,oDACE,oEAAuE,CAEzE,2BACE,YAAa,CACb,0DAA6D,CAE/D,+BACE,0DAA2D,CAC3D,WAAY,CACZ,wDAAyD,CACzD,sEAAuE,CACvE,0DAA2D,CAC3D,8DAA+D,CAG/D,qBAA4B,CAC5B,4DAA6D,CAC7D,aAAgB,CAChB,qCACE,yEAA4E,CAEhF,mBACE,iBAAkB,CAClB,iCAAkC,CAClC,wCAAyC,CACzC,cAAe,CACf,gDAAiD,CACjD,sDAAuD,CACvD,0DAA2D,CAC3D,2BAA4B,CAC5B,8CAAiD,CACjD,oCACE,OAAU,CACZ,yCACE,KAAM,CACN,iEAAoE,CAExE,4BACE,QAAW,CAEb,2BACE,YAAe,CACf,sFACE,iHAAoH,CAExH,wBACE,iBAAkB,CAClB,0CAA2C,CAC3C,qLAAsL,CACtL,iDAAkD,CAClD,qDAAsD,CACtD,qDAAsD,CACtD,0CAA2C,CAC3C,eAAgB,CAChB,kBAAmB,CACnB,4BAA6B,CAC7B,WAAc,CACd,+FACE,0GAA2G,CAC3G,oBAAuB,CACzB,+DACE,sEAAyE,CAC3E,+IAEE,iBAAkB,CAClB,sEAAyE,CAC3E,kCACE,wCAAyC,CACzC,6CAA8C,CAC9C,oDAAqD,CACrD,4EAA6E,CAC7E,8GAA+G,CAC/G,8GAA+G,CAC/G,WAAc,CAChB,oCACE,8EAA+E,CAC/E,8EAA+E,CAC/E,gHAAiH,CACjH,gHAAiH,CACjH,YAAa,CACb,sBAAuB,CACvB,2DAA8D,CAC9D,0CACE,+FAAkG,CACpG,0CACE,+FAAkG,CACtG,sCACE,8FAA+F,CAC/F,mHAAsH,CACxH,yCACE,kBAAqB,CACrB,0DACE,wCAA2C,CAC7C,4DACE,kBAAqB,CACzB,gHACE,oDAAqD,CACrD,mBAAoB,CACpB,yEAA4E,CAEhF,6BACE,iBAAkB,CAClB,aAAc,CACd,8DAA+D,CAC/D,kBAAqB,CAEvB,oCACE,aAAc,CACd,qEAAsE,CACtE,6DAA8D,CAC9D,sDAAyD,CAE3D,6BACE,iBAAkB,CAClB,2CAA4C,CAC5C,+CAAgD,CAChD,sDAAuD,CACvD,+CAAgD,CAChD,oEAAuE,CAEzE,oCACE,YAAa,CACb,kBAAmB,CACnB,+DAAkE,CAEpE,+BACE,4DAA6D,CAC7D,wBAA2B,CAE7B,kDACE,kEAAqE,CAEvE,0BACE,6LAAgM,CAElM,+BAIE,iNAA+D,CAC/D,wDAAyD,CACzD,4DAA6D,CAC7D,iDAAoD,CAEtD,kBACE,sEAAuE,CACvE,wEAAyE,CACzE,yEAA0E,CAC1E,uEAAwE,CACxE,qFAAsF,CACtF,iEAAkE,CAClE,sEAAuE,CACvE,8EAA+E,CAC/E,6EAA8E,CAC9E,gGAAiG,CACjG,4FAA6F,CAC7F,yEAA0E,CAC1E,4FAA6F,CAC7F,yEAA0E,CAC1E,4FAA6F,CAC7F,wFAAyF,CACzF,0EAA2E,CAC3E,6FAA8F,CAC9F,yFAA0F,CAC1F,kEAAmE,CACnE,oEAAqE,CACrE,qEAAsE,CACtE,mEAAoE,CACpE,kEAAmE,CACnE,kEAAmE,CACnE,6EAA8E,CAC9E,4EAA+E,CAEjF,6BACE,aAAc,CACd,UAAW,CACX,yMAA0M,CAC1M,sDAAuD,CACvD,0DAA2D,CAC3D,+CAAgD,CAChD,eAAgB,CAChB,oEAAqE,CACrE,WAAc,CACd,0CACE,mGAAoG,CACpG,6GAA8G,CAC9G,yFAA4F,CAC9F,mCACE,oBAAqB,CACrB,yGAA0G,CAC1G,qFAAwF,CAC1F,mCACE,+FAAgG,CAChG,yGAA0G,CAC1G,qFAAwF,CAC1F,oCACE,gGAAiG,CACjG,0GAA2G,CAC3G,sFAAyF,CAE7F,yBACE,yLAA0L,CAC1L,kDAAmD,CACnD,sDAAuD,CACvD,2CAA8C,CAEhD,sDACE,+DAAkE,CAEpE,eACE,qEAAsE,CACtE,2BAA4B,CAC5B,4BAA6B,CAC7B,gEAAiE,CACjE,wCAAyC,CACzC,oCAAqC,CACrC,wCAAyC,CACzC,iDAAkD,CAClD,mEAAwE,CACxE,wDAAyD,CACzD,mEAAwE,CACxE,wCAAyC,CACzC,2DAA4D,CAC5D,4CAA6C,CAC7C,wDAAyD,CACzD,sDAAuD,CACvD,0CAA2C,CAC3C,0EAA2E,CAC3E,qDAAsD,CACtD,0GAA6G,CAC7G,0GAA6G,CAC7G,0GAA6G,CAC7G,wGAA2G,CAC3G,wGAA2G,CAC3G,wGAA2G,CAC3G,wGAA2G,CAC3G,0CAA2C,CAC3C,0CAA2C,CAC3C,2CAA4C,CAC5C,sCAAuC,CACvC,4CAAkD,CAClD,sCAAuC,CACvC,4CAAsD,CACtD,sCAAuC,CACvC,4CAA6C,CAC7C,4CAA6C,CAC7C,6CAA8C,CAC9C,wCAAyC,CACzC,8CAAoD,CACpD,wCAAyC,CACzC,8CAAwD,CACxD,wCAAyC,CACzC,0CAA2C,CAC3C,iBAAkB,CAClB,iCAAkC,CAClC,mCAAoC,CACpC,eAAgB,CAChB,sDAAuD,CACvD,gDAAiD,CACjD,sBAAyB,CACzB,sBACE,aAAc,CACd,2CAA4C,CAC5C,0DAA2D,CAC3D,6CAAgD,CAClD,qBACE,iBAAkB,CAClB,KAAM,CACN,OAAQ,CACR,QAAS,CACT,MAAO,CACP,aAAc,CACd,UAAW,CACX,8OAAkP,CAClP,6DAA8D,CAC9D,yPAA4P,CAC9P,2BACE,0EAA6E,CAC/E,sDACE,iCAAkC,CAClC,4FAA+F,CACjG,6BACE,8DAAiE,CACnE,6BACE,8DAAiE,CACnE,6BACE,8DAAiE,CACnE,6BACE,8DAAiE,CACnE,6BACE,8DAAiE,CACnE,6BACE,8DAAiE,CACnE,6BACE,8DAAiE,CACnE,6BACE,8DAAiE,CACnE,8BACE,iEAAoE,CACtE,8BACE,iEAAoE,CACtE,8BACE,iEAAoE,CACtE,8BACE,iEAAoE,CACtE,8BACE,iEAAoE,CACtE,8BACE,iEAAoE,CACtE,8BACE,iEAAoE,CACtE,8BACE,iEAAoE,CACtE,+BACE,kEAAqE,CACvE,6BACE,gEAAmE,CACrE,6BACE,gEAAmE,CACrE,6BACE,gEAAmE,CACrE,4BACE,+DAAkE,CACpE,4BACE,+DAAkE,CACpE,4BACE,+DAAkE,CACpE,4BACE,+DAAkE,CAEtE,iCACE,GACE,2BAA8B,CAChC,IACE,0BAA6B,CAC/B,GACE,0BAA6B,CAAE,CAEnC,sBACE,wDAAyD,CACzD,4DAA6D,CAC7D,gEAAiE,CACjE,iBAAkB,CAClB,oCAAqC,CACrC,UAAW,CACX,2CAA8C,CAC9C,4BACE,6CAAgD,CAEpD,aACE,4DAA6D,CAC7D,+DAAgE,CAChE,yCAA0C,CAC1C,2FAA4F,CAC5F,4FAA6F,CAC7F,kFAAmF,CACnF,iGAAkG,CAClG,6DAA8D,CAC9D,gEAAiE,CACjE,0DAA2D,CAC3D,uCAAwC,CACxC,wCAAyC,CACzC,4EAA6E,CAC7E,yCAA0C,CAC1C,yEAA0E,CAC1E,gGAAiG,CACjG,yDAA0D,CAC1D,4DAA6D,CAC7D,0CAA2C,CAC3C,0GAA2G,CAC3G,0DAA2D,CAC3D,6DAA8D,CAC9D,uGAA0G,CAC1G,gCAAiC,CACjC,iCAAkC,CAClC,oDAAqD,CACrD,0EAA2E,CAC3E,qCAAsC,CACtC,qCAAsC,CACtC,qEAAsE,CACtE,qIAEgD,CAChD,iFAAkF,CAClF,iFAAkF,CAClF,kIAEiD,CACjD,6DAA8D,CAC9D,sDAAuD,CACvD,mDAAoD,CACpD,oKAAyK,CACzK,iDAAkD,CAClD,kDAAmD,CACnD,gEAAiE,CACjE,qEAAsE,CACtE,gEAAiE,CACjE,qEAAsE,CACtE,YAAe,CAEjB,mBACE,iBAAkB,CAClB,WAAc,CAEhB,mBACE,gDAAiD,CACjD,sDAAyD,CAE3D,yBACE,iBAAkB,CAClB,6CAAgD,CAChD,gCACE,iBAAkB,CAClB,KAAM,CACN,OAAQ,CACR,QAAS,CACT,MAAO,CACP,UAAW,CACX,qXAA4X,CAC5X,kEAAqE,CAEzE,oBACE,wCAAyC,CACzC,6CAA8C,CAC9C,aAAgB,CAElB,mBACE,iBAAkB,CAClB,KAAM,CACN,mCAAoC,CACpC,UAAa,CACb,+BACE,0GAA6G,CAC/G,+BACE,iGAAkG,CAClG,mGAAsG,CACxG,8BACE,gGAAiG,CACjG,kGAAqG,CAEzG,wBACE,iBAAkB,CAClB,sCAAuC,CACvC,MAAO,CACP,0CAA2C,CAC3C,4CAA6C,CAC7C,+DAAgE,CAChE,yDAA0D,CAC1D,+DAAkE,CAEpE,yBACE,iBAAkB,CAClB,uCAAwC,CACxC,gEAAmE,CAErE,oBACE,iBAAkB,CAClB,kCAAmC,CACnC,oCAAqC,CACrC,sCAAuC,CACvC,wCAAyC,CACzC,cAAe,CACf,2DAA4D,CAC5D,qDAAsD,CACtD,+CAAgD,CAChD,gGAAoG,CACpG,0BACE,2EAA8E,CAChF,0BACE,2EAA4E,CAC5E,SAAY,CACd,2BACE,4EAA+E,CAEnF,oBACE,iDAAoD,CACpD,kCACE,kCAAmC,CACnC,iBAAkB,CAClB,KAAM,CACN,gDAAiD,CACjD,qDAAsD,CACtD,wHAA4H,CAC5H,oDACE,kBAAqB,CACvB,0DACE,iBAAkB,CAClB,SAAY,CAChB,uCACE,sDAAyD,CAE7D,sBACE,YAAa,CACb,qDAAwD,CACxD,yCACE,qCAAsC,CACtC,yDAA4D,CAEhE,cACE,sCAAuC,CACvC,qEAAyE,CACzE,6DAA8D,CAC9D,0CAA2C,CAC3C,6GAAgH,CAChH,mDAAoD,CACpD,oDAAqD,CACrD,0DAA2D,CAC3D,mEAAoE,CACpE,mEAAoE,CACpE,mEAAoE,CACpE,mEAAoE,CACpE,4DAA6D,CAC7D,6DAA8D,CAC9D,yEAA0E,CAC1E,mEAAoE,CACpE,oEAAqE,CACrE,uFAAwF,CACxF,4EAA6E,CAC7E,oEAAqE,CACrE,qEAAsE,CACtE,4EAA6E,CAC7E,iBAAkB,CAClB,oBAAqB,CACrB,gCAAiC,CACjC,kCAAmC,CACnC,eAAgB,CAChB,0IAA+I,CAC/I,sBACE,4DAA+D,CACjE,sBACE,4DAA+D,CACjE,sBACE,4DAA+D,CACjE,sBACE,4DAA+D,CAEnE,uCACE,GACE,sBAAyB,CAC3B,IACE,yBAA4B,CAC9B,GACE,wBAA6B,CAAE,CAEnC,uBACE,iBAAkB,CAClB,yCAA0C,CAC1C,2CAA4C,CAC5C,4BAA6B,CAC7B,8FAAiG,CAEnG,yCACE,GACE,sBAAyB,CAC3B,GACE,yBAA4B,CAAE,CAElC,6BACE,iBAAkB,CAClB,gDAAiD,CACjD,kDAAmD,CACnD,0BAA2B,CAC3B,UAAW,CACX,iBAAkB,CAClB,qIAAsI,CACtI,oGAAuG,CAEzG,+CACE,GACE,uBAA0B,CAC5B,GACE,yBAA4B,CAAE,CAElC,yBACE,iBAAkB,CAClB,KAAM,CACN,MAAO,CACP,UAAW,CACX,WAAY,CACZ,gGAAmG,CACnG,+BACE,iBAAkB,CAClB,0DAA+D,CAC/D,OAAQ,CACR,6CAA8C,CAC9C,+CAAgD,CAChD,UAAW,CACX,uEAAwE,CACxE,iBAAkB,CAClB,0BAA6B,CAEjC,2CACE,GACE,sBAAyB,CAC3B,IACE,yBAA4B,CAC9B,GACE,wBAA4B,CAAE,CAElC,yBACE,iBAAkB,CAClB,KAAM,CACN,MAAO,CACP,UAAW,CACX,WAAY,CACZ,gGAAmG,CACnG,+BACE,iBAAkB,CAClB,0DAA+D,CAC/D,OAAQ,CACR,6CAA8C,CAC9C,+CAAgD,CAChD,UAAW,CACX,uEAAwE,CACxE,iBAAkB,CAClB,0BAA6B,CAEjC,2CACE,GACE,sBAAyB,CAC3B,MACE,yBAA4B,CAC9B,GACE,wBAA4B,CAAE,CAElC,aACE,sDAAuD,CACvD,6EAA+E,CAC/E,oEAAqE,CACrE,uEAAyE,CACzE,2CAA4C,CAC5C,0DAA2D,CAC3D,uFAA0F,CAC1F,2FAA4F,CAC5F,8GAA+G,CAC/G,6EAA8E,CAC9E,qFAAsF,CACtF,kFAAmF,CACnF,yFAA0F,CAC1F,qGAAsG,CACtG,mFAAoF,CACpF,+EAAgF,CAChF,sFAAuF,CACvF,+FAAkG,CAClG,4EAA6E,CAC7E,8DAA+D,CAC/D,iHAAkH,CAClH,+EAAgF,CAChF,oHAAuH,CACvH,2EAA4E,CAC5E,qFAAsF,CACtF,8EAA+E,CAC/E,wEAAyE,CACzE,gEAAiE,CACjE,mJAAoJ,CACpJ,8DAA+D,CAC/D,6DAA8D,CAC9D,iBAAkB,CAClB,oBAAqB,CACrB,iCAAkC,CAClC,sCAAuC,CACvC,0CAA2C,CAC3C,qBAAsB,CACtB,cAAiB,CAEnB,oBACE,iBAAkB,CAClB,cAAe,CACf,SAAY,CACZ,+CACE,2HAA4H,CAC5H,sEAAyE,CAC3E,gDACE,sDAAyD,CAC3D,iDACE,4EAA+E,CAC/E,wDACE,oFAAuF,CAC3F,sCACE,YAAe,CACjB,sDACE,0DAA6D,CAC/D,iFACE,YAAa,CACb,iBAAoB,CACtB,2CACE,YAAe,CACjB,6BACE,kBAAqB,CACrB,iDACE,uDAAwD,CACxD,kBAAqB,CACvB,kDACE,kBAAmB,CACnB,6EAAgF,CAChF,yDACE,qFAAwF,CAEhG,qBACE,iBAAkB,CAClB,oBAAqB,CACrB,uCAAwC,CACxC,yCAA0C,CAC1C,4DAA6D,CAC7D,sDAAyD,CACzD,4BACE,iBAAkB,CAClB,2CAA4C,CAC5C,6CAA8C,CAC9C,aAAc,CACd,+CAAgD,CAChD,iDAAkD,CAClD,UAAW,CACX,oEAAqE,CACrE,8DAA+D,CAC/D,wDAAyD,CACzD,yDAA4D,CAEhE,0BACE,iBAAkB,CAClB,KAAM,CACN,QAAS,CACT,0CAA2C,CAC3C,YAAa,CACb,kBAAmB,CACnB,mDAAoD,CACpD,4CAA+C,CAEjD,oBACE,oBAAqB,CACrB,mDAAoD,CACpD,sCAAuC,CACvC,kBAAqB,CAEvB,kBACE,4EAA+E,CAC/E,iCACE,qDAAwD,CAE5D,8BACE,wEAAyE,CACzE,gFAAiF,CACjF,gFAAiF,CACjF,6CAA8C,CAC9C,2EAA4E,CAC5E,4EAA6E,CAC7E,4FAA6F,CAC7F,uEAAwE,CACxE,mEAAoE,CACpE,oEAAqE,CACrE,sEAAuE,CACvE,0EAA2E,CAC3E,uEAAwE,CACxE,qEAAsE,CACtE,yEAA0E,CAC1E,kFAAmF,CACnF,oFAAqF,CACrF,qFAAsF,CACtF,mFAAoF,CACpF,wDAAyD,CACzD,wCAAyC,CACzC,0CAA2C,CAC3C,2CAA4C,CAC5C,yCAA0C,CAC1C,uEAAwE,CACxE,uEAAwE,CACxE,0EAA2E,CAC3E,oFAAqF,CACrF,8CAA+C,CAC/C,6CAA8C,CAC9C,+EAAgF,CAChF,kFAAmF,CACnF,kFAAmF,CACnF,qFAAsF,CACtF,4FAA+F,CAC/F,+FAAkG,CAClG,6EAAwF,CACxF,2FAA4F,CAC5F,0FAA2F,CAC3F,+FAAgG,CAChG,8FAA+F,CAC/F,4FAA6F,CAC7F,wEAAyE,CACzE,mDAAoD,CACpD,gDAAiD,CACjD,8EAA+E,CAC/E,gDAAiD,CACjD,yEAA0E,CAC1E,gFAAiF,CACjF,gLAAiL,CACjL,qDAAsD,CACtD,qDAAwD,CACxD,qCACE,8BACE,4FAA6F,CAC7F,0FAA2F,CAG3F,sIAAuI,CACvI,oIAJ6F,CAAE,CAMrG,sBACE,0EAA2E,CAC3E,8EAA+E,CAC/E,gFAAiF,CACjF,4EAA6E,CAC7E,gDAAiD,CACjD,kDAAmD,CACnD,mDAAoD,CACpD,iDAAkD,CAClD,YAAa,CACb,WAAc,CACd,2BACE,UAAW,CACX,WAAY,CACZ,cAAe,CACf,gBAAiB,CACjB,kBAAmB,CACnB,kBAAqB,CACvB,wCACE,iBAAkB,CAClB,UAAW,CACX,WAAY,CACZ,cAAe,CACf,0CAA2C,CAC3C,mDAAoD,CACpD,+CAAkD,CACpD,4BACE,YAAa,CACb,iBAAoB,CACtB,4BACE,aAAgB,CAChB,0CACE,oHAAuH,CAC3H,+CACE,YAAe,CACjB,0DACE,mHAAsH,CACxH,mGAEE,mFAAsF,CACxF,0CACE,wFAA2F,CAC3F,8EACE,eAAkB,CACpB,6DACE,uHAA0H,CAC9H,0DACE,YAAa,CACb,yBAA0B,CAC1B,WAAY,CACZ,6BAA8B,CAC9B,+DAAgE,CAChE,iMAAoM,CACpM,4DACE,6MAAgN,CAChN,uEACE,uGAA0G,CAChH,mCACE,+FAAgG,CAChG,qGAAsG,CACtG,qGAAsG,CACtG,2GAA4G,CAC5G,uCAA0C,CAC1C,uDACE,sEAAuE,CACvE,yEAA4E,CAC9E,oEACE,sFAAyF,CAC7F,0CACE,eAAkB,CACpB,mCACE,oGAAqG,CACrG,aAAc,CACd,+DAAgE,CAChE,yCAA2C,CAC3C,iBAAoB,CACpB,qCACE,aAAgB,CAClB,0CACE,eAAiB,CACjB,eAAgB,CAChB,wBAA2B,CAC/B,sCACE,iCAAoC,CACtC,qCACE,kCAAqC,CACvC,kCACE,kGAAmG,CACnG,sGAAuG,CACvG,wGAAyG,CACzG,oGAAqG,CACrG,QAAW,CACX,0GACE,yCAA4C,CAChD,6DACE,2EAA4E,CAC5E,0EAA2E,CAC3E,gEAAmE,CACrE,4BACE,iBAAoB,CACpB,kCACE,iBAAkB,CAClB,KAAM,CACN,QAAS,CACT,MAAO,CACP,UAAW,CACX,QAAS,CACT,+GAAkH,CACpH,0CACE,+FAAkG,CAClG,gDACE,6CAAgD,CACpD,0EACE,sDAAuD,CACvD,eAAgB,CAChB,UAAW,CACX,4BAA+B,CACnC,kDACE,4CAA6C,CAC7C,8CAA+C,CAC/C,+CAAgD,CAChD,6CAA8C,CAC9C,kCAAmC,CACnC,iCAAkC,CAClC,aAAc,CACd,uDAAwD,CACxD,eAAgB,CAChB,kBAAmB,CACnB,eAAkB,CAClB,oDACE,eAAgB,CAChB,aAAgB,CAClB,gEACE,+CAAkD,CACpD,6FACE,YAAe,CACjB,kNACE,SAAY,CACd,sEACE,YAAa,CACb,iBAAoB,CACtB,sFACE,iFAAkF,CAClF,+EAAkF,CACtF,yTAIE,UAAW,CACX,SAAY,CACd,0CACE,iBAAkB,CAClB,cAAe,CACf,gBAAiB,CACjB,eAAkB,CAClB,gDACE,YAAe,CACnB,0CACE,0EAA2E,CAC3E,8EAA+E,CAC/E,gFAAiF,CACjF,4EAA+E,CACjF,+HAGE,gBAAiB,CACjB,mBAAsB,CACxB,yCACE,0DAA2D,CAC3D,4DAA+D,CAC/D,+DACE,kEAAqE,CACrE,mFACE,0EAA6E,CACjF,6DACE,6DAAgE,CACpE,4CACE,yDAA4D,CAC5D,gEACE,mEAAsE,CAC1E,0CACE,uDAAwD,CACxD,gBAAmB,CACnB,oCACE,0CACE,gBAAiB,CACjB,mBAAoB,CACpB,aAAgB,CAAE,CACxB,sDACE,aAAc,CACd,UAAa,CACf,+CACE,sDAAyD,CACzD,0EACE,qEAAwE,CAC5E,mCACE,iCAAoC,CACtC,wCACE,UAAW,CACX,kBAAqB,CACvB,qCACE,iCAAoC,CACtC,0CACE,8BAAiC,CAErC,oCACE,yBACE,0EAA2E,CAC3E,8EAA+E,CAC/E,gFAAiF,CACjF,4EAA6E,CAC7E,gDAAiD,CACjD,kDAAmD,CACnD,mDAAoD,CACpD,iDAAkD,CAClD,YAAa,CACb,WAAc,CACd,8BACE,UAAW,CACX,WAAY,CACZ,cAAe,CACf,gBAAiB,CACjB,kBAAmB,CACnB,kBAAqB,CACvB,2CACE,iBAAkB,CAClB,UAAW,CACX,WAAY,CACZ,cAAe,CACf,0CAA2C,CAC3C,mDAAoD,CACpD,+CAAkD,CACpD,+BACE,YAAa,CACb,iBAAoB,CACtB,+BACE,aAAgB,CAChB,6CACE,oHAAuH,CAC3H,kDACE,YAAe,CACjB,6DACE,mHAAsH,CACxH,yGAEE,mFAAsF,CACxF,6CACE,wFAA2F,CAC3F,iFACE,eAAkB,CACpB,gEACE,uHAA0H,CAC9H,6DACE,YAAa,CACb,yBAA0B,CAC1B,WAAY,CACZ,6BAA8B,CAC9B,+DAAgE,CAChE,iMAAoM,CACpM,+DACE,6MAAgN,CAChN,0EACE,uGAA0G,CAChH,sCACE,+FAAgG,CAChG,qGAAsG,CACtG,qGAAsG,CACtG,2GAA4G,CAC5G,uCAA0C,CAC1C,0DACE,sEAAuE,CACvE,yEAA4E,CAC9E,uEACE,sFAAyF,CAC7F,6CACE,eAAkB,CACpB,sCACE,oGAAqG,CACrG,aAAc,CACd,+DAAgE,CAChE,yCAA2C,CAC3C,iBAAoB,CACpB,wCACE,aAAgB,CAClB,6CACE,eAAiB,CACjB,eAAgB,CAChB,wBAA2B,CAC/B,yCACE,iCAAoC,CACtC,wCACE,kCAAqC,CACvC,qCACE,kGAAmG,CACnG,sGAAuG,CACvG,wGAAyG,CACzG,oGAAqG,CACrG,QAAW,CACX,6GACE,yCAA4C,CAChD,gEACE,2EAA4E,CAC5E,0EAA2E,CAC3E,gEAAmE,CACrE,+BACE,iBAAoB,CACpB,qCACE,iBAAkB,CAClB,KAAM,CACN,QAAS,CACT,MAAO,CACP,UAAW,CACX,QAAS,CACT,+GAAkH,CACpH,6CACE,+FAAkG,CAClG,mDACE,6CAAgD,CACpD,6EACE,sDAAuD,CACvD,eAAgB,CAChB,UAAW,CACX,4BAA+B,CACnC,qDACE,4CAA6C,CAC7C,8CAA+C,CAC/C,+CAAgD,CAChD,6CAA8C,CAC9C,kCAAmC,CACnC,iCAAkC,CAClC,aAAc,CACd,uDAAwD,CACxD,eAAgB,CAChB,kBAAmB,CACnB,eAAkB,CAClB,uDACE,eAAgB,CAChB,aAAgB,CAClB,mEACE,+CAAkD,CACpD,gGACE,YAAe,CACjB,wNACE,SAAY,CACd,yEACE,YAAa,CACb,iBAAoB,CACtB,yFACE,iFAAkF,CAClF,+EAAkF,CACtF,qUAIE,UAAW,CACX,SAAY,CACd,6CACE,iBAAkB,CAClB,cAAe,CACf,gBAAiB,CACjB,eAAkB,CAClB,mDACE,YAAe,CACnB,6CACE,0EAA2E,CAC3E,8EAA+E,CAC/E,gFAAiF,CACjF,4EAA+E,CACjF,wIAGE,gBAAiB,CACjB,mBAAsB,CACxB,4CACE,0DAA2D,CAC3D,4DAA+D,CAC/D,kEACE,kEAAqE,CACrE,sFACE,0EAA6E,CACjF,gEACE,6DAAgE,CACpE,+CACE,yDAA4D,CAC5D,mEACE,mEAAsE,CAC1E,6CACE,uDAAwD,CACxD,gBAAmB,CAAE,CACvB,0DACE,6CACE,gBAAiB,CACjB,mBAAoB,CACpB,aAAgB,CAAE,CAE1B,oCACI,yDACE,aAAc,CACd,UAAa,CACf,kDACE,sDAAyD,CACzD,6EACE,qEAAwE,CAC5E,sCACE,iCAAoC,CACtC,2CACE,UAAW,CACX,kBAAqB,CACvB,wCACE,iCAAoC,CACtC,6CACE,8BAAiC,CAAE,CAEzC,oCACE,yBACE,0EAA2E,CAC3E,8EAA+E,CAC/E,gFAAiF,CACjF,4EAA6E,CAC7E,gDAAiD,CACjD,kDAAmD,CACnD,mDAAoD,CACpD,iDAAkD,CAClD,YAAa,CACb,WAAc,CACd,8BACE,UAAW,CACX,WAAY,CACZ,cAAe,CACf,gBAAiB,CACjB,kBAAmB,CACnB,kBAAqB,CACvB,2CACE,iBAAkB,CAClB,UAAW,CACX,WAAY,CACZ,cAAe,CACf,0CAA2C,CAC3C,mDAAoD,CACpD,+CAAkD,CACpD,+BACE,YAAa,CACb,iBAAoB,CACtB,+BACE,aAAgB,CAChB,6CACE,oHAAuH,CAC3H,kDACE,YAAe,CACjB,6DACE,mHAAsH,CACxH,yGAEE,mFAAsF,CACxF,6CACE,wFAA2F,CAC3F,iFACE,eAAkB,CACpB,gEACE,uHAA0H,CAC9H,6DACE,YAAa,CACb,yBAA0B,CAC1B,WAAY,CACZ,6BAA8B,CAC9B,+DAAgE,CAChE,iMAAoM,CACpM,+DACE,6MAAgN,CAChN,0EACE,uGAA0G,CAChH,sCACE,+FAAgG,CAChG,qGAAsG,CACtG,qGAAsG,CACtG,2GAA4G,CAC5G,uCAA0C,CAC1C,0DACE,sEAAuE,CACvE,yEAA4E,CAC9E,uEACE,sFAAyF,CAC7F,6CACE,eAAkB,CACpB,sCACE,oGAAqG,CACrG,aAAc,CACd,+DAAgE,CAChE,yCAA2C,CAC3C,iBAAoB,CACpB,wCACE,aAAgB,CAClB,6CACE,eAAiB,CACjB,eAAgB,CAChB,wBAA2B,CAC/B,yCACE,iCAAoC,CACtC,wCACE,kCAAqC,CACvC,qCACE,kGAAmG,CACnG,sGAAuG,CACvG,wGAAyG,CACzG,oGAAqG,CACrG,QAAW,CACX,6GACE,yCAA4C,CAChD,gEACE,2EAA4E,CAC5E,0EAA2E,CAC3E,gEAAmE,CACrE,+BACE,iBAAoB,CACpB,qCACE,iBAAkB,CAClB,KAAM,CACN,QAAS,CACT,MAAO,CACP,UAAW,CACX,QAAS,CACT,+GAAkH,CACpH,6CACE,+FAAkG,CAClG,mDACE,6CAAgD,CACpD,6EACE,sDAAuD,CACvD,eAAgB,CAChB,UAAW,CACX,4BAA+B,CACnC,qDACE,4CAA6C,CAC7C,8CAA+C,CAC/C,+CAAgD,CAChD,6CAA8C,CAC9C,kCAAmC,CACnC,iCAAkC,CAClC,aAAc,CACd,uDAAwD,CACxD,eAAgB,CAChB,kBAAmB,CACnB,eAAkB,CAClB,uDACE,eAAgB,CAChB,aAAgB,CAClB,mEACE,+CAAkD,CACpD,gGACE,YAAe,CACjB,wNACE,SAAY,CACd,yEACE,YAAa,CACb,iBAAoB,CACtB,yFACE,iFAAkF,CAClF,+EAAkF,CACtF,qUAIE,UAAW,CACX,SAAY,CACd,6CACE,iBAAkB,CAClB,cAAe,CACf,gBAAiB,CACjB,eAAkB,CAClB,mDACE,YAAe,CACnB,6CACE,0EAA2E,CAC3E,8EAA+E,CAC/E,gFAAiF,CACjF,4EAA+E,CACjF,wIAGE,gBAAiB,CACjB,mBAAsB,CACxB,4CACE,0DAA2D,CAC3D,4DAA+D,CAC/D,kEACE,kEAAqE,CACrE,sFACE,0EAA6E,CACjF,gEACE,6DAAgE,CACpE,+CACE,yDAA4D,CAC5D,mEACE,mEAAsE,CAC1E,6CACE,uDAAwD,CACxD,gBAAmB,CAAE,CACvB,0DACE,6CACE,gBAAiB,CACjB,mBAAoB,CACpB,aAAgB,CAAE,CAE1B,oCACI,yDACE,aAAc,CACd,UAAa,CACf,kDACE,sDAAyD,CACzD,6EACE,qEAAwE,CAC5E,sCACE,iCAAoC,CACtC,2CACE,UAAW,CACX,kBAAqB,CACvB,wCACE,iCAAoC,CACtC,6CACE,8BAAiC,CAAE,CAEzC,qCACE,yBACE,0EAA2E,CAC3E,8EAA+E,CAC/E,gFAAiF,CACjF,4EAA6E,CAC7E,gDAAiD,CACjD,kDAAmD,CACnD,mDAAoD,CACpD,iDAAkD,CAClD,YAAa,CACb,WAAc,CACd,8BACE,UAAW,CACX,WAAY,CACZ,cAAe,CACf,gBAAiB,CACjB,kBAAmB,CACnB,kBAAqB,CACvB,2CACE,iBAAkB,CAClB,UAAW,CACX,WAAY,CACZ,cAAe,CACf,0CAA2C,CAC3C,mDAAoD,CACpD,+CAAkD,CACpD,+BACE,YAAa,CACb,iBAAoB,CACtB,+BACE,aAAgB,CAChB,6CACE,oHAAuH,CAC3H,kDACE,YAAe,CACjB,6DACE,mHAAsH,CACxH,yGAEE,mFAAsF,CACxF,6CACE,wFAA2F,CAC3F,iFACE,eAAkB,CACpB,gEACE,uHAA0H,CAC9H,6DACE,YAAa,CACb,yBAA0B,CAC1B,WAAY,CACZ,6BAA8B,CAC9B,+DAAgE,CAChE,iMAAoM,CACpM,+DACE,6MAAgN,CAChN,0EACE,uGAA0G,CAChH,sCACE,+FAAgG,CAChG,qGAAsG,CACtG,qGAAsG,CACtG,2GAA4G,CAC5G,uCAA0C,CAC1C,0DACE,sEAAuE,CACvE,yEAA4E,CAC9E,uEACE,sFAAyF,CAC7F,6CACE,eAAkB,CACpB,sCACE,oGAAqG,CACrG,aAAc,CACd,+DAAgE,CAChE,yCAA2C,CAC3C,iBAAoB,CACpB,wCACE,aAAgB,CAClB,6CACE,eAAiB,CACjB,eAAgB,CAChB,wBAA2B,CAC/B,yCACE,iCAAoC,CACtC,wCACE,kCAAqC,CACvC,qCACE,kGAAmG,CACnG,sGAAuG,CACvG,wGAAyG,CACzG,oGAAqG,CACrG,QAAW,CACX,6GACE,yCAA4C,CAChD,gEACE,2EAA4E,CAC5E,0EAA2E,CAC3E,gEAAmE,CACrE,+BACE,iBAAoB,CACpB,qCACE,iBAAkB,CAClB,KAAM,CACN,QAAS,CACT,MAAO,CACP,UAAW,CACX,QAAS,CACT,+GAAkH,CACpH,6CACE,+FAAkG,CAClG,mDACE,6CAAgD,CACpD,6EACE,sDAAuD,CACvD,eAAgB,CAChB,UAAW,CACX,4BAA+B,CACnC,qDACE,4CAA6C,CAC7C,8CAA+C,CAC/C,+CAAgD,CAChD,6CAA8C,CAC9C,kCAAmC,CACnC,iCAAkC,CAClC,aAAc,CACd,uDAAwD,CACxD,eAAgB,CAChB,kBAAmB,CACnB,eAAkB,CAClB,uDACE,eAAgB,CAChB,aAAgB,CAClB,mEACE,+CAAkD,CACpD,gGACE,YAAe,CACjB,wNACE,SAAY,CACd,yEACE,YAAa,CACb,iBAAoB,CACtB,yFACE,iFAAkF,CAClF,+EAAkF,CACtF,qUAIE,UAAW,CACX,SAAY,CACd,6CACE,iBAAkB,CAClB,cAAe,CACf,gBAAiB,CACjB,eAAkB,CAClB,mDACE,YAAe,CACnB,6CACE,0EAA2E,CAC3E,8EAA+E,CAC/E,gFAAiF,CACjF,4EAA+E,CACjF,wIAGE,gBAAiB,CACjB,mBAAsB,CACxB,4CACE,0DAA2D,CAC3D,4DAA+D,CAC/D,kEACE,kEAAqE,CACrE,sFACE,0EAA6E,CACjF,gEACE,6DAAgE,CACpE,+CACE,yDAA4D,CAC5D,mEACE,mEAAsE,CAC1E,6CACE,uDAAwD,CACxD,gBAAmB,CAAE,CACvB,2DACE,6CACE,gBAAiB,CACjB,mBAAoB,CACpB,aAAgB,CAAE,CAE1B,qCACI,yDACE,aAAc,CACd,UAAa,CACf,kDACE,sDAAyD,CACzD,6EACE,qEAAwE,CAC5E,sCACE,iCAAoC,CACtC,2CACE,UAAW,CACX,kBAAqB,CACvB,wCACE,iCAAoC,CACtC,6CACE,8BAAiC,CAAE,CAEzC,qCACE,0BACE,0EAA2E,CAC3E,8EAA+E,CAC/E,gFAAiF,CACjF,4EAA6E,CAC7E,gDAAiD,CACjD,kDAAmD,CACnD,mDAAoD,CACpD,iDAAkD,CAClD,YAAa,CACb,WAAc,CACd,+BACE,UAAW,CACX,WAAY,CACZ,cAAe,CACf,gBAAiB,CACjB,kBAAmB,CACnB,kBAAqB,CACvB,4CACE,iBAAkB,CAClB,UAAW,CACX,WAAY,CACZ,cAAe,CACf,0CAA2C,CAC3C,mDAAoD,CACpD,+CAAkD,CACpD,gCACE,YAAa,CACb,iBAAoB,CACtB,gCACE,aAAgB,CAChB,8CACE,oHAAuH,CAC3H,mDACE,YAAe,CACjB,8DACE,mHAAsH,CACxH,2GAEE,mFAAsF,CACxF,8CACE,wFAA2F,CAC3F,kFACE,eAAkB,CACpB,iEACE,uHAA0H,CAC9H,8DACE,YAAa,CACb,yBAA0B,CAC1B,WAAY,CACZ,6BAA8B,CAC9B,+DAAgE,CAChE,iMAAoM,CACpM,gEACE,6MAAgN,CAChN,2EACE,uGAA0G,CAChH,uCACE,+FAAgG,CAChG,qGAAsG,CACtG,qGAAsG,CACtG,2GAA4G,CAC5G,uCAA0C,CAC1C,2DACE,sEAAuE,CACvE,yEAA4E,CAC9E,wEACE,sFAAyF,CAC7F,8CACE,eAAkB,CACpB,uCACE,oGAAqG,CACrG,aAAc,CACd,+DAAgE,CAChE,yCAA2C,CAC3C,iBAAoB,CACpB,yCACE,aAAgB,CAClB,8CACE,eAAiB,CACjB,eAAgB,CAChB,wBAA2B,CAC/B,0CACE,iCAAoC,CACtC,yCACE,kCAAqC,CACvC,sCACE,kGAAmG,CACnG,sGAAuG,CACvG,wGAAyG,CACzG,oGAAqG,CACrG,QAAW,CACX,8GACE,yCAA4C,CAChD,iEACE,2EAA4E,CAC5E,0EAA2E,CAC3E,gEAAmE,CACrE,gCACE,iBAAoB,CACpB,sCACE,iBAAkB,CAClB,KAAM,CACN,QAAS,CACT,MAAO,CACP,UAAW,CACX,QAAS,CACT,+GAAkH,CACpH,8CACE,+FAAkG,CAClG,oDACE,6CAAgD,CACpD,8EACE,sDAAuD,CACvD,eAAgB,CAChB,UAAW,CACX,4BAA+B,CACnC,sDACE,4CAA6C,CAC7C,8CAA+C,CAC/C,+CAAgD,CAChD,6CAA8C,CAC9C,kCAAmC,CACnC,iCAAkC,CAClC,aAAc,CACd,uDAAwD,CACxD,eAAgB,CAChB,kBAAmB,CACnB,eAAkB,CAClB,wDACE,eAAgB,CAChB,aAAgB,CAClB,oEACE,+CAAkD,CACpD,iGACE,YAAe,CACjB,0NACE,SAAY,CACd,0EACE,YAAa,CACb,iBAAoB,CACtB,0FACE,iFAAkF,CAClF,+EAAkF,CACtF,yUAIE,UAAW,CACX,SAAY,CACd,8CACE,iBAAkB,CAClB,cAAe,CACf,gBAAiB,CACjB,eAAkB,CAClB,oDACE,YAAe,CACnB,8CACE,0EAA2E,CAC3E,8EAA+E,CAC/E,gFAAiF,CACjF,4EAA+E,CACjF,2IAGE,gBAAiB,CACjB,mBAAsB,CACxB,6CACE,0DAA2D,CAC3D,4DAA+D,CAC/D,mEACE,kEAAqE,CACrE,uFACE,0EAA6E,CACjF,iEACE,6DAAgE,CACpE,gDACE,yDAA4D,CAC5D,oEACE,mEAAsE,CAC1E,8CACE,uDAAwD,CACxD,gBAAmB,CAAE,CACvB,2DACE,8CACE,gBAAiB,CACjB,mBAAoB,CACpB,aAAgB,CAAE,CAE1B,qCACI,0DACE,aAAc,CACd,UAAa,CACf,mDACE,sDAAyD,CACzD,8EACE,qEAAwE,CAC5E,uCACE,iCAAoC,CACtC,4CACE,UAAW,CACX,kBAAqB,CACvB,yCACE,iCAAoC,CACtC,8CACE,8BAAiC,CAAE,CAEzC,YACE,oEAAqE,CACrE,4DAA6D,CAC7D,kEAAmE,CACnE,6DAA8D,CAC9D,wDAAyD,CACzD,6DAA8D,CAC9D,+DAAgE,CAChE,gEAAiE,CACjE,8DAA+D,CAC/D,mEAAoE,CACpE,kEAAmE,CACnE,kEAAmE,CACnE,wEAAyE,CACzE,kEAAmE,CACnE,qEAAsE,CACtE,2DAA4D,CAC5D,mEAAoE,CACpE,sDAAuD,CACvD,2DAA4D,CAC5D,6DAA8D,CAC9D,8DAA+D,CAC/D,4DAA6D,CAC7D,8EAA+E,CAC/E,+EAAgF,CAChF,kFAAmF,CACnF,mFAAoF,CACpF,8BAA+B,CAC/B,iCAAkC,CAClC,8BAA+B,CAC/B,oCAAqC,CACrC,qCAAsC,CACtC,qCAAsC,CACtC,oCAAqC,CACrC,yCAA0C,CAC1C,4CAA6C,CAC7C,iIAAkI,CAClI,sDAAuD,CACvD,mDAA8D,CAC9D,0DAA2D,CAC3D,sEAAuE,CACvE,sEAAuE,CACvE,iDAAkD,CAClD,wDAAyD,CACzD,+DAAgE,CAChE,+DAAgE,CAChE,gEAAiE,CACjE,8EAAiF,CACjF,6CAA8C,CAC9C,gDAAiD,CACjD,6CAA8C,CAC9C,mEAAoE,CACpE,wEAAyE,CACzE,0EAA2E,CAC3E,yEAA0E,CAC1E,2FAA8F,CAC9F,mFAAsF,CACtF,8FAAiG,CACjG,kFAAqF,CACrF,wFAAyF,CACzF,gFAAiF,CACjF,uFAAwF,CACxF,uFAAwF,CACxF,wFAAyF,CACzF,kCAAmC,CACnC,oCAAqC,CACrC,qCAAsC,CACtC,mCAAoC,CACpC,8CAA+C,CAC/C,gDAAiD,CACjD,iDAAkD,CAClD,+CAAgD,CAChD,qEAAsE,CACtE,iDAAkD,CAClD,6EAA8E,CAC9E,6EAA8E,CAC9E,gFAAiF,CACjF,uFAA0F,CAC1F,0FAA6F,CAC7F,yFAA0F,CAC1F,sDAAuD,CACvD,oFAAqF,CACrF,mEAAoE,CACpE,qKAAsK,CACtK,6EAA8E,CAC9E,qEAAsE,CACtE,gFAAiF,CACjF,oEAAqE,CACrE,0FAA6F,CAC7F,gGAAmG,CACnG,4FAA+F,CAC/F,8DAA+D,CAC/D,iFAAkF,CAClF,yCAA0C,CAC1C,oDAAqD,CACrD,2DAA4D,CAC5D,2DAA4D,CAC5D,4DAA6D,CAC7D,yEAA0E,CAC1E,qEAAsE,CACtE,yFAA0F,CAC1F,qFAAsF,CACtF,sFAAuF,CACvF,qFAAsF,CACtF,uCAAwC,CACxC,kEAAmE,CACnE,8CAA+C,CAC/C,8FAAiG,CACjG,iGAAoG,CACpG,8EAA+E,CAC/E,6EAA8E,CAC9E,0FAA2F,CAC3F,kGAAmG,CACnG,kGAAmG,CACnG,mGAAoG,CACpG,6GAA8G,CAC9G,uGAAwG,CACxG,2EAA4E,CAC5E,0EAA2E,CAC3E,yJAA4J,CAC5J,uJAA0J,CAC1J,4GAA6G,CAC7G,wGAAyG,CACzG,wEAAyE,CACzE,qJAAwJ,CACxJ,sJAAyJ,CACzJ,wGAAyG,CACzG,sEAAuE,CACvE,sEAAuE,CACvE,wEAAyE,CACzE,yEAA0E,CAC1E,uEAAwE,CACxE,yFAA0F,CAC1F,0FAA2F,CAC3F,6FAA8F,CAC9F,8FAA+F,CAC/F,gEAAiE,CACjE,wFAAyF,CACzF,0FAA2F,CAC3F,2FAA4F,CAC5F,yFAA0F,CAC1F,kFAAmF,CACnF,iFAAkF,CAClF,8FAA+F,CAC/F,kCAAmC,CACnC,UAAW,CACX,mDAAsD,CACtD,qCACE,YACE,8EAA+E,CAC/E,4EAA+E,CAAE,CACrF,qCACE,YACE,8GAA+G,CAC/G,4GAA6G,CAC7G,kIAAmI,CACnI,oIAAuI,CAAE,CAC7I,uBACE,kBAAqB,CACvB,+BACE,iBAAoB,CACpB,wCACE,eAAkB,CAClB,0CACE,eAAgB,CAChB,KAAM,CACN,oCAAqC,CACrC,6CAAgD,CAChD,+CACE,iBAAkB,CAClB,OAAQ,CACR,QAAS,CACT,MAAO,CACP,UAC2F,CACnG,+FADQ,wFAEqF,CAC7F,iBACE,sFAAuF,CACvF,iBAAkB,CAClB,oCAAqC,CACrC,2CAA4C,CAC5C,2CAA4C,CAC5C,6JAA8J,CAC9J,0CAA2C,CAC3C,2CAA4C,CAC5C,+CAAgD,CAChD,oCAAqC,CACrC,mDAAoD,CACpD,6CAA8C,CAC9C,+CAAkD,CAClD,4BACE,sFAAyF,CAC3F,2BACE,wFAA2F,CAC7F,4BACE,iBAAoB,CACtB,sBACE,UAAW,CACX,WAAY,CACZ,SAAY,CACd,0BACE,sEAAyE,CAC3E,8BACE,sEAAuE,CACvE,wCAAyC,CACzC,wCAAyC,CACzC,oCAAuC,CAC3C,oBACE,iDAAkD,CAClD,uDAAwD,CACxD,mDAAoD,CACpD,6CAA8C,CAC9C,sCAAuC,CACvC,eAAgB,CAChB,mDAAsD,CACxD,kBACE,qEAAsE,CACtE,yEAA0E,CAC1E,qBAAwB,CAC1B,kBACE,yEAA0E,CAC1E,+EAAkF,CAClF,uBACE,wBAAyB,CACzB,uBAA0B,CAC5B,wCACE,iBAAkB,CAClB,iDAAkD,CAClD,uDAAwD,CACxD,MAAO,CACP,UAAW,CACX,4BAA6B,CAC7B,iIAAoI,CACtI,2CACE,qDAAsD,CACtD,kBAAqB,CACzB,gLACE,SAAY,CACd,8BACE,2CAA8C,CAChD,uBACE,iDAAoD,CACtD,6CAEE,0EAA2E,CAC3E,0EAA2E,CAC3E,mCAAoC,CACpC,yCAA0C,CAC1C,qCAAwC,CAC1C,uBAKE,qCAAwC,CAC1C,gDALE,8BAA+B,CAC/B,iCAAkC,CAClC,oCAAqC,CACrC,qCAOwC,CAL1C,yBAKE,qCAAwC,CAC1C,4DAEE,wCAAyC,CACzC,wCAAyC,CACzC,4BAA6B,CAC7B,oCAAqC,CACrC,qCAAsC,CACtC,qCAAwC,CAC1C,6BACE,wCAAyC,CACzC,qCAAwC,CAC1C,yCACE,eAAkB,CAClB,4DACE,aAAgB,CACpB,4HACE,YAAe,CACjB,6EACE,wFAA2F,CAC7F,0HACE,mBAAsB,CAE1B,kBACE,iCAAkC,CAClC,iBAAkB,CAClB,aAAc,CACd,oCAAqC,CACrC,2CAA4C,CAC5C,2CAA4C,CAC5C,0CAA2C,CAC3C,mDAAoD,CACpD,6CAA8C,CAC9C,+CAAkD,CAClD,gCACE,iCAAoC,CACpC,kCACE,0CAA2C,CAC3C,mDAAoD,CACpD,+CAAkD,CAExD,oBACE,eAAgB,CAChB,UAAW,CACX,6JAA8J,CAC9J,iBAAkB,CAClB,mBAAoB,CACpB,sCAAuC,CACvC,eAAgB,CAChB,mBAAoB,CACpB,gBAAiB,CACjB,2DAA4D,CAC5D,QAAW,CACX,2BACE,iBAAkB,CAClB,KAAM,CACN,OAAQ,CACR,QAAS,CACT,MAAO,CACP,cAAe,CACf,UAAa,CACf,0BACE,6CAAgD,CAClD,0BACE,6CAAgD,CAClD,2BACE,8CAAiD,CAErD,6FAEE,aAAc,CACd,UAAW,CACX,0CAA2C,CAC3C,mDAAoD,CACpD,+CAAkD,CAEpD,oCACE,8BAAiC,CAEnC,qDAEE,mBAAoB,CACpB,eAAgB,CAChB,qBAAsB,CACtB,sCAAyC,CACzC,yFAEE,cAAiB,CACnB,uUAQE,6CAAgD,CAClD,qWAQE,6CAAgD,CAClD,8oBAiBE,sCAAyC,CAE7C,4GAGE,mCAAsC,CAExC,0MAME,8BAA+B,CAC/B,4BAA+B,CAEjC,oBACE,kCAAmC,CACnC,iCAAkC,CAClC,kBAAqB,CACrB,iCACE,yDAA4D,CAC5D,wEACE,sFAAyF,CAC7F,6CACE,uEAAwE,CACxE,0EAA6E,CAC/E,wBACE,mBAAsB,CAE1B,mBACE,sEAAyE,CAE3E,mCACE,0EAA2E,CAC3E,uEAAwE,CACxE,gNAAmN,CACnN,kDACE,uFAA0F,CAE9F,oDAEE,gCAAiC,CACjC,wEAAyE,CACzE,mCAAoC,CACpC,sEAAuE,CACvE,aAAc,CACd,gBAAiB,CACjB,qBAAwB,CAE1B,gCACE,iCAAkC,CAClC,kCAAmC,CACnC,gBAAmB,CAErB,uCACE,uFAAwF,CACxF,qGAAsG,CACtG,qGAAsG,CACtG,uGAAwG,CACxG,iBAAoB,CACpB,qDACE,gBAAmB,CACrB,2DACE,cAAe,CACf,eAAkB,CAClB,oMACE,SAAY,CAChB,mIAEE,iBAAkB,CAClB,OAAQ,CACR,UAAW,CACX,kBAAmB,CACnB,cAAiB,CACnB,kEACE,KAAM,CACN,2EAA4E,CAC5E,uEAAwE,CACxE,sFAAuF,CACvF,iGAAkG,CAClG,+FAAkG,CACpG,iEACE,oEAAqE,CACrE,sEAAuE,CACvE,mBAAoB,CACpB,qFAAsF,CACtF,4FAA+F,CACjG,sJACE,0JAA2J,CAC3J,yJAA0J,CAC1J,sJAAyJ,CAC3J,mDACE,+DAAgE,CAChE,8DAAiE,CACnE,gFACE,uIAA0I,CAC5I,iEACE,0EAA6E,CAC/E,oDACE,uDAA0D,CAC1D,0CACE,oDACE,kBAAmB,CACnB,sCAAyC,CAAE,CAEnD,gCACE,sDAAuD,CACvD,gEAAmE,CACnE,6CACE,kFAAmF,CACnF,gFAAiF,CACjF,8DAA+D,CAC/D,oEAAqE,CACrE,iBAAkB,CAClB,aAAgB,CAEpB,sCACE,0EAA2E,CAC3E,8EAA+E,CAC/E,gFAAiF,CACjF,4EAA6E,CAC7E,YAAa,CACb,UAAW,CACX,qDAAsD,CACtD,2DAA4D,CAC5D,uDAA0D,CAC1D,4CACE,iGAAkG,CAClG,2FAA8F,CAChG,4CACE,iGAAkG,CAClG,2FAA8F,CAChG,6CACE,kGAAmG,CACnG,4FAA+F,CACjG,wDACE,kDAAqD,CAEzD,oDACE,8FAA+F,CAC/F,gGAAiG,CACjG,wDAA2D,CAE7D,4BACE,4EAA+E,CAEjF,gCACE,gGAAiG,CACjG,8GAA+G,CAC/G,8GAA+G,CAC/G,gHAAiH,CACjH,gEAAmE,CAErE,4BACE,aAAc,CACd,yDAA0D,CAC1D,8CAA+C,CAC/C,mBAAsB,CAExB,4BACE,gCAAiC,CACjC,mCAAoC,CACpC,iBAAkB,CAClB,iCAAkC,CAClC,8BAAiC,CACjC,6EAEE,wDAA2D,CAC7D,8FAEE,0EAA6E,CAC7E,sKAEE,SAAY,CAChB,gEACE,iEAAkE,CAClE,uEAA0E,CAC5E,0CACE,oFAAqF,CACrF,yDAA0D,CAC1D,mEAAsE,CACxE,gDACE,YAAa,CACb,iBAAoB,CAExB,wMAGE,iHAAoH,CAEtH,wCACE,wFAA2F,CAE7F,uCACE,0FAA6F,CAE/F,yBACE,mEAAoE,CACpE,6EAA8E,CAC9E,iFAAkF,CAClF,mFAAoF,CACpF,gFAAmF,CACnF,4BACE,+EAAgF,CAChF,iFAAoF,CACpF,6DACE,mEAAoE,CACpE,6EAA8E,CAC9E,mFAAsF,CACtF,0EACE,iGAAoG,CACtG,yEACE,mGAAsG,CAC5G,kCACE,0EAA2E,CAC3E,gFAAmF,CACrF,6CACE,oEAAqE,CACrE,0EAA2E,CAC3E,sEAAyE,CAC3E,6CACE,+EAAgF,CAChF,qFAAwF,CAC1F,2CACE,UAAW,CACX,WAAY,CACZ,iBAAoB,CACtB,qDACE,wFAA2F,CAC7F,oDACE,0FAA6F,CAC/F,6DACE,iHAAkH,CAClH,uHAA0H,CAE9H,yBACE,YAAa,CACb,kBAAqB,CACrB,2CACE,wDAA2D,CAE/D,2BACE,6BAAgC,CAElC,2BACE,6BAAgC,CAElC,2BACE,6BAAgC,CAElC,2BACE,6BAAgC,CAElC,2BACE,6BAAgC,CAElC,2BACE,6BAAgC,CAElC,2BACE,6BAAgC,CAElC,2BACE,6BAAgC,CAElC,2BACE,6BAAgC,CAElC,2BACE,6BAAgC,CAElC,2BACE,6BAAgC,CAElC,2BACE,6BAAgC,CAElC,2BACE,6BAAgC,CAElC,4BACE,8BAAiC,CAEnC,WACE,oBAAqB,CACrB,mEAAoE,CACpE,yEAA0E,CAC1E,qCAAsC,CACtC,uCAAwC,CACxC,mFAAoF,CACpF,sCAAuC,CACvC,2DAA4D,CAC5D,2CAA4C,CAC5C,kEAAmE,CACnE,kIAAmI,CACnI,4HAA6H,CAC7H,yEAA0E,CAC1E,2HAA4H,CAC5H,qDAAsD,CACtD,0DAA2D,CAC3D,8CAA+C,CAC/C,0CAAqD,CACrD,0DAA2D,CAC3D,4DAA6D,CAC7D,6DAA8D,CAC9D,2DAA4D,CAC5D,sEAAuE,CACvE,0FAA2F,CAC3F,sEAAuE,CACvE,yEAA0E,CAC1E,gFAAiF,CACjF,uEAAwE,CACxE,gFAAiF,CACjF,8FAA+F,CAC/F,+FAAgG,CAChG,+EAAgF,CAChF,2CAA4C,CAC5C,6CAA8C,CAC9C,8CAA+C,CAC/C,4CAA6C,CAC7C,2FAA8F,CAC9F,kCAAmC,CACnC,iCAAkC,CAClC,kCAAmC,CACnC,8EAA+E,CAC/E,uCAAwC,CACxC,0CAA2C,CAC3C,4CAA6C,CAC7C,2CAA4C,CAC5C,8EAA+E,CAC/E,8EAA+E,CAC/E,+EAAgF,CAChF,0FAA2F,CAC3F,wFAAyF,CACzF,kEAAmE,CACnE,8DAA+D,CAC/D,4EAA6E,CAC7E,iFAAkF,CAClF,kFAAmF,CACnF,+DAAgE,CAChE,mEAAoE,CACpE,+EAAkF,CAClF,4DAA6D,CAC7D,+DAAgE,CAChE,6DAA8D,CAC9D,qFAAsF,CACtF,wFAAyF,CACzF,sDAAuD,CACvD,iHAAkH,CAClH,qDAAsD,CACtD,iBAAkB,CAClB,YAAa,CACb,qCAAsC,CACtC,oCAAqC,CACrC,eAAkB,CAClB,qCACE,WACE,4EAA+E,CAAE,CACrF,kBACE,iBAAkB,CAClB,OAAQ,CACR,QAAS,CACT,MAAO,CACP,kDAAmD,CACnD,sLAAyL,CAC3L,sCACE,eAAkB,CACpB,sCACE,WAAc,CACd,kDACE,iFAAoF,CACtF,iDACE,iFAAoF,CACxF,sCACE,eAAgB,CAChB,sBAAyB,CAC3B,qDACE,SAAY,CACd,mEACE,cAAe,CACf,uBAA0B,CAC5B,oEACE,aAAc,CACd,uBAA0B,CAC5B,2DACE,wCAA2C,CAC7C,+EACE,6CAAgD,CAClD,oBACE,iFAAkF,CAClF,+FAAgG,CAChG,8FAA+F,CAC/F,+BAAgC,CAChC,qCAAwC,CACxC,qCACE,mFAAsF,CACxF,gDACE,6CAAgD,CAClD,kDACE,2FAA4F,CAC5F,oFAAuF,CACzF,sFACE,sGAAyG,CAC3G,qFACE,uGAA0G,CAG5G,0LACE,gEAAqE,CACvE,mEACE,iCAAoC,CACtC,iDACE,qGAAsG,CACtG,uIAA0I,CAC9I,yBACE,sDAAuD,CACvD,wCAAyC,CACzC,iFAAkF,CAClF,4EAA6E,CAC7E,kFAAmF,CACnF,iCAAkC,CAClC,+BAAgC,CAChC,kCAAmC,CACnC,oCAAqC,CACrC,mBAAoB,CACpB,qBAAsB,CACtB,WAAY,CACZ,SAAY,CACZ,gCACE,KAAM,CACN,UAAa,CACf,0CACE,qBAAsB,CACtB,gDAAmD,CACrD,sDACE,kCAAqC,CACvC,qDACE,qCAAwC,CAC1C,0CACE,0CAA2C,CAC3C,oFAAqF,CACrF,cAAe,CACf,eAAkB,CACpB,+CACE,cAAe,CACf,wBAA2B,CAC/B,kCACE,6DAA8D,CAC9D,sCAAuC,CACvC,kFAAqF,CACrF,yCACE,OAAQ,CACR,SAAY,CACd,8DACE,8CAA+C,CAC/C,8FAAiG,CACnG,gEACE,oGAAqG,CACrG,+FAAgG,CAChG,+FAAkG,CAGpG,wJACE,4FAA+F,CACjG,yDACE,+DAAoE,CACtE,8LAEE,KAAQ,CACZ,0BACE,yEAA4E,CAEhF,iBACE,oBAAqB,CACrB,2CAA4C,CAC5C,iBAAkB,CAClB,YAAa,CACb,cAAe,CACf,eAAgB,CAChB,sBAAuB,CACvB,gCAAmC,CACnC,oCACE,YAAe,CAEnB,iBACE,YAAa,CACb,SAAY,CACZ,8BACE,uEAAwE,CACxE,iGAAkG,CAClG,iGAAoG,CAExG,2CAEE,QAAW,CAEb,kGAIE,iBAAkB,CAClB,OAAQ,CACR,QAAS,CACT,MAAO,CACP,UAAW,CACX,kBAAqB,CAEvB,gFAGE,KAAQ,CAEV,iBACE,sFAAuF,CACvF,iBAAkB,CAClB,YAAa,CACb,MAAO,CACP,yJAA0J,CAC1J,0CAA2C,CAC3C,mCAAoC,CACpC,oBAAqB,CACrB,wDAAyD,CACzD,oDAAuD,CACvD,wBACE,mBAAoB,CACpB,sEAAgE,CAAhE,qEAAgE,CAChE,8MAA+M,CAE/M,qNAAwE,CAC1E,uBACE,sCAAuC,CACvC,0CAA2C,CAC3C,4CAA6C,CAC7C,yCAA0C,CAC1C,uDAAwD,CACxD,0MAA6M,CAC/M,uBACE,uFAA0F,CAC5F,uBACE,uFAA0F,CAC5F,wBACE,wFAA2F,CAC7F,8EAEE,uDAA0D,CAC1D,oGAEE,uCAA0C,CAEhD,0BACE,SAAU,CACV,4CAA6C,CAC7C,aAAc,CACd,4CAA6C,CAC7C,iEAAkE,CAClE,6DAA8D,CAC9D,SAAU,CACV,2NAAgO,CAChO,iGACE,+EAAkF,CACpF,iCACE,iEAAkE,CAClE,0EAA6L,CAA7L,8EAA6L,CAA7L,4EAA6L,CAA7L,kBAA+L,CACjM,wCACE,gHAAiH,CACjH,4DAA+D,CAC/D,2BAA8B,CAChC,yCACE,+GAAgH,CAChH,2DAA8D,CAC9D,0BAA6B,CAC/B,mCACE,kFAAmF,CACnF,mBAAsB,CAE1B,2BACE,oBAAqB,CACrB,gCAAiC,CACjC,uCAA0C,CAE5C,yBACE,+CAAgD,CAChD,2DAA4D,CAC5D,kEAAqE,CAEvE,yBACE,+CAAgD,CAChD,2DAA4D,CAC5D,kEAAqE,CAEvE,yBACE,+CAAgD,CAChD,2DAA4D,CAC5D,kEAAqE,CAEvE,yBACE,+CAAgD,CAChD,2DAA4D,CAC5D,kEAAqE,CAEvE,0BACE,gDAAiD,CACjD,4DAA6D,CAC7D,mEAAsE,CAExE,yBACE,iCACE,oBAAqB,CACrB,gCAAiC,CACjC,uCAA0C,CAC5C,+BACE,+CAAgD,CAChD,2DAA4D,CAC5D,kEAAqE,CACvE,+BACE,+CAAgD,CAChD,2DAA4D,CAC5D,kEAAqE,CACvE,+BACE,+CAAgD,CAChD,2DAA4D,CAC5D,kEAAqE,CACvE,+BACE,+CAAgD,CAChD,2DAA4D,CAC5D,kEAAqE,CACvE,gCACE,gDAAiD,CACjD,4DAA6D,CAC7D,mEAAsE,CAAE,CAE5E,yBACE,iCACE,oBAAqB,CACrB,gCAAiC,CACjC,uCAA0C,CAC5C,+BACE,+CAAgD,CAChD,2DAA4D,CAC5D,kEAAqE,CACvE,+BACE,+CAAgD,CAChD,2DAA4D,CAC5D,kEAAqE,CACvE,+BACE,+CAAgD,CAChD,2DAA4D,CAC5D,kEAAqE,CACvE,+BACE,+CAAgD,CAChD,2DAA4D,CAC5D,kEAAqE,CACvE,gCACE,gDAAiD,CACjD,4DAA6D,CAC7D,mEAAsE,CAAE,CAE5E,yBACE,iCACE,oBAAqB,CACrB,gCAAiC,CACjC,uCAA0C,CAC5C,+BACE,+CAAgD,CAChD,2DAA4D,CAC5D,kEAAqE,CACvE,+BACE,+CAAgD,CAChD,2DAA4D,CAC5D,kEAAqE,CACvE,+BACE,+CAAgD,CAChD,2DAA4D,CAC5D,kEAAqE,CACvE,+BACE,+CAAgD,CAChD,2DAA4D,CAC5D,kEAAqE,CACvE,gCACE,gDAAiD,CACjD,4DAA6D,CAC7D,mEAAsE,CAAE,CAE5E,0BACE,iCACE,oBAAqB,CACrB,gCAAiC,CACjC,uCAA0C,CAC5C,+BACE,+CAAgD,CAChD,2DAA4D,CAC5D,kEAAqE,CACvE,+BACE,+CAAgD,CAChD,2DAA4D,CAC5D,kEAAqE,CACvE,+BACE,+CAAgD,CAChD,2DAA4D,CAC5D,kEAAqE,CACvE,+BACE,+CAAgD,CAChD,2DAA4D,CAC5D,kEAAqE,CACvE,gCACE,gDAAiD,CACjD,4DAA6D,CAC7D,mEAAsE,CAAE,CAE5E,0BACE,kCACE,oBAAqB,CACrB,gCAAiC,CACjC,uCAA0C,CAC5C,gCACE,+CAAgD,CAChD,2DAA4D,CAC5D,kEAAqE,CACvE,gCACE,+CAAgD,CAChD,2DAA4D,CAC5D,kEAAqE,CACvE,gCACE,+CAAgD,CAChD,2DAA4D,CAC5D,kEAAqE,CACvE,gCACE,+CAAgD,CAChD,2DAA4D,CAC5D,kEAAqE,CACvE,iCACE,gDAAiD,CACjD,4DAA6D,CAC7D,mEAAsE,CAAE,CAE5E,WACE,oDAAqD,CACrD,sDAAuD,CACvD,uDAAwD,CACxD,qDAAsD,CACtD,mEAAoE,CACpE,mEAAoE,CACpE,kEAAmE,CACnE,oEAAqE,CACrE,4EAA6E,CAC7E,8EAA+E,CAC/E,iFAAkF,CAClF,yEAA0E,CAC1E,4EAA6E,CAC7E,8EAA+E,CAC/E,sDAAuD,CACvD,qEAAsE,CACtE,0EAA2E,CAC3E,qEAAsE,CACtE,2EAA4E,CAC5E,2DAA4D,CAC5D,gEAAiE,CACjE,qDAAsD,CACtD,oEAAqE,CACrE,yEAA0E,CAC1E,0EAA2E,CAC3E,oEAAqE,CACrE,+EAAgF,CAChF,mFAAoF,CACpF,iGAAkG,CAClG,qDAAsD,CACtD,0DAA2D,CAC3D,0EAA2E,CAC3E,iBAAkB,CAClB,mBAAoB,CACpB,iIAAkI,CAClI,iBAAkB,CAClB,cAAe,CACf,kDAAmD,CACnD,8BAAiC,CACjC,kBACE,iBAAkB,CAClB,KAAM,CACN,OAAQ,CACR,QAAS,CACT,MAAO,CACP,mBAAoB,CACpB,UAAW,CACX,wFAAyF,CACzF,oDAAuD,CACzD,iBACE,+DAAgE,CAChE,6DAA8D,CAC9D,6EAAgF,CAClF,yBACE,oEAAqE,CACrE,kEAAmE,CACnE,kFAAmF,CACnF,kFAAqF,CACvF,iBACE,+DAAgE,CAChE,6DAA8D,CAC9D,6EAA8E,CAC9E,6EAAgF,CAClF,yBACE,0EAA2E,CAC3E,oEAAqE,CACrE,kEAAmE,CACnE,kCAAmC,CACnC,kEAAmE,CACnE,mBAAsB,CACxB,2DACE,6FAAgG,CAEpG,mBACE,YAAa,CACb,kBAAmB,CACnB,sBAAyB,CACzB,gCACE,gCAAiC,CACjC,+EAAgF,CAChF,qBAAsB,CACtB,sBAA0B,CAC1B,iDACE,YAAa,CACb,kBAAmB,CACnB,sBAAuB,CACvB,qEAAwE,CAE9E,kBACE,oCAAuC,CAEzC,iBACE,0CAA2C,CAC3C,mCAAsC,CAExC,iBACE,gDAAiD,CACjD,0CAA2C,CAC3C,mCAAsC,CAExC,YACE,0EAA2E,CAC3E,gEAAiE,CACjE,6DAA8D,CAC9D,oEAAqE,CACrE,gEAAiE,CACjE,6DAA8D,CAC9D,oEAAqE,CACrE,gEAAiE,CACjE,6DAA8D,CAC9D,oEAAqE,CACrE,+DAAgE,CAChE,2DAA4D,CAC5D,mEAAoE,CACpE,+DAAgE,CAChE,2DAA4D,CAC5D,mEAAoE,CACpE,+DAAgE,CAChE,2DAA4D,CAC5D,mEAAoE,CACpE,yCAA0C,CAC1C,qBAAwB,CACxB,qBACE,4CAA6C,CAC7C,gDAAiD,CACjD,gDAAmD,CACrD,qBACE,4CAA6C,CAC7C,gDAAiD,CACjD,gDAAmD,CACrD,qBACE,4CAA6C,CAC7C,gDAAiD,CACjD,gDAAmD,CACrD,oBACE,2CAA4C,CAC5C,+CAAgD,CAChD,+CAAkD,CACpD,oBACE,2CAA4C,CAC5C,+CAAgD,CAChD,+CAAkD,CACpD,oBACE,2CAA4C,CAC5C,+CAAgD,CAChD,+CAAkD,CAEtD,gCACE,sEAAuE,CACvE,sEAAyE,CAE3E,mBACE,8EAA+E,CAC/E,sEAAuE,CACvE,iFAAkF,CAClF,qEAAsE,CACtE,oEAAqE,CACrE,6GAAgH,CAChH,+DAAgE,CAChE,mFAAoF,CACpF,yFAA0F,CAC1F,yFAA0F,CAC1F,4FAA6F,CAC7F,kFAAmF,CACnF,sGAAuG,CACvG,yGAA0G,CAC1G,sGAAuG,CACvG,yGAA0G,CAC1G,wEAAyE,CACzE,4FAA6F,CAC7F,6FAA8F,CAC9F,iFAAkF,CAClF,YAAe,CAEjB,gEACE,+FAAgG,CAChG,qGAAwG,CAE1G,+DACE,gGAAiG,CACjG,sGAAyG,CAE3G,2BACE,mBAAoB,CACpB,iMAAkM,CAClM,oDAAqD,CACrD,wDAAyD,CACzD,6CAA8C,CAC9C,kEAAmE,CACnE,QAAW,CACX,sCACE,uGAA0G,CAC5G,iCACE,qGAAsG,CACtG,oBAAuB,CACzB,iCACE,qGAAwG,CAC1G,yCACE,0GAA2G,CAC3G,sFAAyF,CAC3F,6EACE,wGAAyG,CACzG,oFAAqF,CACrF,mBAAsB,CAE1B,oGAEE,4DAA+D,CAEjE,cACE,iCAAkC,CAClC,yDAA0D,CAC1D,gEAAiE,CACjE,kEAAmE,CACnE,mEAAoE,CACpE,iEAAkE,CAClE,iEAAkE,CAClE,oFAAqF,CACrF,gEAAiE,CACjE,2DAA4D,CAC5D,4DAA6D,CAC7D,6CAA8C,CAC9C,4CAA6C,CAC7C,0CAA2C,CAC3C,+CAAgD,CAChD,+CAAgD,CAChD,4CAA6C,CAC7C,gDAAiD,CACjD,gDAAiD,CACjD,6CAA8C,CAC9C,6CAA8C,CAC9C,8CAA+C,CAC/C,2CAA4C,CAC5C,iBAAkB,CAClB,uCAAwC,CACxC,yCAA4C,CAC5C,4CACE,QAAS,CACT,QAAS,CACT,+KAAkL,CACpL,+CACE,KAAM,CACN,QAAS,CACT,wLAA2L,CAC7L,6CACE,OAAQ,CACR,OAAQ,CACR,kLAAqL,CACvL,8CACE,OAAQ,CACR,MAAO,CACP,qLAAwL,CAE5L,uBACE,iBAAkB,CAClB,iLAAkL,CAClL,gDAAiD,CACjD,yCAA0C,CAC1C,iBAAkB,CAClB,qBAAsB,CACtB,8DAAiE,CACjE,4CACE,eAAkB,CAEtB,qBACE,iBAAkB,CAClB,uCAAwC,CACxC,yCAA0C,CAC1C,mBAAoB,CACpB,8DAAiE,CAEnE,gBACE,8EAA+E,CAC/E,+DAAgE,CAChE,iFAAoF,CACpF,+CAAgD,CAChD,wJAA2J,CAC3J,mBAAoB,CACpB,kBAAqB,CACrB,mCACE,mBAAoB,CACpB,kDAAmD,CACnD,gBAAmB,CAEvB,gFAEE,kEAAqE,CAEvE,sBACE,+CAAkD,CAEpD,gBACE,yDAA0D,CAC1D,4DAA6D,CAC7D,6HAAgI,CAChI,0HAA2H,CAC3H,+DAAgE,CAChE,iEAAkE,CAClE,kEAAmE,CACnE,qCAAsC,CACtC,0DAA2D,CAC3D,sEAAuE,CACvE,gFAAiF,CACjF,qFAAsF,CACtF,mFAAoF,CACpF,gGAAiG,CACjG,kGAAmG,CACnG,qEAAsE,CACtE,2EAA4E,CAC5E,2EAA4E,CAC5E,uFAAwF,CACxF,+EAAgF,CAChF,0FAA2F,CAC3F,8EAA+E,CAC/E,+FAAkG,CAClG,kGAAqG,CACrG,sEAAuE,CACvE,qEAAsE,CACtE,oGAAqG,CACrG,iEAAkE,CAClE,mEAAoE,CACpE,oEAAqE,CACrE,kEAAmE,CACnE,sEAAuE,CACvE,uEAAwE,CACxE,uEAAwE,CACxE,wCAAyC,CACzC,iEAAkE,CAClE,uFAAwF,CACxF,oEAAqE,CACrE,0EAA2E,CAC3E,0EAA2E,CAC3E,6CAA8C,CAC9C,mDAAsD,CAExD,uJACE,wFAAyF,CACzF,iBAAoB,CAEtB,sBACE,iBAAkB,CAClB,YAAa,CACb,QAAS,CACT,kBAAmB,CACnB,WAAY,CACZ,6KAA8K,CAC9K,wCAAyC,CACzC,eAAgB,CAChB,cAAe,CACf,QAAW,CACX,mCACE,2EAA4E,CAC5E,8DAAiE,CACnE,4BACE,oEAAuE,CACzE,kDACE,yDAA4D,CAC5D,wEACE,yGAA4G,CAElH,kCACE,oBAAqB,CACrB,2DAA4D,CAC5D,8DAAiE,CAEnE,4BACE,2DAA8D,CAEhE,6BACE,mBAAoB,CACpB,kBAAmB,CACnB,sBAAuB,CACvB,qOAAsO,CACtO,+DAAgE,CAChE,qEAAsE,CACtE,QAAW,CAEb,mFACE,iBAAkB,CAClB,iEAAkE,CAClE,mEAAoE,CACpE,0FAA6F,CAE/F,2BACE,eAAgB,CAChB,sBAAuB,CACvB,kBAAqB,CAEvB,wBACE,qLAAwL,CAE1L,2BACE,4DAA6D,CAC7D,6CAAgD,CAElD,yBACE,YAAa,CACb,kBAAqB,CAEvB,qEAEE,oEAAuE,CAEzE,wBACE,qDAAsD,CACtD,0CAA2C,CAC3C,QAAW,CACX,8BACE,2EAA8E,CAChF,8BACE,2EAA4E,CAC5E,sEAAyE,CAE7E,sDACE,wIAA2I,CAC3I,kGAAqG,CAEvG,iFACE,wIAA2I,CAC3I,kGAAqG,CAEvG,4GACE,wIAA2I,CAC3I,kGAAqG,CAEvG,uIACE,wIAA2I,CAC3I,kGAAqG,CAEvG,kKACE,wIAA2I,CAC3I,kGAAqG,CAEvG,6LACE,wIAA2I,CAC3I,kGAAqG,CAEvG,wNACE,wIAA2I,CAC3I,kGAAqG,CAEvG,mPACE,wIAA2I,CAC3I,kGAAqG,CAEvG,8QACE,wIAA2I,CAC3I,kGAAqG,CAEvG,ySACE,yIAA4I,CAC5I,kGAAqG,CAEvG,aACE,0BAA2B,CAC3B,+CAAgD,CAChD,kFAAmF,CACnF,0DAA2D,CAC3D,8DAA+D,CAC/D,gEAAiE,CACjE,iEAAkE,CAClE,+DAAgE,CAChE,oEAAqE,CACrE,mEAAoE,CACpE,oEAAqE,CACrE,mEAAoE,CACpE,qGAAsG,CACtG,6BAA8B,CAC9B,4DAA6D,CAC7D,6DAA8D,CAC9D,gEAAiE,CACjE,mEAAoE,CACpE,oEAAqE,CACrE,2DAA4D,CAC5D,8EAA+E,CAC/E,mEAAoE,CACpE,mEAAoE,CACpE,uEAAwE,CACxE,iFAAkF,CAClF,4EAA6E,CAC7E,qGAAsG,CACtG,6CAA8C,CAC9C,8CAA+C,CAC/C,sCAAuC,CACvC,uFAAwF,CACxF,gFAAiF,CACjF,mEAAoE,CACpE,wEAAyE,CACzE,sFAAuF,CACvF,+FAAgG,CAChG,oFAAqF,CACrF,wEAAyE,CACzE,oFAAqF,CACrF,6EAA8E,CAC9E,0DAA2D,CAC3D,uEAAwE,CACxE,8DAA+D,CAC/D,gEAAiE,CACjE,iEAAkE,CAClE,kJAAmJ,CACnJ,sFAAuF,CACvF,uFAAwF,CACxF,iKAAkK,CAClK,wCAAyC,CACzC,yFAA0F,CAC1F,0EAA2E,CAC3E,oEAAqE,CACrE,oGAAuG,CACvG,wEAAyE,CACzE,yEAA0E,CAC1E,uEAAwE,CACxE,6DAA8D,CAC9D,uDAAwD,CACxD,0EAA2E,CAC3E,oEAAqE,CACrE,8BAA+B,CAC/B,uCAAwC,CACxC,0EAA2E,CAC3E,2EAA4E,CAC5E,gEAAiE,CACjE,kEAAmE,CACnE,mEAAoE,CACpE,oJAAqJ,CACrJ,oEAAqE,CACrE,sEAAuE,CACvE,uEAAwE,CACxE,oEAAqE,CACrE,sEAAuE,CACvE,uEAAwE,CACxE,wJAAyJ,CACzJ,wEAAyE,CACzE,uEAAwE,CACxE,+DAAgE,CAChE,iFAAkF,CAClF,yEAA0E,CAC1E,wDAAyD,CACzD,iEAAkE,CAClE,mEAAoE,CACpE,oEAAqE,CACrE,kEAAmE,CACnE,qEAAsE,CACtE,uEAAwE,CACxE,wEAAyE,CACzE,sEAAuE,CACvE,8DAA+D,CAC/D,gEAAiE,CACjE,iEAAkE,CAClE,+DAAgE,CAChE,kEAAmE,CACnE,oEAAqE,CACrE,qEAAsE,CACtE,mEAAoE,CACpE,sEAAuE,CACvE,uEAAwE,CACxE,iBAAkB,CAClB,YAAa,CACb,qBAAsB,CACtB,iCAAoC,CACpC,oCACE,aACE,gFAAiF,CACjF,8EAAiF,CAAE,CACvF,qCACE,aACE,gFAAiF,CACjF,8EAA+E,CAG/E,gEAHiF,CAAE,CAIvF,oCACE,aACE,4DAA6D,CAC7D,kCAAmC,CAGnC,gFAAiF,CACjF,oFAAqF,CACrF,sFALqC,CAAE,CAM3C,qCACE,aACE,gFAAiF,CACjF,oFAAqF,CACrF,sFAAuF,CACvF,kFAAmF,CAGnF,kFAAmF,CACnF,sFAAuF,CACvF,wFAAyF,CACzF,oFAAqF,CAGrF,4EAA6E,CAC7E,gFAAiF,CACjF,kFAAmF,CACnF,8EAZqF,CAAE,CAa3F,6BACE,mDAAoD,CACpD,YAAe,CACjB,4CACE,aAAgB,CAClB,2BACE,4CAA+C,CAC/C,6IAGE,YAAa,CACb,iBAAoB,CAE1B,qBACE,kCAAmC,CACnC,iBAAkB,CAClB,0CAA2C,CAC3C,yKAA0K,CAC1K,4DAA+D,CAC/D,yCACE,iBAAkB,CAClB,kCAAmC,CACnC,sCAAuC,CACvC,6CAAgD,CAEpD,oBACE,qDAAsD,CACtD,oBAAuB,CAEzB,0BACE,YAAa,CACb,uDAAwD,CACxD,4CAA6C,CAC7C,iBAAoB,CACpB,oCACE,0BACE,aAAc,CACd,kBAAqB,CAAE,CAE7B,qBACE,iBAAkB,CAClB,0CAA2C,CAC3C,YAAa,CACb,6BAA8B,CAC9B,UAAW,CACX,yKAA0K,CAC1K,4DAA6D,CAC7D,QAAS,CACT,gDAAmD,CACnD,oCACE,qBACE,YAAa,CACb,iBAAoB,CAAE,CAC1B,mCACE,qCAAsC,CACtC,uIAA0I,CAC1I,6DACE,6EAAgF,CAEtF,0BACE,iBAAkB,CAClB,YAAa,CACb,cAAe,CACf,oBAAqB,CACrB,yDAA0D,CAC1D,2DAA4D,CAC5D,eAAkB,CAEpB,+BACE,gEAAiE,CACjE,eAAgB,CAChB,qBAAwB,CACxB,gDACE,8EAAiF,CAErF,yBACE,gFAAmF,CAErF,+BACE,4DAA6D,CAC7D,iDAAoD,CAEtD,0BACE,uDAA0D,CAE5D,yBACE,iBAAkB,CAClB,YAAa,CACb,qBAAsB,CACtB,WAAY,CACZ,YAAa,CACb,gEAAmE,CACnE,oCACE,yBACE,4DAA+D,CAAE,CAEvE,yBACE,iBAAkB,CAClB,YAAa,CACb,qBAAsB,CACtB,WAAY,CACZ,YAAe,CACf,oCACE,yBACE,eAAkB,CAAE,CAE1B,kBACE,iBAAkB,CAClB,KAAM,CACN,MAAO,CACP,uCAAwC,CACxC,YAAa,CACb,oCAAqC,CACrC,eAAgB,CAChB,eAAgB,CAChB,gCAAiC,CACjC,iBAAkB,CAClB,yDAA0D,CAC1D,6CAAgD,CAChD,gCACE,aAAc,CACd,kBAAqB,CACvB,oCACE,kBACE,aAAc,CACd,WAAY,CACZ,kBAAmB,CACnB,8GAAiH,CAAE,CAEzH,uBAIE,iLAAuD,CACvD,eAAgB,CAChB,8BAAiC,CACjC,8CACE,SAAU,CACV,0DAA2D,CAC3D,4DAA+D,CAC/D,4EACE,YAAe,CACjB,kFACE,mFAAsF,CAE5F,8CACE,kDAAqD,CAEvD,uBACE,iBAAkB,CAClB,oBAAqB,CACrB,yCAA0C,CAC1C,eAAgB,CAChB,4DAA6D,CAC7D,qBAAsB,CACtB,QAAW,CACX,uDACE,iBAAkB,CAClB,6CAA8C,CAC9C,MAAO,CACP,mBAAoB,CACpB,kBAAmB,CACnB,sBAAuB,CACvB,iDAAkD,CAClD,mDAAoD,CACpD,wDAAyD,CACzD,aAAc,CACd,iDAAkD,CAClD,sEAAuE,CACvE,gEAAiE,CACjE,sEAAyE,CAC3E,8BACE,KAAM,CACN,iCAAkC,CAClC,kCAAqC,CACvC,6BACE,yEAA4E,CAC9E,6BACE,yEAA4E,CAC9E,oCACE,6EAA8E,CAC9E,+DAAkE,CAClE,oEACE,iHAAkH,CAClH,6FAAgG,CACpG,qEACE,8EAA+E,CAC/E,mBAAsB,CACtB,mFACE,kHAAmH,CACnH,8FAAiG,CAEvG,mBACE,wCAAyC,CACzC,aAAc,CACd,iBAAkB,CAClB,eAAgB,CAChB,qBAAwB,CAE1B,wBACE,qLAAwL,CACxL,wCACE,SAAY,CAEhB,qBACE,YAAa,CACb,cAAe,CACf,aAAc,CACd,yKAA4K,CAC5K,uBACE,6DAAgE,CAChE,uCACE,2DAA8D,CAEpE,eACE,0BAA2B,CAC3B,YAAa,CACb,kBAAmB,CACnB,sBAAuB,CACvB,WAAY,CACZ,qCAAsC,CACtC,QAAW,CAEb,WACE,yBAA0B,CAC1B,0BAA2B,CAC3B,gCAAiC,CACjC,uCAAwC,CACxC,+CAAgD,CAChD,0BAA2B,CAC3B,qDAAsD,CACtD,iDAAkD,CAClD,2BAA4B,CAC5B,oDAAqD,CACrD,oDAAqD,CACrD,oDAAqD,CACrD,oDAAqD,CACrD,oDAAqD,CACrD,sDAAuD,CACvD,sDAAuD,CACvD,sDAAuD,CACvD,iCAAkC,CAClC,oCAAqC,CACrC,wCAA2C,CAC3C,sBACE,qBAAwB,CAE5B,aACE,iDAAkD,CAClD,mCAAoC,CACpC,cAAe,CACf,qCAAwC,CACxC,oCACE,aACE,uEAA2E,CAAE,CACjF,oCACE,aACE,2GAAgH,CAAE,CACtH,oCACE,aACE,+IAAqJ,CAAE,CAC3J,qCACE,aACE,mLAA0L,CAAE,CAChM,qCACE,aACE,wNAAgO,CAAE,CACtO,uBACE,qBAAwB,CAE5B,qBACE,iCAAoC,CAEtC,4BACE,gCAAmC,CAErC,uBACE,qBAAsB,CACtB,kBAAqB,CACrB,yBACE,qCAAwC,CAE5C,+BACE,6BAA8B,CAC9B,kBAAqB,CACrB,iCACE,qCAAwC,CAE5C,oBACE,kBAAmB,CACnB,+CAAkD,CAClD,sBACE,qCAAwC,CAE5C,4BACE,0BAA2B,CAC3B,uDAA0D,CAC1D,8BACE,qCAAwC,CAE5C,qBACE,cAAiB,CAEnB,6BACE,sBAAyB,CAE3B,uBACE,gBAAmB,CAErB,2CACE,0BAA6B,CAE/B,yCACE,wBAA2B,CAE7B,uCACE,sBAAyB,CAE3B,8CACE,6BAAgC,CAElC,6CACE,4BAA+B,CAEjC,6CACE,4BAA+B,CAEjC,uCACE,sBAAyB,CAE3B,qCACE,oBAAuB,CAEzB,mCACE,kBAAqB,CAEvB,oCACE,mBAAsB,CAExB,qCACE,oBAAuB,CAEzB,yCACE,wBAA2B,CAE7B,uCACE,sBAAyB,CAE3B,qCACE,oBAAuB,CAEzB,sCACE,qBAAwB,CAE1B,4CACE,2BAA8B,CAEhC,2CACE,0BAA6B,CAE/B,6BACE,gBAAmB,CAErB,4BACE,aAAgB,CAElB,sBACE,WAAc,CAEhB,wBACE,aAAgB,CAElB,4BACE,UAAW,CACX,cAAiB,CAEnB,wBACE,UAAa,CAEf,wBACE,UAAa,CAEf,wBACE,UAAa,CAEf,wBACE,UAAa,CAEf,8BACE,aAAgB,CAElB,2BACE,SAAY,CAEd,uCACE,qBAAwB,CAE1B,qCACE,mBAAsB,CAExB,mCACE,iBAAoB,CAEtB,qCACE,mBAAsB,CAExB,oCACE,kBAAqB,CAEvB,yBACE,2BACE,iCAAoC,CACtC,kCACE,gCAAmC,CACrC,6BACE,qBAAsB,CACtB,kBAAqB,CACrB,+BACE,qCAAwC,CAC5C,qCACE,6BAA8B,CAC9B,kBAAqB,CACrB,uCACE,qCAAwC,CAC5C,0BACE,kBAAmB,CACnB,+CAAkD,CAClD,4BACE,qCAAwC,CAC5C,kCACE,0BAA2B,CAC3B,uDAA0D,CAC1D,oCACE,qCAAwC,CAC5C,2BACE,cAAiB,CACnB,mCACE,sBAAyB,CAC3B,6BACE,gBAAmB,CACrB,iDACE,0BAA6B,CAC/B,+CACE,wBAA2B,CAC7B,6CACE,sBAAyB,CAC3B,oDACE,6BAAgC,CAClC,mDACE,4BAA+B,CACjC,mDACE,4BAA+B,CACjC,6CACE,sBAAyB,CAC3B,2CACE,oBAAuB,CACzB,yCACE,kBAAqB,CACvB,0CACE,mBAAsB,CACxB,2CACE,oBAAuB,CACzB,+CACE,wBAA2B,CAC7B,6CACE,sBAAyB,CAC3B,2CACE,oBAAuB,CACzB,4CACE,qBAAwB,CAC1B,kDACE,2BAA8B,CAChC,iDACE,0BAA6B,CAC/B,mCACE,gBAAmB,CACrB,kCACE,aAAgB,CAClB,4BACE,WAAc,CAChB,8BACE,aAAgB,CAClB,kCACE,UAAW,CACX,cAAiB,CACnB,8BACE,UAAa,CACf,8BACE,UAAa,CACf,8BACE,UAAa,CACf,8BACE,UAAa,CACf,oCACE,aAAgB,CAClB,iCACE,SAAY,CACd,6CACE,qBAAwB,CAC1B,2CACE,mBAAsB,CACxB,yCACE,iBAAoB,CACtB,2CACE,mBAAsB,CACxB,0CACE,kBAAqB,CAAE,CAE3B,yBACE,2BACE,iCAAoC,CACtC,kCACE,gCAAmC,CACrC,6BACE,qBAAsB,CACtB,kBAAqB,CACrB,+BACE,qCAAwC,CAC5C,qCACE,6BAA8B,CAC9B,kBAAqB,CACrB,uCACE,qCAAwC,CAC5C,0BACE,kBAAmB,CACnB,+CAAkD,CAClD,4BACE,qCAAwC,CAC5C,kCACE,0BAA2B,CAC3B,uDAA0D,CAC1D,oCACE,qCAAwC,CAC5C,2BACE,cAAiB,CACnB,mCACE,sBAAyB,CAC3B,6BACE,gBAAmB,CACrB,iDACE,0BAA6B,CAC/B,+CACE,wBAA2B,CAC7B,6CACE,sBAAyB,CAC3B,oDACE,6BAAgC,CAClC,mDACE,4BAA+B,CACjC,mDACE,4BAA+B,CACjC,6CACE,sBAAyB,CAC3B,2CACE,oBAAuB,CACzB,yCACE,kBAAqB,CACvB,0CACE,mBAAsB,CACxB,2CACE,oBAAuB,CACzB,+CACE,wBAA2B,CAC7B,6CACE,sBAAyB,CAC3B,2CACE,oBAAuB,CACzB,4CACE,qBAAwB,CAC1B,kDACE,2BAA8B,CAChC,iDACE,0BAA6B,CAC/B,mCACE,gBAAmB,CACrB,kCACE,aAAgB,CAClB,4BACE,WAAc,CAChB,8BACE,aAAgB,CAClB,kCACE,UAAW,CACX,cAAiB,CACnB,8BACE,UAAa,CACf,8BACE,UAAa,CACf,8BACE,UAAa,CACf,8BACE,UAAa,CACf,oCACE,aAAgB,CAClB,iCACE,SAAY,CACd,6CACE,qBAAwB,CAC1B,2CACE,mBAAsB,CACxB,yCACE,iBAAoB,CACtB,2CACE,mBAAsB,CACxB,0CACE,kBAAqB,CAAE,CAE3B,yBACE,2BACE,iCAAoC,CACtC,kCACE,gCAAmC,CACrC,6BACE,qBAAsB,CACtB,kBAAqB,CACrB,+BACE,qCAAwC,CAC5C,qCACE,6BAA8B,CAC9B,kBAAqB,CACrB,uCACE,qCAAwC,CAC5C,0BACE,kBAAmB,CACnB,+CAAkD,CAClD,4BACE,qCAAwC,CAC5C,kCACE,0BAA2B,CAC3B,uDAA0D,CAC1D,oCACE,qCAAwC,CAC5C,2BACE,cAAiB,CACnB,mCACE,sBAAyB,CAC3B,6BACE,gBAAmB,CACrB,iDACE,0BAA6B,CAC/B,+CACE,wBAA2B,CAC7B,6CACE,sBAAyB,CAC3B,oDACE,6BAAgC,CAClC,mDACE,4BAA+B,CACjC,mDACE,4BAA+B,CACjC,6CACE,sBAAyB,CAC3B,2CACE,oBAAuB,CACzB,yCACE,kBAAqB,CACvB,0CACE,mBAAsB,CACxB,2CACE,oBAAuB,CACzB,+CACE,wBAA2B,CAC7B,6CACE,sBAAyB,CAC3B,2CACE,oBAAuB,CACzB,4CACE,qBAAwB,CAC1B,kDACE,2BAA8B,CAChC,iDACE,0BAA6B,CAC/B,mCACE,gBAAmB,CACrB,kCACE,aAAgB,CAClB,4BACE,WAAc,CAChB,8BACE,aAAgB,CAClB,kCACE,UAAW,CACX,cAAiB,CACnB,8BACE,UAAa,CACf,8BACE,UAAa,CACf,8BACE,UAAa,CACf,8BACE,UAAa,CACf,oCACE,aAAgB,CAClB,iCACE,SAAY,CACd,6CACE,qBAAwB,CAC1B,2CACE,mBAAsB,CACxB,yCACE,iBAAoB,CACtB,2CACE,mBAAsB,CACxB,0CACE,kBAAqB,CAAE,CAE3B,0BACE,2BACE,iCAAoC,CACtC,kCACE,gCAAmC,CACrC,6BACE,qBAAsB,CACtB,kBAAqB,CACrB,+BACE,qCAAwC,CAC5C,qCACE,6BAA8B,CAC9B,kBAAqB,CACrB,uCACE,qCAAwC,CAC5C,0BACE,kBAAmB,CACnB,+CAAkD,CAClD,4BACE,qCAAwC,CAC5C,kCACE,0BAA2B,CAC3B,uDAA0D,CAC1D,oCACE,qCAAwC,CAC5C,2BACE,cAAiB,CACnB,mCACE,sBAAyB,CAC3B,6BACE,gBAAmB,CACrB,iDACE,0BAA6B,CAC/B,+CACE,wBAA2B,CAC7B,6CACE,sBAAyB,CAC3B,oDACE,6BAAgC,CAClC,mDACE,4BAA+B,CACjC,mDACE,4BAA+B,CACjC,6CACE,sBAAyB,CAC3B,2CACE,oBAAuB,CACzB,yCACE,kBAAqB,CACvB,0CACE,mBAAsB,CACxB,2CACE,oBAAuB,CACzB,+CACE,wBAA2B,CAC7B,6CACE,sBAAyB,CAC3B,2CACE,oBAAuB,CACzB,4CACE,qBAAwB,CAC1B,kDACE,2BAA8B,CAChC,iDACE,0BAA6B,CAC/B,mCACE,gBAAmB,CACrB,kCACE,aAAgB,CAClB,4BACE,WAAc,CAChB,8BACE,aAAgB,CAClB,kCACE,UAAW,CACX,cAAiB,CACnB,8BACE,UAAa,CACf,8BACE,UAAa,CACf,8BACE,UAAa,CACf,8BACE,UAAa,CACf,oCACE,aAAgB,CAClB,iCACE,SAAY,CACd,6CACE,qBAAwB,CAC1B,2CACE,mBAAsB,CACxB,yCACE,iBAAoB,CACtB,2CACE,mBAAsB,CACxB,0CACE,kBAAqB,CAAE,CAE3B,0BACE,4BACE,iCAAoC,CACtC,mCACE,gCAAmC,CACrC,8BACE,qBAAsB,CACtB,kBAAqB,CACrB,gCACE,qCAAwC,CAC5C,sCACE,6BAA8B,CAC9B,kBAAqB,CACrB,wCACE,qCAAwC,CAC5C,2BACE,kBAAmB,CACnB,+CAAkD,CAClD,6BACE,qCAAwC,CAC5C,mCACE,0BAA2B,CAC3B,uDAA0D,CAC1D,qCACE,qCAAwC,CAC5C,4BACE,cAAiB,CACnB,oCACE,sBAAyB,CAC3B,8BACE,gBAAmB,CACrB,kDACE,0BAA6B,CAC/B,gDACE,wBAA2B,CAC7B,8CACE,sBAAyB,CAC3B,qDACE,6BAAgC,CAClC,oDACE,4BAA+B,CACjC,oDACE,4BAA+B,CACjC,8CACE,sBAAyB,CAC3B,4CACE,oBAAuB,CACzB,0CACE,kBAAqB,CACvB,2CACE,mBAAsB,CACxB,4CACE,oBAAuB,CACzB,gDACE,wBAA2B,CAC7B,8CACE,sBAAyB,CAC3B,4CACE,oBAAuB,CACzB,6CACE,qBAAwB,CAC1B,mDACE,2BAA8B,CAChC,kDACE,0BAA6B,CAC/B,oCACE,gBAAmB,CACrB,mCACE,aAAgB,CAClB,6BACE,WAAc,CAChB,+BACE,aAAgB,CAClB,mCACE,UAAW,CACX,cAAiB,CACnB,+BACE,UAAa,CACf,+BACE,UAAa,CACf,+BACE,UAAa,CACf,+BACE,UAAa,CACf,qCACE,aAAgB,CAClB,kCACE,SAAY,CACd,8CACE,qBAAwB,CAC1B,4CACE,mBAAsB,CACxB,0CACE,iBAAoB,CACtB,4CACE,mBAAsB,CACxB,2CACE,kBAAqB,CAAE,CAE3B,mCACE,kDAAqD,CAEvD,6CACE,qBAAwB,CAE1B,iCACE,gDAAmD,CAErD,2CACE,qBAAwB,CAE1B,iCACE,gDAAmD,CAErD,2CACE,qBAAwB,CAE1B,iCACE,gDAAmD,CAErD,2CACE,qBAAwB,CAE1B,iCACE,gDAAmD,CAErD,2CACE,qBAAwB,CAE1B,iCACE,gDAAmD,CAErD,2CACE,qBAAwB,CAE1B,kCACE,iDAAoD,CAEtD,4CACE,qBAAwB,CAE1B,kCACE,iDAAoD,CAEtD,4CACE,qBAAwB,CAE1B,kCACE,iDAAoD,CAEtD,4CACE,qBAAwB,CAE1B,yBACE,yCACE,kDAAqD,CACvD,mDACE,qBAAwB,CAC1B,uCACE,gDAAmD,CACrD,iDACE,qBAAwB,CAC1B,uCACE,gDAAmD,CACrD,iDACE,qBAAwB,CAC1B,uCACE,gDAAmD,CACrD,iDACE,qBAAwB,CAC1B,uCACE,gDAAmD,CACrD,iDACE,qBAAwB,CAC1B,uCACE,gDAAmD,CACrD,iDACE,qBAAwB,CAC1B,wCACE,iDAAoD,CACtD,kDACE,qBAAwB,CAC1B,wCACE,iDAAoD,CACtD,kDACE,qBAAwB,CAC1B,wCACE,iDAAoD,CACtD,kDACE,qBAAwB,CAAE,CAE9B,yBACE,yCACE,kDAAqD,CACvD,mDACE,qBAAwB,CAC1B,uCACE,gDAAmD,CACrD,iDACE,qBAAwB,CAC1B,uCACE,gDAAmD,CACrD,iDACE,qBAAwB,CAC1B,uCACE,gDAAmD,CACrD,iDACE,qBAAwB,CAC1B,uCACE,gDAAmD,CACrD,iDACE,qBAAwB,CAC1B,uCACE,gDAAmD,CACrD,iDACE,qBAAwB,CAC1B,wCACE,iDAAoD,CACtD,kDACE,qBAAwB,CAC1B,wCACE,iDAAoD,CACtD,kDACE,qBAAwB,CAC1B,wCACE,iDAAoD,CACtD,kDACE,qBAAwB,CAAE,CAE9B,yBACE,yCACE,kDAAqD,CACvD,mDACE,qBAAwB,CAC1B,uCACE,gDAAmD,CACrD,iDACE,qBAAwB,CAC1B,uCACE,gDAAmD,CACrD,iDACE,qBAAwB,CAC1B,uCACE,gDAAmD,CACrD,iDACE,qBAAwB,CAC1B,uCACE,gDAAmD,CACrD,iDACE,qBAAwB,CAC1B,uCACE,gDAAmD,CACrD,iDACE,qBAAwB,CAC1B,wCACE,iDAAoD,CACtD,kDACE,qBAAwB,CAC1B,wCACE,iDAAoD,CACtD,kDACE,qBAAwB,CAC1B,wCACE,iDAAoD,CACtD,kDACE,qBAAwB,CAAE,CAE9B,0BACE,yCACE,kDAAqD,CACvD,mDACE,qBAAwB,CAC1B,uCACE,gDAAmD,CACrD,iDACE,qBAAwB,CAC1B,uCACE,gDAAmD,CACrD,iDACE,qBAAwB,CAC1B,uCACE,gDAAmD,CACrD,iDACE,qBAAwB,CAC1B,uCACE,gDAAmD,CACrD,iDACE,qBAAwB,CAC1B,uCACE,gDAAmD,CACrD,iDACE,qBAAwB,CAC1B,wCACE,iDAAoD,CACtD,kDACE,qBAAwB,CAC1B,wCACE,iDAAoD,CACtD,kDACE,qBAAwB,CAC1B,wCACE,iDAAoD,CACtD,kDACE,qBAAwB,CAAE,CAE9B,0BACE,0CACE,kDAAqD,CACvD,oDACE,qBAAwB,CAC1B,wCACE,gDAAmD,CACrD,kDACE,qBAAwB,CAC1B,wCACE,gDAAmD,CACrD,kDACE,qBAAwB,CAC1B,wCACE,gDAAmD,CACrD,kDACE,qBAAwB,CAC1B,wCACE,gDAAmD,CACrD,kDACE,qBAAwB,CAC1B,wCACE,gDAAmD,CACrD,kDACE,qBAAwB,CAC1B,yCACE,iDAAoD,CACtD,mDACE,qBAAwB,CAC1B,yCACE,iDAAoD,CACtD,mDACE,qBAAwB,CAC1B,yCACE,iDAAoD,CACtD,mDACE,qBAAwB,CAAE,CAI5B,qEACE,kDAAqD,CAIvD,iEACE,gDAAmD,CAIrD,iEACE,gDAAmD,CAIrD,iEACE,gDAAmD,CAIrD,iEACE,gDAAmD,CAIrD,iEACE,gDAAmD,CAIrD,mEACE,iDAAoD,CAItD,mEACE,iDAAoD,CAItD,mEACE,iDAAoD,CAExD,yBAGI,iFACE,kDAAqD,CAGvD,6EACE,gDAAmD,CAGrD,6EACE,gDAAmD,CAGrD,6EACE,gDAAmD,CAGrD,6EACE,gDAAmD,CAGrD,6EACE,gDAAmD,CAGrD,+EACE,iDAAoD,CAGtD,+EACE,iDAAoD,CAGtD,+EACE,iDAAoD,CAAE,CAE5D,yBAGI,iFACE,kDAAqD,CAGvD,6EACE,gDAAmD,CAGrD,6EACE,gDAAmD,CAGrD,6EACE,gDAAmD,CAGrD,6EACE,gDAAmD,CAGrD,6EACE,gDAAmD,CAGrD,+EACE,iDAAoD,CAGtD,+EACE,iDAAoD,CAGtD,+EACE,iDAAoD,CAAE,CAE5D,yBAGI,iFACE,kDAAqD,CAGvD,6EACE,gDAAmD,CAGrD,6EACE,gDAAmD,CAGrD,6EACE,gDAAmD,CAGrD,6EACE,gDAAmD,CAGrD,6EACE,gDAAmD,CAGrD,+EACE,iDAAoD,CAGtD,+EACE,iDAAoD,CAGtD,+EACE,iDAAoD,CAAE,CAE5D,0BAGI,iFACE,kDAAqD,CAGvD,6EACE,gDAAmD,CAGrD,6EACE,gDAAmD,CAGrD,6EACE,gDAAmD,CAGrD,6EACE,gDAAmD,CAGrD,6EACE,gDAAmD,CAGrD,+EACE,iDAAoD,CAGtD,+EACE,iDAAoD,CAGtD,+EACE,iDAAoD,CAAE,CAE5D,0BAGI,mFACE,kDAAqD,CAGvD,+EACE,gDAAmD,CAGrD,+EACE,gDAAmD,CAGrD,+EACE,gDAAmD,CAGrD,+EACE,gDAAmD,CAGrD,+EACE,gDAAmD,CAGrD,iFACE,iDAAoD,CAGtD,iFACE,iDAAoD,CAGtD,iFACE,iDAAoD,CAAE,CAE5D,cACE,0DAA2D,CAC3D,8CAA+C,CAE/C,4CAA6C,CAE7C,yKAA4K,CAC5K,qCAAsC,CACtC,YAAa,CACb,8DAA+D,CAC/D,wDAAyD,CACzD,8FAA+F,CAC/F,8FAAiG,CACjG,0BACE,+CAAkD,CACpD,yBACE,cACE,kJAAsJ,CAAE,CAC5J,yBACE,cACE,sMAA2M,CAAE,CACjN,yBACE,cACE,0PAAgQ,CAAE,CACtQ,0BACE,cACE,8SAAqT,CAAE,CAC3T,0BACE,cACE,mWAA2W,CAAE,CACjX,yBACE,cACE,kJAAsJ,CAAE,CAC5J,yBACE,cACE,sMAA2M,CAAE,CACjN,yBACE,cACE,0PAAgQ,CAAE,CACtQ,0BACE,cACE,8SAAqT,CAAE,CAC3T,0BACE,cACE,mWAA2W,CAAE,CAEnX,WACE,uDAAwD,CACxD,uCAAwC,CACxC,wCAAyC,CACzC,0BAA2B,CAC3B,YAAa,CACb,gDAAoD,CACpD,yCAEE,WAAY,CACZ,YAAa,CACb,yDAA0D,CAC1D,qDAAsD,CACtD,mCAAsC,CACtC,yBACE,yCAEE,uEAA2E,CAAE,CACjF,yBACE,yCAEE,2GAAgH,CAAE,CACtH,yBACE,yCAEE,+IAAqJ,CAAE,CAC3J,0BACE,yCAEE,mLAA0L,CAAE,CAChM,0BACE,yCAEE,wNAAgO,CAAE,CACxO,4BACE,uCAA0C,CAC5C,4BACE,uCAA0C,CAC5C,4BACE,uCAA0C,CAC5C,4BACE,uCAA0C,CAC5C,4BACE,uCAA0C,CAC5C,4BACE,uCAA0C,CAC5C,4BACE,uCAA0C,CAC5C,4BACE,uCAA0C,CAC5C,4BACE,uCAA0C,CAC5C,6BACE,wCAA2C,CAC7C,6BACE,wCAA2C,CAC7C,6BACE,wCAA2C,CAC7C,oCACE,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,mCACE,wCAA2C,CAC7C,mCACE,wCAA2C,CAC7C,mCACE,wCAA2C,CAAE,CACjD,oCACE,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,mCACE,wCAA2C,CAC7C,mCACE,wCAA2C,CAC7C,mCACE,wCAA2C,CAAE,CACjD,oCACE,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,mCACE,wCAA2C,CAC7C,mCACE,wCAA2C,CAC7C,mCACE,wCAA2C,CAAE,CACjD,qCACE,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,kCACE,uCAA0C,CAC5C,mCACE,wCAA2C,CAC7C,mCACE,wCAA2C,CAC7C,mCACE,wCAA2C,CAAE,CACjD,qCACE,mCACE,uCAA0C,CAC5C,mCACE,uCAA0C,CAC5C,mCACE,uCAA0C,CAC5C,mCACE,uCAA0C,CAC5C,mCACE,uCAA0C,CAC5C,mCACE,uCAA0C,CAC5C,mCACE,uCAA0C,CAC5C,mCACE,uCAA0C,CAC5C,mCACE,uCAA0C,CAC5C,oCACE,wCAA2C,CAC7C,oCACE,wCAA2C,CAC7C,oCACE,wCAA2C,CAAE,CACjD,uBACE,uCAA0C,CAC5C,uBACE,uCAA0C,CAC5C,uBACE,uCAA0C,CAC5C,uBACE,uCAA0C,CAC5C,uBACE,uCAA0C,CAC5C,uBACE,uCAA0C,CAC5C,uBACE,uCAA0C,CAC5C,uBACE,uCAA0C,CAC5C,uBACE,uCAA0C,CAC5C,wBACE,wCAA2C,CAC7C,wBACE,wCAA2C,CAC7C,wBACE,wCAA2C,CAC7C,8BACE,8CAA2D,CAC7D,8BACE,8CAA2D,CAC7D,8BACE,8CAA2D,CAC7D,8BACE,8CAA2D,CAC7D,8BACE,8CAA2D,CAC7D,8BACE,8CAA2D,CAC7D,8BACE,8CAA2D,CAC7D,8BACE,8CAA2D,CAC7D,8BACE,+CAA2D,CAC7D,+BACE,+CAA4D,CAC9D,+BACE,+CAA4D,CAC9D,+BACE,+CAA4D,CAC9D,uBACE,eAAkB,CACpB,uBACE,eAAkB,CACpB,uBACE,eAAkB,CACpB,uBACE,eAAkB,CACpB,uBACE,eAAkB,CACpB,uBACE,eAAkB,CACpB,uBACE,eAAkB,CACpB,uBACE,eAAkB,CACpB,uBACE,eAAkB,CACpB,wBACE,gBAAmB,CACrB,wBACE,gBAAmB,CACrB,wBACE,gBAAmB,CACrB,oCACE,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,8BACE,wCAA2C,CAC7C,8BACE,wCAA2C,CAC7C,8BACE,wCAA2C,CAC7C,oCACE,8CAA2D,CAC7D,oCACE,8CAA2D,CAC7D,oCACE,8CAA2D,CAC7D,oCACE,8CAA2D,CAC7D,oCACE,8CAA2D,CAC7D,oCACE,8CAA2D,CAC7D,oCACE,8CAA2D,CAC7D,oCACE,8CAA2D,CAC7D,oCACE,+CAA2D,CAC7D,qCACE,+CAA4D,CAC9D,qCACE,+CAA4D,CAC9D,qCACE,+CAA4D,CAC9D,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,8BACE,gBAAmB,CACrB,8BACE,gBAAmB,CACrB,8BACE,gBAAmB,CAAE,CACzB,oCACE,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,8BACE,wCAA2C,CAC7C,8BACE,wCAA2C,CAC7C,8BACE,wCAA2C,CAC7C,oCACE,8CAA2D,CAC7D,oCACE,8CAA2D,CAC7D,oCACE,8CAA2D,CAC7D,oCACE,8CAA2D,CAC7D,oCACE,8CAA2D,CAC7D,oCACE,8CAA2D,CAC7D,oCACE,8CAA2D,CAC7D,oCACE,8CAA2D,CAC7D,oCACE,+CAA2D,CAC7D,qCACE,+CAA4D,CAC9D,qCACE,+CAA4D,CAC9D,qCACE,+CAA4D,CAC9D,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,8BACE,gBAAmB,CACrB,8BACE,gBAAmB,CACrB,8BACE,gBAAmB,CAAE,CACzB,oCACE,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,8BACE,wCAA2C,CAC7C,8BACE,wCAA2C,CAC7C,8BACE,wCAA2C,CAC7C,oCACE,8CAA2D,CAC7D,oCACE,8CAA2D,CAC7D,oCACE,8CAA2D,CAC7D,oCACE,8CAA2D,CAC7D,oCACE,8CAA2D,CAC7D,oCACE,8CAA2D,CAC7D,oCACE,8CAA2D,CAC7D,oCACE,8CAA2D,CAC7D,oCACE,+CAA2D,CAC7D,qCACE,+CAA4D,CAC9D,qCACE,+CAA4D,CAC9D,qCACE,+CAA4D,CAC9D,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,8BACE,gBAAmB,CACrB,8BACE,gBAAmB,CACrB,8BACE,gBAAmB,CAAE,CACzB,qCACE,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,6BACE,uCAA0C,CAC5C,8BACE,wCAA2C,CAC7C,8BACE,wCAA2C,CAC7C,8BACE,wCAA2C,CAC7C,oCACE,8CAA2D,CAC7D,oCACE,8CAA2D,CAC7D,oCACE,8CAA2D,CAC7D,oCACE,8CAA2D,CAC7D,oCACE,8CAA2D,CAC7D,oCACE,8CAA2D,CAC7D,oCACE,8CAA2D,CAC7D,oCACE,8CAA2D,CAC7D,oCACE,+CAA2D,CAC7D,qCACE,+CAA4D,CAC9D,qCACE,+CAA4D,CAC9D,qCACE,+CAA4D,CAC9D,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,6BACE,eAAkB,CACpB,8BACE,gBAAmB,CACrB,8BACE,gBAAmB,CACrB,8BACE,gBAAmB,CAAE,CACzB,qCACE,8BACE,uCAA0C,CAC5C,8BACE,uCAA0C,CAC5C,8BACE,uCAA0C,CAC5C,8BACE,uCAA0C,CAC5C,8BACE,uCAA0C,CAC5C,8BACE,uCAA0C,CAC5C,8BACE,uCAA0C,CAC5C,8BACE,uCAA0C,CAC5C,8BACE,uCAA0C,CAC5C,+BACE,wCAA2C,CAC7C,+BACE,wCAA2C,CAC7C,+BACE,wCAA2C,CAC7C,qCACE,8CAA2D,CAC7D,qCACE,8CAA2D,CAC7D,qCACE,8CAA2D,CAC7D,qCACE,8CAA2D,CAC7D,qCACE,8CAA2D,CAC7D,qCACE,8CAA2D,CAC7D,qCACE,8CAA2D,CAC7D,qCACE,8CAA2D,CAC7D,qCACE,+CAA2D,CAC7D,sCACE,+CAA4D,CAC9D,sCACE,+CAA4D,CAC9D,sCACE,+CAA4D,CAC9D,8BACE,eAAkB,CACpB,8BACE,eAAkB,CACpB,8BACE,eAAkB,CACpB,8BACE,eAAkB,CACpB,8BACE,eAAkB,CACpB,8BACE,eAAkB,CACpB,8BACE,eAAkB,CACpB,8BACE,eAAkB,CACpB,8BACE,eAAkB,CACpB,+BACE,gBAAmB,CACrB,+BACE,gBAAmB,CACrB,+BACE,gBAAmB,CAAE,CACzB,uBACE,4CAA+C,CAEnD,YACE,4DAA6D,CAC7D,YAAa,CACb,cAAe,CACf,kBAAmB,CACnB,6BAAgC,CAChC,0CACE,qDAAwD,CAE5D,YACE,4DAA6D,CAC7D,YAAa,CACb,gBAAiB,CACjB,SAAU,CACV,QAAW,CAEb,4BACE,WAAc,CAEhB,0CACE,qDAAwD,CAE1D,YACE,6DAA8D,CAC9D,YAAa,CACb,qBAAsB,CACtB,WAAc,CAEhB,4BACE,WAAc,CAEhB,0CACE,uDAA0D","file":"patternfly.min.css","sourcesContent":["@charset \"UTF-8\";\n.pf-t-light, .pf-c-accordion, .pf-c-alert, .pf-c-banner.pf-m-info, .pf-c-banner.pf-m-warning, .pf-c-calendar-month, .pf-c-chip, .pf-c-chip-group, .pf-c-context-selector__menu, .pf-c-data-list, .pf-c-form-control, .pf-c-input-group, .pf-c-menu, .pf-c-page__sidebar.pf-m-light, .pf-c-select, .pf-c-table {\n --pf-global--Color--100: var(--pf-global--Color--dark-100);\n --pf-global--Color--200: var(--pf-global--Color--dark-200);\n --pf-global--BorderColor--100: var(--pf-global--BorderColor--dark-100);\n --pf-global--primary-color--100: var(--pf-global--primary-color--dark-100);\n --pf-global--link--Color: var(--pf-global--link--Color--dark);\n --pf-global--link--Color--hover: var(--pf-global--link--Color--dark--hover);\n --pf-global--BackgroundColor--100: var(--pf-global--BackgroundColor--light-100); }\n\n.pf-t-dark, .pf-c-about-modal-box, .pf-c-banner, .pf-c-login__header, .pf-c-login__footer, .pf-c-page__header, .pf-c-page__main-section[class*=\"pf-m-dark-\"], .pf-c-wizard__header {\n --pf-global--Color--100: var(--pf-global--Color--light-100);\n --pf-global--Color--200: var(--pf-global--Color--light-200);\n --pf-global--BorderColor--100: var(--pf-global--BorderColor--light-100);\n --pf-global--primary-color--100: var(--pf-global--primary-color--light-100);\n --pf-global--link--Color: var(--pf-global--link--Color--light);\n --pf-global--link--Color--hover: var(--pf-global--link--Color--light);\n --pf-global--BackgroundColor--100: var(--pf-global--BackgroundColor--dark-100); }\n .pf-t-dark .pf-c-card, .pf-c-about-modal-box .pf-c-card, .pf-c-banner .pf-c-card, .pf-c-login__header .pf-c-card, .pf-c-login__footer .pf-c-card, .pf-c-page__header .pf-c-card, .pf-c-page__main-section[class*=\"pf-m-dark-\"] .pf-c-card, .pf-c-wizard__header .pf-c-card {\n --pf-c-card--BackgroundColor: var(--pf-global--BackgroundColor--dark-transparent-200); }\n .pf-t-dark .pf-c-button, .pf-c-about-modal-box .pf-c-button, .pf-c-banner .pf-c-button, .pf-c-login__header .pf-c-button, .pf-c-login__footer .pf-c-button, .pf-c-page__header .pf-c-button, .pf-c-page__main-section[class*=\"pf-m-dark-\"] .pf-c-button, .pf-c-wizard__header .pf-c-button {\n --pf-c-button--m-primary--Color: var(--pf-global--primary-color--dark-100);\n --pf-c-button--m-primary--hover--Color: var(--pf-global--primary-color--dark-100);\n --pf-c-button--m-primary--focus--Color: var(--pf-global--primary-color--dark-100);\n --pf-c-button--m-primary--active--Color: var(--pf-global--primary-color--dark-100);\n --pf-c-button--m-primary--BackgroundColor: var(--pf-global--BackgroundColor--light-100);\n --pf-c-button--m-primary--hover--BackgroundColor: var(--pf-global--BackgroundColor--light-300);\n --pf-c-button--m-primary--focus--BackgroundColor: var(--pf-global--BackgroundColor--light-300);\n --pf-c-button--m-primary--active--BackgroundColor: var(--pf-global--BackgroundColor--light-300);\n --pf-c-button--m-secondary--Color: var(--pf-global--Color--light-100);\n --pf-c-button--m-secondary--hover--Color: var(--pf-global--Color--light-100);\n --pf-c-button--m-secondary--focus--Color: var(--pf-global--Color--light-100);\n --pf-c-button--m-secondary--active--Color: var(--pf-global--Color--light-100);\n --pf-c-button--m-secondary--BorderColor: var(--pf-global--Color--light-100);\n --pf-c-button--m-secondary--hover--BorderColor: var(--pf-global--Color--light-100);\n --pf-c-button--m-secondary--focus--BorderColor: var(--pf-global--Color--light-100);\n --pf-c-button--m-secondary--active--BorderColor: var(--pf-global--Color--light-100); }\n\n.pf-c-data-list__item-action, .pf-c-page__header-tools-group, .pf-c-page__header-tools-item, .pf-c-table tr > * {\n --pf-hidden-visible--visible--Visibility: visible;\n --pf-hidden-visible--hidden--Display: none;\n --pf-hidden-visible--hidden--Visibility: hidden;\n --pf-hidden-visible--Display: var(--pf-hidden-visible--visible--Display);\n --pf-hidden-visible--Visibility: var(--pf-hidden-visible--visible--Visibility);\n display: var(--pf-hidden-visible--Display);\n visibility: var(--pf-hidden-visible--Visibility); }\n .pf-m-hidden.pf-c-data-list__item-action, .pf-m-hidden.pf-c-page__header-tools-group, .pf-m-hidden.pf-c-page__header-tools-item, .pf-c-table tr > .pf-m-hidden {\n --pf-hidden-visible--Display: var(--pf-hidden-visible--hidden--Display);\n --pf-hidden-visible--Visibility: var(--pf-hidden-visible--hidden--Visibility); }\n @media screen and (min-width: 576px) {\n .pf-m-hidden-on-sm.pf-c-data-list__item-action, .pf-m-hidden-on-sm.pf-c-page__header-tools-group, .pf-m-hidden-on-sm.pf-c-page__header-tools-item, .pf-c-table tr > .pf-m-hidden-on-sm {\n --pf-hidden-visible--Display: var(--pf-hidden-visible--hidden--Display);\n --pf-hidden-visible--Visibility: var(--pf-hidden-visible--hidden--Visibility); }\n .pf-m-visible-on-sm.pf-c-data-list__item-action, .pf-m-visible-on-sm.pf-c-page__header-tools-group, .pf-m-visible-on-sm.pf-c-page__header-tools-item, .pf-c-table tr > .pf-m-visible-on-sm {\n --pf-hidden-visible--Display: var(--pf-hidden-visible--visible--Display);\n --pf-hidden-visible--Visibility: var(--pf-hidden-visible--visible--Visibility); } }\n @media screen and (min-width: 768px) {\n .pf-m-hidden-on-md.pf-c-data-list__item-action, .pf-m-hidden-on-md.pf-c-page__header-tools-group, .pf-m-hidden-on-md.pf-c-page__header-tools-item, .pf-c-table tr > .pf-m-hidden-on-md {\n --pf-hidden-visible--Display: var(--pf-hidden-visible--hidden--Display);\n --pf-hidden-visible--Visibility: var(--pf-hidden-visible--hidden--Visibility); }\n .pf-m-visible-on-md.pf-c-data-list__item-action, .pf-m-visible-on-md.pf-c-page__header-tools-group, .pf-m-visible-on-md.pf-c-page__header-tools-item, .pf-c-table tr > .pf-m-visible-on-md {\n --pf-hidden-visible--Display: var(--pf-hidden-visible--visible--Display);\n --pf-hidden-visible--Visibility: var(--pf-hidden-visible--visible--Visibility); } }\n @media screen and (min-width: 992px) {\n .pf-m-hidden-on-lg.pf-c-data-list__item-action, .pf-m-hidden-on-lg.pf-c-page__header-tools-group, .pf-m-hidden-on-lg.pf-c-page__header-tools-item, .pf-c-table tr > .pf-m-hidden-on-lg {\n --pf-hidden-visible--Display: var(--pf-hidden-visible--hidden--Display);\n --pf-hidden-visible--Visibility: var(--pf-hidden-visible--hidden--Visibility); }\n .pf-m-visible-on-lg.pf-c-data-list__item-action, .pf-m-visible-on-lg.pf-c-page__header-tools-group, .pf-m-visible-on-lg.pf-c-page__header-tools-item, .pf-c-table tr > .pf-m-visible-on-lg {\n --pf-hidden-visible--Display: var(--pf-hidden-visible--visible--Display);\n --pf-hidden-visible--Visibility: var(--pf-hidden-visible--visible--Visibility); } }\n @media screen and (min-width: 1200px) {\n .pf-m-hidden-on-xl.pf-c-data-list__item-action, .pf-m-hidden-on-xl.pf-c-page__header-tools-group, .pf-m-hidden-on-xl.pf-c-page__header-tools-item, .pf-c-table tr > .pf-m-hidden-on-xl {\n --pf-hidden-visible--Display: var(--pf-hidden-visible--hidden--Display);\n --pf-hidden-visible--Visibility: var(--pf-hidden-visible--hidden--Visibility); }\n .pf-m-visible-on-xl.pf-c-data-list__item-action, .pf-m-visible-on-xl.pf-c-page__header-tools-group, .pf-m-visible-on-xl.pf-c-page__header-tools-item, .pf-c-table tr > .pf-m-visible-on-xl {\n --pf-hidden-visible--Display: var(--pf-hidden-visible--visible--Display);\n --pf-hidden-visible--Visibility: var(--pf-hidden-visible--visible--Visibility); } }\n @media screen and (min-width: 1450px) {\n .pf-m-hidden-on-2xl.pf-c-data-list__item-action, .pf-m-hidden-on-2xl.pf-c-page__header-tools-group, .pf-m-hidden-on-2xl.pf-c-page__header-tools-item, .pf-c-table tr > .pf-m-hidden-on-2xl {\n --pf-hidden-visible--Display: var(--pf-hidden-visible--hidden--Display);\n --pf-hidden-visible--Visibility: var(--pf-hidden-visible--hidden--Visibility); }\n .pf-m-visible-on-2xl.pf-c-data-list__item-action, .pf-m-visible-on-2xl.pf-c-page__header-tools-group, .pf-m-visible-on-2xl.pf-c-page__header-tools-item, .pf-c-table tr > .pf-m-visible-on-2xl {\n --pf-hidden-visible--Display: var(--pf-hidden-visible--visible--Display);\n --pf-hidden-visible--Visibility: var(--pf-hidden-visible--visible--Visibility); } }\n\n:root {\n --pf-global--palette--black-100: #fafafa;\n --pf-global--palette--black-150: #f5f5f5;\n --pf-global--palette--black-200: #f0f0f0;\n --pf-global--palette--black-300: #d2d2d2;\n --pf-global--palette--black-400: #b8bbbe;\n --pf-global--palette--black-500: #8a8d90;\n --pf-global--palette--black-600: #6a6e73;\n --pf-global--palette--black-700: #4f5255;\n --pf-global--palette--black-800: #3c3f42;\n --pf-global--palette--black-850: #212427;\n --pf-global--palette--black-900: #151515;\n --pf-global--palette--black-1000: #030303;\n --pf-global--palette--blue-50: #e7f1fa;\n --pf-global--palette--blue-100: #bee1f4;\n --pf-global--palette--blue-200: #73bcf7;\n --pf-global--palette--blue-300: #2b9af3;\n --pf-global--palette--blue-400: #06c;\n --pf-global--palette--blue-500: #004080;\n --pf-global--palette--blue-600: #002952;\n --pf-global--palette--blue-700: #001223;\n --pf-global--palette--cyan-50: #f2f9f9;\n --pf-global--palette--cyan-100: #a2d9d9;\n --pf-global--palette--cyan-200: #73c5c5;\n --pf-global--palette--cyan-300: #009596;\n --pf-global--palette--cyan-400: #005f60;\n --pf-global--palette--cyan-500: #003737;\n --pf-global--palette--cyan-600: #002323;\n --pf-global--palette--cyan-700: #000f0f;\n --pf-global--palette--gold-50: #fdf7e7;\n --pf-global--palette--gold-100: #f9e0a2;\n --pf-global--palette--gold-200: #f6d173;\n --pf-global--palette--gold-300: #f4c145;\n --pf-global--palette--gold-400: #f0ab00;\n --pf-global--palette--gold-500: #c58c00;\n --pf-global--palette--gold-600: #795600;\n --pf-global--palette--gold-700: #3d2c00;\n --pf-global--palette--green-50: #f3faf2;\n --pf-global--palette--green-100: #bde5b8;\n --pf-global--palette--green-200: #95d58e;\n --pf-global--palette--green-300: #6ec664;\n --pf-global--palette--green-400: #5ba352;\n --pf-global--palette--green-500: #3e8635;\n --pf-global--palette--green-600: #1e4f18;\n --pf-global--palette--green-700: #0f280d;\n --pf-global--palette--light-blue-100: #beedf9;\n --pf-global--palette--light-blue-200: #7cdbf3;\n --pf-global--palette--light-blue-300: #35caed;\n --pf-global--palette--light-blue-400: #00b9e4;\n --pf-global--palette--light-blue-500: #008bad;\n --pf-global--palette--light-blue-600: #005c73;\n --pf-global--palette--light-blue-700: #002d39;\n --pf-global--palette--light-green-100: #e4f5bc;\n --pf-global--palette--light-green-200: #c8eb79;\n --pf-global--palette--light-green-300: #ace12e;\n --pf-global--palette--light-green-400: #92d400;\n --pf-global--palette--light-green-500: #6ca100;\n --pf-global--palette--light-green-600: #486b00;\n --pf-global--palette--light-green-700: #253600;\n --pf-global--palette--orange-100: #f4b678;\n --pf-global--palette--orange-200: #ef9234;\n --pf-global--palette--orange-300: #ec7a08;\n --pf-global--palette--orange-400: #c46100;\n --pf-global--palette--orange-500: #8f4700;\n --pf-global--palette--orange-600: #773d00;\n --pf-global--palette--orange-700: #3b1f00;\n --pf-global--palette--purple-50: #f2f0fc;\n --pf-global--palette--purple-100: #cbc1ff;\n --pf-global--palette--purple-200: #b2a3ff;\n --pf-global--palette--purple-300: #a18fff;\n --pf-global--palette--purple-400: #8476d1;\n --pf-global--palette--purple-500: #6753ac;\n --pf-global--palette--purple-600: #40199a;\n --pf-global--palette--purple-700: #1f0066;\n --pf-global--palette--red-50: #faeae8;\n --pf-global--palette--red-100: #c9190b;\n --pf-global--palette--red-200: #a30000;\n --pf-global--palette--red-300: #7d1007;\n --pf-global--palette--red-400: #470000;\n --pf-global--palette--red-500: #2c0000;\n --pf-global--palette--white: #fff;\n --pf-global--BackgroundColor--100: #fff;\n --pf-global--BackgroundColor--200: #f0f0f0;\n --pf-global--BackgroundColor--light-100: #fff;\n --pf-global--BackgroundColor--light-200: #fafafa;\n --pf-global--BackgroundColor--light-300: #f0f0f0;\n --pf-global--BackgroundColor--dark-100: #151515;\n --pf-global--BackgroundColor--dark-200: #3c3f42;\n --pf-global--BackgroundColor--dark-300: #212427;\n --pf-global--BackgroundColor--dark-400: #4f5255;\n --pf-global--BackgroundColor--dark-transparent-100: rgba(3, 3, 3, 0.62);\n --pf-global--BackgroundColor--dark-transparent-200: rgba(3, 3, 3, 0.32);\n --pf-global--Color--100: #151515;\n --pf-global--Color--200: #6a6e73;\n --pf-global--Color--300: #3c3f42;\n --pf-global--Color--400: #8a8d90;\n --pf-global--Color--light-100: #fff;\n --pf-global--Color--light-200: #f0f0f0;\n --pf-global--Color--light-300: #d2d2d2;\n --pf-global--Color--dark-100: #151515;\n --pf-global--Color--dark-200: #6a6e73;\n --pf-global--active-color--100: #06c;\n --pf-global--active-color--200: #bee1f4;\n --pf-global--active-color--300: #2b9af3;\n --pf-global--active-color--400: #73bcf7;\n --pf-global--disabled-color--100: #6a6e73;\n --pf-global--disabled-color--200: #d2d2d2;\n --pf-global--disabled-color--300: #f0f0f0;\n --pf-global--primary-color--100: #06c;\n --pf-global--primary-color--200: #004080;\n --pf-global--primary-color--light-100: #73bcf7;\n --pf-global--primary-color--dark-100: #06c;\n --pf-global--secondary-color--100: #6a6e73;\n --pf-global--default-color--100: #73c5c5;\n --pf-global--default-color--200: #009596;\n --pf-global--default-color--300: #003737;\n --pf-global--success-color--100: #3e8635;\n --pf-global--success-color--200: #1e4f18;\n --pf-global--info-color--100: #2b9af3;\n --pf-global--info-color--200: #002952;\n --pf-global--warning-color--100: #f0ab00;\n --pf-global--warning-color--200: #795600;\n --pf-global--danger-color--100: #c9190b;\n --pf-global--danger-color--200: #a30000;\n --pf-global--danger-color--300: #470000;\n --pf-global--BoxShadow--sm: 0 0.0625rem 0.125rem 0 rgba(3, 3, 3, 0.12), 0 0 0.125rem 0 rgba(3, 3, 3, 0.06);\n --pf-global--BoxShadow--sm-top: 0 -0.125rem 0.25rem -0.0625rem rgba(3, 3, 3, 0.16);\n --pf-global--BoxShadow--sm-right: 0.125rem 0 0.25rem -0.0625rem rgba(3, 3, 3, 0.16);\n --pf-global--BoxShadow--sm-bottom: 0 0.125rem 0.25rem -0.0625rem rgba(3, 3, 3, 0.16);\n --pf-global--BoxShadow--sm-left: -0.125rem 0 0.25rem -0.0625rem rgba(3, 3, 3, 0.16);\n --pf-global--BoxShadow--md: 0 0.25rem 0.5rem 0rem rgba(3, 3, 3, 0.12), 0 0 0.25rem 0 rgba(3, 3, 3, 0.06);\n --pf-global--BoxShadow--md-top: 0 -0.5rem 0.5rem -0.375rem rgba(3, 3, 3, 0.18);\n --pf-global--BoxShadow--md-right: 0.5rem 0 0.5rem -0.375rem rgba(3, 3, 3, 0.18);\n --pf-global--BoxShadow--md-bottom: 0 0.5rem 0.5rem -0.375rem rgba(3, 3, 3, 0.18);\n --pf-global--BoxShadow--md-left: -0.5rem 0 0.5rem -0.375rem rgba(3, 3, 3, 0.18);\n --pf-global--BoxShadow--lg: 0 0.5rem 1rem 0 rgba(3, 3, 3, 0.16), 0 0 0.375rem 0 rgba(3, 3, 3, 0.08);\n --pf-global--BoxShadow--lg-top: 0 -0.75rem 0.75rem -0.5rem rgba(3, 3, 3, 0.18);\n --pf-global--BoxShadow--lg-right: 0.75rem 0 0.75rem -0.5rem rgba(3, 3, 3, 0.18);\n --pf-global--BoxShadow--lg-bottom: 0 0.75rem 0.75rem -0.5rem rgba(3, 3, 3, 0.18);\n --pf-global--BoxShadow--lg-left: -0.75rem 0 0.75rem -0.5rem rgba(3, 3, 3, 0.18);\n --pf-global--BoxShadow--xl: 0 1rem 2rem 0 rgba(3, 3, 3, 0.16), 0 0 0.5rem 0 rgba(3, 3, 3, 0.1);\n --pf-global--BoxShadow--xl-top: 0 -1rem 1rem -0.5rem rgba(3, 3, 3, 0.2);\n --pf-global--BoxShadow--xl-right: 1rem 0 1rem -0.5rem rgba(3, 3, 3, 0.2);\n --pf-global--BoxShadow--xl-bottom: 0 1rem 1rem -0.5rem rgba(3, 3, 3, 0.2);\n --pf-global--BoxShadow--xl-left: -1rem 0 1rem -0.5rem rgba(3, 3, 3, 0.2);\n --pf-global--BoxShadow--inset: inset 0 0 0.625rem 0 rgba(3, 3, 3, 0.25);\n --pf-global--font-path: \"./assets/fonts\";\n --pf-global--fonticon-path: \"./assets/pficon\";\n --pf-global--spacer--xs: 0.25rem;\n --pf-global--spacer--sm: 0.5rem;\n --pf-global--spacer--md: 1rem;\n --pf-global--spacer--lg: 1.5rem;\n --pf-global--spacer--xl: 2rem;\n --pf-global--spacer--2xl: 3rem;\n --pf-global--spacer--3xl: 4rem;\n --pf-global--spacer--4xl: 5rem;\n --pf-global--spacer--form-element: 0.375rem;\n --pf-global--gutter: 1rem;\n --pf-global--gutter--md: 1.5rem;\n --pf-global--ZIndex--xs: 100;\n --pf-global--ZIndex--sm: 200;\n --pf-global--ZIndex--md: 300;\n --pf-global--ZIndex--lg: 400;\n --pf-global--ZIndex--xl: 500;\n --pf-global--ZIndex--2xl: 600;\n --pf-global--breakpoint--xs: 0;\n --pf-global--breakpoint--sm: 576px;\n --pf-global--breakpoint--md: 768px;\n --pf-global--breakpoint--lg: 992px;\n --pf-global--breakpoint--xl: 1200px;\n --pf-global--breakpoint--2xl: 1450px;\n --pf-global--link--Color: #06c;\n --pf-global--link--Color--hover: #004080;\n --pf-global--link--Color--light: #2b9af3;\n --pf-global--link--Color--light--hover: #73bcf7;\n --pf-global--link--Color--dark: #06c;\n --pf-global--link--Color--dark--hover: #004080;\n --pf-global--link--TextDecoration: none;\n --pf-global--link--TextDecoration--hover: underline;\n --pf-global--BorderWidth--sm: 1px;\n --pf-global--BorderWidth--md: 2px;\n --pf-global--BorderWidth--lg: 3px;\n --pf-global--BorderWidth--xl: 4px;\n --pf-global--BorderColor--100: #d2d2d2;\n --pf-global--BorderColor--200: #8a8d90;\n --pf-global--BorderColor--300: #f0f0f0;\n --pf-global--BorderColor--dark-100: #d2d2d2;\n --pf-global--BorderColor--light-100: #b8bbbe;\n --pf-global--BorderRadius--sm: 3px;\n --pf-global--BorderRadius--lg: 30em;\n --pf-global--icon--Color--light: #6a6e73;\n --pf-global--icon--Color--dark: #151515;\n --pf-global--icon--FontSize--sm: 0.625rem;\n --pf-global--icon--FontSize--md: 1.125rem;\n --pf-global--icon--FontSize--lg: 1.5rem;\n --pf-global--icon--FontSize--xl: 3.375rem;\n --pf-global--FontFamily--sans-serif: \"RedHatText\", \"Overpass\", overpass, helvetica, arial, sans-serif;\n --pf-global--FontFamily--heading--sans-serif: \"RedHatDisplay\", \"Overpass\", overpass, helvetica, arial, sans-serif;\n --pf-global--FontFamily--monospace: \"Liberation Mono\", consolas, \"SFMono-Regular\", menlo, monaco, \"Courier New\", monospace;\n --pf-global--FontFamily--overpass--sans-serif: \"overpass\", overpass, \"open sans\", -apple-system, blinkmacsystemfont, \"Segoe UI\", roboto, \"Helvetica Neue\", arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n --pf-global--FontFamily--overpass--monospace: \"overpass-mono\", overpass-mono, \"SFMono-Regular\", menlo, monaco, consolas, \"Liberation Mono\", \"Courier New\", monospace;\n --pf-global--FontSize--4xl: 2.25rem;\n --pf-global--FontSize--3xl: 1.75rem;\n --pf-global--FontSize--2xl: 1.5rem;\n --pf-global--FontSize--xl: 1.25rem;\n --pf-global--FontSize--lg: 1.125rem;\n --pf-global--FontSize--md: 1rem;\n --pf-global--FontSize--sm: 0.875rem;\n --pf-global--FontSize--xs: 0.75rem;\n --pf-global--FontWeight--light: 300;\n --pf-global--FontWeight--normal: 400;\n --pf-global--FontWeight--semi-bold: 700;\n --pf-global--FontWeight--overpass--semi-bold: 500;\n --pf-global--FontWeight--bold: 700;\n --pf-global--FontWeight--overpass--bold: 600;\n --pf-global--LineHeight--sm: 1.3;\n --pf-global--LineHeight--md: 1.5;\n --pf-global--ListStyle: disc outside;\n --pf-global--Transition: all 250ms cubic-bezier(0.42, 0, 0.58, 1);\n --pf-global--TimingFunction: cubic-bezier(0.645, 0.045, 0.355, 1);\n --pf-global--TransitionDuration: 250ms;\n --pf-global--arrow--width: 0.9375rem;\n --pf-global--arrow--width-lg: 1.5625rem;\n --pf-global--target-size--MinWidth: 44px;\n --pf-global--target-size--MinHeight: 44px; }\n\n.pf-m-overpass-font {\n --pf-global--FontFamily--sans-serif: var(--pf-global--FontFamily--overpass--sans-serif);\n --pf-global--FontFamily--heading--sans-serif: var(--pf-global--FontFamily--sans-serif);\n --pf-global--FontFamily--monospace: var(--pf-global--FontFamily--overpass--monospace);\n --pf-global--FontWeight--semi-bold: var(--pf-global--FontWeight--overpass--semi-bold);\n --pf-global--FontWeight--bold: var(--pf-global--FontWeight--overpass--bold); }\n\n@font-face {\n font-family: \"RedHatDisplay\";\n src: url(\"./assets/fonts/RedHatDisplay/RedHatDisplay-Regular.eot\");\n src: url(\"./assets/fonts/RedHatDisplay/RedHatDisplay-Regular.eot?#iefix\") format(\"embedded-opentype\"), url(\"./assets/fonts/RedHatDisplay/RedHatDisplay-Regular.woff\") format(\"woff\");\n font-style: normal;\n font-weight: 300;\n text-rendering: optimizeLegibility; }\n\n@font-face {\n font-family: \"RedHatDisplay\";\n src: url(\"./assets/fonts/RedHatDisplay/RedHatDisplay-Medium.eot\");\n src: url(\"./assets/fonts/RedHatDisplay/RedHatDisplay-Medium.eot?#iefix\") format(\"embedded-opentype\"), url(\"./assets/fonts/RedHatDisplay/RedHatDisplay-Medium.woff\") format(\"woff\");\n font-style: normal;\n font-weight: 400;\n text-rendering: optimizeLegibility; }\n\n@font-face {\n font-family: \"RedHatDisplay\";\n src: url(\"./assets/fonts/RedHatDisplay/RedHatDisplay-Bold.eot\");\n src: url(\"./assets/fonts/RedHatDisplay/RedHatDisplay-Bold.eot?#iefix\") format(\"embedded-opentype\"), url(\"./assets/fonts/RedHatDisplay/RedHatDisplay-Bold.woff\") format(\"woff\");\n font-style: normal;\n font-weight: 700;\n text-rendering: optimizeLegibility; }\n\n@font-face {\n font-family: \"RedHatText\";\n src: url(\"./assets/fonts/RedHatText/RedHatText-Regular.eot\");\n src: url(\"./assets/fonts/RedHatText/RedHatText-Regular.eot?#iefix\") format(\"embedded-opentype\"), url(\"./assets/fonts/RedHatText/RedHatText-Regular.woff\") format(\"woff\");\n font-style: normal;\n font-weight: 400;\n text-rendering: optimizeLegibility; }\n\n@font-face {\n font-family: \"RedHatText\";\n src: url(\"./assets/fonts/RedHatText/RedHatText-Medium.eot\");\n src: url(\"./assets/fonts/RedHatText/RedHatText-Medium.eot?#iefix\") format(\"embedded-opentype\"), url(\"./assets/fonts/RedHatText/RedHatText-Medium.woff\") format(\"woff\");\n font-style: normal;\n font-weight: 700;\n text-rendering: optimizeLegibility; }\n\n@font-face {\n font-family: \"overpass\";\n font-style: normal;\n font-weight: 200;\n src: url(\"./assets/fonts/overpass-webfont/overpass-thin.eot\");\n src: url(\"./assets/fonts/overpass-webfont/overpass-thin.eot?#iefix\") format(\"embedded-opentype\"), url(\"./assets/fonts/overpass-webfont/overpass-thin.woff2\") format(\"woff2\"), url(\"./assets/fonts/overpass-webfont/overpass-thin.woff\") format(\"woff\"), url(\"./assets/fonts/overpass-webfont/overpass-thin.ttf\") format(\"truetype\"); }\n\n@font-face {\n font-family: \"overpass\";\n font-style: italic;\n font-weight: 200;\n src: url(\"./assets/fonts/overpass-webfont/overpass-thin-italic.eot\");\n src: url(\"./assets/fonts/overpass-webfont/overpass-thin-italic.eot?#iefix\") format(\"embedded-opentype\"), url(\"./assets/fonts/overpass-webfont/overpass-thin-italic.woff2\") format(\"woff2\"), url(\"./assets/fonts/overpass-webfont/overpass-thin-italic.woff\") format(\"woff\"), url(\"./assets/fonts/overpass-webfont/overpass-thin-italic.ttf\") format(\"truetype\"); }\n\n@font-face {\n font-family: \"overpass\";\n font-style: normal;\n font-weight: 300;\n src: url(\"./assets/fonts/overpass-webfont/overpass-extralight.eot\");\n src: url(\"./assets/fonts/overpass-webfont/overpass-extralight.eot?#iefix\") format(\"embedded-opentype\"), url(\"./assets/fonts/overpass-webfont/overpass-extralight.woff2\") format(\"woff2\"), url(\"./assets/fonts/overpass-webfont/overpass-extralight.woff\") format(\"woff\"), url(\"./assets/fonts/overpass-webfont/overpass-extralight.ttf\") format(\"truetype\"); }\n\n@font-face {\n font-family: \"overpass\";\n font-style: italic;\n font-weight: 300;\n src: url(\"./assets/fonts/overpass-webfont/overpass-extralight-italic.eot\");\n src: url(\"./assets/fonts/overpass-webfont/overpass-extralight-italic.eot?#iefix\") format(\"embedded-opentype\"), url(\"./assets/fonts/overpass-webfont/overpass-extralight-italic.woff2\") format(\"woff2\"), url(\"./assets/fonts/overpass-webfont/overpass-extralight-italic.woff\") format(\"woff\"), url(\"./assets/fonts/overpass-webfont/overpass-extralight-italic.ttf\") format(\"truetype\"); }\n\n@font-face {\n font-family: \"overpass\";\n font-style: normal;\n font-weight: 400;\n src: url(\"./assets/fonts/overpass-webfont/overpass-light.eot\");\n src: url(\"./assets/fonts/overpass-webfont/overpass-light.eot?#iefix\") format(\"embedded-opentype\"), url(\"./assets/fonts/overpass-webfont/overpass-light.woff2\") format(\"woff2\"), url(\"./assets/fonts/overpass-webfont/overpass-light.woff\") format(\"woff\"), url(\"./assets/fonts/overpass-webfont/overpass-light.ttf\") format(\"truetype\"); }\n\n@font-face {\n font-family: \"overpass\";\n font-style: italic;\n font-weight: 400;\n src: url(\"./assets/fonts/overpass-webfont/overpass-light-italic.eot\");\n src: url(\"./assets/fonts/overpass-webfont/overpass-light-italic.eot?#iefix\") format(\"embedded-opentype\"), url(\"./assets/fonts/overpass-webfont/overpass-light-italic.woff2\") format(\"woff2\"), url(\"./assets/fonts/overpass-webfont/overpass-light-italic.woff\") format(\"woff\"), url(\"./assets/fonts/overpass-webfont/overpass-light-italic.ttf\") format(\"truetype\"); }\n\n@font-face {\n font-family: \"overpass\";\n font-style: normal;\n font-weight: 500;\n src: url(\"./assets/fonts/overpass-webfont/overpass-regular.eot\");\n src: url(\"./assets/fonts/overpass-webfont/overpass-regular.eot?#iefix\") format(\"embedded-opentype\"), url(\"./assets/fonts/overpass-webfont/overpass-regular.woff2\") format(\"woff2\"), url(\"./assets/fonts/overpass-webfont/overpass-regular.woff\") format(\"woff\"), url(\"./assets/fonts/overpass-webfont/overpass-regular.ttf\") format(\"truetype\"); }\n\n@font-face {\n font-family: \"overpass\";\n font-style: italic;\n font-weight: 500;\n src: url(\"./assets/fonts/overpass-webfont/overpass-italic.eot\");\n src: url(\"./assets/fonts/overpass-webfont/overpass-italic.eot?#iefix\") format(\"embedded-opentype\"), url(\"./assets/fonts/overpass-webfont/overpass-italic.woff2\") format(\"woff2\"), url(\"./assets/fonts/overpass-webfont/overpass-italic.woff\") format(\"woff\"), url(\"./assets/fonts/overpass-webfont/overpass-italic.ttf\") format(\"truetype\"); }\n\n@font-face {\n font-family: \"overpass\";\n font-style: normal;\n font-weight: 600;\n src: url(\"./assets/fonts/overpass-webfont/overpass-semibold.eot\");\n src: url(\"./assets/fonts/overpass-webfont/overpass-semibold.eot?#iefix\") format(\"embedded-opentype\"), url(\"./assets/fonts/overpass-webfont/overpass-semibold.woff2\") format(\"woff2\"), url(\"./assets/fonts/overpass-webfont/overpass-semibold.woff\") format(\"woff\"), url(\"./assets/fonts/overpass-webfont/overpass-semibold.ttf\") format(\"truetype\"); }\n\n@font-face {\n font-family: \"overpass\";\n font-style: italic;\n font-weight: 600;\n src: url(\"./assets/fonts/overpass-webfont/overpass-semibold-italic.eot\");\n src: url(\"./assets/fonts/overpass-webfont/overpass-semibold-italic.eot?#iefix\") format(\"embedded-opentype\"), url(\"./assets/fonts/overpass-webfont/overpass-semibold-italic.woff2\") format(\"woff2\"), url(\"./assets/fonts/overpass-webfont/overpass-semibold-italic.woff\") format(\"woff\"), url(\"./assets/fonts/overpass-webfont/overpass-semibold-italic.ttf\") format(\"truetype\"); }\n\n@font-face {\n font-family: \"overpass\";\n font-style: normal;\n font-weight: 700;\n src: url(\"./assets/fonts/overpass-webfont/overpass-bold.eot\");\n src: url(\"./assets/fonts/overpass-webfont/overpass-bold.eot?#iefix\") format(\"embedded-opentype\"), url(\"./assets/fonts/overpass-webfont/overpass-bold.woff2\") format(\"woff2\"), url(\"./assets/fonts/overpass-webfont/overpass-bold.woff\") format(\"woff\"), url(\"./assets/fonts/overpass-webfont/overpass-bold.ttf\") format(\"truetype\"); }\n\n@font-face {\n font-family: \"overpass\";\n font-style: italic;\n font-weight: 700;\n src: url(\"./assets/fonts/overpass-webfont/overpass-bold-italic.eot\");\n src: url(\"./assets/fonts/overpass-webfont/overpass-bold-italic.eot?#iefix\") format(\"embedded-opentype\"), url(\"./assets/fonts/overpass-webfont/overpass-bold-italic.woff2\") format(\"woff2\"), url(\"./assets/fonts/overpass-webfont/overpass-bold-italic.woff\") format(\"woff\"), url(\"./assets/fonts/overpass-webfont/overpass-bold-italic.ttf\") format(\"truetype\"); }\n\n@font-face {\n font-family: \"overpass\";\n font-style: normal;\n font-weight: 800;\n src: url(\"./assets/fonts/overpass-webfont/overpass-extrabold.eot\");\n src: url(\"./assets/fonts/overpass-webfont/overpass-extrabold.eot?#iefix\") format(\"embedded-opentype\"), url(\"./assets/fonts/overpass-webfont/overpass-extrabold.woff2\") format(\"woff2\"), url(\"./assets/fonts/overpass-webfont/overpass-extrabold.woff\") format(\"woff\"), url(\"./assets/fonts/overpass-webfont/overpass-extrabold.ttf\") format(\"truetype\"); }\n\n@font-face {\n font-family: \"overpass\";\n font-style: italic;\n font-weight: 800;\n src: url(\"./assets/fonts/overpass-webfont/overpass-extrabold-italic.eot\");\n src: url(\"./assets/fonts/overpass-webfont/overpass-extrabold-italic.eot?#iefix\") format(\"embedded-opentype\"), url(\"./assets/fonts/overpass-webfont/overpass-extrabold-italic.woff2\") format(\"woff2\"), url(\"./assets/fonts/overpass-webfont/overpass-extrabold-italic.woff\") format(\"woff\"), url(\"./assets/fonts/overpass-webfont/overpass-extrabold-italic.ttf\") format(\"truetype\"); }\n\n@font-face {\n font-family: \"overpass\";\n font-style: normal;\n font-weight: 900;\n src: url(\"./assets/fonts/overpass-webfont/overpass-heavy.eot\");\n src: url(\"./assets/fonts/overpass-webfont/overpass-heavy.eot?#iefix\") format(\"embedded-opentype\"), url(\"./assets/fonts/overpass-webfont/overpass-heavy.woff2\") format(\"woff2\"), url(\"./assets/fonts/overpass-webfont/overpass-heavy.woff\") format(\"woff\"), url(\"./assets/fonts/overpass-webfont/overpass-heavy.ttf\") format(\"truetype\"); }\n\n@font-face {\n font-family: \"overpass\";\n font-style: italic;\n font-weight: 900;\n src: url(\"./assets/fonts/overpass-webfont/overpass-heavy-italic.eot\");\n src: url(\"./assets/fonts/overpass-webfont/overpass-heavy-italic.eot?#iefix\") format(\"embedded-opentype\"), url(\"./assets/fonts/overpass-webfont/overpass-heavy-italic.woff2\") format(\"woff2\"), url(\"./assets/fonts/overpass-webfont/overpass-heavy-italic.woff\") format(\"woff\"), url(\"./assets/fonts/overpass-webfont/overpass-heavy-italic.ttf\") format(\"truetype\"); }\n\n@font-face {\n font-family: \"overpass-mono\";\n font-style: normal;\n font-weight: 300;\n src: url(\"./assets/fonts/overpass-mono-webfont/overpass-mono-light.eot\");\n src: url(\"./assets/fonts/overpass-mono-webfont/overpass-mono-light.eot?#iefix\") format(\"embedded-opentype\"), url(\"./assets/fonts/overpass-mono-webfont/overpass-mono-light.woff2\") format(\"woff2\"), url(\"./assets/fonts/overpass-mono-webfont/overpass-mono-light.woff\") format(\"woff\"), url(\"./assets/fonts/overpass-mono-webfont/overpass-mono-light.ttf\") format(\"truetype\"); }\n\n@font-face {\n font-family: \"overpass-mono\";\n font-style: normal;\n font-weight: 400;\n src: url(\"./assets/fonts/overpass-mono-webfont/overpass-mono-regular.eot\");\n src: url(\"./assets/fonts/overpass-mono-webfont/overpass-mono-regular.eot?#iefix\") format(\"embedded-opentype\"), url(\"./assets/fonts/overpass-mono-webfont/overpass-mono-regular.woff2\") format(\"woff2\"), url(\"./assets/fonts/overpass-mono-webfont/overpass-mono-regular.woff\") format(\"woff\"), url(\"./assets/fonts/overpass-mono-webfont/overpass-mono-regular.ttf\") format(\"truetype\"); }\n\n@font-face {\n font-family: \"overpass-mono\";\n font-style: normal;\n font-weight: 500;\n src: url(\"./assets/fonts/overpass-mono-webfont/overpass-mono-semibold.eot\");\n src: url(\"./assets/fonts/overpass-mono-webfont/overpass-mono-semibold.eot?#iefix\") format(\"embedded-opentype\"), url(\"./assets/fonts/overpass-mono-webfont/overpass-mono-semibold.woff2\") format(\"woff2\"), url(\"./assets/fonts/overpass-mono-webfont/overpass-mono-semibold.woff\") format(\"woff\"), url(\"./assets/fonts/overpass-mono-webfont/overpass-mono-semibold.ttf\") format(\"truetype\"); }\n\n@font-face {\n font-family: \"overpass-mono\";\n font-style: normal;\n font-weight: 600;\n src: url(\"./assets/fonts/overpass-mono-webfont/overpass-mono-bold.eot\");\n src: url(\"./assets/fonts/overpass-mono-webfont/overpass-mono-bold.eot?#iefix\") format(\"embedded-opentype\"), url(\"./assets/fonts/overpass-mono-webfont/overpass-mono-bold.woff2\") format(\"woff2\"), url(\"./assets/fonts/overpass-mono-webfont/overpass-mono-bold.woff\") format(\"woff\"), url(\"./assets/fonts/overpass-mono-webfont/overpass-mono-bold.ttf\") format(\"truetype\"); }\n\n[class*=\"pf-c-\"], [class*=\"pf-c-\"]::before, [class*=\"pf-c-\"]::after {\n padding: 0;\n margin: 0;\n background-color: transparent; }\n\nhtml {\n font-size: unset !important; }\n\n.pf-screen-reader {\n position: fixed;\n top: 0;\n left: 0;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0; }\n\nhtml,\nbody,\np,\nol,\nul,\nli,\ndl,\ndt,\ndd,\nblockquote,\nfigure,\nfieldset,\nlegend,\ntextarea,\npre,\niframe,\nhr,\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n padding: 0;\n margin: 0; }\n\nhtml,\nbody {\n height: 100%; }\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n font-size: 100%;\n font-weight: var(--pf-global--FontWeight--normal); }\n\nul {\n list-style: none; }\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n margin: 0;\n font-family: inherit;\n font-size: 100%;\n line-height: var(--pf-global--LineHeight--md);\n color: var(--pf-global--Color--100); }\n\nimg,\nembed,\niframe,\nobject,\naudio,\nvideo {\n max-width: 100%;\n height: auto; }\n\niframe {\n border: 0; }\n\ntable {\n border-spacing: 0;\n border-collapse: collapse; }\n\ntd,\nth {\n padding: 0;\n text-align: left; }\n\n*,\n*::before,\n*::after {\n box-sizing: border-box; }\n\nhtml {\n font-family: sans-serif;\n line-height: 1.15; }\n\nbody {\n font-family: var(--pf-global--FontFamily--sans-serif);\n font-size: var(--pf-global--FontSize--md);\n font-weight: var(--pf-global--FontWeight--normal);\n line-height: var(--pf-global--LineHeight--md);\n text-align: left;\n background-color: var(--pf-global--BackgroundColor--100); }\n\na {\n font-weight: var(--pf-global--link--FontWeight);\n color: var(--pf-global--link--Color);\n text-decoration: var(--pf-global--link--TextDecoration); }\n a:hover {\n --pf-global--link--Color: var(--pf-global--link--Color--hover);\n --pf-global--link--TextDecoration: var(--pf-global--link--TextDecoration--hover); }\n\nbutton,\na {\n cursor: pointer; }\n\nbutton::-moz-focus-inner,\n[type=\"button\"]::-moz-focus-inner,\n[type=\"reset\"]::-moz-focus-inner,\n[type=\"submit\"]::-moz-focus-inner {\n padding: 0;\n border-style: none; }\n\nbutton:-moz-focusring,\n[type=\"button\"]:-moz-focusring,\n[type=\"reset\"]:-moz-focusring,\n[type=\"submit\"]:-moz-focusring {\n outline: 1px dotted ButtonText; }\n\n.pf-m-overpass-font a {\n font-weight: var(--pf-global--FontWeight--semi-bold); }\n\n.pf-t-dark.pf-m-transparent {\n background-color: transparent; }\n\n.pf-t-dark.pf-m-transparent-100 {\n background-color: rgba(3, 3, 3, 0.42); }\n\n.pf-t-dark.pf-m-transparent-200 {\n background-color: rgba(3, 3, 3, 0.6); }\n\n.pf-t-dark.pf-m-opaque-100 {\n background-color: #3c3f42; }\n\n.pf-t-dark.pf-m-opaque-200 {\n background-color: #151515; }\n\n.pf-t-light.pf-m-transparent {\n background-color: transparent; }\n\n.pf-t-light.pf-m-opaque-100 {\n background-color: #fff; }\n\n.pf-t-light.pf-m-opaque-200 {\n background-color: #fafafa; }\n\n.pf-t-light.pf-m-opaque-300 {\n background-color: #f0f0f0; }\n\n* .fa,\n* .fas,\n* .far,\n* .fal,\n* .fab {\n -moz-osx-font-smoothing: grayscale;\n -webkit-font-smoothing: antialiased;\n display: inline-block;\n font-style: normal;\n font-variant: normal;\n text-rendering: auto;\n line-height: 1; }\n\n* .fa-lg {\n font-size: 1.33333em;\n line-height: 0.75em;\n vertical-align: -.0667em; }\n\n* .fa-xs {\n font-size: .75em; }\n\n* .fa-sm {\n font-size: .875em; }\n\n* .fa-1x {\n font-size: 1em; }\n\n* .fa-2x {\n font-size: 2em; }\n\n* .fa-3x {\n font-size: 3em; }\n\n* .fa-4x {\n font-size: 4em; }\n\n* .fa-5x {\n font-size: 5em; }\n\n* .fa-6x {\n font-size: 6em; }\n\n* .fa-7x {\n font-size: 7em; }\n\n* .fa-8x {\n font-size: 8em; }\n\n* .fa-9x {\n font-size: 9em; }\n\n* .fa-10x {\n font-size: 10em; }\n\n* .fa-fw {\n text-align: center;\n width: 1.25em; }\n\n* .fa-ul {\n list-style-type: none;\n margin-left: 2.5em;\n padding-left: 0; }\n * .fa-ul > li {\n position: relative; }\n\n* .fa-li {\n left: -2em;\n position: absolute;\n text-align: center;\n width: 2em;\n line-height: inherit; }\n\n* .fa-border {\n border: solid 0.08em #eee;\n border-radius: .1em;\n padding: .2em .25em .15em; }\n\n* .fa-pull-left {\n float: left; }\n\n* .fa-pull-right {\n float: right; }\n\n* .fa.fa-pull-left,\n* .fas.fa-pull-left,\n* .far.fa-pull-left,\n* .fal.fa-pull-left,\n* .fab.fa-pull-left {\n margin-right: .3em; }\n\n* .fa.fa-pull-right,\n* .fas.fa-pull-right,\n* .far.fa-pull-right,\n* .fal.fa-pull-right,\n* .fab.fa-pull-right {\n margin-left: .3em; }\n\n* .fa-spin {\n animation: fa-spin 2s infinite linear; }\n\n* .fa-pulse {\n animation: fa-spin 1s infinite steps(8); }\n\n@keyframes fa-spin {\n 0% {\n transform: rotate(0deg); }\n 100% {\n transform: rotate(360deg); } }\n\n* .fa-rotate-90 {\n -ms-filter: \"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)\";\n transform: rotate(90deg); }\n\n* .fa-rotate-180 {\n -ms-filter: \"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)\";\n transform: rotate(180deg); }\n\n* .fa-rotate-270 {\n -ms-filter: \"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)\";\n transform: rotate(270deg); }\n\n* .fa-flip-horizontal {\n -ms-filter: \"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)\";\n transform: scale(-1, 1); }\n\n* .fa-flip-vertical {\n -ms-filter: \"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)\";\n transform: scale(1, -1); }\n\n* .fa-flip-horizontal.fa-flip-vertical {\n -ms-filter: \"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)\";\n transform: scale(-1, -1); }\n\n* :root .fa-rotate-90,\n* :root .fa-rotate-180,\n* :root .fa-rotate-270,\n* :root .fa-flip-horizontal,\n* :root .fa-flip-vertical {\n filter: none; }\n\n* .fa-stack {\n display: inline-block;\n height: 2em;\n line-height: 2em;\n position: relative;\n vertical-align: middle;\n width: 2.5em; }\n\n* .fa-stack-1x,\n* .fa-stack-2x {\n left: 0;\n position: absolute;\n text-align: center;\n width: 100%; }\n\n* .fa-stack-1x {\n line-height: inherit; }\n\n\n* .fa-stack-2x {\n font-size: 2em; }\n\n* .fa-inverse {\n color: #fff; }\n\n* .fa-500px:before {\n content: \"\\f26e\"; }\n\n* .fa-accessible-icon:before {\n content: \"\\f368\"; }\n\n* .fa-accusoft:before {\n content: \"\\f369\"; }\n\n* .fa-acquisitions-incorporated:before {\n content: \"\\f6af\"; }\n\n* .fa-ad:before {\n content: \"\\f641\"; }\n\n* .fa-address-book:before {\n content: \"\\f2b9\"; }\n\n* .fa-address-card:before {\n content: \"\\f2bb\"; }\n\n* .fa-adjust:before {\n content: \"\\f042\"; }\n\n* .fa-adn:before {\n content: \"\\f170\"; }\n\n* .fa-adobe:before {\n content: \"\\f778\"; }\n\n* .fa-adversal:before {\n content: \"\\f36a\"; }\n\n* .fa-affiliatetheme:before {\n content: \"\\f36b\"; }\n\n* .fa-air-freshener:before {\n content: \"\\f5d0\"; }\n\n* .fa-algolia:before {\n content: \"\\f36c\"; }\n\n* .fa-align-center:before {\n content: \"\\f037\"; }\n\n* .fa-align-justify:before {\n content: \"\\f039\"; }\n\n* .fa-align-left:before {\n content: \"\\f036\"; }\n\n* .fa-align-right:before {\n content: \"\\f038\"; }\n\n* .fa-alipay:before {\n content: \"\\f642\"; }\n\n* .fa-allergies:before {\n content: \"\\f461\"; }\n\n* .fa-amazon:before {\n content: \"\\f270\"; }\n\n* .fa-amazon-pay:before {\n content: \"\\f42c\"; }\n\n* .fa-ambulance:before {\n content: \"\\f0f9\"; }\n\n* .fa-american-sign-language-interpreting:before {\n content: \"\\f2a3\"; }\n\n* .fa-amilia:before {\n content: \"\\f36d\"; }\n\n* .fa-anchor:before {\n content: \"\\f13d\"; }\n\n* .fa-android:before {\n content: \"\\f17b\"; }\n\n* .fa-angellist:before {\n content: \"\\f209\"; }\n\n* .fa-angle-double-down:before {\n content: \"\\f103\"; }\n\n* .fa-angle-double-left:before {\n content: \"\\f100\"; }\n\n* .fa-angle-double-right:before {\n content: \"\\f101\"; }\n\n* .fa-angle-double-up:before {\n content: \"\\f102\"; }\n\n* .fa-angle-down:before {\n content: \"\\f107\"; }\n\n* .fa-angle-left:before {\n content: \"\\f104\"; }\n\n* .fa-angle-right:before {\n content: \"\\f105\"; }\n\n* .fa-angle-up:before {\n content: \"\\f106\"; }\n\n* .fa-angry:before {\n content: \"\\f556\"; }\n\n* .fa-angrycreative:before {\n content: \"\\f36e\"; }\n\n* .fa-angular:before {\n content: \"\\f420\"; }\n\n* .fa-ankh:before {\n content: \"\\f644\"; }\n\n* .fa-app-store:before {\n content: \"\\f36f\"; }\n\n* .fa-app-store-ios:before {\n content: \"\\f370\"; }\n\n* .fa-apper:before {\n content: \"\\f371\"; }\n\n* .fa-apple:before {\n content: \"\\f179\"; }\n\n* .fa-apple-alt:before {\n content: \"\\f5d1\"; }\n\n* .fa-apple-pay:before {\n content: \"\\f415\"; }\n\n* .fa-archive:before {\n content: \"\\f187\"; }\n\n* .fa-archway:before {\n content: \"\\f557\"; }\n\n* .fa-arrow-alt-circle-down:before {\n content: \"\\f358\"; }\n\n* .fa-arrow-alt-circle-left:before {\n content: \"\\f359\"; }\n\n* .fa-arrow-alt-circle-right:before {\n content: \"\\f35a\"; }\n\n* .fa-arrow-alt-circle-up:before {\n content: \"\\f35b\"; }\n\n* .fa-arrow-circle-down:before {\n content: \"\\f0ab\"; }\n\n* .fa-arrow-circle-left:before {\n content: \"\\f0a8\"; }\n\n* .fa-arrow-circle-right:before {\n content: \"\\f0a9\"; }\n\n* .fa-arrow-circle-up:before {\n content: \"\\f0aa\"; }\n\n* .fa-arrow-down:before {\n content: \"\\f063\"; }\n\n* .fa-arrow-left:before {\n content: \"\\f060\"; }\n\n* .fa-arrow-right:before {\n content: \"\\f061\"; }\n\n* .fa-arrow-up:before {\n content: \"\\f062\"; }\n\n* .fa-arrows-alt:before {\n content: \"\\f0b2\"; }\n\n* .fa-arrows-alt-h:before {\n content: \"\\f337\"; }\n\n* .fa-arrows-alt-v:before {\n content: \"\\f338\"; }\n\n* .fa-artstation:before {\n content: \"\\f77a\"; }\n\n* .fa-assistive-listening-systems:before {\n content: \"\\f2a2\"; }\n\n* .fa-asterisk:before {\n content: \"\\f069\"; }\n\n* .fa-asymmetrik:before {\n content: \"\\f372\"; }\n\n* .fa-at:before {\n content: \"\\f1fa\"; }\n\n* .fa-atlas:before {\n content: \"\\f558\"; }\n\n* .fa-atlassian:before {\n content: \"\\f77b\"; }\n\n* .fa-atom:before {\n content: \"\\f5d2\"; }\n\n* .fa-audible:before {\n content: \"\\f373\"; }\n\n* .fa-audio-description:before {\n content: \"\\f29e\"; }\n\n* .fa-autoprefixer:before {\n content: \"\\f41c\"; }\n\n* .fa-avianex:before {\n content: \"\\f374\"; }\n\n* .fa-aviato:before {\n content: \"\\f421\"; }\n\n* .fa-award:before {\n content: \"\\f559\"; }\n\n* .fa-aws:before {\n content: \"\\f375\"; }\n\n* .fa-baby:before {\n content: \"\\f77c\"; }\n\n* .fa-baby-carriage:before {\n content: \"\\f77d\"; }\n\n* .fa-backspace:before {\n content: \"\\f55a\"; }\n\n* .fa-backward:before {\n content: \"\\f04a\"; }\n\n* .fa-balance-scale:before {\n content: \"\\f24e\"; }\n\n* .fa-ban:before {\n content: \"\\f05e\"; }\n\n* .fa-band-aid:before {\n content: \"\\f462\"; }\n\n* .fa-bandcamp:before {\n content: \"\\f2d5\"; }\n\n* .fa-barcode:before {\n content: \"\\f02a\"; }\n\n* .fa-bars:before {\n content: \"\\f0c9\"; }\n\n* .fa-baseball-ball:before {\n content: \"\\f433\"; }\n\n* .fa-basketball-ball:before {\n content: \"\\f434\"; }\n\n* .fa-bath:before {\n content: \"\\f2cd\"; }\n\n* .fa-battery-empty:before {\n content: \"\\f244\"; }\n\n* .fa-battery-full:before {\n content: \"\\f240\"; }\n\n* .fa-battery-half:before {\n content: \"\\f242\"; }\n\n* .fa-battery-quarter:before {\n content: \"\\f243\"; }\n\n* .fa-battery-three-quarters:before {\n content: \"\\f241\"; }\n\n* .fa-bed:before {\n content: \"\\f236\"; }\n\n* .fa-beer:before {\n content: \"\\f0fc\"; }\n\n* .fa-behance:before {\n content: \"\\f1b4\"; }\n\n* .fa-behance-square:before {\n content: \"\\f1b5\"; }\n\n* .fa-bell:before {\n content: \"\\f0f3\"; }\n\n* .fa-bell-slash:before {\n content: \"\\f1f6\"; }\n\n* .fa-bezier-curve:before {\n content: \"\\f55b\"; }\n\n* .fa-bible:before {\n content: \"\\f647\"; }\n\n* .fa-bicycle:before {\n content: \"\\f206\"; }\n\n* .fa-bimobject:before {\n content: \"\\f378\"; }\n\n* .fa-binoculars:before {\n content: \"\\f1e5\"; }\n\n* .fa-biohazard:before {\n content: \"\\f780\"; }\n\n* .fa-birthday-cake:before {\n content: \"\\f1fd\"; }\n\n* .fa-bitbucket:before {\n content: \"\\f171\"; }\n\n* .fa-bitcoin:before {\n content: \"\\f379\"; }\n\n* .fa-bity:before {\n content: \"\\f37a\"; }\n\n* .fa-black-tie:before {\n content: \"\\f27e\"; }\n\n* .fa-blackberry:before {\n content: \"\\f37b\"; }\n\n* .fa-blender:before {\n content: \"\\f517\"; }\n\n* .fa-blender-phone:before {\n content: \"\\f6b6\"; }\n\n* .fa-blind:before {\n content: \"\\f29d\"; }\n\n* .fa-blog:before {\n content: \"\\f781\"; }\n\n* .fa-blogger:before {\n content: \"\\f37c\"; }\n\n* .fa-blogger-b:before {\n content: \"\\f37d\"; }\n\n* .fa-bluetooth:before {\n content: \"\\f293\"; }\n\n* .fa-bluetooth-b:before {\n content: \"\\f294\"; }\n\n* .fa-bold:before {\n content: \"\\f032\"; }\n\n* .fa-bolt:before {\n content: \"\\f0e7\"; }\n\n* .fa-bomb:before {\n content: \"\\f1e2\"; }\n\n* .fa-bone:before {\n content: \"\\f5d7\"; }\n\n* .fa-bong:before {\n content: \"\\f55c\"; }\n\n* .fa-book:before {\n content: \"\\f02d\"; }\n\n* .fa-book-dead:before {\n content: \"\\f6b7\"; }\n\n* .fa-book-open:before {\n content: \"\\f518\"; }\n\n* .fa-book-reader:before {\n content: \"\\f5da\"; }\n\n* .fa-bookmark:before {\n content: \"\\f02e\"; }\n\n* .fa-bowling-ball:before {\n content: \"\\f436\"; }\n\n* .fa-box:before {\n content: \"\\f466\"; }\n\n* .fa-box-open:before {\n content: \"\\f49e\"; }\n\n* .fa-boxes:before {\n content: \"\\f468\"; }\n\n* .fa-braille:before {\n content: \"\\f2a1\"; }\n\n* .fa-brain:before {\n content: \"\\f5dc\"; }\n\n* .fa-briefcase:before {\n content: \"\\f0b1\"; }\n\n* .fa-briefcase-medical:before {\n content: \"\\f469\"; }\n\n* .fa-broadcast-tower:before {\n content: \"\\f519\"; }\n\n* .fa-broom:before {\n content: \"\\f51a\"; }\n\n* .fa-brush:before {\n content: \"\\f55d\"; }\n\n* .fa-btc:before {\n content: \"\\f15a\"; }\n\n* .fa-bug:before {\n content: \"\\f188\"; }\n\n* .fa-building:before {\n content: \"\\f1ad\"; }\n\n* .fa-bullhorn:before {\n content: \"\\f0a1\"; }\n\n* .fa-bullseye:before {\n content: \"\\f140\"; }\n\n* .fa-burn:before {\n content: \"\\f46a\"; }\n\n* .fa-buromobelexperte:before {\n content: \"\\f37f\"; }\n\n* .fa-bus:before {\n content: \"\\f207\"; }\n\n* .fa-bus-alt:before {\n content: \"\\f55e\"; }\n\n* .fa-business-time:before {\n content: \"\\f64a\"; }\n\n* .fa-buysellads:before {\n content: \"\\f20d\"; }\n\n* .fa-calculator:before {\n content: \"\\f1ec\"; }\n\n* .fa-calendar:before {\n content: \"\\f133\"; }\n\n* .fa-calendar-alt:before {\n content: \"\\f073\"; }\n\n* .fa-calendar-check:before {\n content: \"\\f274\"; }\n\n* .fa-calendar-day:before {\n content: \"\\f783\"; }\n\n* .fa-calendar-minus:before {\n content: \"\\f272\"; }\n\n* .fa-calendar-plus:before {\n content: \"\\f271\"; }\n\n* .fa-calendar-times:before {\n content: \"\\f273\"; }\n\n* .fa-calendar-week:before {\n content: \"\\f784\"; }\n\n* .fa-camera:before {\n content: \"\\f030\"; }\n\n* .fa-camera-retro:before {\n content: \"\\f083\"; }\n\n* .fa-campground:before {\n content: \"\\f6bb\"; }\n\n* .fa-canadian-maple-leaf:before {\n content: \"\\f785\"; }\n\n* .fa-candy-cane:before {\n content: \"\\f786\"; }\n\n* .fa-cannabis:before {\n content: \"\\f55f\"; }\n\n* .fa-capsules:before {\n content: \"\\f46b\"; }\n\n* .fa-car:before {\n content: \"\\f1b9\"; }\n\n* .fa-car-alt:before {\n content: \"\\f5de\"; }\n\n* .fa-car-battery:before {\n content: \"\\f5df\"; }\n\n* .fa-car-crash:before {\n content: \"\\f5e1\"; }\n\n* .fa-car-side:before {\n content: \"\\f5e4\"; }\n\n* .fa-caret-down:before {\n content: \"\\f0d7\"; }\n\n* .fa-caret-left:before {\n content: \"\\f0d9\"; }\n\n* .fa-caret-right:before {\n content: \"\\f0da\"; }\n\n* .fa-caret-square-down:before {\n content: \"\\f150\"; }\n\n* .fa-caret-square-left:before {\n content: \"\\f191\"; }\n\n* .fa-caret-square-right:before {\n content: \"\\f152\"; }\n\n* .fa-caret-square-up:before {\n content: \"\\f151\"; }\n\n* .fa-caret-up:before {\n content: \"\\f0d8\"; }\n\n* .fa-carrot:before {\n content: \"\\f787\"; }\n\n* .fa-cart-arrow-down:before {\n content: \"\\f218\"; }\n\n* .fa-cart-plus:before {\n content: \"\\f217\"; }\n\n* .fa-cash-register:before {\n content: \"\\f788\"; }\n\n* .fa-cat:before {\n content: \"\\f6be\"; }\n\n* .fa-cc-amazon-pay:before {\n content: \"\\f42d\"; }\n\n* .fa-cc-amex:before {\n content: \"\\f1f3\"; }\n\n* .fa-cc-apple-pay:before {\n content: \"\\f416\"; }\n\n* .fa-cc-diners-club:before {\n content: \"\\f24c\"; }\n\n* .fa-cc-discover:before {\n content: \"\\f1f2\"; }\n\n* .fa-cc-jcb:before {\n content: \"\\f24b\"; }\n\n* .fa-cc-mastercard:before {\n content: \"\\f1f1\"; }\n\n* .fa-cc-paypal:before {\n content: \"\\f1f4\"; }\n\n* .fa-cc-stripe:before {\n content: \"\\f1f5\"; }\n\n* .fa-cc-visa:before {\n content: \"\\f1f0\"; }\n\n* .fa-centercode:before {\n content: \"\\f380\"; }\n\n* .fa-centos:before {\n content: \"\\f789\"; }\n\n* .fa-certificate:before {\n content: \"\\f0a3\"; }\n\n* .fa-chair:before {\n content: \"\\f6c0\"; }\n\n* .fa-chalkboard:before {\n content: \"\\f51b\"; }\n\n* .fa-chalkboard-teacher:before {\n content: \"\\f51c\"; }\n\n* .fa-charging-station:before {\n content: \"\\f5e7\"; }\n\n* .fa-chart-area:before {\n content: \"\\f1fe\"; }\n\n* .fa-chart-bar:before {\n content: \"\\f080\"; }\n\n* .fa-chart-line:before {\n content: \"\\f201\"; }\n\n* .fa-chart-pie:before {\n content: \"\\f200\"; }\n\n* .fa-check:before {\n content: \"\\f00c\"; }\n\n* .fa-check-circle:before {\n content: \"\\f058\"; }\n\n* .fa-check-double:before {\n content: \"\\f560\"; }\n\n* .fa-check-square:before {\n content: \"\\f14a\"; }\n\n* .fa-chess:before {\n content: \"\\f439\"; }\n\n* .fa-chess-bishop:before {\n content: \"\\f43a\"; }\n\n* .fa-chess-board:before {\n content: \"\\f43c\"; }\n\n* .fa-chess-king:before {\n content: \"\\f43f\"; }\n\n* .fa-chess-knight:before {\n content: \"\\f441\"; }\n\n* .fa-chess-pawn:before {\n content: \"\\f443\"; }\n\n* .fa-chess-queen:before {\n content: \"\\f445\"; }\n\n* .fa-chess-rook:before {\n content: \"\\f447\"; }\n\n* .fa-chevron-circle-down:before {\n content: \"\\f13a\"; }\n\n* .fa-chevron-circle-left:before {\n content: \"\\f137\"; }\n\n* .fa-chevron-circle-right:before {\n content: \"\\f138\"; }\n\n* .fa-chevron-circle-up:before {\n content: \"\\f139\"; }\n\n* .fa-chevron-down:before {\n content: \"\\f078\"; }\n\n* .fa-chevron-left:before {\n content: \"\\f053\"; }\n\n* .fa-chevron-right:before {\n content: \"\\f054\"; }\n\n* .fa-chevron-up:before {\n content: \"\\f077\"; }\n\n* .fa-child:before {\n content: \"\\f1ae\"; }\n\n* .fa-chrome:before {\n content: \"\\f268\"; }\n\n* .fa-church:before {\n content: \"\\f51d\"; }\n\n* .fa-circle:before {\n content: \"\\f111\"; }\n\n* .fa-circle-notch:before {\n content: \"\\f1ce\"; }\n\n* .fa-city:before {\n content: \"\\f64f\"; }\n\n* .fa-clipboard:before {\n content: \"\\f328\"; }\n\n* .fa-clipboard-check:before {\n content: \"\\f46c\"; }\n\n* .fa-clipboard-list:before {\n content: \"\\f46d\"; }\n\n* .fa-clock:before {\n content: \"\\f017\"; }\n\n* .fa-clone:before {\n content: \"\\f24d\"; }\n\n* .fa-closed-captioning:before {\n content: \"\\f20a\"; }\n\n* .fa-cloud:before {\n content: \"\\f0c2\"; }\n\n* .fa-cloud-download-alt:before {\n content: \"\\f381\"; }\n\n* .fa-cloud-meatball:before {\n content: \"\\f73b\"; }\n\n* .fa-cloud-moon:before {\n content: \"\\f6c3\"; }\n\n* .fa-cloud-moon-rain:before {\n content: \"\\f73c\"; }\n\n* .fa-cloud-rain:before {\n content: \"\\f73d\"; }\n\n* .fa-cloud-showers-heavy:before {\n content: \"\\f740\"; }\n\n* .fa-cloud-sun:before {\n content: \"\\f6c4\"; }\n\n* .fa-cloud-sun-rain:before {\n content: \"\\f743\"; }\n\n* .fa-cloud-upload-alt:before {\n content: \"\\f382\"; }\n\n* .fa-cloudscale:before {\n content: \"\\f383\"; }\n\n* .fa-cloudsmith:before {\n content: \"\\f384\"; }\n\n* .fa-cloudversify:before {\n content: \"\\f385\"; }\n\n* .fa-cocktail:before {\n content: \"\\f561\"; }\n\n* .fa-code:before {\n content: \"\\f121\"; }\n\n* .fa-code-branch:before {\n content: \"\\f126\"; }\n\n* .fa-codepen:before {\n content: \"\\f1cb\"; }\n\n* .fa-codiepie:before {\n content: \"\\f284\"; }\n\n* .fa-coffee:before {\n content: \"\\f0f4\"; }\n\n* .fa-cog:before {\n content: \"\\f013\"; }\n\n* .fa-cogs:before {\n content: \"\\f085\"; }\n\n* .fa-coins:before {\n content: \"\\f51e\"; }\n\n* .fa-columns:before {\n content: \"\\f0db\"; }\n\n* .fa-comment:before {\n content: \"\\f075\"; }\n\n* .fa-comment-alt:before {\n content: \"\\f27a\"; }\n\n* .fa-comment-dollar:before {\n content: \"\\f651\"; }\n\n* .fa-comment-dots:before {\n content: \"\\f4ad\"; }\n\n* .fa-comment-slash:before {\n content: \"\\f4b3\"; }\n\n* .fa-comments:before {\n content: \"\\f086\"; }\n\n* .fa-comments-dollar:before {\n content: \"\\f653\"; }\n\n* .fa-compact-disc:before {\n content: \"\\f51f\"; }\n\n* .fa-compass:before {\n content: \"\\f14e\"; }\n\n* .fa-compress:before {\n content: \"\\f066\"; }\n\n* .fa-compress-arrows-alt:before {\n content: \"\\f78c\"; }\n\n* .fa-concierge-bell:before {\n content: \"\\f562\"; }\n\n* .fa-confluence:before {\n content: \"\\f78d\"; }\n\n* .fa-connectdevelop:before {\n content: \"\\f20e\"; }\n\n* .fa-contao:before {\n content: \"\\f26d\"; }\n\n* .fa-cookie:before {\n content: \"\\f563\"; }\n\n* .fa-cookie-bite:before {\n content: \"\\f564\"; }\n\n* .fa-copy:before {\n content: \"\\f0c5\"; }\n\n* .fa-copyright:before {\n content: \"\\f1f9\"; }\n\n* .fa-couch:before {\n content: \"\\f4b8\"; }\n\n* .fa-cpanel:before {\n content: \"\\f388\"; }\n\n* .fa-creative-commons:before {\n content: \"\\f25e\"; }\n\n* .fa-creative-commons-by:before {\n content: \"\\f4e7\"; }\n\n* .fa-creative-commons-nc:before {\n content: \"\\f4e8\"; }\n\n* .fa-creative-commons-nc-eu:before {\n content: \"\\f4e9\"; }\n\n* .fa-creative-commons-nc-jp:before {\n content: \"\\f4ea\"; }\n\n* .fa-creative-commons-nd:before {\n content: \"\\f4eb\"; }\n\n* .fa-creative-commons-pd:before {\n content: \"\\f4ec\"; }\n\n* .fa-creative-commons-pd-alt:before {\n content: \"\\f4ed\"; }\n\n* .fa-creative-commons-remix:before {\n content: \"\\f4ee\"; }\n\n* .fa-creative-commons-sa:before {\n content: \"\\f4ef\"; }\n\n* .fa-creative-commons-sampling:before {\n content: \"\\f4f0\"; }\n\n* .fa-creative-commons-sampling-plus:before {\n content: \"\\f4f1\"; }\n\n* .fa-creative-commons-share:before {\n content: \"\\f4f2\"; }\n\n* .fa-creative-commons-zero:before {\n content: \"\\f4f3\"; }\n\n* .fa-credit-card:before {\n content: \"\\f09d\"; }\n\n* .fa-critical-role:before {\n content: \"\\f6c9\"; }\n\n* .fa-crop:before {\n content: \"\\f125\"; }\n\n* .fa-crop-alt:before {\n content: \"\\f565\"; }\n\n* .fa-cross:before {\n content: \"\\f654\"; }\n\n* .fa-crosshairs:before {\n content: \"\\f05b\"; }\n\n* .fa-crow:before {\n content: \"\\f520\"; }\n\n* .fa-crown:before {\n content: \"\\f521\"; }\n\n* .fa-css3:before {\n content: \"\\f13c\"; }\n\n* .fa-css3-alt:before {\n content: \"\\f38b\"; }\n\n* .fa-cube:before {\n content: \"\\f1b2\"; }\n\n* .fa-cubes:before {\n content: \"\\f1b3\"; }\n\n* .fa-cut:before {\n content: \"\\f0c4\"; }\n\n* .fa-cuttlefish:before {\n content: \"\\f38c\"; }\n\n* .fa-d-and-d:before {\n content: \"\\f38d\"; }\n\n* .fa-d-and-d-beyond:before {\n content: \"\\f6ca\"; }\n\n* .fa-dashcube:before {\n content: \"\\f210\"; }\n\n* .fa-database:before {\n content: \"\\f1c0\"; }\n\n* .fa-deaf:before {\n content: \"\\f2a4\"; }\n\n* .fa-delicious:before {\n content: \"\\f1a5\"; }\n\n* .fa-democrat:before {\n content: \"\\f747\"; }\n\n* .fa-deploydog:before {\n content: \"\\f38e\"; }\n\n* .fa-deskpro:before {\n content: \"\\f38f\"; }\n\n* .fa-desktop:before {\n content: \"\\f108\"; }\n\n* .fa-dev:before {\n content: \"\\f6cc\"; }\n\n* .fa-deviantart:before {\n content: \"\\f1bd\"; }\n\n* .fa-dharmachakra:before {\n content: \"\\f655\"; }\n\n* .fa-dhl:before {\n content: \"\\f790\"; }\n\n* .fa-diagnoses:before {\n content: \"\\f470\"; }\n\n* .fa-diaspora:before {\n content: \"\\f791\"; }\n\n* .fa-dice:before {\n content: \"\\f522\"; }\n\n* .fa-dice-d20:before {\n content: \"\\f6cf\"; }\n\n* .fa-dice-d6:before {\n content: \"\\f6d1\"; }\n\n* .fa-dice-five:before {\n content: \"\\f523\"; }\n\n* .fa-dice-four:before {\n content: \"\\f524\"; }\n\n* .fa-dice-one:before {\n content: \"\\f525\"; }\n\n* .fa-dice-six:before {\n content: \"\\f526\"; }\n\n* .fa-dice-three:before {\n content: \"\\f527\"; }\n\n* .fa-dice-two:before {\n content: \"\\f528\"; }\n\n* .fa-digg:before {\n content: \"\\f1a6\"; }\n\n* .fa-digital-ocean:before {\n content: \"\\f391\"; }\n\n* .fa-digital-tachograph:before {\n content: \"\\f566\"; }\n\n* .fa-directions:before {\n content: \"\\f5eb\"; }\n\n* .fa-discord:before {\n content: \"\\f392\"; }\n\n* .fa-discourse:before {\n content: \"\\f393\"; }\n\n* .fa-divide:before {\n content: \"\\f529\"; }\n\n* .fa-dizzy:before {\n content: \"\\f567\"; }\n\n* .fa-dna:before {\n content: \"\\f471\"; }\n\n* .fa-dochub:before {\n content: \"\\f394\"; }\n\n* .fa-docker:before {\n content: \"\\f395\"; }\n\n* .fa-dog:before {\n content: \"\\f6d3\"; }\n\n* .fa-dollar-sign:before {\n content: \"\\f155\"; }\n\n* .fa-dolly:before {\n content: \"\\f472\"; }\n\n* .fa-dolly-flatbed:before {\n content: \"\\f474\"; }\n\n* .fa-donate:before {\n content: \"\\f4b9\"; }\n\n* .fa-door-closed:before {\n content: \"\\f52a\"; }\n\n* .fa-door-open:before {\n content: \"\\f52b\"; }\n\n* .fa-dot-circle:before {\n content: \"\\f192\"; }\n\n* .fa-dove:before {\n content: \"\\f4ba\"; }\n\n* .fa-download:before {\n content: \"\\f019\"; }\n\n* .fa-draft2digital:before {\n content: \"\\f396\"; }\n\n* .fa-drafting-compass:before {\n content: \"\\f568\"; }\n\n* .fa-dragon:before {\n content: \"\\f6d5\"; }\n\n* .fa-draw-polygon:before {\n content: \"\\f5ee\"; }\n\n* .fa-dribbble:before {\n content: \"\\f17d\"; }\n\n* .fa-dribbble-square:before {\n content: \"\\f397\"; }\n\n* .fa-dropbox:before {\n content: \"\\f16b\"; }\n\n* .fa-drum:before {\n content: \"\\f569\"; }\n\n* .fa-drum-steelpan:before {\n content: \"\\f56a\"; }\n\n* .fa-drumstick-bite:before {\n content: \"\\f6d7\"; }\n\n* .fa-drupal:before {\n content: \"\\f1a9\"; }\n\n* .fa-dumbbell:before {\n content: \"\\f44b\"; }\n\n* .fa-dumpster:before {\n content: \"\\f793\"; }\n\n* .fa-dumpster-fire:before {\n content: \"\\f794\"; }\n\n* .fa-dungeon:before {\n content: \"\\f6d9\"; }\n\n* .fa-dyalog:before {\n content: \"\\f399\"; }\n\n* .fa-earlybirds:before {\n content: \"\\f39a\"; }\n\n* .fa-ebay:before {\n content: \"\\f4f4\"; }\n\n* .fa-edge:before {\n content: \"\\f282\"; }\n\n* .fa-edit:before {\n content: \"\\f044\"; }\n\n* .fa-eject:before {\n content: \"\\f052\"; }\n\n* .fa-elementor:before {\n content: \"\\f430\"; }\n\n* .fa-ellipsis-h:before {\n content: \"\\f141\"; }\n\n* .fa-ellipsis-v:before {\n content: \"\\f142\"; }\n\n* .fa-ello:before {\n content: \"\\f5f1\"; }\n\n* .fa-ember:before {\n content: \"\\f423\"; }\n\n* .fa-empire:before {\n content: \"\\f1d1\"; }\n\n* .fa-envelope:before {\n content: \"\\f0e0\"; }\n\n* .fa-envelope-open:before {\n content: \"\\f2b6\"; }\n\n* .fa-envelope-open-text:before {\n content: \"\\f658\"; }\n\n* .fa-envelope-square:before {\n content: \"\\f199\"; }\n\n* .fa-envira:before {\n content: \"\\f299\"; }\n\n* .fa-equals:before {\n content: \"\\f52c\"; }\n\n* .fa-eraser:before {\n content: \"\\f12d\"; }\n\n* .fa-erlang:before {\n content: \"\\f39d\"; }\n\n* .fa-ethereum:before {\n content: \"\\f42e\"; }\n\n* .fa-ethernet:before {\n content: \"\\f796\"; }\n\n* .fa-etsy:before {\n content: \"\\f2d7\"; }\n\n* .fa-euro-sign:before {\n content: \"\\f153\"; }\n\n* .fa-exchange-alt:before {\n content: \"\\f362\"; }\n\n* .fa-exclamation:before {\n content: \"\\f12a\"; }\n\n* .fa-exclamation-circle:before {\n content: \"\\f06a\"; }\n\n* .fa-exclamation-triangle:before {\n content: \"\\f071\"; }\n\n* .fa-expand:before {\n content: \"\\f065\"; }\n\n* .fa-expand-arrows-alt:before {\n content: \"\\f31e\"; }\n\n* .fa-expeditedssl:before {\n content: \"\\f23e\"; }\n\n* .fa-external-link-alt:before {\n content: \"\\f35d\"; }\n\n* .fa-external-link-square-alt:before {\n content: \"\\f360\"; }\n\n* .fa-eye:before {\n content: \"\\f06e\"; }\n\n* .fa-eye-dropper:before {\n content: \"\\f1fb\"; }\n\n* .fa-eye-slash:before {\n content: \"\\f070\"; }\n\n* .fa-facebook:before {\n content: \"\\f09a\"; }\n\n* .fa-facebook-f:before {\n content: \"\\f39e\"; }\n\n* .fa-facebook-messenger:before {\n content: \"\\f39f\"; }\n\n* .fa-facebook-square:before {\n content: \"\\f082\"; }\n\n* .fa-fantasy-flight-games:before {\n content: \"\\f6dc\"; }\n\n* .fa-fast-backward:before {\n content: \"\\f049\"; }\n\n* .fa-fast-forward:before {\n content: \"\\f050\"; }\n\n* .fa-fax:before {\n content: \"\\f1ac\"; }\n\n* .fa-feather:before {\n content: \"\\f52d\"; }\n\n* .fa-feather-alt:before {\n content: \"\\f56b\"; }\n\n* .fa-fedex:before {\n content: \"\\f797\"; }\n\n* .fa-fedora:before {\n content: \"\\f798\"; }\n\n* .fa-female:before {\n content: \"\\f182\"; }\n\n* .fa-fighter-jet:before {\n content: \"\\f0fb\"; }\n\n* .fa-figma:before {\n content: \"\\f799\"; }\n\n* .fa-file:before {\n content: \"\\f15b\"; }\n\n* .fa-file-alt:before {\n content: \"\\f15c\"; }\n\n* .fa-file-archive:before {\n content: \"\\f1c6\"; }\n\n* .fa-file-audio:before {\n content: \"\\f1c7\"; }\n\n* .fa-file-code:before {\n content: \"\\f1c9\"; }\n\n* .fa-file-contract:before {\n content: \"\\f56c\"; }\n\n* .fa-file-csv:before {\n content: \"\\f6dd\"; }\n\n* .fa-file-download:before {\n content: \"\\f56d\"; }\n\n* .fa-file-excel:before {\n content: \"\\f1c3\"; }\n\n* .fa-file-export:before {\n content: \"\\f56e\"; }\n\n* .fa-file-image:before {\n content: \"\\f1c5\"; }\n\n* .fa-file-import:before {\n content: \"\\f56f\"; }\n\n* .fa-file-invoice:before {\n content: \"\\f570\"; }\n\n* .fa-file-invoice-dollar:before {\n content: \"\\f571\"; }\n\n* .fa-file-medical:before {\n content: \"\\f477\"; }\n\n* .fa-file-medical-alt:before {\n content: \"\\f478\"; }\n\n* .fa-file-pdf:before {\n content: \"\\f1c1\"; }\n\n* .fa-file-powerpoint:before {\n content: \"\\f1c4\"; }\n\n* .fa-file-prescription:before {\n content: \"\\f572\"; }\n\n* .fa-file-signature:before {\n content: \"\\f573\"; }\n\n* .fa-file-upload:before {\n content: \"\\f574\"; }\n\n* .fa-file-video:before {\n content: \"\\f1c8\"; }\n\n* .fa-file-word:before {\n content: \"\\f1c2\"; }\n\n* .fa-fill:before {\n content: \"\\f575\"; }\n\n* .fa-fill-drip:before {\n content: \"\\f576\"; }\n\n* .fa-film:before {\n content: \"\\f008\"; }\n\n* .fa-filter:before {\n content: \"\\f0b0\"; }\n\n* .fa-fingerprint:before {\n content: \"\\f577\"; }\n\n* .fa-fire:before {\n content: \"\\f06d\"; }\n\n* .fa-fire-alt:before {\n content: \"\\f7e4\"; }\n\n* .fa-fire-extinguisher:before {\n content: \"\\f134\"; }\n\n* .fa-firefox:before {\n content: \"\\f269\"; }\n\n* .fa-first-aid:before {\n content: \"\\f479\"; }\n\n* .fa-first-order:before {\n content: \"\\f2b0\"; }\n\n* .fa-first-order-alt:before {\n content: \"\\f50a\"; }\n\n* .fa-firstdraft:before {\n content: \"\\f3a1\"; }\n\n* .fa-fish:before {\n content: \"\\f578\"; }\n\n* .fa-fist-raised:before {\n content: \"\\f6de\"; }\n\n* .fa-flag:before {\n content: \"\\f024\"; }\n\n* .fa-flag-checkered:before {\n content: \"\\f11e\"; }\n\n* .fa-flag-usa:before {\n content: \"\\f74d\"; }\n\n* .fa-flask:before {\n content: \"\\f0c3\"; }\n\n* .fa-flickr:before {\n content: \"\\f16e\"; }\n\n* .fa-flipboard:before {\n content: \"\\f44d\"; }\n\n* .fa-flushed:before {\n content: \"\\f579\"; }\n\n* .fa-fly:before {\n content: \"\\f417\"; }\n\n* .fa-folder:before {\n content: \"\\f07b\"; }\n\n* .fa-folder-minus:before {\n content: \"\\f65d\"; }\n\n* .fa-folder-open:before {\n content: \"\\f07c\"; }\n\n* .fa-folder-plus:before {\n content: \"\\f65e\"; }\n\n* .fa-font:before {\n content: \"\\f031\"; }\n\n* .fa-font-awesome:before {\n content: \"\\f2b4\"; }\n\n* .fa-font-awesome-alt:before {\n content: \"\\f35c\"; }\n\n* .fa-font-awesome-flag:before {\n content: \"\\f425\"; }\n\n* .fa-font-awesome-logo-full:before {\n content: \"\\f4e6\"; }\n\n* .fa-fonticons:before {\n content: \"\\f280\"; }\n\n* .fa-fonticons-fi:before {\n content: \"\\f3a2\"; }\n\n* .fa-football-ball:before {\n content: \"\\f44e\"; }\n\n* .fa-fort-awesome:before {\n content: \"\\f286\"; }\n\n* .fa-fort-awesome-alt:before {\n content: \"\\f3a3\"; }\n\n* .fa-forumbee:before {\n content: \"\\f211\"; }\n\n* .fa-forward:before {\n content: \"\\f04e\"; }\n\n* .fa-foursquare:before {\n content: \"\\f180\"; }\n\n* .fa-free-code-camp:before {\n content: \"\\f2c5\"; }\n\n* .fa-freebsd:before {\n content: \"\\f3a4\"; }\n\n* .fa-frog:before {\n content: \"\\f52e\"; }\n\n* .fa-frown:before {\n content: \"\\f119\"; }\n\n* .fa-frown-open:before {\n content: \"\\f57a\"; }\n\n* .fa-fulcrum:before {\n content: \"\\f50b\"; }\n\n* .fa-funnel-dollar:before {\n content: \"\\f662\"; }\n\n* .fa-futbol:before {\n content: \"\\f1e3\"; }\n\n* .fa-galactic-republic:before {\n content: \"\\f50c\"; }\n\n* .fa-galactic-senate:before {\n content: \"\\f50d\"; }\n\n* .fa-gamepad:before {\n content: \"\\f11b\"; }\n\n* .fa-gas-pump:before {\n content: \"\\f52f\"; }\n\n* .fa-gavel:before {\n content: \"\\f0e3\"; }\n\n* .fa-gem:before {\n content: \"\\f3a5\"; }\n\n* .fa-genderless:before {\n content: \"\\f22d\"; }\n\n* .fa-get-pocket:before {\n content: \"\\f265\"; }\n\n* .fa-gg:before {\n content: \"\\f260\"; }\n\n* .fa-gg-circle:before {\n content: \"\\f261\"; }\n\n* .fa-ghost:before {\n content: \"\\f6e2\"; }\n\n* .fa-gift:before {\n content: \"\\f06b\"; }\n\n* .fa-gifts:before {\n content: \"\\f79c\"; }\n\n* .fa-git:before {\n content: \"\\f1d3\"; }\n\n* .fa-git-square:before {\n content: \"\\f1d2\"; }\n\n* .fa-github:before {\n content: \"\\f09b\"; }\n\n* .fa-github-alt:before {\n content: \"\\f113\"; }\n\n* .fa-github-square:before {\n content: \"\\f092\"; }\n\n* .fa-gitkraken:before {\n content: \"\\f3a6\"; }\n\n* .fa-gitlab:before {\n content: \"\\f296\"; }\n\n* .fa-gitter:before {\n content: \"\\f426\"; }\n\n* .fa-glass-cheers:before {\n content: \"\\f79f\"; }\n\n* .fa-glass-martini:before {\n content: \"\\f000\"; }\n\n* .fa-glass-martini-alt:before {\n content: \"\\f57b\"; }\n\n* .fa-glass-whiskey:before {\n content: \"\\f7a0\"; }\n\n* .fa-glasses:before {\n content: \"\\f530\"; }\n\n* .fa-glide:before {\n content: \"\\f2a5\"; }\n\n* .fa-glide-g:before {\n content: \"\\f2a6\"; }\n\n* .fa-globe:before {\n content: \"\\f0ac\"; }\n\n* .fa-globe-africa:before {\n content: \"\\f57c\"; }\n\n* .fa-globe-americas:before {\n content: \"\\f57d\"; }\n\n* .fa-globe-asia:before {\n content: \"\\f57e\"; }\n\n* .fa-globe-europe:before {\n content: \"\\f7a2\"; }\n\n* .fa-gofore:before {\n content: \"\\f3a7\"; }\n\n* .fa-golf-ball:before {\n content: \"\\f450\"; }\n\n* .fa-goodreads:before {\n content: \"\\f3a8\"; }\n\n* .fa-goodreads-g:before {\n content: \"\\f3a9\"; }\n\n* .fa-google:before {\n content: \"\\f1a0\"; }\n\n* .fa-google-drive:before {\n content: \"\\f3aa\"; }\n\n* .fa-google-play:before {\n content: \"\\f3ab\"; }\n\n* .fa-google-plus:before {\n content: \"\\f2b3\"; }\n\n* .fa-google-plus-g:before {\n content: \"\\f0d5\"; }\n\n* .fa-google-plus-square:before {\n content: \"\\f0d4\"; }\n\n* .fa-google-wallet:before {\n content: \"\\f1ee\"; }\n\n* .fa-gopuram:before {\n content: \"\\f664\"; }\n\n* .fa-graduation-cap:before {\n content: \"\\f19d\"; }\n\n* .fa-gratipay:before {\n content: \"\\f184\"; }\n\n* .fa-grav:before {\n content: \"\\f2d6\"; }\n\n* .fa-greater-than:before {\n content: \"\\f531\"; }\n\n* .fa-greater-than-equal:before {\n content: \"\\f532\"; }\n\n* .fa-grimace:before {\n content: \"\\f57f\"; }\n\n* .fa-grin:before {\n content: \"\\f580\"; }\n\n* .fa-grin-alt:before {\n content: \"\\f581\"; }\n\n* .fa-grin-beam:before {\n content: \"\\f582\"; }\n\n* .fa-grin-beam-sweat:before {\n content: \"\\f583\"; }\n\n* .fa-grin-hearts:before {\n content: \"\\f584\"; }\n\n* .fa-grin-squint:before {\n content: \"\\f585\"; }\n\n* .fa-grin-squint-tears:before {\n content: \"\\f586\"; }\n\n* .fa-grin-stars:before {\n content: \"\\f587\"; }\n\n* .fa-grin-tears:before {\n content: \"\\f588\"; }\n\n* .fa-grin-tongue:before {\n content: \"\\f589\"; }\n\n* .fa-grin-tongue-squint:before {\n content: \"\\f58a\"; }\n\n* .fa-grin-tongue-wink:before {\n content: \"\\f58b\"; }\n\n* .fa-grin-wink:before {\n content: \"\\f58c\"; }\n\n* .fa-grip-horizontal:before {\n content: \"\\f58d\"; }\n\n* .fa-grip-lines:before {\n content: \"\\f7a4\"; }\n\n* .fa-grip-lines-vertical:before {\n content: \"\\f7a5\"; }\n\n* .fa-grip-vertical:before {\n content: \"\\f58e\"; }\n\n* .fa-gripfire:before {\n content: \"\\f3ac\"; }\n\n* .fa-grunt:before {\n content: \"\\f3ad\"; }\n\n* .fa-guitar:before {\n content: \"\\f7a6\"; }\n\n* .fa-gulp:before {\n content: \"\\f3ae\"; }\n\n* .fa-h-square:before {\n content: \"\\f0fd\"; }\n\n* .fa-hacker-news:before {\n content: \"\\f1d4\"; }\n\n* .fa-hacker-news-square:before {\n content: \"\\f3af\"; }\n\n* .fa-hackerrank:before {\n content: \"\\f5f7\"; }\n\n* .fa-hammer:before {\n content: \"\\f6e3\"; }\n\n* .fa-hamsa:before {\n content: \"\\f665\"; }\n\n* .fa-hand-holding:before {\n content: \"\\f4bd\"; }\n\n* .fa-hand-holding-heart:before {\n content: \"\\f4be\"; }\n\n* .fa-hand-holding-usd:before {\n content: \"\\f4c0\"; }\n\n* .fa-hand-lizard:before {\n content: \"\\f258\"; }\n\n* .fa-hand-paper:before {\n content: \"\\f256\"; }\n\n* .fa-hand-peace:before {\n content: \"\\f25b\"; }\n\n* .fa-hand-point-down:before {\n content: \"\\f0a7\"; }\n\n* .fa-hand-point-left:before {\n content: \"\\f0a5\"; }\n\n* .fa-hand-point-right:before {\n content: \"\\f0a4\"; }\n\n* .fa-hand-point-up:before {\n content: \"\\f0a6\"; }\n\n* .fa-hand-pointer:before {\n content: \"\\f25a\"; }\n\n* .fa-hand-rock:before {\n content: \"\\f255\"; }\n\n* .fa-hand-scissors:before {\n content: \"\\f257\"; }\n\n* .fa-hand-spock:before {\n content: \"\\f259\"; }\n\n* .fa-hands:before {\n content: \"\\f4c2\"; }\n\n* .fa-hands-helping:before {\n content: \"\\f4c4\"; }\n\n* .fa-handshake:before {\n content: \"\\f2b5\"; }\n\n* .fa-hanukiah:before {\n content: \"\\f6e6\"; }\n\n* .fa-hashtag:before {\n content: \"\\f292\"; }\n\n* .fa-hat-wizard:before {\n content: \"\\f6e8\"; }\n\n* .fa-haykal:before {\n content: \"\\f666\"; }\n\n* .fa-hdd:before {\n content: \"\\f0a0\"; }\n\n* .fa-heading:before {\n content: \"\\f1dc\"; }\n\n* .fa-headphones:before {\n content: \"\\f025\"; }\n\n* .fa-headphones-alt:before {\n content: \"\\f58f\"; }\n\n* .fa-headset:before {\n content: \"\\f590\"; }\n\n* .fa-heart:before {\n content: \"\\f004\"; }\n\n* .fa-heart-broken:before {\n content: \"\\f7a9\"; }\n\n* .fa-heartbeat:before {\n content: \"\\f21e\"; }\n\n* .fa-helicopter:before {\n content: \"\\f533\"; }\n\n* .fa-highlighter:before {\n content: \"\\f591\"; }\n\n* .fa-hiking:before {\n content: \"\\f6ec\"; }\n\n* .fa-hippo:before {\n content: \"\\f6ed\"; }\n\n* .fa-hips:before {\n content: \"\\f452\"; }\n\n* .fa-hire-a-helper:before {\n content: \"\\f3b0\"; }\n\n* .fa-history:before {\n content: \"\\f1da\"; }\n\n* .fa-hockey-puck:before {\n content: \"\\f453\"; }\n\n* .fa-holly-berry:before {\n content: \"\\f7aa\"; }\n\n* .fa-home:before {\n content: \"\\f015\"; }\n\n* .fa-hooli:before {\n content: \"\\f427\"; }\n\n* .fa-hornbill:before {\n content: \"\\f592\"; }\n\n* .fa-horse:before {\n content: \"\\f6f0\"; }\n\n* .fa-horse-head:before {\n content: \"\\f7ab\"; }\n\n* .fa-hospital:before {\n content: \"\\f0f8\"; }\n\n* .fa-hospital-alt:before {\n content: \"\\f47d\"; }\n\n* .fa-hospital-symbol:before {\n content: \"\\f47e\"; }\n\n* .fa-hot-tub:before {\n content: \"\\f593\"; }\n\n* .fa-hotel:before {\n content: \"\\f594\"; }\n\n* .fa-hotjar:before {\n content: \"\\f3b1\"; }\n\n* .fa-hourglass:before {\n content: \"\\f254\"; }\n\n* .fa-hourglass-end:before {\n content: \"\\f253\"; }\n\n* .fa-hourglass-half:before {\n content: \"\\f252\"; }\n\n* .fa-hourglass-start:before {\n content: \"\\f251\"; }\n\n* .fa-house-damage:before {\n content: \"\\f6f1\"; }\n\n* .fa-houzz:before {\n content: \"\\f27c\"; }\n\n* .fa-hryvnia:before {\n content: \"\\f6f2\"; }\n\n* .fa-html5:before {\n content: \"\\f13b\"; }\n\n* .fa-hubspot:before {\n content: \"\\f3b2\"; }\n\n* .fa-i-cursor:before {\n content: \"\\f246\"; }\n\n* .fa-icicles:before {\n content: \"\\f7ad\"; }\n\n* .fa-id-badge:before {\n content: \"\\f2c1\"; }\n\n* .fa-id-card:before {\n content: \"\\f2c2\"; }\n\n* .fa-id-card-alt:before {\n content: \"\\f47f\"; }\n\n* .fa-igloo:before {\n content: \"\\f7ae\"; }\n\n* .fa-image:before {\n content: \"\\f03e\"; }\n\n* .fa-images:before {\n content: \"\\f302\"; }\n\n* .fa-imdb:before {\n content: \"\\f2d8\"; }\n\n* .fa-inbox:before {\n content: \"\\f01c\"; }\n\n* .fa-indent:before {\n content: \"\\f03c\"; }\n\n* .fa-industry:before {\n content: \"\\f275\"; }\n\n* .fa-infinity:before {\n content: \"\\f534\"; }\n\n* .fa-info:before {\n content: \"\\f129\"; }\n\n* .fa-info-circle:before {\n content: \"\\f05a\"; }\n\n* .fa-instagram:before {\n content: \"\\f16d\"; }\n\n* .fa-intercom:before {\n content: \"\\f7af\"; }\n\n* .fa-internet-explorer:before {\n content: \"\\f26b\"; }\n\n* .fa-invision:before {\n content: \"\\f7b0\"; }\n\n* .fa-ioxhost:before {\n content: \"\\f208\"; }\n\n* .fa-italic:before {\n content: \"\\f033\"; }\n\n* .fa-itunes:before {\n content: \"\\f3b4\"; }\n\n* .fa-itunes-note:before {\n content: \"\\f3b5\"; }\n\n* .fa-java:before {\n content: \"\\f4e4\"; }\n\n* .fa-jedi:before {\n content: \"\\f669\"; }\n\n* .fa-jedi-order:before {\n content: \"\\f50e\"; }\n\n* .fa-jenkins:before {\n content: \"\\f3b6\"; }\n\n* .fa-jira:before {\n content: \"\\f7b1\"; }\n\n* .fa-joget:before {\n content: \"\\f3b7\"; }\n\n* .fa-joint:before {\n content: \"\\f595\"; }\n\n* .fa-joomla:before {\n content: \"\\f1aa\"; }\n\n* .fa-journal-whills:before {\n content: \"\\f66a\"; }\n\n* .fa-js:before {\n content: \"\\f3b8\"; }\n\n* .fa-js-square:before {\n content: \"\\f3b9\"; }\n\n* .fa-jsfiddle:before {\n content: \"\\f1cc\"; }\n\n* .fa-kaaba:before {\n content: \"\\f66b\"; }\n\n* .fa-kaggle:before {\n content: \"\\f5fa\"; }\n\n* .fa-key:before {\n content: \"\\f084\"; }\n\n* .fa-keybase:before {\n content: \"\\f4f5\"; }\n\n* .fa-keyboard:before {\n content: \"\\f11c\"; }\n\n* .fa-keycdn:before {\n content: \"\\f3ba\"; }\n\n* .fa-khanda:before {\n content: \"\\f66d\"; }\n\n* .fa-kickstarter:before {\n content: \"\\f3bb\"; }\n\n* .fa-kickstarter-k:before {\n content: \"\\f3bc\"; }\n\n* .fa-kiss:before {\n content: \"\\f596\"; }\n\n* .fa-kiss-beam:before {\n content: \"\\f597\"; }\n\n* .fa-kiss-wink-heart:before {\n content: \"\\f598\"; }\n\n* .fa-kiwi-bird:before {\n content: \"\\f535\"; }\n\n* .fa-korvue:before {\n content: \"\\f42f\"; }\n\n* .fa-landmark:before {\n content: \"\\f66f\"; }\n\n* .fa-language:before {\n content: \"\\f1ab\"; }\n\n* .fa-laptop:before {\n content: \"\\f109\"; }\n\n* .fa-laptop-code:before {\n content: \"\\f5fc\"; }\n\n* .fa-laravel:before {\n content: \"\\f3bd\"; }\n\n* .fa-lastfm:before {\n content: \"\\f202\"; }\n\n* .fa-lastfm-square:before {\n content: \"\\f203\"; }\n\n* .fa-laugh:before {\n content: \"\\f599\"; }\n\n* .fa-laugh-beam:before {\n content: \"\\f59a\"; }\n\n* .fa-laugh-squint:before {\n content: \"\\f59b\"; }\n\n* .fa-laugh-wink:before {\n content: \"\\f59c\"; }\n\n* .fa-layer-group:before {\n content: \"\\f5fd\"; }\n\n* .fa-leaf:before {\n content: \"\\f06c\"; }\n\n* .fa-leanpub:before {\n content: \"\\f212\"; }\n\n* .fa-lemon:before {\n content: \"\\f094\"; }\n\n* .fa-less:before {\n content: \"\\f41d\"; }\n\n* .fa-less-than:before {\n content: \"\\f536\"; }\n\n* .fa-less-than-equal:before {\n content: \"\\f537\"; }\n\n* .fa-level-down-alt:before {\n content: \"\\f3be\"; }\n\n* .fa-level-up-alt:before {\n content: \"\\f3bf\"; }\n\n* .fa-life-ring:before {\n content: \"\\f1cd\"; }\n\n* .fa-lightbulb:before {\n content: \"\\f0eb\"; }\n\n* .fa-line:before {\n content: \"\\f3c0\"; }\n\n* .fa-link:before {\n content: \"\\f0c1\"; }\n\n* .fa-linkedin:before {\n content: \"\\f08c\"; }\n\n* .fa-linkedin-in:before {\n content: \"\\f0e1\"; }\n\n* .fa-linode:before {\n content: \"\\f2b8\"; }\n\n* .fa-linux:before {\n content: \"\\f17c\"; }\n\n* .fa-lira-sign:before {\n content: \"\\f195\"; }\n\n* .fa-list:before {\n content: \"\\f03a\"; }\n\n* .fa-list-alt:before {\n content: \"\\f022\"; }\n\n* .fa-list-ol:before {\n content: \"\\f0cb\"; }\n\n* .fa-list-ul:before {\n content: \"\\f0ca\"; }\n\n* .fa-location-arrow:before {\n content: \"\\f124\"; }\n\n* .fa-lock:before {\n content: \"\\f023\"; }\n\n* .fa-lock-open:before {\n content: \"\\f3c1\"; }\n\n* .fa-long-arrow-alt-down:before {\n content: \"\\f309\"; }\n\n* .fa-long-arrow-alt-left:before {\n content: \"\\f30a\"; }\n\n* .fa-long-arrow-alt-right:before {\n content: \"\\f30b\"; }\n\n* .fa-long-arrow-alt-up:before {\n content: \"\\f30c\"; }\n\n* .fa-low-vision:before {\n content: \"\\f2a8\"; }\n\n* .fa-luggage-cart:before {\n content: \"\\f59d\"; }\n\n* .fa-lyft:before {\n content: \"\\f3c3\"; }\n\n* .fa-magento:before {\n content: \"\\f3c4\"; }\n\n* .fa-magic:before {\n content: \"\\f0d0\"; }\n\n* .fa-magnet:before {\n content: \"\\f076\"; }\n\n* .fa-mail-bulk:before {\n content: \"\\f674\"; }\n\n* .fa-mailchimp:before {\n content: \"\\f59e\"; }\n\n* .fa-male:before {\n content: \"\\f183\"; }\n\n* .fa-mandalorian:before {\n content: \"\\f50f\"; }\n\n* .fa-map:before {\n content: \"\\f279\"; }\n\n* .fa-map-marked:before {\n content: \"\\f59f\"; }\n\n* .fa-map-marked-alt:before {\n content: \"\\f5a0\"; }\n\n* .fa-map-marker:before {\n content: \"\\f041\"; }\n\n* .fa-map-marker-alt:before {\n content: \"\\f3c5\"; }\n\n* .fa-map-pin:before {\n content: \"\\f276\"; }\n\n* .fa-map-signs:before {\n content: \"\\f277\"; }\n\n* .fa-markdown:before {\n content: \"\\f60f\"; }\n\n* .fa-marker:before {\n content: \"\\f5a1\"; }\n\n* .fa-mars:before {\n content: \"\\f222\"; }\n\n* .fa-mars-double:before {\n content: \"\\f227\"; }\n\n* .fa-mars-stroke:before {\n content: \"\\f229\"; }\n\n* .fa-mars-stroke-h:before {\n content: \"\\f22b\"; }\n\n* .fa-mars-stroke-v:before {\n content: \"\\f22a\"; }\n\n* .fa-mask:before {\n content: \"\\f6fa\"; }\n\n* .fa-mastodon:before {\n content: \"\\f4f6\"; }\n\n* .fa-maxcdn:before {\n content: \"\\f136\"; }\n\n* .fa-medal:before {\n content: \"\\f5a2\"; }\n\n* .fa-medapps:before {\n content: \"\\f3c6\"; }\n\n* .fa-medium:before {\n content: \"\\f23a\"; }\n\n* .fa-medium-m:before {\n content: \"\\f3c7\"; }\n\n* .fa-medkit:before {\n content: \"\\f0fa\"; }\n\n* .fa-medrt:before {\n content: \"\\f3c8\"; }\n\n* .fa-meetup:before {\n content: \"\\f2e0\"; }\n\n* .fa-megaport:before {\n content: \"\\f5a3\"; }\n\n* .fa-meh:before {\n content: \"\\f11a\"; }\n\n* .fa-meh-blank:before {\n content: \"\\f5a4\"; }\n\n* .fa-meh-rolling-eyes:before {\n content: \"\\f5a5\"; }\n\n* .fa-memory:before {\n content: \"\\f538\"; }\n\n* .fa-mendeley:before {\n content: \"\\f7b3\"; }\n\n* .fa-menorah:before {\n content: \"\\f676\"; }\n\n* .fa-mercury:before {\n content: \"\\f223\"; }\n\n* .fa-meteor:before {\n content: \"\\f753\"; }\n\n* .fa-microchip:before {\n content: \"\\f2db\"; }\n\n* .fa-microphone:before {\n content: \"\\f130\"; }\n\n* .fa-microphone-alt:before {\n content: \"\\f3c9\"; }\n\n* .fa-microphone-alt-slash:before {\n content: \"\\f539\"; }\n\n* .fa-microphone-slash:before {\n content: \"\\f131\"; }\n\n* .fa-microscope:before {\n content: \"\\f610\"; }\n\n* .fa-microsoft:before {\n content: \"\\f3ca\"; }\n\n* .fa-minus:before {\n content: \"\\f068\"; }\n\n* .fa-minus-circle:before {\n content: \"\\f056\"; }\n\n* .fa-minus-square:before {\n content: \"\\f146\"; }\n\n* .fa-mitten:before {\n content: \"\\f7b5\"; }\n\n* .fa-mix:before {\n content: \"\\f3cb\"; }\n\n* .fa-mixcloud:before {\n content: \"\\f289\"; }\n\n* .fa-mizuni:before {\n content: \"\\f3cc\"; }\n\n* .fa-mobile:before {\n content: \"\\f10b\"; }\n\n* .fa-mobile-alt:before {\n content: \"\\f3cd\"; }\n\n* .fa-modx:before {\n content: \"\\f285\"; }\n\n* .fa-monero:before {\n content: \"\\f3d0\"; }\n\n* .fa-money-bill:before {\n content: \"\\f0d6\"; }\n\n* .fa-money-bill-alt:before {\n content: \"\\f3d1\"; }\n\n* .fa-money-bill-wave:before {\n content: \"\\f53a\"; }\n\n* .fa-money-bill-wave-alt:before {\n content: \"\\f53b\"; }\n\n* .fa-money-check:before {\n content: \"\\f53c\"; }\n\n* .fa-money-check-alt:before {\n content: \"\\f53d\"; }\n\n* .fa-monument:before {\n content: \"\\f5a6\"; }\n\n* .fa-moon:before {\n content: \"\\f186\"; }\n\n* .fa-mortar-pestle:before {\n content: \"\\f5a7\"; }\n\n* .fa-mosque:before {\n content: \"\\f678\"; }\n\n* .fa-motorcycle:before {\n content: \"\\f21c\"; }\n\n* .fa-mountain:before {\n content: \"\\f6fc\"; }\n\n* .fa-mouse-pointer:before {\n content: \"\\f245\"; }\n\n* .fa-mug-hot:before {\n content: \"\\f7b6\"; }\n\n* .fa-music:before {\n content: \"\\f001\"; }\n\n* .fa-napster:before {\n content: \"\\f3d2\"; }\n\n* .fa-neos:before {\n content: \"\\f612\"; }\n\n* .fa-network-wired:before {\n content: \"\\f6ff\"; }\n\n* .fa-neuter:before {\n content: \"\\f22c\"; }\n\n* .fa-newspaper:before {\n content: \"\\f1ea\"; }\n\n* .fa-nimblr:before {\n content: \"\\f5a8\"; }\n\n* .fa-nintendo-switch:before {\n content: \"\\f418\"; }\n\n* .fa-node:before {\n content: \"\\f419\"; }\n\n* .fa-node-js:before {\n content: \"\\f3d3\"; }\n\n* .fa-not-equal:before {\n content: \"\\f53e\"; }\n\n* .fa-notes-medical:before {\n content: \"\\f481\"; }\n\n* .fa-npm:before {\n content: \"\\f3d4\"; }\n\n* .fa-ns8:before {\n content: \"\\f3d5\"; }\n\n* .fa-nutritionix:before {\n content: \"\\f3d6\"; }\n\n* .fa-object-group:before {\n content: \"\\f247\"; }\n\n* .fa-object-ungroup:before {\n content: \"\\f248\"; }\n\n* .fa-odnoklassniki:before {\n content: \"\\f263\"; }\n\n* .fa-odnoklassniki-square:before {\n content: \"\\f264\"; }\n\n* .fa-oil-can:before {\n content: \"\\f613\"; }\n\n* .fa-old-republic:before {\n content: \"\\f510\"; }\n\n* .fa-om:before {\n content: \"\\f679\"; }\n\n* .fa-opencart:before {\n content: \"\\f23d\"; }\n\n* .fa-openid:before {\n content: \"\\f19b\"; }\n\n* .fa-opera:before {\n content: \"\\f26a\"; }\n\n* .fa-optin-monster:before {\n content: \"\\f23c\"; }\n\n* .fa-osi:before {\n content: \"\\f41a\"; }\n\n* .fa-otter:before {\n content: \"\\f700\"; }\n\n* .fa-outdent:before {\n content: \"\\f03b\"; }\n\n* .fa-page4:before {\n content: \"\\f3d7\"; }\n\n* .fa-pagelines:before {\n content: \"\\f18c\"; }\n\n* .fa-paint-brush:before {\n content: \"\\f1fc\"; }\n\n* .fa-paint-roller:before {\n content: \"\\f5aa\"; }\n\n* .fa-palette:before {\n content: \"\\f53f\"; }\n\n* .fa-palfed:before {\n content: \"\\f3d8\"; }\n\n* .fa-pallet:before {\n content: \"\\f482\"; }\n\n* .fa-paper-plane:before {\n content: \"\\f1d8\"; }\n\n* .fa-paperclip:before {\n content: \"\\f0c6\"; }\n\n* .fa-parachute-box:before {\n content: \"\\f4cd\"; }\n\n* .fa-paragraph:before {\n content: \"\\f1dd\"; }\n\n* .fa-parking:before {\n content: \"\\f540\"; }\n\n* .fa-passport:before {\n content: \"\\f5ab\"; }\n\n* .fa-pastafarianism:before {\n content: \"\\f67b\"; }\n\n* .fa-paste:before {\n content: \"\\f0ea\"; }\n\n* .fa-patreon:before {\n content: \"\\f3d9\"; }\n\n* .fa-pause:before {\n content: \"\\f04c\"; }\n\n* .fa-pause-circle:before {\n content: \"\\f28b\"; }\n\n* .fa-paw:before {\n content: \"\\f1b0\"; }\n\n* .fa-paypal:before {\n content: \"\\f1ed\"; }\n\n* .fa-peace:before {\n content: \"\\f67c\"; }\n\n* .fa-pen:before {\n content: \"\\f304\"; }\n\n* .fa-pen-alt:before {\n content: \"\\f305\"; }\n\n* .fa-pen-fancy:before {\n content: \"\\f5ac\"; }\n\n* .fa-pen-nib:before {\n content: \"\\f5ad\"; }\n\n* .fa-pen-square:before {\n content: \"\\f14b\"; }\n\n* .fa-pencil-alt:before {\n content: \"\\f303\"; }\n\n* .fa-pencil-ruler:before {\n content: \"\\f5ae\"; }\n\n* .fa-penny-arcade:before {\n content: \"\\f704\"; }\n\n* .fa-people-carry:before {\n content: \"\\f4ce\"; }\n\n* .fa-percent:before {\n content: \"\\f295\"; }\n\n* .fa-percentage:before {\n content: \"\\f541\"; }\n\n* .fa-periscope:before {\n content: \"\\f3da\"; }\n\n* .fa-person-booth:before {\n content: \"\\f756\"; }\n\n* .fa-phabricator:before {\n content: \"\\f3db\"; }\n\n* .fa-phoenix-framework:before {\n content: \"\\f3dc\"; }\n\n* .fa-phoenix-squadron:before {\n content: \"\\f511\"; }\n\n* .fa-phone:before {\n content: \"\\f095\"; }\n\n* .fa-phone-slash:before {\n content: \"\\f3dd\"; }\n\n* .fa-phone-square:before {\n content: \"\\f098\"; }\n\n* .fa-phone-volume:before {\n content: \"\\f2a0\"; }\n\n* .fa-php:before {\n content: \"\\f457\"; }\n\n* .fa-pied-piper:before {\n content: \"\\f2ae\"; }\n\n* .fa-pied-piper-alt:before {\n content: \"\\f1a8\"; }\n\n* .fa-pied-piper-hat:before {\n content: \"\\f4e5\"; }\n\n* .fa-pied-piper-pp:before {\n content: \"\\f1a7\"; }\n\n* .fa-piggy-bank:before {\n content: \"\\f4d3\"; }\n\n* .fa-pills:before {\n content: \"\\f484\"; }\n\n* .fa-pinterest:before {\n content: \"\\f0d2\"; }\n\n* .fa-pinterest-p:before {\n content: \"\\f231\"; }\n\n* .fa-pinterest-square:before {\n content: \"\\f0d3\"; }\n\n* .fa-place-of-worship:before {\n content: \"\\f67f\"; }\n\n* .fa-plane:before {\n content: \"\\f072\"; }\n\n* .fa-plane-arrival:before {\n content: \"\\f5af\"; }\n\n* .fa-plane-departure:before {\n content: \"\\f5b0\"; }\n\n* .fa-play:before {\n content: \"\\f04b\"; }\n\n* .fa-play-circle:before {\n content: \"\\f144\"; }\n\n* .fa-playstation:before {\n content: \"\\f3df\"; }\n\n* .fa-plug:before {\n content: \"\\f1e6\"; }\n\n* .fa-plus:before {\n content: \"\\f067\"; }\n\n* .fa-plus-circle:before {\n content: \"\\f055\"; }\n\n* .fa-plus-square:before {\n content: \"\\f0fe\"; }\n\n* .fa-podcast:before {\n content: \"\\f2ce\"; }\n\n* .fa-poll:before {\n content: \"\\f681\"; }\n\n* .fa-poll-h:before {\n content: \"\\f682\"; }\n\n* .fa-poo:before {\n content: \"\\f2fe\"; }\n\n* .fa-poo-storm:before {\n content: \"\\f75a\"; }\n\n* .fa-poop:before {\n content: \"\\f619\"; }\n\n* .fa-portrait:before {\n content: \"\\f3e0\"; }\n\n* .fa-pound-sign:before {\n content: \"\\f154\"; }\n\n* .fa-power-off:before {\n content: \"\\f011\"; }\n\n* .fa-pray:before {\n content: \"\\f683\"; }\n\n* .fa-praying-hands:before {\n content: \"\\f684\"; }\n\n* .fa-prescription:before {\n content: \"\\f5b1\"; }\n\n* .fa-prescription-bottle:before {\n content: \"\\f485\"; }\n\n* .fa-prescription-bottle-alt:before {\n content: \"\\f486\"; }\n\n* .fa-print:before {\n content: \"\\f02f\"; }\n\n* .fa-procedures:before {\n content: \"\\f487\"; }\n\n* .fa-product-hunt:before {\n content: \"\\f288\"; }\n\n* .fa-project-diagram:before {\n content: \"\\f542\"; }\n\n* .fa-pushed:before {\n content: \"\\f3e1\"; }\n\n* .fa-puzzle-piece:before {\n content: \"\\f12e\"; }\n\n* .fa-python:before {\n content: \"\\f3e2\"; }\n\n* .fa-qq:before {\n content: \"\\f1d6\"; }\n\n* .fa-qrcode:before {\n content: \"\\f029\"; }\n\n* .fa-question:before {\n content: \"\\f128\"; }\n\n* .fa-question-circle:before {\n content: \"\\f059\"; }\n\n* .fa-quidditch:before {\n content: \"\\f458\"; }\n\n* .fa-quinscape:before {\n content: \"\\f459\"; }\n\n* .fa-quora:before {\n content: \"\\f2c4\"; }\n\n* .fa-quote-left:before {\n content: \"\\f10d\"; }\n\n* .fa-quote-right:before {\n content: \"\\f10e\"; }\n\n* .fa-quran:before {\n content: \"\\f687\"; }\n\n* .fa-r-project:before {\n content: \"\\f4f7\"; }\n\n* .fa-radiation:before {\n content: \"\\f7b9\"; }\n\n* .fa-radiation-alt:before {\n content: \"\\f7ba\"; }\n\n* .fa-rainbow:before {\n content: \"\\f75b\"; }\n\n* .fa-random:before {\n content: \"\\f074\"; }\n\n* .fa-raspberry-pi:before {\n content: \"\\f7bb\"; }\n\n* .fa-ravelry:before {\n content: \"\\f2d9\"; }\n\n* .fa-react:before {\n content: \"\\f41b\"; }\n\n* .fa-reacteurope:before {\n content: \"\\f75d\"; }\n\n* .fa-readme:before {\n content: \"\\f4d5\"; }\n\n* .fa-rebel:before {\n content: \"\\f1d0\"; }\n\n* .fa-receipt:before {\n content: \"\\f543\"; }\n\n* .fa-recycle:before {\n content: \"\\f1b8\"; }\n\n* .fa-red-river:before {\n content: \"\\f3e3\"; }\n\n* .fa-reddit:before {\n content: \"\\f1a1\"; }\n\n* .fa-reddit-alien:before {\n content: \"\\f281\"; }\n\n* .fa-reddit-square:before {\n content: \"\\f1a2\"; }\n\n* .fa-redhat:before {\n content: \"\\f7bc\"; }\n\n* .fa-redo:before {\n content: \"\\f01e\"; }\n\n* .fa-redo-alt:before {\n content: \"\\f2f9\"; }\n\n* .fa-registered:before {\n content: \"\\f25d\"; }\n\n* .fa-renren:before {\n content: \"\\f18b\"; }\n\n* .fa-reply:before {\n content: \"\\f3e5\"; }\n\n* .fa-reply-all:before {\n content: \"\\f122\"; }\n\n* .fa-replyd:before {\n content: \"\\f3e6\"; }\n\n* .fa-republican:before {\n content: \"\\f75e\"; }\n\n* .fa-researchgate:before {\n content: \"\\f4f8\"; }\n\n* .fa-resolving:before {\n content: \"\\f3e7\"; }\n\n* .fa-restroom:before {\n content: \"\\f7bd\"; }\n\n* .fa-retweet:before {\n content: \"\\f079\"; }\n\n* .fa-rev:before {\n content: \"\\f5b2\"; }\n\n* .fa-ribbon:before {\n content: \"\\f4d6\"; }\n\n* .fa-ring:before {\n content: \"\\f70b\"; }\n\n* .fa-road:before {\n content: \"\\f018\"; }\n\n* .fa-robot:before {\n content: \"\\f544\"; }\n\n* .fa-rocket:before {\n content: \"\\f135\"; }\n\n* .fa-rocketchat:before {\n content: \"\\f3e8\"; }\n\n* .fa-rockrms:before {\n content: \"\\f3e9\"; }\n\n* .fa-route:before {\n content: \"\\f4d7\"; }\n\n* .fa-rss:before {\n content: \"\\f09e\"; }\n\n* .fa-rss-square:before {\n content: \"\\f143\"; }\n\n* .fa-ruble-sign:before {\n content: \"\\f158\"; }\n\n* .fa-ruler:before {\n content: \"\\f545\"; }\n\n* .fa-ruler-combined:before {\n content: \"\\f546\"; }\n\n* .fa-ruler-horizontal:before {\n content: \"\\f547\"; }\n\n* .fa-ruler-vertical:before {\n content: \"\\f548\"; }\n\n* .fa-running:before {\n content: \"\\f70c\"; }\n\n* .fa-rupee-sign:before {\n content: \"\\f156\"; }\n\n* .fa-sad-cry:before {\n content: \"\\f5b3\"; }\n\n* .fa-sad-tear:before {\n content: \"\\f5b4\"; }\n\n* .fa-safari:before {\n content: \"\\f267\"; }\n\n* .fa-sass:before {\n content: \"\\f41e\"; }\n\n* .fa-satellite:before {\n content: \"\\f7bf\"; }\n\n* .fa-satellite-dish:before {\n content: \"\\f7c0\"; }\n\n* .fa-save:before {\n content: \"\\f0c7\"; }\n\n* .fa-schlix:before {\n content: \"\\f3ea\"; }\n\n* .fa-school:before {\n content: \"\\f549\"; }\n\n* .fa-screwdriver:before {\n content: \"\\f54a\"; }\n\n* .fa-scribd:before {\n content: \"\\f28a\"; }\n\n* .fa-scroll:before {\n content: \"\\f70e\"; }\n\n* .fa-sd-card:before {\n content: \"\\f7c2\"; }\n\n* .fa-search:before {\n content: \"\\f002\"; }\n\n* .fa-search-dollar:before {\n content: \"\\f688\"; }\n\n* .fa-search-location:before {\n content: \"\\f689\"; }\n\n* .fa-search-minus:before {\n content: \"\\f010\"; }\n\n* .fa-search-plus:before {\n content: \"\\f00e\"; }\n\n* .fa-searchengin:before {\n content: \"\\f3eb\"; }\n\n* .fa-seedling:before {\n content: \"\\f4d8\"; }\n\n* .fa-sellcast:before {\n content: \"\\f2da\"; }\n\n* .fa-sellsy:before {\n content: \"\\f213\"; }\n\n* .fa-server:before {\n content: \"\\f233\"; }\n\n* .fa-servicestack:before {\n content: \"\\f3ec\"; }\n\n* .fa-shapes:before {\n content: \"\\f61f\"; }\n\n* .fa-share:before {\n content: \"\\f064\"; }\n\n* .fa-share-alt:before {\n content: \"\\f1e0\"; }\n\n* .fa-share-alt-square:before {\n content: \"\\f1e1\"; }\n\n* .fa-share-square:before {\n content: \"\\f14d\"; }\n\n* .fa-shekel-sign:before {\n content: \"\\f20b\"; }\n\n* .fa-shield-alt:before {\n content: \"\\f3ed\"; }\n\n* .fa-ship:before {\n content: \"\\f21a\"; }\n\n* .fa-shipping-fast:before {\n content: \"\\f48b\"; }\n\n* .fa-shirtsinbulk:before {\n content: \"\\f214\"; }\n\n* .fa-shoe-prints:before {\n content: \"\\f54b\"; }\n\n* .fa-shopping-bag:before {\n content: \"\\f290\"; }\n\n* .fa-shopping-basket:before {\n content: \"\\f291\"; }\n\n* .fa-shopping-cart:before {\n content: \"\\f07a\"; }\n\n* .fa-shopware:before {\n content: \"\\f5b5\"; }\n\n* .fa-shower:before {\n content: \"\\f2cc\"; }\n\n* .fa-shuttle-van:before {\n content: \"\\f5b6\"; }\n\n* .fa-sign:before {\n content: \"\\f4d9\"; }\n\n* .fa-sign-in-alt:before {\n content: \"\\f2f6\"; }\n\n* .fa-sign-language:before {\n content: \"\\f2a7\"; }\n\n* .fa-sign-out-alt:before {\n content: \"\\f2f5\"; }\n\n* .fa-signal:before {\n content: \"\\f012\"; }\n\n* .fa-signature:before {\n content: \"\\f5b7\"; }\n\n* .fa-sim-card:before {\n content: \"\\f7c4\"; }\n\n* .fa-simplybuilt:before {\n content: \"\\f215\"; }\n\n* .fa-sistrix:before {\n content: \"\\f3ee\"; }\n\n* .fa-sitemap:before {\n content: \"\\f0e8\"; }\n\n* .fa-sith:before {\n content: \"\\f512\"; }\n\n* .fa-skating:before {\n content: \"\\f7c5\"; }\n\n* .fa-sketch:before {\n content: \"\\f7c6\"; }\n\n* .fa-skiing:before {\n content: \"\\f7c9\"; }\n\n* .fa-skiing-nordic:before {\n content: \"\\f7ca\"; }\n\n* .fa-skull:before {\n content: \"\\f54c\"; }\n\n* .fa-skull-crossbones:before {\n content: \"\\f714\"; }\n\n* .fa-skyatlas:before {\n content: \"\\f216\"; }\n\n* .fa-skype:before {\n content: \"\\f17e\"; }\n\n* .fa-slack:before {\n content: \"\\f198\"; }\n\n* .fa-slack-hash:before {\n content: \"\\f3ef\"; }\n\n* .fa-slash:before {\n content: \"\\f715\"; }\n\n* .fa-sleigh:before {\n content: \"\\f7cc\"; }\n\n* .fa-sliders-h:before {\n content: \"\\f1de\"; }\n\n* .fa-slideshare:before {\n content: \"\\f1e7\"; }\n\n* .fa-smile:before {\n content: \"\\f118\"; }\n\n* .fa-smile-beam:before {\n content: \"\\f5b8\"; }\n\n* .fa-smile-wink:before {\n content: \"\\f4da\"; }\n\n* .fa-smog:before {\n content: \"\\f75f\"; }\n\n* .fa-smoking:before {\n content: \"\\f48d\"; }\n\n* .fa-smoking-ban:before {\n content: \"\\f54d\"; }\n\n* .fa-sms:before {\n content: \"\\f7cd\"; }\n\n* .fa-snapchat:before {\n content: \"\\f2ab\"; }\n\n* .fa-snapchat-ghost:before {\n content: \"\\f2ac\"; }\n\n* .fa-snapchat-square:before {\n content: \"\\f2ad\"; }\n\n* .fa-snowboarding:before {\n content: \"\\f7ce\"; }\n\n* .fa-snowflake:before {\n content: \"\\f2dc\"; }\n\n* .fa-snowman:before {\n content: \"\\f7d0\"; }\n\n* .fa-snowplow:before {\n content: \"\\f7d2\"; }\n\n* .fa-socks:before {\n content: \"\\f696\"; }\n\n* .fa-solar-panel:before {\n content: \"\\f5ba\"; }\n\n* .fa-sort:before {\n content: \"\\f0dc\"; }\n\n* .fa-sort-alpha-down:before {\n content: \"\\f15d\"; }\n\n* .fa-sort-alpha-up:before {\n content: \"\\f15e\"; }\n\n* .fa-sort-amount-down:before {\n content: \"\\f160\"; }\n\n* .fa-sort-amount-up:before {\n content: \"\\f161\"; }\n\n* .fa-sort-down:before {\n content: \"\\f0dd\"; }\n\n* .fa-sort-numeric-down:before {\n content: \"\\f162\"; }\n\n* .fa-sort-numeric-up:before {\n content: \"\\f163\"; }\n\n* .fa-sort-up:before {\n content: \"\\f0de\"; }\n\n* .fa-soundcloud:before {\n content: \"\\f1be\"; }\n\n* .fa-sourcetree:before {\n content: \"\\f7d3\"; }\n\n* .fa-spa:before {\n content: \"\\f5bb\"; }\n\n* .fa-space-shuttle:before {\n content: \"\\f197\"; }\n\n* .fa-speakap:before {\n content: \"\\f3f3\"; }\n\n* .fa-spider:before {\n content: \"\\f717\"; }\n\n* .fa-spinner:before {\n content: \"\\f110\"; }\n\n* .fa-splotch:before {\n content: \"\\f5bc\"; }\n\n* .fa-spotify:before {\n content: \"\\f1bc\"; }\n\n* .fa-spray-can:before {\n content: \"\\f5bd\"; }\n\n* .fa-square:before {\n content: \"\\f0c8\"; }\n\n* .fa-square-full:before {\n content: \"\\f45c\"; }\n\n* .fa-square-root-alt:before {\n content: \"\\f698\"; }\n\n* .fa-squarespace:before {\n content: \"\\f5be\"; }\n\n* .fa-stack-exchange:before {\n content: \"\\f18d\"; }\n\n* .fa-stack-overflow:before {\n content: \"\\f16c\"; }\n\n* .fa-stamp:before {\n content: \"\\f5bf\"; }\n\n* .fa-star:before {\n content: \"\\f005\"; }\n\n* .fa-star-and-crescent:before {\n content: \"\\f699\"; }\n\n* .fa-star-half:before {\n content: \"\\f089\"; }\n\n* .fa-star-half-alt:before {\n content: \"\\f5c0\"; }\n\n* .fa-star-of-david:before {\n content: \"\\f69a\"; }\n\n* .fa-star-of-life:before {\n content: \"\\f621\"; }\n\n* .fa-staylinked:before {\n content: \"\\f3f5\"; }\n\n* .fa-steam:before {\n content: \"\\f1b6\"; }\n\n* .fa-steam-square:before {\n content: \"\\f1b7\"; }\n\n* .fa-steam-symbol:before {\n content: \"\\f3f6\"; }\n\n* .fa-step-backward:before {\n content: \"\\f048\"; }\n\n* .fa-step-forward:before {\n content: \"\\f051\"; }\n\n* .fa-stethoscope:before {\n content: \"\\f0f1\"; }\n\n* .fa-sticker-mule:before {\n content: \"\\f3f7\"; }\n\n* .fa-sticky-note:before {\n content: \"\\f249\"; }\n\n* .fa-stop:before {\n content: \"\\f04d\"; }\n\n* .fa-stop-circle:before {\n content: \"\\f28d\"; }\n\n* .fa-stopwatch:before {\n content: \"\\f2f2\"; }\n\n* .fa-store:before {\n content: \"\\f54e\"; }\n\n* .fa-store-alt:before {\n content: \"\\f54f\"; }\n\n* .fa-strava:before {\n content: \"\\f428\"; }\n\n* .fa-stream:before {\n content: \"\\f550\"; }\n\n* .fa-street-view:before {\n content: \"\\f21d\"; }\n\n* .fa-strikethrough:before {\n content: \"\\f0cc\"; }\n\n* .fa-stripe:before {\n content: \"\\f429\"; }\n\n* .fa-stripe-s:before {\n content: \"\\f42a\"; }\n\n* .fa-stroopwafel:before {\n content: \"\\f551\"; }\n\n* .fa-studiovinari:before {\n content: \"\\f3f8\"; }\n\n* .fa-stumbleupon:before {\n content: \"\\f1a4\"; }\n\n* .fa-stumbleupon-circle:before {\n content: \"\\f1a3\"; }\n\n* .fa-subscript:before {\n content: \"\\f12c\"; }\n\n* .fa-subway:before {\n content: \"\\f239\"; }\n\n* .fa-suitcase:before {\n content: \"\\f0f2\"; }\n\n* .fa-suitcase-rolling:before {\n content: \"\\f5c1\"; }\n\n* .fa-sun:before {\n content: \"\\f185\"; }\n\n* .fa-superpowers:before {\n content: \"\\f2dd\"; }\n\n* .fa-superscript:before {\n content: \"\\f12b\"; }\n\n* .fa-supple:before {\n content: \"\\f3f9\"; }\n\n* .fa-surprise:before {\n content: \"\\f5c2\"; }\n\n* .fa-suse:before {\n content: \"\\f7d6\"; }\n\n* .fa-swatchbook:before {\n content: \"\\f5c3\"; }\n\n* .fa-swimmer:before {\n content: \"\\f5c4\"; }\n\n* .fa-swimming-pool:before {\n content: \"\\f5c5\"; }\n\n* .fa-synagogue:before {\n content: \"\\f69b\"; }\n\n* .fa-sync:before {\n content: \"\\f021\"; }\n\n* .fa-sync-alt:before {\n content: \"\\f2f1\"; }\n\n* .fa-syringe:before {\n content: \"\\f48e\"; }\n\n* .fa-table:before {\n content: \"\\f0ce\"; }\n\n* .fa-table-tennis:before {\n content: \"\\f45d\"; }\n\n* .fa-tablet:before {\n content: \"\\f10a\"; }\n\n* .fa-tablet-alt:before {\n content: \"\\f3fa\"; }\n\n* .fa-tablets:before {\n content: \"\\f490\"; }\n\n* .fa-tachometer-alt:before {\n content: \"\\f3fd\"; }\n\n* .fa-tag:before {\n content: \"\\f02b\"; }\n\n* .fa-tags:before {\n content: \"\\f02c\"; }\n\n* .fa-tape:before {\n content: \"\\f4db\"; }\n\n* .fa-tasks:before {\n content: \"\\f0ae\"; }\n\n* .fa-taxi:before {\n content: \"\\f1ba\"; }\n\n* .fa-teamspeak:before {\n content: \"\\f4f9\"; }\n\n* .fa-teeth:before {\n content: \"\\f62e\"; }\n\n* .fa-teeth-open:before {\n content: \"\\f62f\"; }\n\n* .fa-telegram:before {\n content: \"\\f2c6\"; }\n\n* .fa-telegram-plane:before {\n content: \"\\f3fe\"; }\n\n* .fa-temperature-high:before {\n content: \"\\f769\"; }\n\n* .fa-temperature-low:before {\n content: \"\\f76b\"; }\n\n* .fa-tencent-weibo:before {\n content: \"\\f1d5\"; }\n\n* .fa-tenge:before {\n content: \"\\f7d7\"; }\n\n* .fa-terminal:before {\n content: \"\\f120\"; }\n\n* .fa-text-height:before {\n content: \"\\f034\"; }\n\n* .fa-text-width:before {\n content: \"\\f035\"; }\n\n* .fa-th:before {\n content: \"\\f00a\"; }\n\n* .fa-th-large:before {\n content: \"\\f009\"; }\n\n* .fa-th-list:before {\n content: \"\\f00b\"; }\n\n* .fa-the-red-yeti:before {\n content: \"\\f69d\"; }\n\n* .fa-theater-masks:before {\n content: \"\\f630\"; }\n\n* .fa-themeco:before {\n content: \"\\f5c6\"; }\n\n* .fa-themeisle:before {\n content: \"\\f2b2\"; }\n\n* .fa-thermometer:before {\n content: \"\\f491\"; }\n\n* .fa-thermometer-empty:before {\n content: \"\\f2cb\"; }\n\n* .fa-thermometer-full:before {\n content: \"\\f2c7\"; }\n\n* .fa-thermometer-half:before {\n content: \"\\f2c9\"; }\n\n* .fa-thermometer-quarter:before {\n content: \"\\f2ca\"; }\n\n* .fa-thermometer-three-quarters:before {\n content: \"\\f2c8\"; }\n\n* .fa-think-peaks:before {\n content: \"\\f731\"; }\n\n* .fa-thumbs-down:before {\n content: \"\\f165\"; }\n\n* .fa-thumbs-up:before {\n content: \"\\f164\"; }\n\n* .fa-thumbtack:before {\n content: \"\\f08d\"; }\n\n* .fa-ticket-alt:before {\n content: \"\\f3ff\"; }\n\n* .fa-times:before {\n content: \"\\f00d\"; }\n\n* .fa-times-circle:before {\n content: \"\\f057\"; }\n\n* .fa-tint:before {\n content: \"\\f043\"; }\n\n* .fa-tint-slash:before {\n content: \"\\f5c7\"; }\n\n* .fa-tired:before {\n content: \"\\f5c8\"; }\n\n* .fa-toggle-off:before {\n content: \"\\f204\"; }\n\n* .fa-toggle-on:before {\n content: \"\\f205\"; }\n\n* .fa-toilet:before {\n content: \"\\f7d8\"; }\n\n* .fa-toilet-paper:before {\n content: \"\\f71e\"; }\n\n* .fa-toolbox:before {\n content: \"\\f552\"; }\n\n* .fa-tools:before {\n content: \"\\f7d9\"; }\n\n* .fa-tooth:before {\n content: \"\\f5c9\"; }\n\n* .fa-torah:before {\n content: \"\\f6a0\"; }\n\n* .fa-torii-gate:before {\n content: \"\\f6a1\"; }\n\n* .fa-tractor:before {\n content: \"\\f722\"; }\n\n* .fa-trade-federation:before {\n content: \"\\f513\"; }\n\n* .fa-trademark:before {\n content: \"\\f25c\"; }\n\n* .fa-traffic-light:before {\n content: \"\\f637\"; }\n\n* .fa-train:before {\n content: \"\\f238\"; }\n\n* .fa-tram:before {\n content: \"\\f7da\"; }\n\n* .fa-transgender:before {\n content: \"\\f224\"; }\n\n* .fa-transgender-alt:before {\n content: \"\\f225\"; }\n\n* .fa-trash:before {\n content: \"\\f1f8\"; }\n\n* .fa-trash-alt:before {\n content: \"\\f2ed\"; }\n\n* .fa-tree:before {\n content: \"\\f1bb\"; }\n\n* .fa-trello:before {\n content: \"\\f181\"; }\n\n* .fa-tripadvisor:before {\n content: \"\\f262\"; }\n\n* .fa-trophy:before {\n content: \"\\f091\"; }\n\n* .fa-truck:before {\n content: \"\\f0d1\"; }\n\n* .fa-truck-loading:before {\n content: \"\\f4de\"; }\n\n* .fa-truck-monster:before {\n content: \"\\f63b\"; }\n\n* .fa-truck-moving:before {\n content: \"\\f4df\"; }\n\n* .fa-truck-pickup:before {\n content: \"\\f63c\"; }\n\n* .fa-tshirt:before {\n content: \"\\f553\"; }\n\n* .fa-tty:before {\n content: \"\\f1e4\"; }\n\n* .fa-tumblr:before {\n content: \"\\f173\"; }\n\n* .fa-tumblr-square:before {\n content: \"\\f174\"; }\n\n* .fa-tv:before {\n content: \"\\f26c\"; }\n\n* .fa-twitch:before {\n content: \"\\f1e8\"; }\n\n* .fa-twitter:before {\n content: \"\\f099\"; }\n\n* .fa-twitter-square:before {\n content: \"\\f081\"; }\n\n* .fa-typo3:before {\n content: \"\\f42b\"; }\n\n* .fa-uber:before {\n content: \"\\f402\"; }\n\n* .fa-ubuntu:before {\n content: \"\\f7df\"; }\n\n* .fa-uikit:before {\n content: \"\\f403\"; }\n\n* .fa-umbrella:before {\n content: \"\\f0e9\"; }\n\n* .fa-umbrella-beach:before {\n content: \"\\f5ca\"; }\n\n* .fa-underline:before {\n content: \"\\f0cd\"; }\n\n* .fa-undo:before {\n content: \"\\f0e2\"; }\n\n* .fa-undo-alt:before {\n content: \"\\f2ea\"; }\n\n* .fa-uniregistry:before {\n content: \"\\f404\"; }\n\n* .fa-universal-access:before {\n content: \"\\f29a\"; }\n\n* .fa-university:before {\n content: \"\\f19c\"; }\n\n* .fa-unlink:before {\n content: \"\\f127\"; }\n\n* .fa-unlock:before {\n content: \"\\f09c\"; }\n\n* .fa-unlock-alt:before {\n content: \"\\f13e\"; }\n\n* .fa-untappd:before {\n content: \"\\f405\"; }\n\n* .fa-upload:before {\n content: \"\\f093\"; }\n\n* .fa-ups:before {\n content: \"\\f7e0\"; }\n\n* .fa-usb:before {\n content: \"\\f287\"; }\n\n* .fa-user:before {\n content: \"\\f007\"; }\n\n* .fa-user-alt:before {\n content: \"\\f406\"; }\n\n* .fa-user-alt-slash:before {\n content: \"\\f4fa\"; }\n\n* .fa-user-astronaut:before {\n content: \"\\f4fb\"; }\n\n* .fa-user-check:before {\n content: \"\\f4fc\"; }\n\n* .fa-user-circle:before {\n content: \"\\f2bd\"; }\n\n* .fa-user-clock:before {\n content: \"\\f4fd\"; }\n\n* .fa-user-cog:before {\n content: \"\\f4fe\"; }\n\n* .fa-user-edit:before {\n content: \"\\f4ff\"; }\n\n* .fa-user-friends:before {\n content: \"\\f500\"; }\n\n* .fa-user-graduate:before {\n content: \"\\f501\"; }\n\n* .fa-user-injured:before {\n content: \"\\f728\"; }\n\n* .fa-user-lock:before {\n content: \"\\f502\"; }\n\n* .fa-user-md:before {\n content: \"\\f0f0\"; }\n\n* .fa-user-minus:before {\n content: \"\\f503\"; }\n\n* .fa-user-ninja:before {\n content: \"\\f504\"; }\n\n* .fa-user-plus:before {\n content: \"\\f234\"; }\n\n* .fa-user-secret:before {\n content: \"\\f21b\"; }\n\n* .fa-user-shield:before {\n content: \"\\f505\"; }\n\n* .fa-user-slash:before {\n content: \"\\f506\"; }\n\n* .fa-user-tag:before {\n content: \"\\f507\"; }\n\n* .fa-user-tie:before {\n content: \"\\f508\"; }\n\n* .fa-user-times:before {\n content: \"\\f235\"; }\n\n* .fa-users:before {\n content: \"\\f0c0\"; }\n\n* .fa-users-cog:before {\n content: \"\\f509\"; }\n\n* .fa-usps:before {\n content: \"\\f7e1\"; }\n\n* .fa-ussunnah:before {\n content: \"\\f407\"; }\n\n* .fa-utensil-spoon:before {\n content: \"\\f2e5\"; }\n\n* .fa-utensils:before {\n content: \"\\f2e7\"; }\n\n* .fa-vaadin:before {\n content: \"\\f408\"; }\n\n* .fa-vector-square:before {\n content: \"\\f5cb\"; }\n\n* .fa-venus:before {\n content: \"\\f221\"; }\n\n* .fa-venus-double:before {\n content: \"\\f226\"; }\n\n* .fa-venus-mars:before {\n content: \"\\f228\"; }\n\n* .fa-viacoin:before {\n content: \"\\f237\"; }\n\n* .fa-viadeo:before {\n content: \"\\f2a9\"; }\n\n* .fa-viadeo-square:before {\n content: \"\\f2aa\"; }\n\n* .fa-vial:before {\n content: \"\\f492\"; }\n\n* .fa-vials:before {\n content: \"\\f493\"; }\n\n* .fa-viber:before {\n content: \"\\f409\"; }\n\n* .fa-video:before {\n content: \"\\f03d\"; }\n\n* .fa-video-slash:before {\n content: \"\\f4e2\"; }\n\n* .fa-vihara:before {\n content: \"\\f6a7\"; }\n\n* .fa-vimeo:before {\n content: \"\\f40a\"; }\n\n* .fa-vimeo-square:before {\n content: \"\\f194\"; }\n\n* .fa-vimeo-v:before {\n content: \"\\f27d\"; }\n\n* .fa-vine:before {\n content: \"\\f1ca\"; }\n\n* .fa-vk:before {\n content: \"\\f189\"; }\n\n* .fa-vnv:before {\n content: \"\\f40b\"; }\n\n* .fa-volleyball-ball:before {\n content: \"\\f45f\"; }\n\n* .fa-volume-down:before {\n content: \"\\f027\"; }\n\n* .fa-volume-mute:before {\n content: \"\\f6a9\"; }\n\n* .fa-volume-off:before {\n content: \"\\f026\"; }\n\n* .fa-volume-up:before {\n content: \"\\f028\"; }\n\n* .fa-vote-yea:before {\n content: \"\\f772\"; }\n\n* .fa-vr-cardboard:before {\n content: \"\\f729\"; }\n\n* .fa-vuejs:before {\n content: \"\\f41f\"; }\n\n* .fa-walking:before {\n content: \"\\f554\"; }\n\n* .fa-wallet:before {\n content: \"\\f555\"; }\n\n* .fa-warehouse:before {\n content: \"\\f494\"; }\n\n* .fa-water:before {\n content: \"\\f773\"; }\n\n* .fa-weebly:before {\n content: \"\\f5cc\"; }\n\n* .fa-weibo:before {\n content: \"\\f18a\"; }\n\n* .fa-weight:before {\n content: \"\\f496\"; }\n\n* .fa-weight-hanging:before {\n content: \"\\f5cd\"; }\n\n* .fa-weixin:before {\n content: \"\\f1d7\"; }\n\n* .fa-whatsapp:before {\n content: \"\\f232\"; }\n\n* .fa-whatsapp-square:before {\n content: \"\\f40c\"; }\n\n* .fa-wheelchair:before {\n content: \"\\f193\"; }\n\n* .fa-whmcs:before {\n content: \"\\f40d\"; }\n\n* .fa-wifi:before {\n content: \"\\f1eb\"; }\n\n* .fa-wikipedia-w:before {\n content: \"\\f266\"; }\n\n* .fa-wind:before {\n content: \"\\f72e\"; }\n\n* .fa-window-close:before {\n content: \"\\f410\"; }\n\n* .fa-window-maximize:before {\n content: \"\\f2d0\"; }\n\n* .fa-window-minimize:before {\n content: \"\\f2d1\"; }\n\n* .fa-window-restore:before {\n content: \"\\f2d2\"; }\n\n* .fa-windows:before {\n content: \"\\f17a\"; }\n\n* .fa-wine-bottle:before {\n content: \"\\f72f\"; }\n\n* .fa-wine-glass:before {\n content: \"\\f4e3\"; }\n\n* .fa-wine-glass-alt:before {\n content: \"\\f5ce\"; }\n\n* .fa-wix:before {\n content: \"\\f5cf\"; }\n\n* .fa-wizards-of-the-coast:before {\n content: \"\\f730\"; }\n\n* .fa-wolf-pack-battalion:before {\n content: \"\\f514\"; }\n\n* .fa-won-sign:before {\n content: \"\\f159\"; }\n\n* .fa-wordpress:before {\n content: \"\\f19a\"; }\n\n* .fa-wordpress-simple:before {\n content: \"\\f411\"; }\n\n* .fa-wpbeginner:before {\n content: \"\\f297\"; }\n\n* .fa-wpexplorer:before {\n content: \"\\f2de\"; }\n\n* .fa-wpforms:before {\n content: \"\\f298\"; }\n\n* .fa-wpressr:before {\n content: \"\\f3e4\"; }\n\n* .fa-wrench:before {\n content: \"\\f0ad\"; }\n\n* .fa-x-ray:before {\n content: \"\\f497\"; }\n\n* .fa-xbox:before {\n content: \"\\f412\"; }\n\n* .fa-xing:before {\n content: \"\\f168\"; }\n\n* .fa-xing-square:before {\n content: \"\\f169\"; }\n\n* .fa-y-combinator:before {\n content: \"\\f23b\"; }\n\n* .fa-yahoo:before {\n content: \"\\f19e\"; }\n\n* .fa-yandex:before {\n content: \"\\f413\"; }\n\n* .fa-yandex-international:before {\n content: \"\\f414\"; }\n\n* .fa-yarn:before {\n content: \"\\f7e3\"; }\n\n* .fa-yelp:before {\n content: \"\\f1e9\"; }\n\n* .fa-yen-sign:before {\n content: \"\\f157\"; }\n\n* .fa-yin-yang:before {\n content: \"\\f6ad\"; }\n\n* .fa-yoast:before {\n content: \"\\f2b1\"; }\n\n* .fa-youtube:before {\n content: \"\\f167\"; }\n\n* .fa-youtube-square:before {\n content: \"\\f431\"; }\n\n* .fa-zhihu:before {\n content: \"\\f63f\"; }\n\n* .sr-only {\n border: 0;\n clip: rect(0, 0, 0, 0);\n height: 1px;\n margin: -1px;\n overflow: hidden;\n padding: 0;\n position: absolute;\n width: 1px; }\n\n* .sr-only-focusable:active, * .sr-only-focusable:focus {\n clip: auto;\n height: auto;\n margin: 0;\n overflow: visible;\n position: static;\n width: auto; }\n\n@font-face {\n font-family: \"Font Awesome 5 Free\";\n font-style: normal;\n font-weight: 900;\n src: url(\"./assets/fonts/webfonts/fa-solid-900.eot\");\n src: url(\"./assets/fonts/webfonts/fa-solid-900.eot?#iefix\") format(\"embedded-opentype\"), url(\"./assets/fonts/webfonts/fa-solid-900.woff2\") format(\"woff2\"), url(\"./assets/fonts/webfonts/fa-solid-900.woff\") format(\"woff\"), url(\"./assets/fonts/webfonts/fa-solid-900.ttf\") format(\"truetype\"), url(\"./assets/fonts/webfonts/fa-solid-900.svg#fontawesome\") format(\"svg\"); }\n\n.fa,\n.fas {\n font-family: \"Font Awesome 5 Free\";\n font-weight: 900; }\n\n@font-face {\n font-family: \"pficon\";\n src: url(\"./assets/pficon/pficon.eot\");\n src: url(\"./assets/pficon/pficon.eot?#iefix\") format(\"eot\"), url(\"./assets/pficon/pficon.woff2\") format(\"woff2\"), url(\"./assets/pficon/pficon.woff\") format(\"woff\"), url(\"./assets/pficon/pficon.ttf\") format(\"truetype\"), url(\"./assets/pficon/pficon.svg#pficon\") format(\"svg\"); }\n\n.pf-icon-aa-circle-o:before, .pf-icon-add-circle-o:before, .pf-icon-ansible-tower:before, .pf-icon-applications:before, .pf-icon-arrow:before, .pf-icon-asleep:before, .pf-icon-attention-bell:before, .pf-icon-automation:before, .pf-icon-bell:before, .pf-icon-blueprint:before, .pf-icon-build:before, .pf-icon-builder-image:before, .pf-icon-bundle:before, .pf-icon-catalog:before, .pf-icon-chat:before, .pf-icon-close:before, .pf-icon-cloud-security:before, .pf-icon-cloud-tenant:before, .pf-icon-cluster:before, .pf-icon-connected:before, .pf-icon-container-node:before, .pf-icon-cpu:before, .pf-icon-degraded:before, .pf-icon-disconnected:before, .pf-icon-domain:before, .pf-icon-edit:before, .pf-icon-enhancement:before, .pf-icon-enterprise:before, .pf-icon-equalizer:before, .pf-icon-error-circle-o:before, .pf-icon-export:before, .pf-icon-filter:before, .pf-icon-flavor:before, .pf-icon-folder-close:before, .pf-icon-folder-open:before, .pf-icon-globe-route:before, .pf-icon-help:before, .pf-icon-history:before, .pf-icon-home:before, .pf-icon-import:before, .pf-icon-in-progress:before, .pf-icon-info:before, .pf-icon-infrastructure:before, .pf-icon-integration:before, .pf-icon-key:before, .pf-icon-locked:before, .pf-icon-maintenance:before, .pf-icon-memory:before, .pf-icon-messages:before, .pf-icon-middleware:before, .pf-icon-migration:before, .pf-icon-module:before, .pf-icon-monitoring:before, .pf-icon-namespaces:before, .pf-icon-network:before, .pf-icon-new-process:before, .pf-icon-not-started:before, .pf-icon-off:before, .pf-icon-ok:before, .pf-icon-on-running:before, .pf-icon-on:before, .pf-icon-openshift:before, .pf-icon-openstack:before, .pf-icon-optimize:before, .pf-icon-orders:before, .pf-icon-os-image:before, .pf-icon-package:before, .pf-icon-paused:before, .pf-icon-pending:before, .pf-icon-pficon-dragdrop:before, .pf-icon-pficon-history:before, .pf-icon-pficon-network-range:before, .pf-icon-pficon-satellite:before, .pf-icon-pficon-sort-common-asc:before, .pf-icon-pficon-sort-common-desc:before, .pf-icon-pficon-template:before, .pf-icon-pficon-vcenter:before, .pf-icon-plugged:before, .pf-icon-port:before, .pf-icon-print:before, .pf-icon-private:before, .pf-icon-process-automation:before, .pf-icon-project:before, .pf-icon-rebalance:before, .pf-icon-rebooting:before, .pf-icon-regions:before, .pf-icon-registry:before, .pf-icon-remove2:before, .pf-icon-replicator:before, .pf-icon-repository:before, .pf-icon-resource-pool:before, .pf-icon-resources-almost-empty:before, .pf-icon-resources-almost-full:before, .pf-icon-resources-empty:before, .pf-icon-resources-full:before, .pf-icon-running:before, .pf-icon-save:before, .pf-icon-screen:before, .pf-icon-security:before, .pf-icon-server-group:before, .pf-icon-server:before, .pf-icon-service-catalog:before, .pf-icon-service:before, .pf-icon-services:before, .pf-icon-spinner:before, .pf-icon-spinner2:before, .pf-icon-storage-domain:before, .pf-icon-tenant:before, .pf-icon-thumb-tack:before, .pf-icon-topology:before, .pf-icon-trend-down:before, .pf-icon-trend-up:before, .pf-icon-unknown:before, .pf-icon-unlocked:before, .pf-icon-unplugged:before, .pf-icon-user:before, .pf-icon-users:before, .pf-icon-virtual-machine:before, .pf-icon-volume:before, .pf-icon-warning-triangle:before, .pf-icon-zone:before {\n font-family: \"pficon\";\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n font-style: normal;\n font-variant: normal;\n font-weight: normal;\n text-decoration: none;\n text-transform: none; }\n\n.pf-icon-aa-circle-o:before {\n content: \"\"; }\n\n.pf-icon-add-circle-o:before {\n content: \"\"; }\n\n.pf-icon-ansible-tower:before {\n content: \"\"; }\n\n.pf-icon-applications:before {\n content: \"\"; }\n\n.pf-icon-arrow:before {\n content: \"\"; }\n\n.pf-icon-asleep:before {\n content: \"\"; }\n\n.pf-icon-attention-bell:before {\n content: \"\"; }\n\n.pf-icon-automation:before {\n content: \"\"; }\n\n.pf-icon-bell:before {\n content: \"\"; }\n\n.pf-icon-blueprint:before {\n content: \"\"; }\n\n.pf-icon-build:before {\n content: \"\"; }\n\n.pf-icon-builder-image:before {\n content: \"\"; }\n\n.pf-icon-bundle:before {\n content: \"\"; }\n\n.pf-icon-catalog:before {\n content: \"\"; }\n\n.pf-icon-chat:before {\n content: \"\"; }\n\n.pf-icon-close:before {\n content: \"\"; }\n\n.pf-icon-cloud-security:before {\n content: \"\"; }\n\n.pf-icon-cloud-tenant:before {\n content: \"\"; }\n\n.pf-icon-cluster:before {\n content: \"\"; }\n\n.pf-icon-connected:before {\n content: \"\"; }\n\n.pf-icon-container-node:before {\n content: \"\"; }\n\n.pf-icon-cpu:before {\n content: \"\"; }\n\n.pf-icon-degraded:before {\n content: \"\"; }\n\n.pf-icon-disconnected:before {\n content: \"\"; }\n\n.pf-icon-domain:before {\n content: \"\"; }\n\n.pf-icon-edit:before {\n content: \"\"; }\n\n.pf-icon-enhancement:before {\n content: \"\"; }\n\n.pf-icon-enterprise:before {\n content: \"\"; }\n\n.pf-icon-equalizer:before {\n content: \"\"; }\n\n.pf-icon-error-circle-o:before {\n content: \"\"; }\n\n.pf-icon-export:before {\n content: \"\"; }\n\n.pf-icon-filter:before {\n content: \"\"; }\n\n.pf-icon-flavor:before {\n content: \"\"; }\n\n.pf-icon-folder-close:before {\n content: \"\"; }\n\n.pf-icon-folder-open:before {\n content: \"\"; }\n\n.pf-icon-globe-route:before {\n content: \"\"; }\n\n.pf-icon-help:before {\n content: \"\"; }\n\n.pf-icon-history:before {\n content: \"\"; }\n\n.pf-icon-home:before {\n content: \"\"; }\n\n.pf-icon-import:before {\n content: \"\"; }\n\n.pf-icon-in-progress:before {\n content: \"\"; }\n\n.pf-icon-info:before {\n content: \"\"; }\n\n.pf-icon-infrastructure:before {\n content: \"\"; }\n\n.pf-icon-integration:before {\n content: \"\"; }\n\n.pf-icon-key:before {\n content: \"\"; }\n\n.pf-icon-locked:before {\n content: \"\"; }\n\n.pf-icon-maintenance:before {\n content: \"\"; }\n\n.pf-icon-memory:before {\n content: \"\"; }\n\n.pf-icon-messages:before {\n content: \"\"; }\n\n.pf-icon-middleware:before {\n content: \"\"; }\n\n.pf-icon-migration:before {\n content: \"\"; }\n\n.pf-icon-module:before {\n content: \"\"; }\n\n.pf-icon-monitoring:before {\n content: \"\"; }\n\n.pf-icon-namespaces:before {\n content: \"\"; }\n\n.pf-icon-network:before {\n content: \"\"; }\n\n.pf-icon-new-process:before {\n content: \"\"; }\n\n.pf-icon-not-started:before {\n content: \"\"; }\n\n.pf-icon-off:before {\n content: \"\"; }\n\n.pf-icon-ok:before {\n content: \"\"; }\n\n.pf-icon-on-running:before {\n content: \"\"; }\n\n.pf-icon-on:before {\n content: \"\"; }\n\n.pf-icon-openshift:before {\n content: \"\"; }\n\n.pf-icon-openstack:before {\n content: \"\"; }\n\n.pf-icon-optimize:before {\n content: \"\"; }\n\n.pf-icon-orders:before {\n content: \"\"; }\n\n.pf-icon-os-image:before {\n content: \"\"; }\n\n.pf-icon-package:before {\n content: \"\"; }\n\n.pf-icon-paused:before {\n content: \"\"; }\n\n.pf-icon-pending:before {\n content: \"\"; }\n\n.pf-icon-pficon-dragdrop:before {\n content: \"\"; }\n\n.pf-icon-pficon-history:before {\n content: \"\"; }\n\n.pf-icon-pficon-network-range:before {\n content: \"\"; }\n\n.pf-icon-pficon-satellite:before {\n content: \"\"; }\n\n.pf-icon-pficon-sort-common-asc:before {\n content: \"\"; }\n\n.pf-icon-pficon-sort-common-desc:before {\n content: \"\"; }\n\n.pf-icon-pficon-template:before {\n content: \"\"; }\n\n.pf-icon-pficon-vcenter:before {\n content: \"\"; }\n\n.pf-icon-plugged:before {\n content: \"\"; }\n\n.pf-icon-port:before {\n content: \"\"; }\n\n.pf-icon-print:before {\n content: \"\"; }\n\n.pf-icon-private:before {\n content: \"\"; }\n\n.pf-icon-process-automation:before {\n content: \"\"; }\n\n.pf-icon-project:before {\n content: \"\"; }\n\n.pf-icon-rebalance:before {\n content: \"\"; }\n\n.pf-icon-rebooting:before {\n content: \"\"; }\n\n.pf-icon-regions:before {\n content: \"\"; }\n\n.pf-icon-registry:before {\n content: \"\"; }\n\n.pf-icon-remove2:before {\n content: \"\"; }\n\n.pf-icon-replicator:before {\n content: \"\"; }\n\n.pf-icon-repository:before {\n content: \"\"; }\n\n.pf-icon-resource-pool:before {\n content: \"\"; }\n\n.pf-icon-resources-almost-empty:before {\n content: \"\"; }\n\n.pf-icon-resources-almost-full:before {\n content: \"\"; }\n\n.pf-icon-resources-empty:before {\n content: \"\"; }\n\n.pf-icon-resources-full:before {\n content: \"\"; }\n\n.pf-icon-running:before {\n content: \"\"; }\n\n.pf-icon-save:before {\n content: \"\"; }\n\n.pf-icon-screen:before {\n content: \"\"; }\n\n.pf-icon-security:before {\n content: \"\"; }\n\n.pf-icon-server-group:before {\n content: \"\"; }\n\n.pf-icon-server:before {\n content: \"\"; }\n\n.pf-icon-service-catalog:before {\n content: \"\"; }\n\n.pf-icon-service:before {\n content: \"\"; }\n\n.pf-icon-services:before {\n content: \"\"; }\n\n.pf-icon-spinner:before {\n content: \"\"; }\n\n.pf-icon-spinner2:before {\n content: \"\"; }\n\n.pf-icon-storage-domain:before {\n content: \"\"; }\n\n.pf-icon-tenant:before {\n content: \"\"; }\n\n.pf-icon-thumb-tack:before {\n content: \"\"; }\n\n.pf-icon-topology:before {\n content: \"\"; }\n\n.pf-icon-trend-down:before {\n content: \"\"; }\n\n.pf-icon-trend-up:before {\n content: \"\"; }\n\n.pf-icon-unknown:before {\n content: \"\"; }\n\n.pf-icon-unlocked:before {\n content: \"\"; }\n\n.pf-icon-unplugged:before {\n content: \"\"; }\n\n.pf-icon-user:before {\n content: \"\"; }\n\n.pf-icon-users:before {\n content: \"\"; }\n\n.pf-icon-virtual-machine:before {\n content: \"\"; }\n\n.pf-icon-volume:before {\n content: \"\"; }\n\n.pf-icon-warning-triangle:before {\n content: \"\"; }\n\n.pf-icon-zone:before {\n content: \"\"; }\n\n.pf-c-about-modal-box {\n --pf-c-about-modal-box--BackgroundColor: var(--pf-global--palette--black-1000);\n --pf-c-about-modal-box--BoxShadow: 0 0 100px 0 rgba(255, 255, 255, .05);\n --pf-c-about-modal-box--ZIndex: var(--pf-global--ZIndex--xl);\n --pf-c-about-modal-box--Height: 100%;\n --pf-c-about-modal-box--lg--Height: 47.625rem;\n --pf-c-about-modal-box--lg--MaxHeight: calc(100% - var(--pf-global--spacer--xl));\n --pf-c-about-modal-box--Width: 100vw;\n --pf-c-about-modal-box--lg--Width: calc(100% - (var(--pf-global--spacer--3xl) * 2));\n --pf-c-about-modal-box--lg--MaxWidth: 77rem;\n --pf-c-about-modal-box--PaddingTop: var(--pf-global--spacer--xl);\n --pf-c-about-modal-box--PaddingRight: var(--pf-global--spacer--xl);\n --pf-c-about-modal-box--PaddingBottom: var(--pf-global--spacer--xl);\n --pf-c-about-modal-box--PaddingLeft: var(--pf-global--spacer--xl);\n --pf-c-about-modal-box--sm--PaddingTop: var(--pf-global--spacer--3xl);\n --pf-c-about-modal-box--sm--PaddingRight: var(--pf-global--spacer--3xl);\n --pf-c-about-modal-box--sm--PaddingBottom: var(--pf-global--spacer--3xl);\n --pf-c-about-modal-box--sm--PaddingLeft: var(--pf-global--spacer--3xl);\n --pf-c-about-modal-box--sm--grid-template-columns: 5fr 1fr;\n --pf-c-about-modal-box--lg--grid-template-columns: 1fr .6fr;\n --pf-c-about-modal-box__brand--PaddingTop: var(--pf-global--spacer--2xl);\n --pf-c-about-modal-box__brand--PaddingRight: var(--pf-global--spacer--xl);\n --pf-c-about-modal-box__brand--PaddingLeft: var(--pf-global--spacer--xl);\n --pf-c-about-modal-box__brand--PaddingBottom: var(--pf-global--spacer--xl);\n --pf-c-about-modal-box__brand--sm--PaddingRight: var(--pf-global--spacer--3xl);\n --pf-c-about-modal-box__brand--sm--PaddingLeft: var(--pf-global--spacer--3xl);\n --pf-c-about-modal-box__brand--sm--PaddingBottom: var(--pf-global--spacer--3xl);\n --pf-c-about-modal-box__close--ZIndex: var(--pf-global--ZIndex--2xl);\n --pf-c-about-modal-box__close--PaddingTop: var(--pf-global--spacer--2xl);\n --pf-c-about-modal-box__close--PaddingRight: var(--pf-global--spacer--xl);\n --pf-c-about-modal-box__close--PaddingBottom: var(--pf-global--spacer--xl);\n --pf-c-about-modal-box__close--sm--PaddingBottom: var(--pf-global--spacer--3xl);\n --pf-c-about-modal-box__close--sm--PaddingRight: 0;\n --pf-c-about-modal-box__close--lg--PaddingRight: var(--pf-global--spacer--3xl);\n --pf-c-about-modal-box__close--c-button--Color: var(--pf-global--Color--100);\n --pf-c-about-modal-box__close--c-button--FontSize: var(--pf-global--FontSize--xl);\n --pf-c-about-modal-box__close--c-button--BorderRadius: var(--pf-global--BorderRadius--lg);\n --pf-c-about-modal-box__close--c-button--Width: calc(var(--pf-c-about-modal-box__close--c-button--FontSize) * 2);\n --pf-c-about-modal-box__close--c-button--Height: calc(var(--pf-c-about-modal-box__close--c-button--FontSize) * 2);\n --pf-c-about-modal-box__close--c-button--BackgroundColor: var(--pf-global--palette--black-1000);\n --pf-c-about-modal-box__close--c-button--hover--BackgroundColor: rgba(3, 3, 3, 0.4);\n --pf-c-about-modal-box__hero--sm--BackgroundImage: url(\"./assets/images/pfbg_992@2x.jpg\");\n --pf-c-about-modal-box__hero--sm--BackgroundPosition: top left;\n --pf-c-about-modal-box__hero--sm--BackgroundSize: cover;\n --pf-c-about-modal-box__brand-image--Height: 2.5rem;\n --pf-c-about-modal-box__header--PaddingRight: var(--pf-global--spacer--xl);\n --pf-c-about-modal-box__header--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-about-modal-box__header--PaddingLeft: var(--pf-global--spacer--xl);\n --pf-c-about-modal-box__header--sm--PaddingRight: var(--pf-global--spacer--3xl);\n --pf-c-about-modal-box__header--sm--PaddingLeft: var(--pf-global--spacer--3xl);\n --pf-c-about-modal-box__strapline--PaddingTop: var(--pf-global--spacer--xl);\n --pf-c-about-modal-box__strapline--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-about-modal-box__strapline--sm--PaddingTop: var(--pf-global--spacer--2xl);\n --pf-c-about-modal-box__content--MarginTop: var(--pf-global--spacer--xl);\n --pf-c-about-modal-box__content--MarginRight: var(--pf-global--spacer--xl);\n --pf-c-about-modal-box__content--MarginBottom: var(--pf-global--spacer--xl);\n --pf-c-about-modal-box__content--MarginLeft: var(--pf-global--spacer--xl);\n --pf-c-about-modal-box__content--sm--MarginTop: var(--pf-global--spacer--2xl);\n --pf-c-about-modal-box__content--sm--MarginRight: var(--pf-global--spacer--3xl);\n --pf-c-about-modal-box__content--sm--MarginBottom: var(--pf-global--spacer--2xl);\n --pf-c-about-modal-box__content--sm--MarginLeft: var(--pf-global--spacer--3xl);\n color: var(--pf-global--Color--100);\n position: relative;\n z-index: var(--pf-c-about-modal-box--ZIndex);\n display: grid;\n grid-template-rows: max-content max-content auto;\n grid-template-areas: \"brand close\" \"header header\" \"content content\";\n width: var(--pf-c-about-modal-box--Width);\n height: var(--pf-c-about-modal-box--Height);\n overflow-x: hidden;\n overflow-y: auto;\n background-color: var(--pf-c-about-modal-box--BackgroundColor);\n box-shadow: var(--pf-c-about-modal-box--BoxShadow); }\n @media screen and (min-width: 576px) {\n .pf-c-about-modal-box {\n --pf-c-about-modal-box--PaddingTop: var(--pf-c-about-modal-box--sm--PaddingTop);\n --pf-c-about-modal-box--PaddingRight: var(--pf-c-about-modal-box--sm--PaddingRight);\n --pf-c-about-modal-box--PaddingBottom: var(--pf-c-about-modal-box--sm--PaddingBottom);\n --pf-c-about-modal-box--PaddingLeft: var(--pf-c-about-modal-box--sm--PaddingLeft); } }\n @media screen and (min-width: 576px) {\n .pf-c-about-modal-box {\n --pf-c-about-modal-box__brand--PaddingRight: var(--pf-c-about-modal-box__brand--sm--PaddingRight);\n --pf-c-about-modal-box__brand--PaddingLeft: var(--pf-c-about-modal-box__brand--sm--PaddingLeft);\n --pf-c-about-modal-box__brand--PaddingBottom: var(--pf-c-about-modal-box__brand--sm--PaddingBottom); } }\n @media only screen and (min-width: 576px) {\n .pf-c-about-modal-box {\n --pf-c-about-modal-box__close--PaddingRight: var(--pf-c-about-modal-box__close--sm--PaddingRight);\n --pf-c-about-modal-box__close--PaddingBottom: var(--pf-c-about-modal-box__close--sm--PaddingBottom); } }\n @media only screen and (min-width: 992px) {\n .pf-c-about-modal-box {\n --pf-c-about-modal-box__close--PaddingRight: var(--pf-c-about-modal-box__close--lg--PaddingRight); } }\n @media only screen and (min-width: 576px) {\n .pf-c-about-modal-box {\n --pf-c-about-modal-box__header--PaddingRight: var(--pf-c-about-modal-box__header--sm--PaddingRight);\n --pf-c-about-modal-box__header--PaddingLeft: var(--pf-c-about-modal-box__header--sm--PaddingLeft); } }\n @media only screen and (min-width: 576px) {\n .pf-c-about-modal-box {\n --pf-c-about-modal-box__strapline--PaddingTop: var(--pf-c-about-modal-box__strapline--sm--PaddingTop); } }\n @media only screen and (min-width: 576px) {\n .pf-c-about-modal-box {\n --pf-c-about-modal-box__content--MarginTop: var(--pf-c-about-modal-box__content--sm--MarginTop);\n --pf-c-about-modal-box__content--MarginRight: var(--pf-c-about-modal-box__content--sm--MarginRight);\n --pf-c-about-modal-box__content--MarginBottom: var(--pf-c-about-modal-box__content--sm--MarginBottom);\n --pf-c-about-modal-box__content--MarginLeft: var(--pf-c-about-modal-box__content--sm--MarginLeft); } }\n @media only screen and (min-width: 576px) {\n .pf-c-about-modal-box {\n grid-template-columns: var(--pf-c-about-modal-box--sm--grid-template-columns);\n grid-template-areas: \"brand hero\" \"header hero\" \"content hero\"; } }\n @media only screen and (min-width: 992px) {\n .pf-c-about-modal-box {\n --pf-c-about-modal-box--Height: var(--pf-c-about-modal-box--lg--Height);\n --pf-c-about-modal-box--Width: var(--pf-c-about-modal-box--lg--Width);\n grid-template-columns: var(--pf-c-about-modal-box--lg--grid-template-columns);\n grid-template-rows: max-content max-content auto;\n max-width: var(--pf-c-about-modal-box--lg--MaxWidth);\n max-height: var(--pf-c-about-modal-box--lg--MaxHeight); } }\n\n.pf-c-about-modal-box__brand {\n grid-area: brand;\n display: flex;\n padding: var(--pf-c-about-modal-box__brand--PaddingTop) var(--pf-c-about-modal-box__brand--PaddingRight) var(--pf-c-about-modal-box__brand--PaddingBottom) var(--pf-c-about-modal-box__brand--PaddingLeft); }\n\n.pf-c-about-modal-box__brand-image {\n height: var(--pf-c-about-modal-box__brand-image--Height); }\n\n.pf-c-about-modal-box__header {\n grid-area: header;\n display: flex;\n flex-direction: column;\n padding-right: var(--pf-c-about-modal-box__header--PaddingRight);\n padding-bottom: var(--pf-c-about-modal-box__header--PaddingBottom);\n padding-left: var(--pf-c-about-modal-box__header--PaddingLeft); }\n\n.pf-c-about-modal-box__strapline {\n padding-top: var(--pf-c-about-modal-box__strapline--PaddingTop);\n margin-top: auto;\n font-size: var(--pf-c-about-modal-box__strapline--FontSize); }\n\n.pf-c-about-modal-box__content {\n display: flex;\n flex-direction: column;\n grid-area: content;\n margin: var(--pf-c-about-modal-box__content--MarginTop) var(--pf-c-about-modal-box__content--MarginRight) var(--pf-c-about-modal-box__content--MarginBottom) var(--pf-c-about-modal-box__content--MarginLeft);\n overflow-x: hidden;\n overflow-y: auto;\n overscroll-behavior: contain;\n -webkit-overflow-scrolling: touch;\n word-break: break-word; }\n @media screen and (min-width: 576px) {\n .pf-c-about-modal-box__content {\n overflow: visible;\n overscroll-behavior: auto; } }\n\n.pf-c-about-modal-box__close {\n grid-area: close;\n position: sticky;\n top: 0;\n display: flex;\n align-items: flex-start;\n justify-content: flex-end;\n padding-top: var(--pf-c-about-modal-box__close--PaddingTop);\n padding-right: var(--pf-c-about-modal-box__close--PaddingRight);\n padding-bottom: var(--pf-c-about-modal-box__close--PaddingBottom); }\n @media only screen and (min-width: 576px) {\n .pf-c-about-modal-box__close {\n grid-area: 1 / 2;\n justify-content: center; } }\n @media only screen and (min-width: 992px) {\n .pf-c-about-modal-box__close {\n justify-content: flex-end; } }\n .pf-c-about-modal-box__close .pf-c-button.pf-m-plain {\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--pf-c-about-modal-box__close--c-button--Width);\n height: var(--pf-c-about-modal-box__close--c-button--Height);\n font-size: var(--pf-c-about-modal-box__close--c-button--FontSize);\n color: var(--pf-c-about-modal-box__close--c-button--Color);\n background-color: var(--pf-c-about-modal-box__close--c-button--BackgroundColor);\n border-radius: var(--pf-c-about-modal-box__close--c-button--BorderRadius); }\n .pf-c-about-modal-box__close .pf-c-button.pf-m-plain:hover {\n --pf-c-about-modal-box__close--c-button--BackgroundColor: var(--pf-c-about-modal-box__close--c-button--hover--BackgroundColor); }\n\n.pf-c-about-modal-box__hero {\n display: none;\n visibility: hidden; }\n @media only screen and (min-width: 576px) {\n .pf-c-about-modal-box__hero {\n display: block;\n visibility: visible;\n background-image: var(--pf-c-about-modal-box__hero--sm--BackgroundImage);\n background-repeat: no-repeat;\n background-attachment: fixed;\n background-position: var(--pf-c-about-modal-box__hero--sm--BackgroundPosition);\n background-size: var(--pf-c-about-modal-box__hero--sm--BackgroundSize);\n grid-area: hero; } }\n\n.pf-c-accordion {\n --pf-c-accordion--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-accordion__toggle--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-accordion__toggle--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-accordion__toggle--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-accordion__toggle--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-accordion__toggle--before--BackgroundColor: transparent;\n --pf-c-accordion__toggle--hover--BackgroundColor: var(--pf-global--BackgroundColor--200);\n --pf-c-accordion__toggle--focus--BackgroundColor: var(--pf-global--BackgroundColor--200);\n --pf-c-accordion__toggle--active--BackgroundColor: var(--pf-global--BackgroundColor--200);\n --pf-c-accordion__toggle--before--Width: var(--pf-global--BorderWidth--lg);\n --pf-c-accordion__toggle--m-expanded--before--BackgroundColor: var(--pf-global--primary-color--100);\n --pf-c-accordion__toggle-text--MaxWidth: calc(100% - var(--pf-global--spacer--lg));\n --pf-c-accordion__toggle--hover__toggle-text--Color: var(--pf-global--link--Color);\n --pf-c-accordion__toggle--active__toggle-text--Color: var(--pf-global--link--Color);\n --pf-c-accordion__toggle--active__toggle-text--FontWeight: var(--pf-global--FontWeight--semi-bold);\n --pf-c-accordion__toggle--focus__toggle-text--Color: var(--pf-global--link--Color);\n --pf-c-accordion__toggle--focus__toggle-text--FontWeight: var(--pf-global--FontWeight--semi-bold);\n --pf-c-accordion__toggle--m-expanded__toggle-text--Color: var(--pf-global--link--Color);\n --pf-c-accordion__toggle--m-expanded__toggle-text--FontWeight: var(--pf-global--FontWeight--semi-bold);\n --pf-c-accordion__toggle-icon--Transition: .2s ease-in 0s;\n --pf-c-accordion__toggle--m-expanded__toggle-icon--Rotate: 90deg;\n --pf-c-accordion__expanded-content-body--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-accordion__expanded-content-body--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-accordion__expanded-content-body--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-accordion__expanded-content-body--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-accordion__expanded-content--Color: var(--pf-global--Color--200);\n --pf-c-accordion__expanded-content--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-accordion__expanded-content-body--before--BackgroundColor: transparent;\n --pf-c-accordion__expanded-content-body--before--Width: var(--pf-global--BorderWidth--lg);\n --pf-c-accordion__expanded-content--m-expanded__expanded-content-body--before--BackgroundColor: var(--pf-global--primary-color--100);\n --pf-c-accordion__expanded-content--m-fixed--MaxHeight: 9.375rem;\n color: var(--pf-global--Color--100);\n background-color: var(--pf-c-accordion--BackgroundColor); }\n\n.pf-c-accordion__toggle {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n padding: var(--pf-c-accordion__toggle--PaddingTop) var(--pf-c-accordion__toggle--PaddingRight) var(--pf-c-accordion__toggle--PaddingBottom) var(--pf-c-accordion__toggle--PaddingLeft);\n border: 0; }\n .pf-c-accordion__toggle::before {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: var(--pf-c-accordion__toggle--before--Width);\n content: \"\";\n background-color: var(--pf-c-accordion__toggle--before--BackgroundColor); }\n .pf-c-accordion__toggle.pf-m-expanded {\n --pf-c-accordion__toggle--before--BackgroundColor: var(--pf-c-accordion__toggle--m-expanded--before--BackgroundColor); }\n .pf-c-accordion__toggle.pf-m-expanded .pf-c-accordion__toggle-text {\n font-weight: var(--pf-c-accordion__toggle--m-expanded__toggle-text--FontWeight);\n color: var(--pf-c-accordion__toggle--m-expanded__toggle-text--Color); }\n .pf-c-accordion__toggle.pf-m-expanded .pf-c-accordion__toggle-icon {\n transform: rotate(var(--pf-c-accordion__toggle--m-expanded__toggle-icon--Rotate)); }\n .pf-c-accordion__toggle:hover {\n background-color: var(--pf-c-accordion__toggle--hover--BackgroundColor); }\n .pf-c-accordion__toggle:hover .pf-c-accordion__toggle-text {\n color: var(--pf-c-accordion__toggle--hover__toggle-text--Color); }\n .pf-c-accordion__toggle:focus {\n background-color: var(--pf-c-accordion__toggle--focus--BackgroundColor); }\n .pf-c-accordion__toggle:focus .pf-c-accordion__toggle-text {\n font-weight: var(--pf-c-accordion__toggle--focus__toggle-text--FontWeight);\n color: var(--pf-c-accordion__toggle--focus__toggle-text--Color); }\n .pf-c-accordion__toggle:active {\n background-color: var(--pf-c-accordion__toggle--active--BackgroundColor); }\n .pf-c-accordion__toggle:active .pf-c-accordion__toggle-text {\n font-weight: var(--pf-c-accordion__toggle--active__toggle-text--FontWeight);\n color: var(--pf-c-accordion__toggle--active__toggle-text--Color); }\n\n.pf-c-accordion__toggle-text {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n max-width: var(--pf-c-accordion__toggle-text--MaxWidth); }\n\n.pf-c-accordion__toggle-icon {\n transition: var(--pf-c-accordion__toggle-icon--Transition); }\n\n.pf-c-accordion__expanded-content {\n font-size: var(--pf-c-accordion__expanded-content--FontSize);\n color: var(--pf-c-accordion__expanded-content--Color); }\n .pf-c-accordion__expanded-content.pf-m-fixed {\n max-height: var(--pf-c-accordion__expanded-content--m-fixed--MaxHeight);\n overflow-y: auto; }\n .pf-c-accordion__expanded-content.pf-m-expanded {\n --pf-c-accordion__expanded-content-body--before--BackgroundColor: var(--pf-c-accordion__expanded-content--m-expanded__expanded-content-body--before--BackgroundColor); }\n\n.pf-c-accordion__expanded-content-body {\n position: relative;\n padding: var(--pf-c-accordion__expanded-content-body--PaddingTop) var(--pf-c-accordion__expanded-content-body--PaddingRight) var(--pf-c-accordion__expanded-content-body--PaddingBottom) var(--pf-c-accordion__expanded-content-body--PaddingLeft); }\n .pf-c-accordion__expanded-content-body::before {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: var(--pf-c-accordion__expanded-content-body--before--Width);\n content: \"\";\n background-color: var(--pf-c-accordion__expanded-content-body--before--BackgroundColor); }\n\n.pf-c-action-list {\n --pf-c-action-list--m-icon--spacer: 0;\n --pf-c-action-list--child--spacer-base: var(--pf-global--spacer--md);\n --pf-c-action-list--group--spacer-base: var(--pf-global--spacer--2xl); }\n\n.pf-c-action-list,\n.pf-c-action-list__group {\n --pf-c-action-list--child--spacer: var(--pf-c-action-list--child--spacer-base);\n --pf-c-action-list--group--spacer: var(--pf-c-action-list--group--spacer-base);\n display: flex;\n align-items: center; }\n .pf-c-action-list > * + *,\n .pf-c-action-list__group > * + * {\n margin-left: var(--pf-c-action-list--child--spacer); }\n .pf-c-action-list > * + .pf-c-action-list__group,\n .pf-c-action-list .pf-c-action-list__group + *,\n .pf-c-action-list__group > * + .pf-c-action-list__group,\n .pf-c-action-list__group .pf-c-action-list__group + * {\n margin-left: var(--pf-c-action-list--group--spacer); }\n .pf-c-action-list.pf-m-icons,\n .pf-c-action-list__group.pf-m-icons {\n --pf-c-action-list--child--spacer: var(--pf-c-action-list--m-icon--spacer); }\n\n.pf-c-alert {\n --pf-c-alert--BoxShadow: var(--pf-global--BoxShadow--lg);\n --pf-c-alert--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-alert--GridTemplateColumns: max-content 1fr max-content;\n --pf-c-alert--BorderTopWidth: var(--pf-global--BorderWidth--md);\n --pf-c-alert--BorderTopColor: var(--pf-global--default-color--200);\n --pf-c-alert--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-alert--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-alert--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-alert--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-alert__FontSize: var(--pf-global--FontSize--sm);\n --pf-c-alert__icon--Color: var(--pf-global--default-color--200);\n --pf-c-alert__icon--MarginTop: 0.0625rem;\n --pf-c-alert__icon--MarginRight: var(--pf-global--spacer--sm);\n --pf-c-alert__icon--FontSize: var(--pf-global--icon--FontSize--md);\n --pf-c-alert__title--FontWeight: var(--pf-global--FontWeight--bold);\n --pf-c-alert__title--Color: var(--pf-global--default-color--300);\n --pf-c-alert__title--max-lines: 1;\n --pf-c-alert__action--MarginTop: calc(var(--pf-global--spacer--form-element) * -1);\n --pf-c-alert__action--MarginBottom: calc(var(--pf-global--spacer--form-element) * -1);\n --pf-c-alert__action--TranslateY: 0.125rem;\n --pf-c-alert__action--MarginRight: calc(var(--pf-global--spacer--sm) * -1);\n --pf-c-alert__description--PaddingTop: var(--pf-global--spacer--xs);\n --pf-c-alert__action-group--PaddingTop: var(--pf-global--spacer--xs);\n --pf-c-alert__description--action-group--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-alert__action-group__c-button--not-last-child--MarginRight: var(--pf-global--spacer--lg);\n --pf-c-alert--m-success--BorderTopColor: var(--pf-global--success-color--100);\n --pf-c-alert--m-success__icon--Color: var(--pf-global--success-color--100);\n --pf-c-alert--m-success__title--Color: var(--pf-global--success-color--200);\n --pf-c-alert--m-danger--BorderTopColor: var(--pf-global--danger-color--100);\n --pf-c-alert--m-danger__icon--Color: var(--pf-global--danger-color--100);\n --pf-c-alert--m-danger__title--Color: var(--pf-global--danger-color--200);\n --pf-c-alert--m-warning--BorderTopColor: var(--pf-global--warning-color--100);\n --pf-c-alert--m-warning__icon--Color: var(--pf-global--warning-color--100);\n --pf-c-alert--m-warning__title--Color: var(--pf-global--warning-color--200);\n --pf-c-alert--m-info--BorderTopColor: var(--pf-global--info-color--100);\n --pf-c-alert--m-info__icon--Color: var(--pf-global--info-color--100);\n --pf-c-alert--m-info__title--Color: var(--pf-global--info-color--200);\n --pf-c-alert--m-inline--BoxShadow: none;\n --pf-c-alert--m-inline--BackgroundColor: var(--pf-global--palette--cyan-50);\n --pf-c-alert--m-inline--m-success--BackgroundColor: var(--pf-global--palette--green-50);\n --pf-c-alert--m-inline--m-danger--BackgroundColor: var(--pf-global--palette--red-50);\n --pf-c-alert--m-inline--m-warning--BackgroundColor: var(--pf-global--palette--gold-50);\n --pf-c-alert--m-inline--m-info--BackgroundColor: var(--pf-global--palette--blue-50);\n color: var(--pf-global--Color--100);\n position: relative;\n display: grid;\n padding: var(--pf-c-alert--PaddingTop) var(--pf-c-alert--PaddingRight) var(--pf-c-alert--PaddingBottom) var(--pf-c-alert--PaddingLeft);\n font-size: var(--pf-c-alert__FontSize);\n background-color: var(--pf-c-alert--BackgroundColor);\n border-top: var(--pf-c-alert--BorderTopWidth) solid var(--pf-c-alert--BorderTopColor);\n box-shadow: var(--pf-c-alert--BoxShadow);\n grid-template-columns: var(--pf-c-alert--GridTemplateColumns);\n grid-template-areas: \"icon title action\" \". description description\" \". actiongroup actiongroup\"; }\n .pf-c-alert.pf-m-success {\n --pf-c-alert--BorderTopColor: var(--pf-c-alert--m-success--BorderTopColor);\n --pf-c-alert__icon--Color: var(--pf-c-alert--m-success__icon--Color);\n --pf-c-alert__title--Color: var(--pf-c-alert--m-success__title--Color);\n --pf-c-alert--m-inline--BackgroundColor: var(--pf-c-alert--m-inline--m-success--BackgroundColor); }\n .pf-c-alert.pf-m-danger {\n --pf-c-alert--BorderTopColor: var(--pf-c-alert--m-danger--BorderTopColor);\n --pf-c-alert__icon--Color: var(--pf-c-alert--m-danger__icon--Color);\n --pf-c-alert__title--Color: var(--pf-c-alert--m-danger__title--Color);\n --pf-c-alert--m-inline--BackgroundColor: var(--pf-c-alert--m-inline--m-danger--BackgroundColor); }\n .pf-c-alert.pf-m-warning {\n --pf-c-alert--BorderTopColor: var(--pf-c-alert--m-warning--BorderTopColor);\n --pf-c-alert__icon--Color: var(--pf-c-alert--m-warning__icon--Color);\n --pf-c-alert__title--Color: var(--pf-c-alert--m-warning__title--Color);\n --pf-c-alert--m-inline--BackgroundColor: var(--pf-c-alert--m-inline--m-warning--BackgroundColor); }\n .pf-c-alert.pf-m-info {\n --pf-c-alert--BorderTopColor: var(--pf-c-alert--m-info--BorderTopColor);\n --pf-c-alert__icon--Color: var(--pf-c-alert--m-info__icon--Color);\n --pf-c-alert__title--Color: var(--pf-c-alert--m-info__title--Color);\n --pf-c-alert--m-inline--BackgroundColor: var(--pf-c-alert--m-inline--m-info--BackgroundColor); }\n .pf-c-alert.pf-m-inline {\n --pf-c-alert--BoxShadow: var(--pf-c-alert--m-inline--BoxShadow);\n --pf-c-alert--BackgroundColor: var(--pf-c-alert--m-inline--BackgroundColor); }\n\n.pf-c-alert__icon {\n grid-area: icon;\n display: flex;\n margin-top: var(--pf-c-alert__icon--MarginTop);\n margin-right: var(--pf-c-alert__icon--MarginRight);\n font-size: var(--pf-c-alert__icon--FontSize);\n color: var(--pf-c-alert__icon--Color); }\n\n.pf-c-alert__title {\n grid-area: title;\n font-weight: var(--pf-c-alert__title--FontWeight);\n color: var(--pf-c-alert__title--Color);\n word-break: break-word; }\n .pf-c-alert__title.pf-m-truncate {\n display: -webkit-box;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: var(--pf-c-alert__title--max-lines);\n overflow: hidden; }\n\n.pf-c-alert__description {\n grid-area: description;\n padding-top: var(--pf-c-alert__description--PaddingTop);\n word-break: break-word; }\n .pf-c-alert__description + .pf-c-alert__action-group {\n --pf-c-alert__action-group--PaddingTop: var(--pf-c-alert__description--action-group--PaddingTop); }\n\n.pf-c-alert__action {\n grid-area: action;\n margin-top: var(--pf-c-alert__action--MarginTop);\n margin-right: var(--pf-c-alert__action--MarginRight);\n margin-bottom: var(--pf-c-alert__action--MarginBottom);\n transform: translateY(var(--pf-c-alert__action--TranslateY)); }\n .pf-c-alert__action > .pf-c-button {\n --pf-c-button--LineHeight: 1; }\n\n.pf-c-alert__action-group {\n grid-area: actiongroup;\n padding-top: var(--pf-c-alert__action-group--PaddingTop); }\n .pf-c-alert__action-group > .pf-c-button {\n --pf-c-button--m-link--m-inline--hover--TextDecoration: none; }\n .pf-c-alert__action-group > .pf-c-button:not(:last-child) {\n margin-right: var(--pf-c-alert__action-group__c-button--not-last-child--MarginRight); }\n\n.pf-m-overpass-font .pf-c-alert__title {\n --pf-c-alert__title--FontWeight: var(--pf-global--FontWeight--normal); }\n\n.pf-c-alert-group {\n --pf-c-alert-group__item--MarginTop: var(--pf-global--spacer--sm);\n --pf-c-alert-group--m-toast--Top: var(--pf-global--spacer--2xl);\n --pf-c-alert-group--m-toast--Right: var(--pf-global--spacer--xl);\n --pf-c-alert-group--m-toast--MaxWidth: 37.5rem;\n --pf-c-alert-group--m-toast--ZIndex: var(--pf-global--ZIndex--2xl); }\n .pf-c-alert-group > * + * {\n margin-top: var(--pf-c-alert-group__item--MarginTop); }\n .pf-c-alert-group.pf-m-toast {\n position: fixed;\n top: var(--pf-c-alert-group--m-toast--Top);\n right: var(--pf-c-alert-group--m-toast--Right);\n z-index: var(--pf-c-alert-group--m-toast--ZIndex);\n width: calc(100% - calc(var(--pf-c-alert-group--m-toast--Right) * 2));\n max-width: var(--pf-c-alert-group--m-toast--MaxWidth); }\n\n.pf-c-app-launcher {\n --pf-c-app-launcher__menu--BackgroundColor: var(--pf-global--BackgroundColor--light-100);\n --pf-c-app-launcher__menu--BoxShadow: var(--pf-global--BoxShadow--md);\n --pf-c-app-launcher__menu--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-app-launcher__menu--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-app-launcher__menu--Top: calc(100% + var(--pf-global--spacer--xs));\n --pf-c-app-launcher__menu--ZIndex: var(--pf-global--ZIndex--sm);\n --pf-c-app-launcher--m-top__menu--Top: 0;\n --pf-c-app-launcher--m-top__menu--TranslateY: calc(-100% - var(--pf-global--spacer--xs));\n --pf-c-app-launcher__toggle--PaddingTop: var(--pf-global--spacer--form-element);\n --pf-c-app-launcher__toggle--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-app-launcher__toggle--PaddingBottom: var(--pf-global--spacer--form-element);\n --pf-c-app-launcher__toggle--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-app-launcher__toggle--Color: var(--pf-global--Color--200);\n --pf-c-app-launcher__toggle--hover--Color: var(--pf-global--Color--100);\n --pf-c-app-launcher__toggle--active--Color: var(--pf-global--Color--100);\n --pf-c-app-launcher__toggle--focus--Color: var(--pf-global--Color--100);\n --pf-c-app-launcher__toggle--disabled--Color: var(--pf-global--disabled-color--200);\n --pf-c-app-launcher__toggle--m-expanded--Color: var(--pf-global--Color--100);\n --pf-c-app-launcher__menu-search--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-app-launcher__menu-search--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-app-launcher__menu-search--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-app-launcher__menu-search--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-app-launcher__menu-search--BottomBorderColor: var(--pf-global--BorderColor--100);\n --pf-c-app-launcher__menu-search--BottomBorderWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-app-launcher__menu-search--MarginBottom: var(--pf-global--spacer--sm);\n --pf-c-app-launcher__menu-item--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-app-launcher__menu-item--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-app-launcher__menu-item--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-app-launcher__menu-item--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-app-launcher__menu-item--Color: var(--pf-global--Color--dark-100);\n --pf-c-app-launcher__menu-item--FontWeight: var(--pf-global--FontWeight--normal);\n --pf-c-app-launcher__menu-item--Width: 100%;\n --pf-c-app-launcher__menu-item--disabled--Color: var(--pf-global--Color--dark-200);\n --pf-c-app-launcher__menu-item--hover--BackgroundColor: var(--pf-global--BackgroundColor--light-300);\n --pf-c-app-launcher__menu-item--m-link--PaddingRight: 0;\n --pf-c-app-launcher__menu-item--m-link--hover--BackgroundColor: transparent;\n --pf-c-app-launcher__menu-item--m-action--Color: var(--pf-global--disabled-color--200);\n --pf-c-app-launcher__menu-item--m-action--Width: auto;\n --pf-c-app-launcher__menu-item--m-action--FontSize: var(--pf-global--icon--FontSize--sm);\n --pf-c-app-launcher__menu-item--m-action--hover--BackgroundColor: transparent;\n --pf-c-app-launcher__menu-item--hover__menu-item--m-action--Color: var(--pf-global--Color--200);\n --pf-c-app-launcher__menu-item--m-action--hover--Color: var(--pf-global--Color--100);\n --pf-c-app-launcher__menu-item--m-favorite__menu-item--m-action--Color: var(--pf-global--palette--gold-400);\n --pf-c-app-launcher__menu-item-icon--MarginRight: var(--pf-global--spacer--sm);\n --pf-c-app-launcher__menu-item-icon--Width: var(--pf-global--icon--FontSize--lg);\n --pf-c-app-launcher__menu-item-icon--Height: var(--pf-global--icon--FontSize--lg);\n --pf-c-app-launcher__menu-item-external-icon--Color: var(--pf-global--link--Color);\n --pf-c-app-launcher__menu-item-external-icon--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-app-launcher__menu-item-external-icon--TranslateY: -0.0625rem;\n --pf-c-app-launcher__menu-item-external-icon--FontSize: var(--pf-global--icon--FontSize--sm);\n --pf-c-app-launcher__group--group--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-app-launcher__group-title--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-app-launcher__group-title--PaddingRight: var(--pf-c-app-launcher__menu-item--PaddingRight);\n --pf-c-app-launcher__group-title--PaddingBottom: var(--pf-c-app-launcher__menu-item--PaddingBottom);\n --pf-c-app-launcher__group-title--PaddingLeft: var(--pf-c-app-launcher__menu-item--PaddingLeft);\n --pf-c-app-launcher__group-title--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-app-launcher__group-title--FontWeight: var(--pf-global--FontWeight--semi-bold);\n --pf-c-app-launcher__group-title--Color: var(--pf-global--Color--dark-200);\n --pf-c-app-launcher--c-divider--MarginTop: var(--pf-global--spacer--sm);\n --pf-c-app-launcher--c-divider--MarginBottom: var(--pf-global--spacer--sm);\n position: relative;\n display: inline-block;\n max-width: 100%; }\n .pf-c-app-launcher.pf-m-expanded > .pf-c-app-launcher__toggle {\n color: var(--pf-c-app-launcher__toggle--m-expanded--Color); }\n .pf-c-app-launcher .pf-c-divider {\n margin-top: var(--pf-c-app-launcher--c-divider--MarginTop);\n margin-bottom: var(--pf-c-app-launcher--c-divider--MarginBottom); }\n .pf-c-app-launcher .pf-c-divider:last-child {\n --pf-c-app-launcher--c-divider--MarginBottom: 0; }\n\n.pf-c-app-launcher__toggle {\n padding: var(--pf-c-app-launcher__toggle--PaddingTop) var(--pf-c-app-launcher__toggle--PaddingRight) var(--pf-c-app-launcher__toggle--PaddingBottom) var(--pf-c-app-launcher__toggle--PaddingLeft);\n color: var(--pf-c-app-launcher__toggle--Color);\n border: none; }\n .pf-c-app-launcher__toggle:hover {\n --pf-c-app-launcher__toggle--Color: var(--pf-c-app-launcher__toggle--hover--Color); }\n .pf-c-app-launcher__toggle:active, .pf-c-app-launcher__toggle.pf-m-active {\n --pf-c-app-launcher__toggle--Color: var(--pf-c-app-launcher__toggle--active--Color); }\n .pf-c-app-launcher__toggle:focus {\n --pf-c-app-launcher__toggle--Color: var(--pf-c-app-launcher__toggle--focus--Color); }\n .pf-c-app-launcher__toggle:disabled {\n --pf-c-app-launcher__toggle--Color: var(--pf-c-app-launcher__toggle--disabled--Color);\n pointer-events: none; }\n\n.pf-c-app-launcher__menu {\n position: absolute;\n top: var(--pf-c-app-launcher__menu--Top);\n z-index: var(--pf-c-app-launcher__menu--ZIndex);\n min-width: 100%;\n padding-top: var(--pf-c-app-launcher__menu--PaddingTop);\n padding-bottom: var(--pf-c-app-launcher__menu--PaddingBottom);\n background-color: var(--pf-c-app-launcher__menu--BackgroundColor);\n background-clip: padding-box;\n box-shadow: var(--pf-c-app-launcher__menu--BoxShadow); }\n .pf-c-app-launcher__menu.pf-m-align-right {\n right: 0; }\n .pf-c-app-launcher.pf-m-top .pf-c-app-launcher__menu {\n --pf-c-app-launcher__menu--Top: var(--pf-c-app-launcher--m-top__menu--Top);\n transform: translateY(var(--pf-c-app-launcher--m-top__menu--TranslateY)); }\n\n.pf-c-app-launcher__menu-search {\n padding: var(--pf-c-app-launcher__menu-search--PaddingTop) var(--pf-c-app-launcher__menu-search--PaddingRight) var(--pf-c-app-launcher__menu-search--PaddingBottom) var(--pf-c-app-launcher__menu-search--PaddingLeft);\n margin-bottom: var(--pf-c-app-launcher__menu-search--MarginBottom);\n border-bottom: var(--pf-c-app-launcher__menu-search--BottomBorderWidth) solid var(--pf-c-app-launcher__menu-search--BottomBorderColor); }\n\n.pf-c-app-launcher__menu-wrapper {\n display: flex; }\n .pf-c-app-launcher__menu-wrapper.pf-m-favorite {\n --pf-c-app-launcher__menu-item--m-action--Color: var(--pf-c-app-launcher__menu-item--m-favorite__menu-item--m-action--Color); }\n\n.pf-c-app-launcher__menu-item {\n display: flex;\n align-items: center;\n width: var(--pf-c-app-launcher__menu-item--Width);\n padding: var(--pf-c-app-launcher__menu-item--PaddingTop) var(--pf-c-app-launcher__menu-item--PaddingRight) var(--pf-c-app-launcher__menu-item--PaddingBottom) var(--pf-c-app-launcher__menu-item--PaddingLeft);\n font-weight: var(--pf-c-app-launcher__menu-item--FontWeight);\n color: var(--pf-c-app-launcher__menu-item--Color);\n white-space: nowrap;\n border: 0; }\n .pf-c-app-launcher__menu-item:hover, .pf-c-app-launcher__menu-item:focus {\n --pf-c-app-launcher__menu-item--m-action--Color: var(--pf-c-app-launcher__menu-item--hover__menu-item--m-action--Color);\n text-decoration: none; }\n .pf-c-app-launcher__menu-wrapper:hover,\n .pf-c-app-launcher__menu-wrapper:focus-within,\n .pf-c-app-launcher__menu-wrapper.pf-m-focus, .pf-c-app-launcher__menu-item:hover, .pf-c-app-launcher__menu-item:focus {\n background-color: var(--pf-c-app-launcher__menu-item--hover--BackgroundColor); }\n .pf-c-app-launcher__menu-item:disabled, .pf-c-app-launcher__menu-item.pf-m-disabled {\n --pf-c-app-launcher__menu-item--Color: var(--pf-c-app-launcher__menu-item--disabled--Color);\n pointer-events: none; }\n .pf-c-app-launcher__menu-wrapper:disabled, .pf-c-app-launcher__menu-wrapper.pf-m-disabled, .pf-c-app-launcher__menu-item:disabled, .pf-c-app-launcher__menu-item.pf-m-disabled {\n background-color: transparent; }\n .pf-c-app-launcher__menu-wrapper.pf-m-external:hover .pf-c-app-launcher__menu-item-external-icon, .pf-c-app-launcher__menu-wrapper.pf-m-external:focus .pf-c-app-launcher__menu-item-external-icon, .pf-c-app-launcher__menu-item.pf-m-external:hover .pf-c-app-launcher__menu-item-external-icon, .pf-c-app-launcher__menu-item.pf-m-external:focus .pf-c-app-launcher__menu-item-external-icon {\n opacity: 1; }\n .pf-c-app-launcher__menu-item.pf-m-link {\n --pf-c-app-launcher__menu-item--PaddingRight: var(--pf-c-app-launcher__menu-item--m-link--PaddingRight);\n --pf-c-app-launcher__menu-item--hover--BackgroundColor: var(--pf-c-app-launcher__menu-item--m-link--hover--BackgroundColor); }\n .pf-c-app-launcher__menu-item.pf-m-action {\n --pf-c-app-launcher__menu-item--Color: var(--pf-c-app-launcher__menu-item--m-action--Color);\n --pf-c-app-launcher__menu-item--Width: var(--pf-c-app-launcher__menu-item--m-action--Width);\n --pf-c-app-launcher__menu-item--hover--BackgroundColor: var(--pf-c-app-launcher__menu-item--m-action--hover--BackgroundColor);\n font-size: var(--pf-c-app-launcher__menu-item--m-action--FontSize); }\n .pf-c-app-launcher__menu-item.pf-m-action:hover, .pf-c-app-launcher__menu-item.pf-m-action:focus {\n --pf-c-app-launcher__menu-item--m-action--Color: var(--pf-c-app-launcher__menu-item--m-action--hover--Color); }\n\n.pf-c-app-launcher__menu-item-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--pf-c-app-launcher__menu-item-icon--Width);\n height: var(--pf-c-app-launcher__menu-item-icon--Height);\n margin-right: var(--pf-c-app-launcher__menu-item-icon--MarginRight); }\n .pf-c-app-launcher__menu-item-icon > * {\n max-width: 100%;\n max-height: 100%; }\n\n.pf-c-app-launcher__menu-item-external-icon {\n padding-left: var(--pf-c-app-launcher__menu-item-external-icon--PaddingLeft);\n margin-left: auto;\n font-size: var(--pf-c-app-launcher__menu-item-external-icon--FontSize);\n color: var(--pf-c-app-launcher__menu-item-external-icon--Color);\n opacity: 0;\n transform: translateY(var(--pf-c-app-launcher__menu-item-external-icon--TranslateY)); }\n\n.pf-c-app-launcher__group + .pf-c-app-launcher__group {\n padding-top: var(--pf-c-app-launcher__group--group--PaddingTop); }\n\n.pf-c-app-launcher__group-title {\n padding-top: var(--pf-c-app-launcher__group-title--PaddingTop);\n padding-right: var(--pf-c-app-launcher__group-title--PaddingRight);\n padding-bottom: var(--pf-c-app-launcher__group-title--PaddingBottom);\n padding-left: var(--pf-c-app-launcher__group-title--PaddingLeft);\n font-size: var(--pf-c-app-launcher__group-title--FontSize);\n font-weight: var(--pf-c-app-launcher__group-title--FontWeight);\n color: var(--pf-c-app-launcher__group-title--Color); }\n\n.pf-c-avatar {\n --pf-c-avatar--BorderRadius: var(--pf-global--BorderRadius--lg);\n --pf-c-avatar--Width: 2.25rem;\n --pf-c-avatar--Height: 2.25rem;\n width: var(--pf-c-avatar--Width);\n height: var(--pf-c-avatar--Height);\n border-radius: var(--pf-c-avatar--BorderRadius); }\n\n.pf-c-backdrop {\n --pf-c-backdrop--ZIndex: var(--pf-global--ZIndex--lg);\n --pf-c-backdrop--BackgroundColor: var(--pf-global--BackgroundColor--dark-transparent-100);\n position: fixed;\n top: 0;\n left: 0;\n z-index: var(--pf-c-backdrop--ZIndex);\n width: 100%;\n height: 100%;\n background-color: var(--pf-c-backdrop--BackgroundColor); }\n\n.pf-c-backdrop__open {\n overflow: hidden; }\n\n.pf-c-background-image {\n --pf-c-background-image--BackgroundColor: var(--pf-global--BackgroundColor--dark-100);\n --pf-c-background-image--BackgroundImage: url(\"./assets/images/pfbg_576.jpg\");\n --pf-c-background-image--BackgroundImage-2x: url(\"./assets/images/pfbg_576@2x.jpg\");\n --pf-c-background-image--BackgroundImage--sm: url(\"./assets/images/pfbg_768.jpg\");\n --pf-c-background-image--BackgroundImage--sm-2x: url(\"./assets/images/pfbg_768@2x.jpg\");\n --pf-c-background-image--BackgroundImage--lg: url(\"./assets/images/pfbg_2000.jpg\");\n --pf-c-background-image--Filter: url(\"#image_overlay\"); }\n .pf-c-background-image::before {\n position: fixed;\n top: 0;\n left: 0;\n z-index: -1;\n width: 100%;\n height: 100%;\n content: \"\";\n background-color: var(--pf-c-background-image--BackgroundColor);\n background-image: var(--pf-c-background-image--BackgroundImage);\n filter: var(--pf-c-background-image--Filter);\n background-repeat: no-repeat;\n background-size: cover; }\n @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {\n .pf-c-background-image::before {\n --pf-c-background-image--BackgroundImage: var(--pf-c-background-image--BackgroundImage-2x); } }\n @media (min-width: 576px) {\n .pf-c-background-image::before {\n --pf-c-background-image--BackgroundImage: var(--pf-c-background-image--BackgroundImage--sm); } }\n @media (min-width: 576px) and (-webkit-min-device-pixel-ratio: 2), (min-width: 576px) and (min-resolution: 192dpi) {\n .pf-c-background-image::before {\n --pf-c-background-image--BackgroundImage: var(--pf-c-background-image--BackgroundImage--sm-2x); } }\n @media (min-width: 992px) {\n .pf-c-background-image::before {\n --pf-c-background-image--BackgroundImage: var(--pf-c-background-image--BackgroundImage--lg); } }\n\n.pf-c-background-image__filter {\n display: block; }\n\n.pf-c-badge {\n --pf-c-badge--BorderRadius: var(--pf-global--BorderRadius--lg);\n --pf-c-badge--FontSize: var(--pf-global--FontSize--xs);\n --pf-c-badge--FontWeight: var(--pf-global--FontWeight--bold);\n --pf-c-badge--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-badge--PaddingLeft: var(--pf-global--spacer--sm);\n --pf-c-badge--Color: var(--pf-global--Color--dark-100);\n --pf-c-badge--MinWidth: var(--pf-global--spacer--xl);\n --pf-c-badge--m-read--BackgroundColor: var(--pf-global--BackgroundColor--200);\n --pf-c-badge--m-read--Color: var(--pf-global--Color--dark-100);\n --pf-c-badge--m-unread--BackgroundColor: var(--pf-global--primary-color--100);\n --pf-c-badge--m-unread--Color: var(--pf-global--Color--light-100);\n display: inline-block;\n min-width: var(--pf-c-badge--MinWidth);\n padding-right: var(--pf-c-badge--PaddingRight);\n padding-left: var(--pf-c-badge--PaddingLeft);\n font-size: var(--pf-c-badge--FontSize);\n font-weight: var(--pf-c-badge--FontWeight);\n color: var(--pf-c-badge--Color);\n text-align: center;\n background-color: var(--pf-c-badge--BackgroundColor);\n border-radius: var(--pf-c-badge--BorderRadius); }\n .pf-c-badge.pf-m-read {\n --pf-c-badge--Color: var(--pf-c-badge--m-read--Color);\n --pf-c-badge--BackgroundColor: var(--pf-c-badge--m-read--BackgroundColor); }\n .pf-c-badge.pf-m-unread {\n --pf-c-badge--Color: var(--pf-c-badge--m-unread--Color);\n --pf-c-badge--BackgroundColor: var(--pf-c-badge--m-unread--BackgroundColor); }\n\n.pf-c-banner {\n --pf-c-banner--PaddingTop: var(--pf-global--spacer--xs);\n --pf-c-banner--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-banner--md--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-banner--PaddingBottom: var(--pf-global--spacer--xs);\n --pf-c-banner--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-banner--md--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-banner--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-banner--Color: var(--pf-global--Color--100);\n --pf-c-banner--BackgroundColor: var(--pf-global--BackgroundColor--dark-400);\n --pf-c-banner--m-info--BackgroundColor: var(--pf-global--palette--blue-200);\n --pf-c-banner--m-danger--BackgroundColor: var(--pf-global--danger-color--100);\n --pf-c-banner--m-success--BackgroundColor: var(--pf-global--success-color--100);\n --pf-c-banner--m-warning--BackgroundColor: var(--pf-global--warning-color--100);\n --pf-c-banner--m-sticky--ZIndex: var(--pf-global--ZIndex--md);\n --pf-c-banner--m-sticky--BoxShadow: var(--pf-global--BoxShadow--md-bottom);\n color: var(--pf-global--Color--100);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n padding: var(--pf-c-banner--PaddingTop) var(--pf-c-banner--PaddingRight) var(--pf-c-banner--PaddingBottom) var(--pf-c-banner--PaddingLeft);\n flex-shrink: 0;\n font-size: var(--pf-c-banner--FontSize);\n color: var(--pf-c-banner--Color);\n white-space: nowrap;\n background-color: var(--pf-c-banner--BackgroundColor); }\n @media (min-width: 768px) {\n .pf-c-banner {\n --pf-c-banner--PaddingRight: var(--pf-c-banner--md--PaddingRight);\n --pf-c-banner--PaddingLeft: var(--pf-c-banner--md--PaddingLeft); } }\n .pf-c-banner.pf-m-info {\n color: var(--pf-global--Color--100);\n --pf-c-banner--BackgroundColor: var(--pf-c-banner--m-info--BackgroundColor); }\n .pf-c-banner.pf-m-danger {\n --pf-c-banner--BackgroundColor: var(--pf-c-banner--m-danger--BackgroundColor); }\n .pf-c-banner.pf-m-success {\n --pf-c-banner--BackgroundColor: var(--pf-c-banner--m-success--BackgroundColor); }\n .pf-c-banner.pf-m-warning {\n color: var(--pf-global--Color--100);\n --pf-c-banner--BackgroundColor: var(--pf-c-banner--m-warning--BackgroundColor); }\n .pf-c-banner.pf-m-sticky {\n position: sticky;\n top: 0;\n z-index: var(--pf-c-banner--m-sticky--ZIndex);\n box-shadow: var(--pf-c-banner--m-sticky--BoxShadow); }\n\n.pf-c-breadcrumb {\n --pf-c-breadcrumb__item--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-breadcrumb__item--LineHeight: var(--pf-global--LineHeight--sm);\n --pf-c-breadcrumb__item--MarginRight: var(--pf-global--spacer--sm);\n --pf-c-breadcrumb__item-divider--Color: var(--pf-global--BorderColor--200);\n --pf-c-breadcrumb__item-divider--MarginRight: var(--pf-global--spacer--sm);\n --pf-c-breadcrumb__item-divider--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-breadcrumb__link--m-current--Color: var(--pf-global--Color--100);\n --pf-c-breadcrumb__heading--FontSize: var(--pf-global--FontSize--sm);\n display: inline-flex; }\n\n.pf-c-breadcrumb__list {\n display: flex;\n flex-wrap: wrap;\n align-items: center; }\n\n.pf-c-breadcrumb__item {\n display: flex;\n align-items: baseline;\n font-size: var(--pf-c-breadcrumb__item--FontSize);\n font-weight: var(--pf-c-breadcrumb__item--FontWeight);\n line-height: var(--pf-c-breadcrumb__item--LineHeight);\n white-space: nowrap;\n list-style: none; }\n .pf-c-breadcrumb__item:not(:last-child) {\n margin-right: var(--pf-c-breadcrumb__item--MarginRight); }\n\n.pf-c-breadcrumb__item-divider {\n margin-right: var(--pf-c-breadcrumb__item-divider--MarginRight);\n font-size: var(--pf-c-breadcrumb__item-divider--FontSize);\n line-height: 1;\n color: var(--pf-c-breadcrumb__item-divider--Color); }\n\n.pf-c-breadcrumb__link {\n font-size: inherit;\n font-weight: var(--pf-c-breadcrumb__link--FontWeight);\n line-height: inherit;\n word-break: break-word; }\n .pf-c-breadcrumb__link.pf-m-current {\n cursor: default; }\n .pf-c-breadcrumb__link.pf-m-current, .pf-c-breadcrumb__link.pf-m-current:hover {\n color: var(--pf-c-breadcrumb__link--m-current--Color);\n text-decoration: none; }\n\n.pf-c-breadcrumb__heading {\n display: inline;\n font-size: var(--pf-c-breadcrumb__heading--FontSize); }\n\n.pf-c-breadcrumb__link,\n.pf-c-breadcrumb__heading {\n white-space: normal; }\n\n.pf-m-overpass-font .pf-c-breadcrumb__link,\n.pf-m-overpass-font .pf-c-breadcrumb__item {\n font-weight: var(--pf-global--FontWeight--semi-bold); }\n\n.pf-c-breadcrumb__list > :first-child .pf-c-breadcrumb__item-divider {\n display: none;\n visibility: hidden; }\n\n.pf-c-button {\n --pf-c-button--PaddingTop: var(--pf-global--spacer--form-element);\n --pf-c-button--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-button--PaddingBottom: var(--pf-global--spacer--form-element);\n --pf-c-button--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-button--LineHeight: var(--pf-global--LineHeight--md);\n --pf-c-button--FontWeight: var(--pf-global--FontWeight--normal);\n --pf-c-button--FontSize: var(--pf-global--FontSize--md);\n --pf-c-button--BorderRadius: var(--pf-global--BorderRadius--sm);\n --pf-c-button--after--BorderRadius: var(--pf-global--BorderRadius--sm);\n --pf-c-button--after--BorderColor: transparent;\n --pf-c-button--after--BorderWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-button--hover--after--BorderWidth: var(--pf-global--BorderWidth--md);\n --pf-c-button--focus--after--BorderWidth: var(--pf-global--BorderWidth--md);\n --pf-c-button--active--after--BorderWidth: var(--pf-global--BorderWidth--md);\n --pf-c-button--disabled--Color: var(--pf-global--disabled-color--100);\n --pf-c-button--disabled--BackgroundColor: var(--pf-global--disabled-color--200);\n --pf-c-button--disabled--after--BorderColor: transparent;\n --pf-c-button--m-primary--BackgroundColor: var(--pf-global--primary-color--100);\n --pf-c-button--m-primary--Color: var(--pf-global--Color--light-100);\n --pf-c-button--m-primary--hover--BackgroundColor: var(--pf-global--primary-color--200);\n --pf-c-button--m-primary--hover--Color: var(--pf-global--Color--light-100);\n --pf-c-button--m-primary--focus--BackgroundColor: var(--pf-global--primary-color--200);\n --pf-c-button--m-primary--focus--Color: var(--pf-global--Color--light-100);\n --pf-c-button--m-primary--active--BackgroundColor: var(--pf-global--primary-color--200);\n --pf-c-button--m-primary--active--Color: var(--pf-global--Color--light-100);\n --pf-c-button--m-secondary--BackgroundColor: transparent;\n --pf-c-button--m-secondary--after--BorderColor: var(--pf-global--primary-color--100);\n --pf-c-button--m-secondary--Color: var(--pf-global--primary-color--100);\n --pf-c-button--m-secondary--hover--BackgroundColor: transparent;\n --pf-c-button--m-secondary--hover--after--BorderColor: var(--pf-global--primary-color--100);\n --pf-c-button--m-secondary--hover--Color: var(--pf-global--primary-color--100);\n --pf-c-button--m-secondary--focus--BackgroundColor: transparent;\n --pf-c-button--m-secondary--focus--after--BorderColor: var(--pf-global--primary-color--100);\n --pf-c-button--m-secondary--focus--Color: var(--pf-global--primary-color--100);\n --pf-c-button--m-secondary--active--BackgroundColor: transparent;\n --pf-c-button--m-secondary--active--after--BorderColor: var(--pf-global--primary-color--100);\n --pf-c-button--m-secondary--active--Color: var(--pf-global--primary-color--100);\n --pf-c-button--m-tertiary--BackgroundColor: transparent;\n --pf-c-button--m-tertiary--after--BorderColor: var(--pf-global--Color--100);\n --pf-c-button--m-tertiary--Color: var(--pf-global--Color--100);\n --pf-c-button--m-tertiary--hover--BackgroundColor: transparent;\n --pf-c-button--m-tertiary--hover--after--BorderColor: var(--pf-global--Color--100);\n --pf-c-button--m-tertiary--hover--Color: var(--pf-global--Color--100);\n --pf-c-button--m-tertiary--focus--BackgroundColor: transparent;\n --pf-c-button--m-tertiary--focus--after--BorderColor: var(--pf-global--Color--100);\n --pf-c-button--m-tertiary--focus--Color: var(--pf-global--Color--100);\n --pf-c-button--m-tertiary--active--BackgroundColor: transparent;\n --pf-c-button--m-tertiary--active--after--BorderColor: var(--pf-global--Color--100);\n --pf-c-button--m-tertiary--active--Color: var(--pf-global--Color--100);\n --pf-c-button--m-warning--BackgroundColor: var(--pf-global--warning-color--100);\n --pf-c-button--m-warning--Color: var(--pf-global--Color--dark-100);\n --pf-c-button--m-warning--hover--BackgroundColor: var(--pf-global--palette--gold-500);\n --pf-c-button--m-warning--hover--Color: var(--pf-global--Color--dark-100);\n --pf-c-button--m-warning--focus--BackgroundColor: var(--pf-global--palette--gold-500);\n --pf-c-button--m-warning--focus--Color: var(--pf-global--Color--dark-100);\n --pf-c-button--m-warning--active--BackgroundColor: var(--pf-global--palette--gold-500);\n --pf-c-button--m-warning--active--Color: var(--pf-global--Color--dark-100);\n --pf-c-button--m-danger--BackgroundColor: var(--pf-global--danger-color--100);\n --pf-c-button--m-danger--Color: var(--pf-global--Color--light-100);\n --pf-c-button--m-danger--hover--BackgroundColor: var(--pf-global--danger-color--200);\n --pf-c-button--m-danger--hover--Color: var(--pf-global--Color--light-100);\n --pf-c-button--m-danger--focus--BackgroundColor: var(--pf-global--danger-color--200);\n --pf-c-button--m-danger--focus--Color: var(--pf-global--Color--light-100);\n --pf-c-button--m-danger--active--BackgroundColor: var(--pf-global--danger-color--200);\n --pf-c-button--m-danger--active--Color: var(--pf-global--Color--light-100);\n --pf-c-button--m-link--BackgroundColor: transparent;\n --pf-c-button--m-link--Color: var(--pf-global--link--Color);\n --pf-c-button--m-link--hover--BackgroundColor: transparent;\n --pf-c-button--m-link--hover--Color: var(--pf-global--link--Color--hover);\n --pf-c-button--m-link--focus--BackgroundColor: transparent;\n --pf-c-button--m-link--focus--Color: var(--pf-global--link--Color--hover);\n --pf-c-button--m-link--active--BackgroundColor: transparent;\n --pf-c-button--m-link--active--Color: var(--pf-global--link--Color--hover);\n --pf-c-button--m-link--disabled--BackgroundColor: transparent;\n --pf-c-button--m-link--m-inline--FontSize: inherit;\n --pf-c-button--m-link--m-inline--hover--TextDecoration: var(--pf-global--link--TextDecoration--hover);\n --pf-c-button--m-link--m-inline--hover--Color: var(--pf-global--link--Color--hover);\n --pf-c-button--m-plain--BackgroundColor: transparent;\n --pf-c-button--m-plain--Color: var(--pf-global--Color--200);\n --pf-c-button--m-plain--hover--BackgroundColor: transparent;\n --pf-c-button--m-plain--hover--Color: var(--pf-global--Color--100);\n --pf-c-button--m-plain--focus--BackgroundColor: transparent;\n --pf-c-button--m-plain--focus--Color: var(--pf-global--Color--100);\n --pf-c-button--m-plain--active--BackgroundColor: transparent;\n --pf-c-button--m-plain--active--Color: var(--pf-global--Color--100);\n --pf-c-button--m-plain--disabled--Color: var(--pf-global--disabled-color--200);\n --pf-c-button--m-plain--disabled--BackgroundColor: transparent;\n --pf-c-button--m-control--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-button--m-control--Color: var(--pf-global--Color--100);\n --pf-c-button--m-control--BorderRadius: 0;\n --pf-c-button--m-control--after--BorderWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-button--m-control--after--BorderTopColor: var(--pf-global--BorderColor--300);\n --pf-c-button--m-control--after--BorderRightColor: var(--pf-global--BorderColor--300);\n --pf-c-button--m-control--after--BorderBottomColor: var(--pf-global--BorderColor--200);\n --pf-c-button--m-control--after--BorderLeftColor: var(--pf-global--BorderColor--300);\n --pf-c-button--m-control--disabled--BackgroundColor: var(--pf-global--disabled-color--300);\n --pf-c-button--m-control--hover--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-button--m-control--hover--Color: var(--pf-global--Color--100);\n --pf-c-button--m-control--hover--after--BorderBottomWidth: var(--pf-global--BorderWidth--md);\n --pf-c-button--m-control--hover--after--BorderBottomColor: var(--pf-global--active-color--100);\n --pf-c-button--m-control--active--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-button--m-control--active--Color: var(--pf-global--Color--100);\n --pf-c-button--m-control--active--after--BorderBottomWidth: var(--pf-global--BorderWidth--md);\n --pf-c-button--m-control--active--after--BorderBottomColor: var(--pf-global--active-color--100);\n --pf-c-button--m-control--focus--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-button--m-control--focus--Color: var(--pf-global--Color--100);\n --pf-c-button--m-control--focus--after--BorderBottomWidth: var(--pf-global--BorderWidth--md);\n --pf-c-button--m-control--focus--after--BorderBottomColor: var(--pf-global--active-color--100);\n --pf-c-button--m-control--m-expanded--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-button--m-control--m-expanded--Color: var(--pf-global--Color--100);\n --pf-c-button--m-control--m-expanded--after--BorderBottomWidth: var(--pf-global--BorderWidth--md);\n --pf-c-button--m-control--m-expanded--after--BorderBottomColor: var(--pf-global--active-color--100);\n --pf-c-button--m-small--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-button--m-display-lg--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-button--m-display-lg--PaddingRight: var(--pf-global--spacer--xl);\n --pf-c-button--m-display-lg--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-button--m-display-lg--PaddingLeft: var(--pf-global--spacer--xl);\n --pf-c-button--m-display-lg--FontWeight: var(--pf-global--FontWeight--bold);\n --pf-c-button--m-link--m-display-lg--FontSize: var(--pf-global--FontSize--lg);\n --pf-c-button__icon--m-start--MarginRight: var(--pf-global--spacer--xs);\n --pf-c-button__icon--m-end--MarginLeft: var(--pf-global--spacer--xs);\n --pf-c-button__progress--width: calc(var(--pf-global--icon--FontSize--md) + var(--pf-global--spacer--sm));\n --pf-c-button__progress--Opacity: 0;\n --pf-c-button__progress--TranslateY: -50%;\n --pf-c-button__progress--Top: 50%;\n --pf-c-button__progress--Left: var(--pf-global--spacer--md);\n --pf-c-button--m-progress--TransitionProperty: padding;\n --pf-c-button--m-progress--TransitionDuration: var(--pf-global--TransitionDuration);\n --pf-c-button--m-progress--PaddingRight: calc(var(--pf-global--spacer--md) + var(--pf-c-button__progress--width) / 2);\n --pf-c-button--m-progress--PaddingLeft: calc(var(--pf-global--spacer--md) + var(--pf-c-button__progress--width) / 2);\n --pf-c-button--m-in-progress--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-button--m-in-progress--PaddingLeft: calc(var(--pf-global--spacer--md) + var(--pf-c-button__progress--width));\n position: relative;\n display: inline-block;\n padding: var(--pf-c-button--PaddingTop) var(--pf-c-button--PaddingRight) var(--pf-c-button--PaddingBottom) var(--pf-c-button--PaddingLeft);\n font-size: var(--pf-c-button--FontSize);\n font-weight: var(--pf-c-button--FontWeight);\n line-height: var(--pf-c-button--LineHeight);\n text-align: center;\n white-space: nowrap;\n user-select: none;\n border: 0;\n border-radius: var(--pf-c-button--BorderRadius); }\n .pf-c-button::after {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n pointer-events: none;\n content: \"\";\n border: var(--pf-c-button--after--BorderWidth) solid;\n border-color: var(--pf-c-button--after--BorderColor);\n border-radius: var(--pf-c-button--after--BorderRadius); }\n .pf-c-button:hover {\n --pf-c-button--after--BorderWidth: var(--pf-c-button--hover--after--BorderWidth);\n text-decoration: none; }\n .pf-c-button:focus {\n --pf-c-button--after--BorderWidth: var(--pf-c-button--focus--after--BorderWidth); }\n .pf-c-button:active, .pf-c-button.pf-m-active {\n --pf-c-button--after--BorderWidth: var(--pf-c-button--active--after--BorderWidth); }\n .pf-c-button.pf-m-block {\n display: block;\n width: 100%; }\n .pf-c-button.pf-m-small {\n --pf-c-button--FontSize: var(--pf-c-button--m-small--FontSize); }\n .pf-c-button.pf-m-primary.pf-m-display-lg, .pf-c-button.pf-m-secondary.pf-m-display-lg, .pf-c-button.pf-m-tertiary.pf-m-display-lg, .pf-c-button.pf-m-link.pf-m-display-lg {\n --pf-c-button--PaddingTop: var(--pf-c-button--m-display-lg--PaddingTop);\n --pf-c-button--PaddingRight: var(--pf-c-button--m-display-lg--PaddingRight);\n --pf-c-button--PaddingBottom: var(--pf-c-button--m-display-lg--PaddingBottom);\n --pf-c-button--PaddingLeft: var(--pf-c-button--m-display-lg--PaddingLeft);\n --pf-c-button--FontWeight: var(--pf-c-button--m-display-lg--FontWeight); }\n .pf-c-button.pf-m-primary {\n color: var(--pf-c-button--m-primary--Color);\n background-color: var(--pf-c-button--m-primary--BackgroundColor); }\n .pf-c-button.pf-m-primary:hover {\n --pf-c-button--m-primary--Color: var(--pf-c-button--m-primary--hover--Color);\n --pf-c-button--m-primary--BackgroundColor: var(--pf-c-button--m-primary--hover--BackgroundColor); }\n .pf-c-button.pf-m-primary:focus {\n --pf-c-button--m-primary--Color: var(--pf-c-button--m-primary--focus--Color);\n --pf-c-button--m-primary--BackgroundColor: var(--pf-c-button--m-primary--focus--BackgroundColor); }\n .pf-c-button.pf-m-primary:active, .pf-c-button.pf-m-primary.pf-m-active {\n --pf-c-button--m-primary--Color: var(--pf-c-button--m-primary--active--Color);\n --pf-c-button--m-primary--BackgroundColor: var(--pf-c-button--m-primary--active--BackgroundColor); }\n .pf-c-button.pf-m-secondary {\n --pf-c-button--after--BorderColor: var(--pf-c-button--m-secondary--after--BorderColor);\n color: var(--pf-c-button--m-secondary--Color);\n background-color: var(--pf-c-button--m-secondary--BackgroundColor); }\n .pf-c-button.pf-m-secondary:hover {\n --pf-c-button--m-secondary--Color: var(--pf-c-button--m-secondary--hover--Color);\n --pf-c-button--m-secondary--BackgroundColor: var(--pf-c-button--m-secondary--hover--BackgroundColor);\n --pf-c-button--after--BorderColor: var(--pf-c-button--m-secondary--hover--after--BorderColor); }\n .pf-c-button.pf-m-secondary:focus {\n --pf-c-button--m-secondary--Color: var(--pf-c-button--m-secondary--focus--Color);\n --pf-c-button--m-secondary--BackgroundColor: var(--pf-c-button--m-secondary--focus--BackgroundColor);\n --pf-c-button--after--BorderColor: var(--pf-c-button--m-secondary--focus--after--BorderColor); }\n .pf-c-button.pf-m-secondary.pf-m-active, .pf-c-button.pf-m-secondary:active {\n --pf-c-button--m-secondary--Color: var(--pf-c-button--m-secondary--active--Color);\n --pf-c-button--m-secondary--BackgroundColor: var(--pf-c-button--m-secondary--active--BackgroundColor);\n --pf-c-button--after--BorderColor: var(--pf-c-button--m-secondary--active--after--BorderColor); }\n .pf-c-button.pf-m-tertiary {\n --pf-c-button--after--BorderColor: var(--pf-c-button--m-tertiary--after--BorderColor);\n color: var(--pf-c-button--m-tertiary--Color);\n background-color: var(--pf-c-button--m-tertiary--BackgroundColor); }\n .pf-c-button.pf-m-tertiary:hover {\n --pf-c-button--m-tertiary--Color: var(--pf-c-button--m-tertiary--hover--Color);\n --pf-c-button--m-tertiary--BackgroundColor: var(--pf-c-button--m-tertiary--hover--BackgroundColor);\n --pf-c-button--after--BorderColor: var(--pf-c-button--m-tertiary--hover--after--BorderColor); }\n .pf-c-button.pf-m-tertiary:focus {\n --pf-c-button--m-tertiary--Color: var(--pf-c-button--m-tertiary--focus--Color);\n --pf-c-button--m-tertiary--BackgroundColor: var(--pf-c-button--m-tertiary--focus--BackgroundColor);\n --pf-c-button--after--BorderColor: var(--pf-c-button--m-tertiary--focus--after--BorderColor); }\n .pf-c-button.pf-m-tertiary:active, .pf-c-button.pf-m-tertiary.pf-m-active {\n --pf-c-button--m-tertiary--Color: var(--pf-c-button--m-tertiary--active--Color);\n --pf-c-button--m-tertiary--BackgroundColor: var(--pf-c-button--m-tertiary--active--BackgroundColor);\n --pf-c-button--after--BorderColor: var(--pf-c-button--m-tertiary--active--after--BorderColor); }\n .pf-c-button.pf-m-danger {\n color: var(--pf-c-button--m-danger--Color);\n background-color: var(--pf-c-button--m-danger--BackgroundColor); }\n .pf-c-button.pf-m-danger:hover {\n --pf-c-button--m-danger--Color: var(--pf-c-button--m-danger--hover--Color);\n --pf-c-button--m-danger--BackgroundColor: var(--pf-c-button--m-danger--hover--BackgroundColor); }\n .pf-c-button.pf-m-danger:focus {\n --pf-c-button--m-danger--Color: var(--pf-c-button--m-danger--focus--Color);\n --pf-c-button--m-danger--BackgroundColor: var(--pf-c-button--m-danger--focus--BackgroundColor); }\n .pf-c-button.pf-m-danger:active, .pf-c-button.pf-m-danger.pf-m-active {\n --pf-c-button--m-danger--Color: var(--pf-c-button--m-danger--active--Color);\n --pf-c-button--m-danger--BackgroundColor: var(--pf-c-button--m-danger--active--BackgroundColor); }\n .pf-c-button.pf-m-warning {\n color: var(--pf-c-button--m-warning--Color);\n background-color: var(--pf-c-button--m-warning--BackgroundColor); }\n .pf-c-button.pf-m-warning:hover {\n --pf-c-button--m-warning--Color: var(--pf-c-button--m-warning--hover--Color);\n --pf-c-button--m-warning--BackgroundColor: var(--pf-c-button--m-warning--hover--BackgroundColor); }\n .pf-c-button.pf-m-warning:focus {\n --pf-c-button--m-warning--Color: var(--pf-c-button--m-warning--focus--Color);\n --pf-c-button--m-warning--BackgroundColor: var(--pf-c-button--m-warning--focus--BackgroundColor); }\n .pf-c-button.pf-m-warning:active, .pf-c-button.pf-m-warning.pf-m-active {\n --pf-c-button--m-warning--Color: var(--pf-c-button--m-warning--active--Color);\n --pf-c-button--m-warning--BackgroundColor: var(--pf-c-button--m-warning--active--BackgroundColor); }\n .pf-c-button.pf-m-link {\n --pf-c-button--disabled--BackgroundColor: var(--pf-c-button--m-link--disabled--BackgroundColor);\n color: var(--pf-c-button--m-link--Color);\n background-color: var(--pf-c-button--m-link--BackgroundColor); }\n .pf-c-button.pf-m-link:not(.pf-m-inline):hover {\n --pf-c-button--m-link--Color: var(--pf-c-button--m-link--hover--Color);\n --pf-c-button--m-link--BackgroundColor: var(--pf-c-button--m-link--hover--BackgroundColor); }\n .pf-c-button.pf-m-link:not(.pf-m-inline):focus {\n --pf-c-button--m-link--Color: var(--pf-c-button--m-link--focus--Color);\n --pf-c-button--m-link--BackgroundColor: var(--pf-c-button--m-link--focus--BackgroundColor); }\n .pf-c-button.pf-m-link:not(.pf-m-inline):active, .pf-c-button.pf-m-link:not(.pf-m-inline).pf-m-active {\n --pf-c-button--m-link--Color: var(--pf-c-button--m-link--active--Color);\n --pf-c-button--m-link--BackgroundColor: var(--pf-c-button--m-link--active--BackgroundColor); }\n .pf-c-button.pf-m-link.pf-m-inline {\n --pf-c-button--FontSize: var(--pf-c-button--m-link--m-inline--FontSize);\n display: inline;\n padding: 0;\n text-align: left;\n white-space: normal;\n cursor: pointer; }\n .pf-c-button.pf-m-link.pf-m-inline:hover {\n --pf-c-button--m-link--Color: var(--pf-c-button--m-link--m-inline--hover--Color);\n text-decoration: var(--pf-c-button--m-link--m-inline--hover--TextDecoration); }\n .pf-c-button.pf-m-link.pf-m-display-lg {\n --pf-c-button--FontSize: var(--pf-c-button--m-link--m-display-lg--FontSize); }\n .pf-c-button.pf-m-control {\n --pf-c-button--BorderRadius: var(--pf-c-button--m-control--BorderRadius);\n --pf-c-button--disabled--BackgroundColor: var(--pf-c-button--m-control--disabled--BackgroundColor);\n --pf-c-button--after--BorderWidth: var(--pf-c-button--m-control--after--BorderWidth);\n --pf-c-button--after--BorderColor: var(--pf-c-button--m-control--after--BorderTopColor) var(--pf-c-button--m-control--after--BorderRightColor) var(--pf-c-button--m-control--after--BorderBottomColor) var(--pf-c-button--m-control--after--BorderLeftColor);\n color: var(--pf-c-button--m-control--Color);\n background-color: var(--pf-c-button--m-control--BackgroundColor); }\n .pf-c-button.pf-m-control::after {\n border-radius: initial; }\n .pf-c-button.pf-m-control:hover {\n --pf-c-button--m-control--Color: var(--pf-c-button--m-control--hover--Color);\n --pf-c-button--m-control--BackgroundColor: var(--pf-c-button--m-control--hover--BackgroundColor);\n --pf-c-button--m-control--after--BorderBottomColor: var(--pf-c-button--m-control--hover--after--BorderBottomColor); }\n .pf-c-button.pf-m-control:hover::after {\n border-bottom-width: var(--pf-c-button--m-control--hover--after--BorderBottomWidth); }\n .pf-c-button.pf-m-control:active, .pf-c-button.pf-m-control.pf-m-active {\n --pf-c-button--m-control--Color: var(--pf-c-button--m-control--active--Color);\n --pf-c-button--m-control--BackgroundColor: var(--pf-c-button--m-control--active--BackgroundColor);\n --pf-c-button--m-control--after--BorderBottomColor: var(--pf-c-button--m-control--active--after--BorderBottomColor); }\n .pf-c-button.pf-m-control:active::after, .pf-c-button.pf-m-control.pf-m-active::after {\n border-bottom-width: var(--pf-c-button--m-control--active--after--BorderBottomWidth); }\n .pf-c-button.pf-m-control:focus {\n --pf-c-button--m-control--Color: var(--pf-c-button--m-control--focus--Color);\n --pf-c-button--m-control--BackgroundColor: var(--pf-c-button--m-control--focus--BackgroundColor);\n --pf-c-button--m-control--after--BorderBottomColor: var(--pf-c-button--m-control--focus--after--BorderBottomColor); }\n .pf-c-button.pf-m-control:focus::after {\n border-bottom-width: var(--pf-c-button--m-control--focus--after--BorderBottomWidth); }\n .pf-c-button.pf-m-control.pf-m-expanded {\n --pf-c-button--m-control--Color: var(--pf-c-button--m-control--m-expanded--Color);\n --pf-c-button--m-control--BackgroundColor: var(--pf-c-button--m-control--m-expanded--BackgroundColor);\n --pf-c-button--m-control--after--BorderBottomColor: var(--pf-c-button--m-control--m-expanded--after--BorderBottomColor); }\n .pf-c-button.pf-m-control.pf-m-expanded::after {\n border-bottom-width: var(--pf-c-button--m-control--m-expanded--after--BorderBottomWidth); }\n .pf-c-button.pf-m-plain {\n --pf-c-button--disabled--Color: var(--pf-c-button--m-plain--disabled--Color);\n --pf-c-button--disabled--BackgroundColor: var(--pf-c-button--m-plain--disabled--BackgroundColor);\n color: var(--pf-c-button--m-plain--Color);\n background-color: var(--pf-c-button--m-plain--BackgroundColor); }\n .pf-c-button.pf-m-plain:hover {\n --pf-c-button--m-plain--Color: var(--pf-c-button--m-plain--hover--Color);\n --pf-c-button--m-plain--BackgroundColor: var(--pf-c-button--m-plain--hover--BackgroundColor); }\n .pf-c-button.pf-m-plain:active, .pf-c-button.pf-m-plain.pf-m-active {\n --pf-c-button--m-plain--Color: var(--pf-c-button--m-plain--active--Color);\n --pf-c-button--m-plain--BackgroundColor: var(--pf-c-button--m-plain--active--BackgroundColor); }\n .pf-c-button.pf-m-plain:focus {\n --pf-c-button--m-plain--Color: var(--pf-c-button--m-plain--focus--Color);\n --pf-c-button--m-plain--BackgroundColor: var(--pf-c-button--m-plain--focus--BackgroundColor); }\n .pf-c-button:disabled, .pf-c-button.pf-m-disabled {\n pointer-events: none; }\n .pf-c-button:disabled, .pf-c-button.pf-m-disabled, .pf-c-button.pf-m-aria-disabled {\n --pf-c-button--after--BorderColor: var(--pf-c-button--disabled--after--BorderColor);\n color: var(--pf-c-button--disabled--Color);\n background-color: var(--pf-c-button--disabled--BackgroundColor); }\n .pf-c-button.pf-m-aria-disabled {\n --pf-c-button--after--BorderWidth: 0;\n --pf-c-button--m-link--m-inline--hover--TextDecoration: none;\n cursor: default; }\n .pf-c-button.pf-m-progress {\n --pf-c-button--PaddingRight: var(--pf-c-button--m-progress--PaddingRight);\n --pf-c-button--PaddingLeft: var(--pf-c-button--m-progress--PaddingLeft);\n transition: var(--pf-c-button--m-progress--TransitionProperty) var(--pf-c-button--m-progress--TransitionDuration); }\n .pf-c-button.pf-m-in-progress {\n --pf-c-button--PaddingRight: var(--pf-c-button--m-in-progress--PaddingRight);\n --pf-c-button--PaddingLeft: var(--pf-c-button--m-in-progress--PaddingLeft); }\n\n.pf-c-button__icon.pf-m-start {\n margin-right: var(--pf-c-button__icon--m-start--MarginRight); }\n\n.pf-c-button__icon.pf-m-end {\n margin-left: var(--pf-c-button__icon--m-end--MarginLeft); }\n\n.pf-c-button__progress {\n position: absolute;\n top: var(--pf-c-button__progress--Top);\n left: var(--pf-c-button__progress--Left);\n line-height: 1;\n transform: translateY(var(--pf-c-button__progress--TranslateY)); }\n .pf-c-button__progress .pf-c-spinner {\n --pf-c-spinner--Color: currentColor; }\n\n.pf-m-overpass-font .pf-c-button {\n --pf-c-button--FontWeight: var(--pf-global--FontWeight--semi-bold); }\n\n.pf-c-calendar-month {\n --pf-c-calendar-month--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-calendar-month--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-calendar-month--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-calendar-month--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-calendar-month--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-calendar-month--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-calendar-month__header--MarginBottom: var(--pf-global--spacer--md);\n --pf-c-calendar-month__header-year--Width: 8ch;\n --pf-c-calendar-month__header-nav-control--MarginRight: 0;\n --pf-c-calendar-month__header-nav-control--MarginLeft: 0;\n --pf-c-calendar-month__header-nav-control--m-prev-month--MarginRight: var(--pf-global--spacer--sm);\n --pf-c-calendar-month__header-nav-control--m-prev-month--MarginLeft: calc(var(--pf-global--spacer--md) * -1);\n --pf-c-calendar-month__header-nav-control--m-next-month--MarginRight: calc(var(--pf-global--spacer--md) * -1);\n --pf-c-calendar-month__header-nav-control--m-next-month--MarginLeft: var(--pf-global--spacer--sm);\n --pf-c-calendar-month__days--BorderBottomWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-calendar-month__days--BorderBottomColor: var(--pf-global--BorderColor--100);\n --pf-c-calendar-month__day--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-calendar-month__day--FontWeight: var(--pf-global--FontWeight--normal);\n --pf-c-calendar-month__dates-cell--PaddingTop: 0.125rem;\n --pf-c-calendar-month__dates-cell--PaddingRight: 0.125rem;\n --pf-c-calendar-month__dates-cell--PaddingBottom: 0.125rem;\n --pf-c-calendar-month__dates-cell--PaddingLeft: 0.125rem;\n --pf-c-calendar-month__dates-row--first-child__dates-cell--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-calendar-month__dates-cell--m-current__date--BackgroundColor: var(--pf-global--BackgroundColor--200);\n --pf-c-calendar-month__dates-cell--m-selected__date--BackgroundColor: var(--pf-global--active-color--100);\n --pf-c-calendar-month__dates-cell--m-selected__date--hover--BackgroundColor: var(--pf-global--active-color--100);\n --pf-c-calendar-month__dates-cell--m-selected__date--focus--BackgroundColor: var(--pf-global--primary-color--200);\n --pf-c-calendar-month__dates-cell--m-selected__date--focus--after--BorderColor: var(--pf-global--primary-color--200);\n --pf-c-calendar-month__date-cell--m-selected__date--focus--BoxShadow: 0 0 0.3125rem var(--pf-global--primary-color--100);\n --pf-c-calendar-month__dates-cell--m-selected__date--Color: var(--pf-global--Color--light-100);\n --pf-c-calendar-month__dates-cell--before--BackgroundColor: transparent;\n --pf-c-calendar-month__dates-cell--before--Top: 0;\n --pf-c-calendar-month__dates-cell--before--Right: 0;\n --pf-c-calendar-month__dates-cell--before--Bottom: var(--pf-c-calendar-month__dates-cell--PaddingBottom);\n --pf-c-calendar-month__dates-cell--before--Left: 0;\n --pf-c-calendar-month__dates-cell--m-in-range--before--BackgroundColor: var(--pf-global--palette--blue-50);\n --pf-c-calendar-month__dates-cell--m-in-range--m-start-range--before--Left: 50%;\n --pf-c-calendar-month__dates-cell--m-in-range--m-end-range--before--Right: 50%;\n --pf-c-calendar-month__dates-cell--m-in-range__date--hover--BackgroundColor: var(--pf-global--palette--blue-100);\n --pf-c-calendar-month__dates-cell--m-in-range__date--focus--BackgroundColor: var(--pf-global--palette--blue-100);\n --pf-c-calendar-month__dates-cell--m-adjacent-month__date--Color: var(--pf-global--disabled-color--100);\n --pf-c-calendar-month__date--Width: 4ch;\n --pf-c-calendar-month__date--Height: 4ch;\n --pf-c-calendar-month__date--BorderRadius: var(--pf-global--BorderRadius--lg);\n --pf-c-calendar-month__date--Color: var(--pf-global--Color--100);\n --pf-c-calendar-month__date--BackgroundColor: transparent;\n --pf-c-calendar-month__date--disabled--Color: var(--pf-global--disabled-color--200);\n --pf-c-calendar-month__date--after--BorderWidth: var(--pf-global--BorderWidth--md);\n --pf-c-calendar-month__date--after--BorderColor: transparent;\n --pf-c-calendar-month__date--hover--BackgroundColor: var(--pf-global--palette--blue-50);\n --pf-c-calendar-month__date--focus--BackgroundColor: var(--pf-global--palette--blue-50);\n --pf-c-calendar-month__date--focus--after--BorderColor: var(--pf-global--active-color--100);\n --pf-c-calendar-month__date--focus--BoxShadow: none;\n color: var(--pf-global--Color--100);\n display: inline-flex;\n flex-direction: column;\n padding: var(--pf-c-calendar-month--PaddingTop) var(--pf-c-calendar-month--PaddingRight) var(--pf-c-calendar-month--PaddingBottom) var(--pf-c-calendar-month--PaddingLeft);\n font-size: var(--pf-c-calendar-month--FontSize);\n background-color: var(--pf-c-calendar-month--BackgroundColor); }\n\n.pf-c-calendar-month__header {\n display: flex;\n margin-bottom: var(--pf-c-calendar-month__header--MarginBottom); }\n\n.pf-c-calendar-month__header-nav-control {\n margin-right: var(--pf-c-calendar-month__header-nav-control--MarginRight);\n margin-left: var(--pf-c-calendar-month__header-nav-control--MarginLeft); }\n .pf-c-calendar-month__header-nav-control.pf-m-prev-month {\n --pf-c-calendar-month__header-nav-control--MarginRight: var(--pf-c-calendar-month__header-nav-control--m-prev-month--MarginRight);\n --pf-c-calendar-month__header-nav-control--MarginLeft: var(--pf-c-calendar-month__header-nav-control--m-prev-month--MarginLeft); }\n .pf-c-calendar-month__header-nav-control.pf-m-next-month {\n --pf-c-calendar-month__header-nav-control--MarginRight: var(--pf-c-calendar-month__header-nav-control--m-next-month--MarginRight);\n --pf-c-calendar-month__header-nav-control--MarginLeft: var(--pf-c-calendar-month__header-nav-control--m-next-month--MarginLeft); }\n\n.pf-c-calendar-month__header-month {\n flex-grow: 1; }\n\n.pf-c-calendar-month__header-year {\n width: var(--pf-c-calendar-month__header-year--Width); }\n\n.pf-c-calendar-month__calendar {\n table-layout: fixed; }\n\n.pf-c-calendar-month__days {\n border-bottom: var(--pf-c-calendar-month__days--BorderBottomWidth) solid var(--pf-c-calendar-month__days--BorderBottomColor); }\n\n.pf-c-calendar-month__day {\n padding-bottom: var(--pf-c-calendar-month__day--PaddingBottom);\n font-weight: var(--pf-c-calendar-month__day--FontWeight);\n text-align: center; }\n\n.pf-c-calendar-month__dates-row:first-child {\n --pf-c-calendar-month__dates-cell--PaddingTop: var(--pf-c-calendar-month__dates-row--first-child__dates-cell--PaddingTop); }\n\n.pf-c-calendar-month__dates-cell {\n --pf-c-calendar-month__dates-cell--before--Top: var(--pf-c-calendar-month__dates-cell--PaddingTop);\n position: relative;\n padding: var(--pf-c-calendar-month__dates-cell--PaddingTop) var(--pf-c-calendar-month__dates-cell--PaddingRight) var(--pf-c-calendar-month__dates-cell--PaddingBottom) var(--pf-c-calendar-month__dates-cell--PaddingLeft);\n text-align: center; }\n .pf-c-calendar-month__dates-cell::before {\n position: absolute;\n top: var(--pf-c-calendar-month__dates-cell--before--Top);\n right: var(--pf-c-calendar-month__dates-cell--before--Right);\n bottom: var(--pf-c-calendar-month__dates-cell--before--Bottom);\n left: var(--pf-c-calendar-month__dates-cell--before--Left);\n content: \"\";\n background-color: var(--pf-c-calendar-month__dates-cell--before--BackgroundColor); }\n .pf-c-calendar-month__dates-cell.pf-m-current {\n --pf-c-calendar-month__date--BackgroundColor: var(--pf-c-calendar-month__dates-cell--m-current__date--BackgroundColor); }\n .pf-c-calendar-month__dates-cell.pf-m-in-range {\n --pf-c-calendar-month__dates-cell--before--BackgroundColor: var(--pf-c-calendar-month__dates-cell--m-in-range--before--BackgroundColor);\n --pf-c-calendar-month__date--hover--BackgroundColor: var(--pf-c-calendar-month__dates-cell--m-in-range__date--hover--BackgroundColor);\n --pf-c-calendar-month__date--focus--BackgroundColor: var(--pf-c-calendar-month__dates-cell--m-in-range__date--focus--BackgroundColor); }\n .pf-c-calendar-month__dates-cell.pf-m-start-range {\n --pf-c-calendar-month__dates-cell--before--Left: var(--pf-c-calendar-month__dates-cell--m-in-range--m-start-range--before--Left); }\n .pf-c-calendar-month__dates-cell.pf-m-end-range {\n --pf-c-calendar-month__dates-cell--before--Right: var(--pf-c-calendar-month__dates-cell--m-in-range--m-end-range--before--Right); }\n .pf-c-calendar-month__dates-cell.pf-m-adjacent-month {\n --pf-c-calendar-month__date--Color: var(--pf-c-calendar-month__dates-cell--m-adjacent-month__date--Color); }\n .pf-c-calendar-month__dates-cell.pf-m-selected {\n --pf-c-calendar-month__date--BackgroundColor: var(--pf-c-calendar-month__dates-cell--m-selected__date--BackgroundColor);\n --pf-c-calendar-month__date--hover--BackgroundColor: var(--pf-c-calendar-month__dates-cell--m-selected__date--hover--BackgroundColor);\n --pf-c-calendar-month__date--focus--BackgroundColor: var(--pf-c-calendar-month__dates-cell--m-selected__date--focus--BackgroundColor);\n --pf-c-calendar-month__date--focus--after--BorderColor: var(--pf-c-calendar-month__dates-cell--m-selected__date--focus--after--BorderColor);\n --pf-c-calendar-month__date--focus--BoxShadow: var(--pf-c-calendar-month__date-cell--m-selected__date--focus--BoxShadow);\n --pf-c-calendar-month__date--Color: var(--pf-c-calendar-month__dates-cell--m-selected__date--Color); }\n .pf-c-calendar-month__dates-cell.pf-m-disabled {\n --pf-c-calendar-month__dates-cell--before--BackgroundColor: transparent;\n --pf-c-calendar-month__date--BackgroundColor: transparent; }\n\n.pf-c-calendar-month__date {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--pf-c-calendar-month__date--Width);\n height: var(--pf-c-calendar-month__date--Height);\n line-height: 1;\n color: var(--pf-c-calendar-month__date--Color);\n background-color: var(--pf-c-calendar-month__date--BackgroundColor);\n border: 0; }\n .pf-c-calendar-month__date::after {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n content: \"\";\n border: var(--pf-c-calendar-month__date--after--BorderWidth) solid var(--pf-c-calendar-month__date--after--BorderColor); }\n .pf-c-calendar-month__date, .pf-c-calendar-month__date::after {\n border-radius: var(--pf-c-calendar-month__date--BorderRadius); }\n .pf-c-calendar-month__date:hover, .pf-c-calendar-month__date.pf-m-hover {\n --pf-c-calendar-month__date--BackgroundColor: var(--pf-c-calendar-month__date--hover--BackgroundColor); }\n .pf-c-calendar-month__date:focus, .pf-c-calendar-month__date.pf-m-focus {\n --pf-c-calendar-month__date--BackgroundColor: var(--pf-c-calendar-month__date--focus--BackgroundColor);\n --pf-c-calendar-month__date--after--BorderColor: var(--pf-c-calendar-month__date--focus--after--BorderColor);\n outline: 0;\n box-shadow: var(--pf-c-calendar-month__date--focus--BoxShadow); }\n .pf-c-calendar-month__date:disabled {\n pointer-events: none;\n --pf-c-calendar-month__date--Color: var(--pf-c-calendar-month__date--disabled--Color);\n --pf-c-calendar-month__date--hover--focus--BorderColor: transparent; }\n\n.pf-c-card {\n --pf-c-card--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-card--BoxShadow: var(--pf-global--BoxShadow--sm);\n --pf-c-card--m-hoverable--hover--BoxShadow: var(--pf-global--BoxShadow--lg);\n --pf-c-card--m-selectable--hover--BoxShadow: var(--pf-global--BoxShadow--lg);\n --pf-c-card--m-selectable--focus--BoxShadow: var(--pf-global--BoxShadow--lg);\n --pf-c-card--m-selectable--active--BoxShadow: var(--pf-global--BoxShadow--lg);\n --pf-c-card--m-selectable--m-selected--BoxShadow: var(--pf-global--BoxShadow--lg);\n --pf-c-card--m-selectable--m-selected--before--Height: var(--pf-global--BorderWidth--lg);\n --pf-c-card--m-selectable--m-selected--before--BackgroundColor: var(--pf-global--active-color--100);\n --pf-c-card--m-compact__body--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-card--m-compact__footer--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-card--m-compact--first-child--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-card--m-compact--child--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-card--m-compact--child--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-card--m-compact--child--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-card--m-compact--c-divider--child--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-card--m-compact__title--not--last-child--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-card--m-flat--BorderWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-card--m-flat--BorderColor: var(--pf-global--BorderColor--100);\n --pf-c-card--first-child--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-card--child--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-card--child--PaddingBottom: var(--pf-global--spacer--lg);\n --pf-c-card--child--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-card--c-divider--child--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-card__header-toggle--MarginTop: calc(var(--pf-global--spacer--form-element) * -1);\n --pf-c-card__header-toggle--MarginRight: var(--pf-global--spacer--xs);\n --pf-c-card__header-toggle--MarginBottom: calc(var(--pf-global--spacer--form-element) * -1);\n --pf-c-card__header-toggle--MarginLeft: calc(var(--pf-global--spacer--md) * -1);\n --pf-c-card__header-toggle-icon--Transition: var(--pf-global--Transition);\n --pf-c-card--m-expanded__header-toggle-icon--Rotate: 90deg;\n --pf-c-card__title--FontSize: var(--pf-global--FontSize--md);\n --pf-c-card__title--FontWeight: var(--pf-global--FontWeight--bold);\n --pf-c-card__title--not--last-child--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-card__body--FontSize: var(--pf-global--FontSize--md);\n --pf-c-card__footer--FontSize: var(--pf-global--FontSize--md);\n --pf-c-card__actions--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-card__actions--child--MarginLeft: var(--pf-global--spacer--sm);\n display: flex;\n flex-direction: column;\n background-color: var(--pf-c-card--BackgroundColor);\n box-shadow: var(--pf-c-card--BoxShadow); }\n .pf-c-card.pf-m-hoverable:hover {\n box-shadow: var(--pf-c-card--m-hoverable--hover--BoxShadow); }\n .pf-c-card.pf-m-selectable {\n position: relative;\n cursor: pointer; }\n .pf-c-card.pf-m-selectable:hover {\n box-shadow: var(--pf-c-card--m-selectable--hover--BoxShadow); }\n .pf-c-card.pf-m-selectable:focus {\n box-shadow: var(--pf-c-card--m-selectable--focus--BoxShadow); }\n .pf-c-card.pf-m-selectable:active {\n box-shadow: var(--pf-c-card--m-selectable--active--BoxShadow); }\n .pf-c-card.pf-m-selectable.pf-m-selected {\n box-shadow: var(--pf-c-card--m-selectable--m-selected--BoxShadow); }\n .pf-c-card.pf-m-selectable.pf-m-selected::before {\n position: absolute;\n top: 0;\n right: 0;\n left: 0;\n height: var(--pf-c-card--m-selectable--m-selected--before--Height);\n content: \"\";\n background-color: var(--pf-c-card--m-selectable--m-selected--before--BackgroundColor); }\n .pf-c-card.pf-m-compact {\n --pf-c-card__body--FontSize: var(--pf-c-card--m-compact__body--FontSize);\n --pf-c-card__footer--FontSize: var(--pf-c-card--m-compact__footer--FontSize);\n --pf-c-card--first-child--PaddingTop: var(--pf-c-card--m-compact--first-child--PaddingTop);\n --pf-c-card--child--PaddingRight: var(--pf-c-card--m-compact--child--PaddingRight);\n --pf-c-card--child--PaddingBottom: var(--pf-c-card--m-compact--child--PaddingBottom);\n --pf-c-card--child--PaddingLeft: var(--pf-c-card--m-compact--child--PaddingLeft);\n --pf-c-card--c-divider--child--PaddingTop: var(--pf-c-card--m-compact--c-divider--child--PaddingTop);\n --pf-c-card__title--not--last-child--PaddingBottom: var(--pf-c-card--m-compact__title--not--last-child--PaddingBottom); }\n .pf-c-card.pf-m-flat {\n --pf-c-card--BoxShadow: none;\n border: var(--pf-c-card--m-flat--BorderWidth) solid var(--pf-c-card--m-flat--BorderColor); }\n .pf-c-card.pf-m-expanded .pf-c-card__header-toggle-icon {\n transform: rotate(var(--pf-c-card--m-expanded__header-toggle-icon--Rotate)); }\n .pf-c-card > .pf-c-divider + .pf-c-card__header,\n .pf-c-card > .pf-c-divider + .pf-c-card__title,\n .pf-c-card > .pf-c-divider + .pf-c-card__body,\n .pf-c-card > .pf-c-divider + .pf-c-card__footer {\n padding-top: var(--pf-c-card--c-divider--child--PaddingTop); }\n\n.pf-c-card__header {\n display: flex;\n flex-direction: row;\n align-items: center; }\n .pf-c-card__header .pf-c-card__title {\n padding: 0; }\n\n.pf-c-card__header-toggle {\n align-self: flex-start;\n margin: var(--pf-c-card__header-toggle--MarginTop) var(--pf-c-card__header-toggle--MarginRight) var(--pf-c-card__header-toggle--MarginBottom) var(--pf-c-card__header-toggle--MarginLeft); }\n\n.pf-c-card__header-toggle-icon {\n display: inline-block;\n transition: var(--pf-c-card__header-toggle-icon--Transition); }\n\n.pf-c-card__title {\n font-family: var(--pf-c-card__title--FontFamily);\n font-weight: var(--pf-c-card__title--FontWeight); }\n\n.pf-c-card__actions {\n display: flex;\n align-items: center;\n align-self: flex-start;\n order: 1;\n padding-left: var(--pf-c-card__actions--PaddingLeft);\n margin: var(--pf-c-card__header-toggle--MarginTop) var(--pf-c-card__header-toggle--MarginRight) var(--pf-c-card__header-toggle--MarginBottom) auto; }\n .pf-c-card__actions > * + * {\n margin-left: var(--pf-c-card__actions--child--MarginLeft); }\n .pf-c-card__actions + .pf-c-card__title,\n .pf-c-card__actions + .pf-c-card__body,\n .pf-c-card__actions + .pf-c-card__footer {\n padding: 0; }\n\n.pf-c-card__header,\n.pf-c-card__title,\n.pf-c-card__body,\n.pf-c-card__footer {\n padding-right: var(--pf-c-card--child--PaddingRight);\n padding-bottom: var(--pf-c-card--child--PaddingBottom);\n padding-left: var(--pf-c-card--child--PaddingLeft); }\n .pf-c-card__header:first-child,\n .pf-c-card__title:first-child,\n .pf-c-card__body:first-child,\n .pf-c-card__footer:first-child {\n padding-top: var(--pf-c-card--first-child--PaddingTop); }\n\n.pf-c-card__header:not(:last-child),\n.pf-c-card__title:not(:last-child) {\n padding-bottom: var(--pf-c-card__title--not--last-child--PaddingBottom); }\n\n.pf-c-card__expandable-content {\n --pf-c-card--first-child--PaddingTop: 0; }\n\n.pf-c-card__body:not(.pf-m-no-fill) {\n flex: 1 1 auto; }\n\n.pf-c-card__body {\n font-size: var(--pf-c-card__body--FontSize); }\n\n.pf-c-card__footer {\n font-size: var(--pf-c-card__footer--FontSize); }\n\n.pf-m-overpass-font .pf-c-card .pf-c-card__title {\n font-weight: var(--pf-global--FontWeight--normal); }\n\n.pf-c-check {\n --pf-c-check--GridGap: var(--pf-global--spacer--xs) var(--pf-global--spacer--sm);\n --pf-c-check__label--disabled--Color: var(--pf-global--disabled-color--100);\n --pf-c-check__label--Color: var(--pf-global--Color--100);\n --pf-c-check__label--FontWeight: var(--pf-global--FontWeight--normal);\n --pf-c-check__label--FontSize: var(--pf-global--FontSize--md);\n --pf-c-check__label--LineHeight: var(--pf-global--LineHeight--sm);\n --pf-c-check__input--MarginTop: -0.1875rem;\n --pf-c-check__description--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-check__description--Color: var(--pf-global--Color--200);\n display: grid;\n grid-template-columns: auto 1fr;\n grid-gap: var(--pf-c-check--GridGap);\n align-items: center;\n justify-items: start; }\n\n.pf-c-check__label {\n font-size: var(--pf-c-check__label--FontSize);\n font-weight: var(--pf-c-check__label--FontWeight);\n line-height: var(--pf-c-check__label--LineHeight);\n color: var(--pf-c-check__label--Color); }\n\n.pf-c-check__input {\n margin-top: var(--pf-c-check__input--MarginTop); }\n\n.pf-c-check__description {\n grid-column: 2;\n font-size: var(--pf-c-check__description--FontSize);\n color: var(--pf-c-check__description--Color); }\n\nlabel.pf-c-check, .pf-c-check__label,\n.pf-c-check__input {\n cursor: pointer; }\n\n.pf-c-check__label:disabled, .pf-c-check__label.pf-m-disabled,\n.pf-c-check__input:disabled,\n.pf-c-check__input.pf-m-disabled {\n --pf-c-check__label--Color: var(--pf-c-check__label--disabled--Color);\n cursor: not-allowed; }\n\n.pf-c-chip {\n --pf-c-chip--PaddingTop: var(--pf-global--spacer--xs);\n --pf-c-chip--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-chip--PaddingBottom: var(--pf-global--spacer--xs);\n --pf-c-chip--PaddingLeft: var(--pf-global--spacer--sm);\n --pf-c-chip--BackgroundColor: var(--pf-global--Color--light-100);\n --pf-c-chip--BorderRadius: var(--pf-global--BorderRadius--sm);\n --pf-c-chip--before--BorderColor: var(--pf-global--BorderColor--300);\n --pf-c-chip--before--BorderWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-chip--before--BorderRadius: var(--pf-c-chip--BorderRadius);\n --pf-c-chip--m-overflow__text--Color: var(--pf-global--primary-color--100);\n --pf-c-chip--m-draggable--BackgroundColor: var(--pf-global--BackgroundColor--200);\n --pf-c-chip--m-draggable--BoxShadow: var(--pf-global--BoxShadow--sm);\n --pf-c-chip--m-draggable__icon--FontSize: var(--pf-global--icon--FontSize--sm);\n --pf-c-chip__text--FontSize: var(--pf-global--FontSize--xs);\n --pf-c-chip__text--Color: var(--pf-global--Color--100);\n --pf-c-chip__text--MaxWidth: 16ch;\n --pf-c-chip__c-button--PaddingTop: var(--pf-global--spacer--xs);\n --pf-c-chip__c-button--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-chip__c-button--PaddingBottom: var(--pf-global--spacer--xs);\n --pf-c-chip__c-button--PaddingLeft: var(--pf-global--spacer--sm);\n --pf-c-chip__c-button--MarginTop: calc(var(--pf-c-chip--PaddingTop) * -1);\n --pf-c-chip__c-button--MarginRight: calc(var(--pf-c-chip--PaddingRight) / 2 * -1);\n --pf-c-chip__c-button--MarginBottom: calc(var(--pf-c-chip--PaddingBottom) * -1);\n --pf-c-chip__c-button--FontSize: var(--pf-global--FontSize--xs);\n --pf-c-chip__c-badge--MarginLeft: var(--pf-global--spacer--xs);\n --pf-c-chip__icon--MarginLeft: var(--pf-global--spacer--sm);\n color: var(--pf-global--Color--100);\n position: relative;\n display: inline-flex;\n align-items: center;\n padding: var(--pf-c-chip--PaddingTop) var(--pf-c-chip--PaddingRight) var(--pf-c-chip--PaddingBottom) var(--pf-c-chip--PaddingLeft);\n list-style: none;\n background-color: var(--pf-c-chip--BackgroundColor);\n border-radius: var(--pf-c-chip--BorderRadius); }\n .pf-c-chip::before {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n content: \"\";\n border: var(--pf-c-chip--before--BorderWidth) solid var(--pf-c-chip--before--BorderColor);\n border-radius: var(--pf-c-chip--before--BorderRadius); }\n .pf-c-chip.pf-m-overflow {\n border: 0; }\n .pf-c-chip.pf-m-overflow .pf-c-chip__text {\n color: var(--pf-c-chip--m-overflow__text--Color); }\n .pf-c-chip.pf-m-draggable {\n --pf-c-chip--BackgroundColor: var(--pf-c-chip--m-draggable--BackgroundColor);\n box-shadow: var(--pf-c-chip--m-draggable--BoxShadow); }\n .pf-c-chip.pf-m-draggable .pf-c-chip__icon {\n font-size: var(--pf-c-chip--m-draggable__icon--FontSize); }\n .pf-c-chip .pf-c-button {\n --pf-c-button--PaddingTop: var(--pf-c-chip__c-button--PaddingTop);\n --pf-c-button--PaddingRight: var(--pf-c-chip__c-button--PaddingRight);\n --pf-c-button--PaddingBottom: var(--pf-c-chip__c-button--PaddingBottom);\n --pf-c-button--PaddingLeft: var(--pf-c-chip__c-button--PaddingLeft);\n --pf-c-button--FontSize: var(--pf-c-chip__c-button--FontSize);\n margin-top: var(--pf-c-chip__c-button--MarginTop);\n margin-right: var(--pf-c-chip__c-button--MarginRight);\n margin-bottom: var(--pf-c-chip__c-button--MarginBottom); }\n .pf-c-chip .pf-c-badge {\n margin-left: var(--pf-c-chip__c-badge--MarginLeft); }\n\n.pf-c-chip__text {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n position: relative;\n max-width: var(--pf-c-chip__text--MaxWidth);\n font-size: var(--pf-c-chip__text--FontSize);\n color: var(--pf-c-chip__text--Color); }\n\n.pf-c-chip__icon + .pf-c-chip__text,\n.pf-c-chip__text + .pf-c-chip__icon {\n margin-left: var(--pf-c-chip__icon--MarginLeft); }\n\n.pf-c-chip-group {\n color: var(--pf-global--Color--100);\n --pf-c-chip-group__list--MarginBottom: calc(var(--pf-global--spacer--xs) * -1);\n --pf-c-chip-group__list--MarginRight: calc(var(--pf-global--spacer--xs) * -1);\n --pf-c-chip-group--m-category--PaddingTop: var(--pf-global--spacer--xs);\n --pf-c-chip-group--m-category--PaddingRight: var(--pf-global--spacer--xs);\n --pf-c-chip-group--m-category--PaddingBottom: var(--pf-global--spacer--xs);\n --pf-c-chip-group--m-category--PaddingLeft: var(--pf-global--spacer--sm);\n --pf-c-chip-group--m-category--BorderRadius: var(--pf-global--BorderRadius--sm);\n --pf-c-chip-group--m-category--BackgroundColor: var(--pf-global--BackgroundColor--200);\n --pf-c-chip-group__label--MarginRight: var(--pf-global--spacer--sm);\n --pf-c-chip-group__label--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-chip-group__label--MaxWidth: 18ch;\n --pf-c-chip-group__close--MarginTop: calc(var(--pf-global--spacer--xs) * -1);\n --pf-c-chip-group__close--MarginBottom: calc(var(--pf-global--spacer--xs) * -1);\n --pf-c-chip-group__list-item--MarginRight: var(--pf-global--spacer--xs);\n --pf-c-chip-group__list-item--MarginBottom: var(--pf-global--spacer--xs); }\n .pf-c-chip-group.pf-m-category {\n padding-top: var(--pf-c-chip-group--m-category--PaddingTop);\n padding-right: var(--pf-c-chip-group--m-category--PaddingRight);\n padding-bottom: var(--pf-c-chip-group--m-category--PaddingBottom);\n padding-left: var(--pf-c-chip-group--m-category--PaddingLeft);\n background-color: var(--pf-c-chip-group--m-category--BackgroundColor);\n border-radius: var(--pf-c-chip-group--m-category--BorderRadius); }\n\n.pf-c-chip-group__main {\n display: flex;\n flex: 1;\n flex-wrap: wrap;\n align-items: baseline; }\n\n.pf-c-chip-group__list {\n margin-right: var(--pf-c-chip-group__list--MarginRight);\n margin-bottom: var(--pf-c-chip-group__list--MarginBottom); }\n\n.pf-c-chip-group,\n.pf-c-chip-group__list {\n display: inline-flex;\n flex-wrap: wrap;\n align-items: center; }\n\n.pf-c-chip-group__list-item {\n display: inline-flex;\n margin-right: var(--pf-c-chip-group__list-item--MarginRight);\n margin-bottom: var(--pf-c-chip-group__list-item--MarginBottom); }\n\n.pf-c-chip-group__label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n max-width: var(--pf-c-chip-group__label--MaxWidth);\n margin-right: var(--pf-c-chip-group__label--MarginRight);\n font-size: var(--pf-c-chip-group__label--FontSize); }\n\n.pf-c-chip-group__close {\n display: flex;\n align-self: flex-start;\n margin-top: var(--pf-c-chip-group__close--MarginTop);\n margin-bottom: var(--pf-c-chip-group__close--MarginBottom); }\n\n.pf-c-clipboard-copy {\n --pf-c-clipboard-copy__toggle-icon--Transition: .2s ease-in 0s;\n --pf-c-clipboard-copy--m-expanded__toggle-icon--Rotate: 90deg;\n --pf-c-clipboard-copy__expandable-content--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-clipboard-copy__expandable-content--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-clipboard-copy__expandable-content--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-clipboard-copy__expandable-content--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-clipboard-copy__expandable-content--BackgroundColor: var(--pf-global--BackgroundColor--light-100);\n --pf-c-clipboard-copy__expandable-content--BorderTopWidth: 0;\n --pf-c-clipboard-copy__expandable-content--BorderRightWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-clipboard-copy__expandable-content--BorderBottomWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-clipboard-copy__expandable-content--BorderLeftWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-clipboard-copy__expandable-content--BorderColor: var(--pf-global--BorderColor--100);\n --pf-c-clipboard-copy__expandable-content--OutlineOffset: calc(-1 * var(--pf-global--spacer--xs)); }\n .pf-c-clipboard-copy.pf-m-expanded .pf-c-clipboard-copy__toggle-icon {\n transform: rotate(var(--pf-c-clipboard-copy--m-expanded__toggle-icon--Rotate)); }\n\n.pf-c-clipboard-copy__group {\n display: flex; }\n .pf-c-clipboard-copy__group > * + * {\n margin-left: -1px; }\n\n.pf-c-clipboard-copy__toggle-icon {\n transition: var(--pf-c-clipboard-copy__toggle-icon--Transition); }\n\n.pf-c-clipboard-copy__expandable-content {\n padding: var(--pf-c-clipboard-copy__expandable-content--PaddingTop) var(--pf-c-clipboard-copy__expandable-content--PaddingRight) var(--pf-c-clipboard-copy__expandable-content--PaddingBottom) var(--pf-c-clipboard-copy__expandable-content--PaddingLeft);\n word-wrap: break-word;\n background-color: var(--pf-c-clipboard-copy__expandable-content--BackgroundColor);\n background-clip: padding-box;\n border: solid var(--pf-c-clipboard-copy__expandable-content--BorderColor);\n border-width: var(--pf-c-clipboard-copy__expandable-content--BorderTopWidth) var(--pf-c-clipboard-copy__expandable-content--BorderRightWidth) var(--pf-c-clipboard-copy__expandable-content--BorderBottomWidth) var(--pf-c-clipboard-copy__expandable-content--BorderLeftWidth);\n box-shadow: var(--pf-c-clipboard-copy__expandable-content--BoxShadow); }\n .pf-c-clipboard-copy__expandable-content pre {\n white-space: pre-wrap; }\n\n.pf-c-code-editor {\n --pf-c-code-editor__controls--c-button--m-control--Color: var(--pf-global--Color--200);\n --pf-c-code-editor__controls--c-button--m-control--hover--Color: var(--pf-global--Color--100);\n --pf-c-code-editor__controls--c-button--m-control--focus--Color: var(--pf-global--Color--100);\n --pf-c-code-editor__controls--c-button--m-control--disabled--after--BorderBottomColor: var(--pf-global--BorderColor--100);\n --pf-c-code-editor__header--before--BorderBottomWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-code-editor__header--before--BorderBottomColor: var(--pf-global--BorderColor--100);\n --pf-c-code-editor__main--BorderColor: var(--pf-global--BorderColor--100);\n --pf-c-code-editor__main--BorderWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-code-editor__main--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-code-editor--m-read-only__main--BackgroundColor: var(--pf-global--disabled-color--300);\n --pf-c-code-editor__main--m-drag-hover--before--BorderWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-code-editor__main--m-drag-hover--before--BorderColor: var(--pf-global--primary-color--100);\n --pf-c-code-editor__main--m-drag-hover--after--BackgroundColor: var(--pf-global--primary-color--100);\n --pf-c-code-editor__main--m-drag-hover--after--Opacity: .1;\n --pf-c-code-editor__code--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-code-editor__code--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-code-editor__code--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-code-editor__code--PaddingLeft: var(--pf-global--spacer--sm);\n --pf-c-code-editor__code-pre--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-code-editor__code-pre--FontFamily: var(--pf-global--FontFamily--monospace);\n --pf-c-code-editor__tab--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-code-editor__tab--Color: var(--pf-global--Color--200);\n --pf-c-code-editor__tab--PaddingTop: var(--pf-global--spacer--form-element);\n --pf-c-code-editor__tab--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-code-editor__tab--PaddingBottom: var(--pf-global--spacer--form-element);\n --pf-c-code-editor__tab--PaddingLeft: var(--pf-global--spacer--sm);\n --pf-c-code-editor__tab--BorderTopWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-code-editor__tab--BorderRightWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-code-editor__tab--BorderBottomWidth: 0;\n --pf-c-code-editor__tab--BorderLeftWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-code-editor__tab--BorderColor: var(--pf-global--BorderColor--100);\n --pf-c-code-editor__tab-icon--text--MarginLeft: var(--pf-global--spacer--sm); }\n .pf-c-code-editor.pf-m-read-only {\n --pf-c-code-editor__main--BackgroundColor: var(--pf-c-code-editor--m-read-only__main--BackgroundColor); }\n\n.pf-c-code-editor__header {\n position: relative;\n display: flex;\n align-items: flex-end; }\n .pf-c-code-editor__header::before {\n position: absolute;\n right: 0;\n bottom: 0;\n left: 0;\n pointer-events: none;\n content: \"\";\n border-bottom: var(--pf-c-code-editor__header--before--BorderBottomWidth) solid var(--pf-c-code-editor__header--before--BorderBottomColor); }\n\n.pf-c-code-editor__controls {\n display: flex; }\n .pf-c-code-editor__controls .pf-c-button.pf-m-control {\n --pf-c-button--m-control--Color: var(--pf-c-code-editor__controls--c-button--m-control--Color); }\n .pf-c-code-editor__controls .pf-c-button.pf-m-control:hover {\n --pf-c-code-editor__controls--c-button--m-control--Color: var(--pf-c-code-editor__controls--c-button--m-control--hover--Color); }\n .pf-c-code-editor__controls .pf-c-button.pf-m-control:focus {\n --pf-c-code-editor__controls--c-button--m-control--Color: var(--pf-c-code-editor__controls--c-button--m-control--focus--Color); }\n .pf-c-code-editor__controls .pf-c-button.pf-m-control:disabled::after {\n border-bottom-color: var(--pf-c-code-editor__controls--c-button--m-control--disabled--after--BorderBottomColor); }\n\n.pf-c-code-editor__main {\n position: relative;\n background-color: var(--pf-c-code-editor__main--BackgroundColor);\n border: var(--pf-c-code-editor__main--BorderWidth) solid;\n border-color: var(--pf-c-code-editor__main--BorderColor); }\n .pf-c-code-editor__main.pf-m-drag-hover::after {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n content: \"\";\n background-color: var(--pf-c-code-editor__main--m-drag-hover--after--BackgroundColor);\n opacity: var(--pf-c-code-editor__main--m-drag-hover--after--Opacity); }\n .pf-c-code-editor__main.pf-m-drag-hover::before {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n content: \"\";\n border: var(--pf-c-code-editor__main--m-drag-hover--before--BorderWidth) solid var(--pf-c-code-editor__main--m-drag-hover--before--BorderColor); }\n .pf-c-code-editor__main .monaco-editor {\n background-color: var(--pf-c-code-editor__main--BackgroundColor); }\n\n.pf-c-code-editor__header + .pf-c-code-editor__main {\n border-top-width: 0; }\n\n.pf-c-code-editor__code {\n position: relative;\n padding: var(--pf-c-code-editor__code--PaddingTop) var(--pf-c-code-editor__code--PaddingRight) var(--pf-c-code-editor__code--PaddingBottom) var(--pf-c-code-editor__code--PaddingLeft); }\n .pf-c-code-editor__code .pf-c-code-editor__code-pre {\n font-family: var(--pf-c-code-editor__code-pre--FontFamily);\n font-size: var(--pf-c-code-editor__code-pre--FontSize);\n white-space: pre-wrap; }\n\n.pf-c-code-editor__tab {\n position: relative;\n display: flex;\n align-items: center;\n padding: var(--pf-c-code-editor__tab--PaddingTop) var(--pf-c-code-editor__tab--PaddingRight) var(--pf-c-code-editor__tab--PaddingBottom) var(--pf-c-code-editor__tab--PaddingLeft);\n margin-left: auto;\n color: var(--pf-c-code-editor__tab--Color);\n background-color: var(--pf-c-code-editor__tab--BackgroundColor);\n border-color: var(--pf-c-code-editor__tab--BorderColor);\n border-style: solid;\n border-width: var(--pf-c-code-editor__tab--BorderTopWidth) var(--pf-c-code-editor__tab--BorderRightWidth) var(--pf-c-code-editor__tab--BorderBottomWidth) var(--pf-c-code-editor__tab--BorderLeftWidth); }\n\n.pf-c-code-editor__tab-icon + .pf-c-code-editor__tab-text {\n margin-left: var(--pf-c-code-editor__tab-icon--text--MarginLeft); }\n\n.pf-c-content {\n --pf-c-content--MarginBottom: var(--pf-global--spacer--md);\n --pf-c-content--LineHeight: var(--pf-global--LineHeight--md);\n --pf-c-content--FontSize: var(--pf-global--FontSize--md);\n --pf-c-content--FontWeight: var(--pf-global--FontWeight--normal);\n --pf-c-content--Color: var(--pf-global--Color--100);\n --pf-c-content--heading--FontFamily: var(--pf-global--FontFamily--heading--sans-serif);\n --pf-c-content--h1--MarginTop: var(--pf-global--spacer--lg);\n --pf-c-content--h1--MarginBottom: var(--pf-global--spacer--sm);\n --pf-c-content--h1--LineHeight: var(--pf-global--LineHeight--sm);\n --pf-c-content--h1--FontSize: var(--pf-global--FontSize--2xl);\n --pf-c-content--h1--FontWeight: var(--pf-global--FontWeight--normal);\n --pf-c-content--h2--MarginTop: var(--pf-global--spacer--lg);\n --pf-c-content--h2--MarginBottom: var(--pf-global--spacer--sm);\n --pf-c-content--h2--LineHeight: var(--pf-global--LineHeight--md);\n --pf-c-content--h2--FontSize: var(--pf-global--FontSize--xl);\n --pf-c-content--h2--FontWeight: var(--pf-global--FontWeight--normal);\n --pf-c-content--h3--MarginTop: var(--pf-global--spacer--lg);\n --pf-c-content--h3--MarginBottom: var(--pf-global--spacer--sm);\n --pf-c-content--h3--LineHeight: var(--pf-global--LineHeight--md);\n --pf-c-content--h3--FontSize: var(--pf-global--FontSize--lg);\n --pf-c-content--h3--FontWeight: var(--pf-global--FontWeight--normal);\n --pf-c-content--h4--MarginTop: var(--pf-global--spacer--lg);\n --pf-c-content--h4--MarginBottom: var(--pf-global--spacer--sm);\n --pf-c-content--h4--LineHeight: var(--pf-global--LineHeight--md);\n --pf-c-content--h4--FontSize: var(--pf-global--FontSize--md);\n --pf-c-content--h4--FontWeight: var(--pf-global--FontWeight--normal);\n --pf-c-content--h5--MarginTop: var(--pf-global--spacer--lg);\n --pf-c-content--h5--MarginBottom: var(--pf-global--spacer--sm);\n --pf-c-content--h5--LineHeight: var(--pf-global--LineHeight--md);\n --pf-c-content--h5--FontSize: var(--pf-global--FontSize--md);\n --pf-c-content--h5--FontWeight: var(--pf-global--FontWeight--normal);\n --pf-c-content--h6--MarginTop: var(--pf-global--spacer--lg);\n --pf-c-content--h6--MarginBottom: var(--pf-global--spacer--sm);\n --pf-c-content--h6--LineHeight: var(--pf-global--LineHeight--md);\n --pf-c-content--h6--FontSize: var(--pf-global--FontSize--md);\n --pf-c-content--h6--FontWeight: var(--pf-global--FontWeight--normal);\n --pf-c-content--small--MarginBottom: var(--pf-global--spacer--md);\n --pf-c-content--small--LineHeight: var(--pf-global--LineHeight--md);\n --pf-c-content--small--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-content--small--Color: var(--pf-global--Color--200);\n --pf-c-content--a--Color: var(--pf-global--link--Color);\n --pf-c-content--a--TextDecoration: var(--pf-global--link--TextDecoration);\n --pf-c-content--a--hover--Color: var(--pf-global--link--Color--hover);\n --pf-c-content--a--hover--TextDecoration: var(--pf-global--link--TextDecoration--hover);\n --pf-c-content--blockquote--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-content--blockquote--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-content--blockquote--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-content--blockquote--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-content--blockquote--Color: var(--pf-global--Color--200);\n --pf-c-content--blockquote--BorderLeftColor: var(--pf-global--BorderColor--100);\n --pf-c-content--blockquote--BorderLeftWidth: var(--pf-global--BorderWidth--lg);\n --pf-c-content--ol--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-content--ol--MarginLeft: var(--pf-global--spacer--lg);\n --pf-c-content--ol--nested--MarginTop: var(--pf-global--spacer--sm);\n --pf-c-content--ol--nested--MarginLeft: var(--pf-global--spacer--sm);\n --pf-c-content--ul--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-content--ul--MarginLeft: var(--pf-global--spacer--lg);\n --pf-c-content--ul--nested--MarginTop: var(--pf-global--spacer--sm);\n --pf-c-content--ul--nested--MarginLeft: var(--pf-global--spacer--sm);\n --pf-c-content--ul--ListStyle: var(--pf-global--ListStyle);\n --pf-c-content--li--MarginTop: var(--pf-global--spacer--sm);\n --pf-c-content--dl--ColumnGap: var(--pf-global--spacer--2xl);\n --pf-c-content--dl--RowGap: var(--pf-global--spacer--md);\n --pf-c-content--dt--FontWeight: var(--pf-global--FontWeight--semi-bold);\n --pf-c-content--dt--MarginTop: var(--pf-global--spacer--md);\n --pf-c-content--dt--sm--MarginTop: 0;\n --pf-c-content--hr--Height: var(--pf-global--BorderWidth--sm);\n --pf-c-content--hr--BackgroundColor: var(--pf-global--BorderColor--100);\n font-size: var(--pf-c-content--FontSize);\n line-height: var(--pf-c-content--LineHeight);\n color: var(--pf-c-content--Color); }\n .pf-c-content a {\n color: var(--pf-c-content--a--Color);\n text-decoration: var(--pf-c-content--a--TextDecoration); }\n .pf-c-content a:hover {\n --pf-c-content--a--Color: var(--pf-c-content--a--hover--Color);\n --pf-c-content--a--TextDecoration: var(--pf-c-content--a--hover--TextDecoration); }\n .pf-c-content li + li {\n margin-top: var(--pf-c-content--li--MarginTop); }\n .pf-c-content p:not(:last-child),\n .pf-c-content dl:not(:last-child),\n .pf-c-content ol:not(:last-child),\n .pf-c-content ul:not(:last-child),\n .pf-c-content blockquote:not(:last-child),\n .pf-c-content small:not(:last-child),\n .pf-c-content pre:not(:last-child),\n .pf-c-content table:not(:last-child),\n .pf-c-content hr:not(:last-child) {\n margin-bottom: var(--pf-c-content--MarginBottom); }\n .pf-c-content h1,\n .pf-c-content h2,\n .pf-c-content h3,\n .pf-c-content h4,\n .pf-c-content h5,\n .pf-c-content h6 {\n margin: 0;\n font-family: var(--pf-c-content--heading--FontFamily); }\n .pf-c-content h1:first-child,\n .pf-c-content h2:first-child,\n .pf-c-content h3:first-child,\n .pf-c-content h4:first-child,\n .pf-c-content h5:first-child,\n .pf-c-content h6:first-child {\n margin-top: 0; }\n .pf-c-content h1:last-child,\n .pf-c-content h2:last-child,\n .pf-c-content h3:last-child,\n .pf-c-content h4:last-child,\n .pf-c-content h5:last-child,\n .pf-c-content h6:last-child {\n margin-bottom: 0; }\n .pf-c-content ol,\n .pf-c-content ul {\n margin: 0; }\n .pf-c-content h1 {\n margin-top: var(--pf-c-content--h1--MarginTop);\n margin-bottom: var(--pf-c-content--h1--MarginBottom);\n font-size: var(--pf-c-content--h1--FontSize);\n font-weight: var(--pf-c-content--h1--FontWeight);\n line-height: var(--pf-c-content--h1--LineHeight); }\n .pf-c-content h2 {\n margin-top: var(--pf-c-content--h2--MarginTop);\n margin-bottom: var(--pf-c-content--h2--MarginBottom);\n font-size: var(--pf-c-content--h2--FontSize);\n font-weight: var(--pf-c-content--h2--FontWeight);\n line-height: var(--pf-c-content--h2--LineHeight); }\n .pf-c-content h3 {\n margin-top: var(--pf-c-content--h3--MarginTop);\n margin-bottom: var(--pf-c-content--h3--MarginBottom);\n font-size: var(--pf-c-content--h3--FontSize);\n font-weight: var(--pf-c-content--h3--FontWeight);\n line-height: var(--pf-c-content--h3--LineHeight); }\n .pf-c-content h4 {\n margin-top: var(--pf-c-content--h4--MarginTop);\n margin-bottom: var(--pf-c-content--h4--MarginBottom);\n font-size: var(--pf-c-content--h4--FontSize);\n font-weight: var(--pf-c-content--h4--FontWeight);\n line-height: var(--pf-c-content--h4--LineHeight); }\n .pf-c-content h5 {\n margin-top: var(--pf-c-content--h5--MarginTop);\n margin-bottom: var(--pf-c-content--h5--MarginBottom);\n font-size: var(--pf-c-content--h5--FontSize);\n font-weight: var(--pf-c-content--h5--FontWeight);\n line-height: var(--pf-c-content--h5--LineHeight); }\n .pf-c-content h6 {\n margin-top: var(--pf-c-content--h6--MarginTop);\n margin-bottom: var(--pf-c-content--h6--MarginBottom);\n font-size: var(--pf-c-content--h6--FontSize);\n font-weight: var(--pf-c-content--h6--FontWeight);\n line-height: var(--pf-c-content--h6--LineHeight); }\n .pf-c-content small {\n display: block;\n font-size: var(--pf-c-content--small--FontSize);\n line-height: var(--pf-c-content--small--LineHeight);\n color: var(--pf-c-content--small--Color); }\n .pf-c-content small:not(:last-child) {\n margin-bottom: var(--pf-c-content--small--MarginBottom); }\n .pf-c-content blockquote {\n padding: var(--pf-c-content--blockquote--PaddingTop) var(--pf-c-content--blockquote--PaddingRight) var(--pf-c-content--blockquote--PaddingBottom) var(--pf-c-content--blockquote--PaddingLeft);\n color: var(--pf-c-content--blockquote--Color);\n border-left: var(--pf-c-content--blockquote--BorderLeftWidth) solid var(--pf-c-content--blockquote--BorderLeftColor); }\n .pf-c-content hr {\n height: var(--pf-c-content--hr--Height);\n background-color: var(--pf-c-content--hr--BackgroundColor);\n border: none; }\n .pf-c-content ol {\n padding-left: var(--pf-c-content--ol--PaddingLeft);\n margin-left: var(--pf-c-content--ol--MarginLeft); }\n .pf-c-content ol ul {\n margin-top: var(--pf-c-content--ul--nested--MarginTop);\n --pf-c-content--ul--MarginLeft: var(--pf-c-content--ul--nested--MarginLeft); }\n .pf-c-content ol ol {\n margin-top: var(--pf-c-content--ol--nested--MarginTop);\n --pf-c-content--ol--MarginLeft: var(--pf-c-content--ol--nested--MarginLeft); }\n .pf-c-content ul {\n padding-left: var(--pf-c-content--ul--PaddingLeft);\n margin-left: var(--pf-c-content--ul--MarginLeft);\n list-style: var(--pf-c-content--ul--ListStyle); }\n .pf-c-content ul ul {\n margin-top: var(--pf-c-content--ul--nested--MarginTop);\n --pf-c-content--ul--MarginLeft: var(--pf-c-content--ul--nested--MarginLeft); }\n .pf-c-content ul ol {\n margin-top: var(--pf-c-content--ol--nested--MarginTop);\n --pf-c-content--ol--MarginLeft: var(--pf-c-content--ol--nested--MarginLeft); }\n .pf-c-content dl {\n display: grid;\n grid-template-columns: 1fr; }\n @media screen and (min-width: 576px) {\n .pf-c-content dl {\n grid-template: auto / auto 1fr;\n grid-column-gap: var(--pf-c-content--dl--ColumnGap);\n grid-row-gap: var(--pf-c-content--dl--RowGap); } }\n .pf-c-content dt {\n font-weight: var(--pf-c-content--dt--FontWeight); }\n .pf-c-content dt:not(:first-child) {\n margin-top: var(--pf-c-content--dt--MarginTop); }\n @media screen and (min-width: 576px) {\n .pf-c-content dt:not(:first-child) {\n --pf-c-content--dt--MarginTop: var(--pf-c-content--dt--sm--MarginTop); } }\n @media screen and (min-width: 576px) {\n .pf-c-content dt {\n grid-column: 1; } }\n @media screen and (min-width: 576px) {\n .pf-c-content dd {\n grid-column: 2; } }\n\n.pf-m-overpass-font .pf-c-content {\n --pf-c-content--h2--LineHeight: var(--pf-global--LineHeight--sm);\n --pf-c-content--h4--FontWeight: var(--pf-global--FontWeight--semi-bold);\n --pf-c-content--h5--FontWeight: var(--pf-global--FontWeight--semi-bold);\n --pf-c-content--h6--FontWeight: var(--pf-global--FontWeight--semi-bold); }\n .pf-m-overpass-font .pf-c-content blockquote {\n font-weight: var(--pf-global--FontWeight--light); }\n\n.pf-c-context-selector {\n --pf-c-context-selector--Width: 15.625rem;\n --pf-c-context-selector__toggle--PaddingTop: var(--pf-global--spacer--form-element);\n --pf-c-context-selector__toggle--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-context-selector__toggle--PaddingBottom: var(--pf-global--spacer--form-element);\n --pf-c-context-selector__toggle--PaddingLeft: var(--pf-global--spacer--sm);\n --pf-c-context-selector__toggle--BorderWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-context-selector__toggle--BorderTopColor: var(--pf-global--BorderColor--300);\n --pf-c-context-selector__toggle--BorderRightColor: var(--pf-global--BorderColor--300);\n --pf-c-context-selector__toggle--BorderBottomColor: var(--pf-global--BorderColor--200);\n --pf-c-context-selector__toggle--BorderLeftColor: var(--pf-global--BorderColor--300);\n --pf-c-context-selector__toggle--Color: var(--pf-global--Color--100);\n --pf-c-context-selector__toggle--hover--BorderBottomColor: var(--pf-global--active-color--100);\n --pf-c-context-selector__toggle--active--BorderBottomWidth: var(--pf-global--BorderWidth--md);\n --pf-c-context-selector__toggle--active--BorderBottomColor: var(--pf-global--active-color--100);\n --pf-c-context-selector__toggle--expanded--BorderBottomWidth: var(--pf-global--BorderWidth--md);\n --pf-c-context-selector__toggle--expanded--BorderBottomColor: var(--pf-global--active-color--100);\n --pf-c-context-selector__toggle-text--FontSize: var(--pf-global--FontSize--md);\n --pf-c-context-selector__toggle-text--FontWeight: var(--pf-global--FontWeight--normal);\n --pf-c-context-selector__toggle-text--LineHeight: var(--pf-global--LineHeight--md);\n --pf-c-context-selector__toggle-icon--MarginRight: var(--pf-global--spacer--sm);\n --pf-c-context-selector__toggle-icon--MarginLeft: var(--pf-global--spacer--md);\n --pf-c-context-selector__menu--Top: calc(100% + var(--pf-global--spacer--xs));\n --pf-c-context-selector__menu--ZIndex: var(--pf-global--ZIndex--sm);\n --pf-c-context-selector__menu--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-context-selector__menu--BackgroundColor: var(--pf-global--BackgroundColor--light-100);\n --pf-c-context-selector__menu--BoxShadow: var(--pf-global--BoxShadow--md);\n --pf-c-context-selector__menu-search--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-context-selector__menu-search--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-context-selector__menu-search--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-context-selector__menu-search--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-context-selector__menu-search--BorderBottomColor: var(--pf-global--BorderColor--100);\n --pf-c-context-selector__menu-search--BorderBottomWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-context-selector__menu-footer--BoxShadow: var(--pf-global--BoxShadow--sm-top);\n --pf-c-context-selector__menu-footer--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-context-selector__menu-footer--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-context-selector__menu-footer--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-context-selector__menu-footer--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-context-selector__menu-list--MaxHeight: 12.5rem;\n --pf-c-context-selector__menu-list-item--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-context-selector__menu-list-item--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-context-selector__menu-list-item--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-context-selector__menu-list-item--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-context-selector__menu-list-item--hover--BackgroundColor: var(--pf-global--BackgroundColor--light-300);\n --pf-c-context-selector__menu-list-item--disabled--Color: var(--pf-global--Color--dark-200);\n position: relative;\n display: inline-block;\n width: var(--pf-c-context-selector--Width);\n max-width: 100%; }\n\n.pf-c-context-selector__toggle {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n padding: var(--pf-c-context-selector__toggle--PaddingTop) var(--pf-c-context-selector__toggle--PaddingRight) var(--pf-c-context-selector__toggle--PaddingBottom) var(--pf-c-context-selector__toggle--PaddingLeft);\n color: var(--pf-c-context-selector__toggle--Color);\n white-space: nowrap;\n cursor: pointer;\n border: none; }\n .pf-c-context-selector__toggle::before {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n content: \"\";\n border: var(--pf-c-context-selector__toggle--BorderWidth) solid;\n border-color: var(--pf-c-context-selector__toggle--BorderTopColor) var(--pf-c-context-selector__toggle--BorderRightColor) var(--pf-c-context-selector__toggle--BorderBottomColor) var(--pf-c-context-selector__toggle--BorderLeftColor); }\n .pf-c-context-selector__toggle:hover::before {\n --pf-c-context-selector__toggle--BorderBottomColor: var(--pf-c-context-selector__toggle--hover--BorderBottomColor); }\n .pf-c-context-selector__toggle:active::before, .pf-c-context-selector__toggle.pf-m-active::before, .pf-c-context-selector__toggle:focus-within::before {\n --pf-c-context-selector__toggle--BorderBottomColor: var(--pf-c-context-selector__toggle--active--BorderBottomColor);\n border-bottom-width: var(--pf-c-context-selector__toggle--active--BorderBottomWidth); }\n .pf-m-expanded > .pf-c-context-selector__toggle::before {\n --pf-c-context-selector__toggle--BorderBottomColor: var(--pf-c-context-selector__toggle--expanded--BorderBottomColor);\n border-bottom-width: var(--pf-c-context-selector__toggle--expanded--BorderBottomWidth); }\n .pf-c-context-selector__toggle .pf-c-context-selector__toggle-icon {\n margin-right: var(--pf-c-context-selector__toggle-icon--MarginRight);\n margin-left: var(--pf-c-context-selector__toggle-icon--MarginLeft); }\n .pf-c-context-selector__toggle .pf-c-context-selector__toggle-text {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: var(--pf-c-context-selector__toggle-text--FontSize);\n font-weight: var(--pf-c-context-selector__toggle-text--FontWeight);\n line-height: var(--pf-c-context-selector__toggle-text--LineHeight); }\n\n.pf-c-context-selector__menu {\n color: var(--pf-global--Color--100);\n position: absolute;\n top: var(--pf-c-context-selector__menu--Top);\n z-index: var(--pf-c-context-selector__menu--ZIndex);\n min-width: 100%;\n padding-top: var(--pf-c-context-selector__menu--PaddingTop);\n background-color: var(--pf-c-context-selector__menu--BackgroundColor);\n background-clip: padding-box;\n box-shadow: var(--pf-c-context-selector__menu--BoxShadow); }\n\n.pf-c-context-selector__menu-search {\n position: relative;\n padding: var(--pf-c-context-selector__menu-search--PaddingTop) var(--pf-c-context-selector__menu-search--PaddingRight) var(--pf-c-context-selector__menu-search--PaddingBottom) var(--pf-c-context-selector__menu-search--PaddingLeft);\n border-bottom: var(--pf-c-context-selector__menu-search--BorderBottomWidth) solid var(--pf-c-context-selector__menu-search--BorderBottomColor); }\n\n.pf-c-context-selector__menu-footer {\n padding: var(--pf-c-context-selector__menu-footer--PaddingTop) var(--pf-c-context-selector__menu-footer--PaddingRight) var(--pf-c-context-selector__menu-footer--PaddingBottom) var(--pf-c-context-selector__menu-footer--PaddingLeft);\n text-align: right;\n box-shadow: var(--pf-c-context-selector__menu-footer--BoxShadow); }\n\n.pf-c-context-selector__menu-list {\n max-height: var(--pf-c-context-selector__menu-list--MaxHeight);\n overflow-y: scroll; }\n\n.pf-c-context-selector__menu-list-item {\n display: flex;\n align-items: center;\n width: 100%;\n padding: var(--pf-c-context-selector__menu-list-item--PaddingTop) var(--pf-c-context-selector__menu-list-item--PaddingRight) var(--pf-c-context-selector__menu-list-item--PaddingBottom) var(--pf-c-context-selector__menu-list-item--PaddingLeft);\n white-space: nowrap;\n border: none; }\n .pf-c-context-selector__menu-list-item:hover, .pf-c-context-selector__menu-list-item:focus {\n text-decoration: none;\n background-color: var(--pf-c-context-selector__menu-list-item--hover--BackgroundColor); }\n .pf-c-context-selector__menu-list-item:disabled {\n color: var(--pf-c-context-selector__menu-list-item--disabled--Color);\n pointer-events: none; }\n\n@media screen and (min-width: 768px) {\n .pf-c-data-list:not([class*=\"pf-m-grid\"]) {\n --pf-c-data-list__cell--cell--PaddingTop: var(--pf-c-data-list__cell--cell--md--PaddingTop);\n --pf-c-data-list__cell--PaddingBottom: var(--pf-c-data-list__cell--md--PaddingBottom);\n --pf-c-data-list__item-control--MarginRight: var(--pf-c-data-list__item-control--md--MarginRight);\n --pf-c-data-list__item-action--MarginLeft: var(--pf-c-data-list__item-action--md--MarginLeft);\n --pf-c-data-list__expandable-content-body--PaddingTop: var(--pf-c-data-list__expandable-content-body--md--PaddingTop);\n --pf-c-data-list__expandable-content-body--PaddingBottom: var(--pf-c-data-list__expandable-content-body--md--PaddingBottom);\n --pf-c-data-list--m-compact__cell--PaddingBottom: var(--pf-c-data-list--m-compact__cell--md--PaddingBottom);\n --pf-c-data-list--m-compact__cell-cell--PaddingTop: var(--pf-c-data-list--m-compact__cell-cell--md--PaddingTop); } }\n @media screen and (min-width: 768px) and (min-width: 1200px) {\n .pf-c-data-list:not([class*=\"pf-m-grid\"]) {\n --pf-c-data-list__item-row--PaddingRight: var(--pf-c-data-list__item-row--xl--PaddingRight);\n --pf-c-data-list__item-row--PaddingLeft: var(--pf-c-data-list__item-row--xl--PaddingLeft);\n --pf-c-data-list__expandable-content-body--PaddingRight: var(--pf-c-data-list__expandable-content-body--xl--PaddingRight);\n --pf-c-data-list__expandable-content-body--PaddingLeft: var(--pf-c-data-list__expandable-content-body--xl--PaddingLeft); } }\n\n@media screen and (min-width: 768px) {\n .pf-c-data-list:not([class*=\"pf-m-grid\"]) .pf-c-data-list__item-content {\n display: flex;\n flex-wrap: wrap;\n flex-grow: 1;\n padding-bottom: var(--pf-c-data-list__item-content--md--PaddingBottom); }\n .pf-c-data-list:not([class*=\"pf-m-grid\"]) .pf-c-data-list__cell:not(:last-child):not(.pf-m-icon) {\n margin-right: var(--pf-c-data-list__cell--MarginRight); }\n .pf-c-data-list:not([class*=\"pf-m-grid\"]) .pf-c-data-list__cell + .pf-c-data-list__cell {\n flex: 1;\n order: initial; }\n .pf-c-data-list:not([class*=\"pf-m-grid\"]) .pf-c-data-list__cell.pf-m-align-right {\n margin-left: auto; }\n .pf-c-data-list:not([class*=\"pf-m-grid\"]) .pf-c-data-list__cell.pf-m-no-fill {\n flex-grow: 0; }\n .pf-c-data-list:not([class*=\"pf-m-grid\"]) .pf-c-data-list__cell.pf-m-flex-2 {\n flex-grow: 2; }\n .pf-c-data-list:not([class*=\"pf-m-grid\"]) .pf-c-data-list__cell.pf-m-flex-3 {\n flex-grow: 3; }\n .pf-c-data-list:not([class*=\"pf-m-grid\"]) .pf-c-data-list__cell.pf-m-flex-4 {\n flex-grow: 4; }\n .pf-c-data-list:not([class*=\"pf-m-grid\"]) .pf-c-data-list__cell.pf-m-flex-5 {\n flex-grow: 5; }\n .pf-c-data-list:not([class*=\"pf-m-grid\"]) .pf-c-data-list__expandable-content {\n max-height: initial;\n overflow-y: visible; } }\n\n@media screen and (min-width: 0) {\n .pf-c-data-list.pf-m-grid-none {\n --pf-c-data-list__cell--cell--PaddingTop: var(--pf-c-data-list__cell--cell--md--PaddingTop);\n --pf-c-data-list__cell--PaddingBottom: var(--pf-c-data-list__cell--md--PaddingBottom);\n --pf-c-data-list__item-control--MarginRight: var(--pf-c-data-list__item-control--md--MarginRight);\n --pf-c-data-list__item-action--MarginLeft: var(--pf-c-data-list__item-action--md--MarginLeft);\n --pf-c-data-list__expandable-content-body--PaddingTop: var(--pf-c-data-list__expandable-content-body--md--PaddingTop);\n --pf-c-data-list__expandable-content-body--PaddingBottom: var(--pf-c-data-list__expandable-content-body--md--PaddingBottom);\n --pf-c-data-list--m-compact__cell--PaddingBottom: var(--pf-c-data-list--m-compact__cell--md--PaddingBottom);\n --pf-c-data-list--m-compact__cell-cell--PaddingTop: var(--pf-c-data-list--m-compact__cell-cell--md--PaddingTop); } }\n @media screen and (min-width: 0) and (min-width: 1200px) {\n .pf-c-data-list.pf-m-grid-none {\n --pf-c-data-list__item-row--PaddingRight: var(--pf-c-data-list__item-row--xl--PaddingRight);\n --pf-c-data-list__item-row--PaddingLeft: var(--pf-c-data-list__item-row--xl--PaddingLeft);\n --pf-c-data-list__expandable-content-body--PaddingRight: var(--pf-c-data-list__expandable-content-body--xl--PaddingRight);\n --pf-c-data-list__expandable-content-body--PaddingLeft: var(--pf-c-data-list__expandable-content-body--xl--PaddingLeft); } }\n\n@media screen and (min-width: 0) {\n .pf-c-data-list.pf-m-grid-none .pf-c-data-list__item-content {\n display: flex;\n flex-wrap: wrap;\n flex-grow: 1;\n padding-bottom: var(--pf-c-data-list__item-content--md--PaddingBottom); }\n .pf-c-data-list.pf-m-grid-none .pf-c-data-list__cell:not(:last-child):not(.pf-m-icon) {\n margin-right: var(--pf-c-data-list__cell--MarginRight); }\n .pf-c-data-list.pf-m-grid-none .pf-c-data-list__cell + .pf-c-data-list__cell {\n flex: 1;\n order: initial; }\n .pf-c-data-list.pf-m-grid-none .pf-c-data-list__cell.pf-m-align-right {\n margin-left: auto; }\n .pf-c-data-list.pf-m-grid-none .pf-c-data-list__cell.pf-m-no-fill {\n flex-grow: 0; }\n .pf-c-data-list.pf-m-grid-none .pf-c-data-list__cell.pf-m-flex-2 {\n flex-grow: 2; }\n .pf-c-data-list.pf-m-grid-none .pf-c-data-list__cell.pf-m-flex-3 {\n flex-grow: 3; }\n .pf-c-data-list.pf-m-grid-none .pf-c-data-list__cell.pf-m-flex-4 {\n flex-grow: 4; }\n .pf-c-data-list.pf-m-grid-none .pf-c-data-list__cell.pf-m-flex-5 {\n flex-grow: 5; }\n .pf-c-data-list.pf-m-grid-none .pf-c-data-list__expandable-content {\n max-height: initial;\n overflow-y: visible; } }\n\n@media screen and (min-width: 576px) {\n .pf-c-data-list.pf-m-grid-sm {\n --pf-c-data-list__cell--cell--PaddingTop: var(--pf-c-data-list__cell--cell--md--PaddingTop);\n --pf-c-data-list__cell--PaddingBottom: var(--pf-c-data-list__cell--md--PaddingBottom);\n --pf-c-data-list__item-control--MarginRight: var(--pf-c-data-list__item-control--md--MarginRight);\n --pf-c-data-list__item-action--MarginLeft: var(--pf-c-data-list__item-action--md--MarginLeft);\n --pf-c-data-list__expandable-content-body--PaddingTop: var(--pf-c-data-list__expandable-content-body--md--PaddingTop);\n --pf-c-data-list__expandable-content-body--PaddingBottom: var(--pf-c-data-list__expandable-content-body--md--PaddingBottom);\n --pf-c-data-list--m-compact__cell--PaddingBottom: var(--pf-c-data-list--m-compact__cell--md--PaddingBottom);\n --pf-c-data-list--m-compact__cell-cell--PaddingTop: var(--pf-c-data-list--m-compact__cell-cell--md--PaddingTop); } }\n @media screen and (min-width: 576px) and (min-width: 1200px) {\n .pf-c-data-list.pf-m-grid-sm {\n --pf-c-data-list__item-row--PaddingRight: var(--pf-c-data-list__item-row--xl--PaddingRight);\n --pf-c-data-list__item-row--PaddingLeft: var(--pf-c-data-list__item-row--xl--PaddingLeft);\n --pf-c-data-list__expandable-content-body--PaddingRight: var(--pf-c-data-list__expandable-content-body--xl--PaddingRight);\n --pf-c-data-list__expandable-content-body--PaddingLeft: var(--pf-c-data-list__expandable-content-body--xl--PaddingLeft); } }\n\n@media screen and (min-width: 576px) {\n .pf-c-data-list.pf-m-grid-sm .pf-c-data-list__item-content {\n display: flex;\n flex-wrap: wrap;\n flex-grow: 1;\n padding-bottom: var(--pf-c-data-list__item-content--md--PaddingBottom); }\n .pf-c-data-list.pf-m-grid-sm .pf-c-data-list__cell:not(:last-child):not(.pf-m-icon) {\n margin-right: var(--pf-c-data-list__cell--MarginRight); }\n .pf-c-data-list.pf-m-grid-sm .pf-c-data-list__cell + .pf-c-data-list__cell {\n flex: 1;\n order: initial; }\n .pf-c-data-list.pf-m-grid-sm .pf-c-data-list__cell.pf-m-align-right {\n margin-left: auto; }\n .pf-c-data-list.pf-m-grid-sm .pf-c-data-list__cell.pf-m-no-fill {\n flex-grow: 0; }\n .pf-c-data-list.pf-m-grid-sm .pf-c-data-list__cell.pf-m-flex-2 {\n flex-grow: 2; }\n .pf-c-data-list.pf-m-grid-sm .pf-c-data-list__cell.pf-m-flex-3 {\n flex-grow: 3; }\n .pf-c-data-list.pf-m-grid-sm .pf-c-data-list__cell.pf-m-flex-4 {\n flex-grow: 4; }\n .pf-c-data-list.pf-m-grid-sm .pf-c-data-list__cell.pf-m-flex-5 {\n flex-grow: 5; }\n .pf-c-data-list.pf-m-grid-sm .pf-c-data-list__expandable-content {\n max-height: initial;\n overflow-y: visible; } }\n\n@media screen and (min-width: 768px) {\n .pf-c-data-list.pf-m-grid-md {\n --pf-c-data-list__cell--cell--PaddingTop: var(--pf-c-data-list__cell--cell--md--PaddingTop);\n --pf-c-data-list__cell--PaddingBottom: var(--pf-c-data-list__cell--md--PaddingBottom);\n --pf-c-data-list__item-control--MarginRight: var(--pf-c-data-list__item-control--md--MarginRight);\n --pf-c-data-list__item-action--MarginLeft: var(--pf-c-data-list__item-action--md--MarginLeft);\n --pf-c-data-list__expandable-content-body--PaddingTop: var(--pf-c-data-list__expandable-content-body--md--PaddingTop);\n --pf-c-data-list__expandable-content-body--PaddingBottom: var(--pf-c-data-list__expandable-content-body--md--PaddingBottom);\n --pf-c-data-list--m-compact__cell--PaddingBottom: var(--pf-c-data-list--m-compact__cell--md--PaddingBottom);\n --pf-c-data-list--m-compact__cell-cell--PaddingTop: var(--pf-c-data-list--m-compact__cell-cell--md--PaddingTop); } }\n @media screen and (min-width: 768px) and (min-width: 1200px) {\n .pf-c-data-list.pf-m-grid-md {\n --pf-c-data-list__item-row--PaddingRight: var(--pf-c-data-list__item-row--xl--PaddingRight);\n --pf-c-data-list__item-row--PaddingLeft: var(--pf-c-data-list__item-row--xl--PaddingLeft);\n --pf-c-data-list__expandable-content-body--PaddingRight: var(--pf-c-data-list__expandable-content-body--xl--PaddingRight);\n --pf-c-data-list__expandable-content-body--PaddingLeft: var(--pf-c-data-list__expandable-content-body--xl--PaddingLeft); } }\n\n@media screen and (min-width: 768px) {\n .pf-c-data-list.pf-m-grid-md .pf-c-data-list__item-content {\n display: flex;\n flex-wrap: wrap;\n flex-grow: 1;\n padding-bottom: var(--pf-c-data-list__item-content--md--PaddingBottom); }\n .pf-c-data-list.pf-m-grid-md .pf-c-data-list__cell:not(:last-child):not(.pf-m-icon) {\n margin-right: var(--pf-c-data-list__cell--MarginRight); }\n .pf-c-data-list.pf-m-grid-md .pf-c-data-list__cell + .pf-c-data-list__cell {\n flex: 1;\n order: initial; }\n .pf-c-data-list.pf-m-grid-md .pf-c-data-list__cell.pf-m-align-right {\n margin-left: auto; }\n .pf-c-data-list.pf-m-grid-md .pf-c-data-list__cell.pf-m-no-fill {\n flex-grow: 0; }\n .pf-c-data-list.pf-m-grid-md .pf-c-data-list__cell.pf-m-flex-2 {\n flex-grow: 2; }\n .pf-c-data-list.pf-m-grid-md .pf-c-data-list__cell.pf-m-flex-3 {\n flex-grow: 3; }\n .pf-c-data-list.pf-m-grid-md .pf-c-data-list__cell.pf-m-flex-4 {\n flex-grow: 4; }\n .pf-c-data-list.pf-m-grid-md .pf-c-data-list__cell.pf-m-flex-5 {\n flex-grow: 5; }\n .pf-c-data-list.pf-m-grid-md .pf-c-data-list__expandable-content {\n max-height: initial;\n overflow-y: visible; } }\n\n@media screen and (min-width: 992px) {\n .pf-c-data-list.pf-m-grid-lg {\n --pf-c-data-list__cell--cell--PaddingTop: var(--pf-c-data-list__cell--cell--md--PaddingTop);\n --pf-c-data-list__cell--PaddingBottom: var(--pf-c-data-list__cell--md--PaddingBottom);\n --pf-c-data-list__item-control--MarginRight: var(--pf-c-data-list__item-control--md--MarginRight);\n --pf-c-data-list__item-action--MarginLeft: var(--pf-c-data-list__item-action--md--MarginLeft);\n --pf-c-data-list__expandable-content-body--PaddingTop: var(--pf-c-data-list__expandable-content-body--md--PaddingTop);\n --pf-c-data-list__expandable-content-body--PaddingBottom: var(--pf-c-data-list__expandable-content-body--md--PaddingBottom);\n --pf-c-data-list--m-compact__cell--PaddingBottom: var(--pf-c-data-list--m-compact__cell--md--PaddingBottom);\n --pf-c-data-list--m-compact__cell-cell--PaddingTop: var(--pf-c-data-list--m-compact__cell-cell--md--PaddingTop); } }\n @media screen and (min-width: 992px) and (min-width: 1200px) {\n .pf-c-data-list.pf-m-grid-lg {\n --pf-c-data-list__item-row--PaddingRight: var(--pf-c-data-list__item-row--xl--PaddingRight);\n --pf-c-data-list__item-row--PaddingLeft: var(--pf-c-data-list__item-row--xl--PaddingLeft);\n --pf-c-data-list__expandable-content-body--PaddingRight: var(--pf-c-data-list__expandable-content-body--xl--PaddingRight);\n --pf-c-data-list__expandable-content-body--PaddingLeft: var(--pf-c-data-list__expandable-content-body--xl--PaddingLeft); } }\n\n@media screen and (min-width: 992px) {\n .pf-c-data-list.pf-m-grid-lg .pf-c-data-list__item-content {\n display: flex;\n flex-wrap: wrap;\n flex-grow: 1;\n padding-bottom: var(--pf-c-data-list__item-content--md--PaddingBottom); }\n .pf-c-data-list.pf-m-grid-lg .pf-c-data-list__cell:not(:last-child):not(.pf-m-icon) {\n margin-right: var(--pf-c-data-list__cell--MarginRight); }\n .pf-c-data-list.pf-m-grid-lg .pf-c-data-list__cell + .pf-c-data-list__cell {\n flex: 1;\n order: initial; }\n .pf-c-data-list.pf-m-grid-lg .pf-c-data-list__cell.pf-m-align-right {\n margin-left: auto; }\n .pf-c-data-list.pf-m-grid-lg .pf-c-data-list__cell.pf-m-no-fill {\n flex-grow: 0; }\n .pf-c-data-list.pf-m-grid-lg .pf-c-data-list__cell.pf-m-flex-2 {\n flex-grow: 2; }\n .pf-c-data-list.pf-m-grid-lg .pf-c-data-list__cell.pf-m-flex-3 {\n flex-grow: 3; }\n .pf-c-data-list.pf-m-grid-lg .pf-c-data-list__cell.pf-m-flex-4 {\n flex-grow: 4; }\n .pf-c-data-list.pf-m-grid-lg .pf-c-data-list__cell.pf-m-flex-5 {\n flex-grow: 5; }\n .pf-c-data-list.pf-m-grid-lg .pf-c-data-list__expandable-content {\n max-height: initial;\n overflow-y: visible; } }\n\n@media screen and (min-width: 1200px) {\n .pf-c-data-list.pf-m-grid-xl {\n --pf-c-data-list__cell--cell--PaddingTop: var(--pf-c-data-list__cell--cell--md--PaddingTop);\n --pf-c-data-list__cell--PaddingBottom: var(--pf-c-data-list__cell--md--PaddingBottom);\n --pf-c-data-list__item-control--MarginRight: var(--pf-c-data-list__item-control--md--MarginRight);\n --pf-c-data-list__item-action--MarginLeft: var(--pf-c-data-list__item-action--md--MarginLeft);\n --pf-c-data-list__expandable-content-body--PaddingTop: var(--pf-c-data-list__expandable-content-body--md--PaddingTop);\n --pf-c-data-list__expandable-content-body--PaddingBottom: var(--pf-c-data-list__expandable-content-body--md--PaddingBottom);\n --pf-c-data-list--m-compact__cell--PaddingBottom: var(--pf-c-data-list--m-compact__cell--md--PaddingBottom);\n --pf-c-data-list--m-compact__cell-cell--PaddingTop: var(--pf-c-data-list--m-compact__cell-cell--md--PaddingTop); } }\n @media screen and (min-width: 1200px) and (min-width: 1200px) {\n .pf-c-data-list.pf-m-grid-xl {\n --pf-c-data-list__item-row--PaddingRight: var(--pf-c-data-list__item-row--xl--PaddingRight);\n --pf-c-data-list__item-row--PaddingLeft: var(--pf-c-data-list__item-row--xl--PaddingLeft);\n --pf-c-data-list__expandable-content-body--PaddingRight: var(--pf-c-data-list__expandable-content-body--xl--PaddingRight);\n --pf-c-data-list__expandable-content-body--PaddingLeft: var(--pf-c-data-list__expandable-content-body--xl--PaddingLeft); } }\n\n@media screen and (min-width: 1200px) {\n .pf-c-data-list.pf-m-grid-xl .pf-c-data-list__item-content {\n display: flex;\n flex-wrap: wrap;\n flex-grow: 1;\n padding-bottom: var(--pf-c-data-list__item-content--md--PaddingBottom); }\n .pf-c-data-list.pf-m-grid-xl .pf-c-data-list__cell:not(:last-child):not(.pf-m-icon) {\n margin-right: var(--pf-c-data-list__cell--MarginRight); }\n .pf-c-data-list.pf-m-grid-xl .pf-c-data-list__cell + .pf-c-data-list__cell {\n flex: 1;\n order: initial; }\n .pf-c-data-list.pf-m-grid-xl .pf-c-data-list__cell.pf-m-align-right {\n margin-left: auto; }\n .pf-c-data-list.pf-m-grid-xl .pf-c-data-list__cell.pf-m-no-fill {\n flex-grow: 0; }\n .pf-c-data-list.pf-m-grid-xl .pf-c-data-list__cell.pf-m-flex-2 {\n flex-grow: 2; }\n .pf-c-data-list.pf-m-grid-xl .pf-c-data-list__cell.pf-m-flex-3 {\n flex-grow: 3; }\n .pf-c-data-list.pf-m-grid-xl .pf-c-data-list__cell.pf-m-flex-4 {\n flex-grow: 4; }\n .pf-c-data-list.pf-m-grid-xl .pf-c-data-list__cell.pf-m-flex-5 {\n flex-grow: 5; }\n .pf-c-data-list.pf-m-grid-xl .pf-c-data-list__expandable-content {\n max-height: initial;\n overflow-y: visible; } }\n\n@media screen and (min-width: 1450px) {\n .pf-c-data-list.pf-m-grid-2xl {\n --pf-c-data-list__cell--cell--PaddingTop: var(--pf-c-data-list__cell--cell--md--PaddingTop);\n --pf-c-data-list__cell--PaddingBottom: var(--pf-c-data-list__cell--md--PaddingBottom);\n --pf-c-data-list__item-control--MarginRight: var(--pf-c-data-list__item-control--md--MarginRight);\n --pf-c-data-list__item-action--MarginLeft: var(--pf-c-data-list__item-action--md--MarginLeft);\n --pf-c-data-list__expandable-content-body--PaddingTop: var(--pf-c-data-list__expandable-content-body--md--PaddingTop);\n --pf-c-data-list__expandable-content-body--PaddingBottom: var(--pf-c-data-list__expandable-content-body--md--PaddingBottom);\n --pf-c-data-list--m-compact__cell--PaddingBottom: var(--pf-c-data-list--m-compact__cell--md--PaddingBottom);\n --pf-c-data-list--m-compact__cell-cell--PaddingTop: var(--pf-c-data-list--m-compact__cell-cell--md--PaddingTop); } }\n @media screen and (min-width: 1450px) and (min-width: 1200px) {\n .pf-c-data-list.pf-m-grid-2xl {\n --pf-c-data-list__item-row--PaddingRight: var(--pf-c-data-list__item-row--xl--PaddingRight);\n --pf-c-data-list__item-row--PaddingLeft: var(--pf-c-data-list__item-row--xl--PaddingLeft);\n --pf-c-data-list__expandable-content-body--PaddingRight: var(--pf-c-data-list__expandable-content-body--xl--PaddingRight);\n --pf-c-data-list__expandable-content-body--PaddingLeft: var(--pf-c-data-list__expandable-content-body--xl--PaddingLeft); } }\n\n@media screen and (min-width: 1450px) {\n .pf-c-data-list.pf-m-grid-2xl .pf-c-data-list__item-content {\n display: flex;\n flex-wrap: wrap;\n flex-grow: 1;\n padding-bottom: var(--pf-c-data-list__item-content--md--PaddingBottom); }\n .pf-c-data-list.pf-m-grid-2xl .pf-c-data-list__cell:not(:last-child):not(.pf-m-icon) {\n margin-right: var(--pf-c-data-list__cell--MarginRight); }\n .pf-c-data-list.pf-m-grid-2xl .pf-c-data-list__cell + .pf-c-data-list__cell {\n flex: 1;\n order: initial; }\n .pf-c-data-list.pf-m-grid-2xl .pf-c-data-list__cell.pf-m-align-right {\n margin-left: auto; }\n .pf-c-data-list.pf-m-grid-2xl .pf-c-data-list__cell.pf-m-no-fill {\n flex-grow: 0; }\n .pf-c-data-list.pf-m-grid-2xl .pf-c-data-list__cell.pf-m-flex-2 {\n flex-grow: 2; }\n .pf-c-data-list.pf-m-grid-2xl .pf-c-data-list__cell.pf-m-flex-3 {\n flex-grow: 3; }\n .pf-c-data-list.pf-m-grid-2xl .pf-c-data-list__cell.pf-m-flex-4 {\n flex-grow: 4; }\n .pf-c-data-list.pf-m-grid-2xl .pf-c-data-list__cell.pf-m-flex-5 {\n flex-grow: 5; }\n .pf-c-data-list.pf-m-grid-2xl .pf-c-data-list__expandable-content {\n max-height: initial;\n overflow-y: visible; } }\n\n.pf-c-data-list {\n --pf-c-data-list--BorderTopColor: var(--pf-global--BorderColor--300);\n --pf-c-data-list--BorderTopWidth: var(--pf-global--spacer--sm);\n --pf-c-data-list--sm--BorderTopWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-data-list--sm--BorderTopColor: var(--pf-global--BorderColor--100);\n --pf-c-data-list__item--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-data-list__item--m-selected--ZIndex: var(--pf-global--ZIndex--xs);\n --pf-c-data-list__item--m-expanded--before--BackgroundColor: var(--pf-global--active-color--100);\n --pf-c-data-list__item--m-selected--before--BackgroundColor: var(--pf-global--active-color--100);\n --pf-c-data-list__item--m-selected--BoxShadow: var(--pf-global--BoxShadow--sm-top), var(--pf-global--BoxShadow--sm-bottom);\n --pf-c-data-list__item--m-selectable--OutlineOffset: calc(-1 * var(--pf-global--spacer--xs));\n --pf-c-data-list__item--m-selectable--hover--ZIndex: calc(var(--pf-c-data-list__item--m-selected--ZIndex) + 1);\n --pf-c-data-list__item--m-selectable--hover--BoxShadow: var(--pf-global--BoxShadow--sm-top), var(--pf-global--BoxShadow--sm-bottom);\n --pf-c-data-list__item--m-selectable--focus--BoxShadow: var(--pf-global--BoxShadow--sm-top), var(--pf-global--BoxShadow--sm-bottom);\n --pf-c-data-list__item--m-selectable--active--BoxShadow: var(--pf-global--BoxShadow--sm-top), var(--pf-global--BoxShadow--sm-bottom);\n --pf-c-data-list__item--m-expanded--m-selectable--before--BackgroundColor: var(--pf-global--active-color--300);\n --pf-c-data-list__item--BorderBottomColor: var(--pf-global--BorderColor--300);\n --pf-c-data-list__item--BorderBottomWidth: 0.5rem;\n --pf-c-data-list__item--m-selectable--hover--item--BorderTopColor: var(--pf-c-data-list__item--BorderBottomColor);\n --pf-c-data-list__item--m-selectable--hover--item--BorderTopWidth: var(--pf-c-data-list__item--BorderBottomWidth);\n --pf-c-data-list__item--sm--BorderBottomWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-data-list__item--sm--BorderBottomColor: var(--pf-global--BorderColor--100);\n --pf-c-data-list__item--before--BackgroundColor: transparent;\n --pf-c-data-list__item--before--Width: var(--pf-global--BorderWidth--lg);\n --pf-c-data-list__item--before--Transition: var(--pf-global--Transition);\n --pf-c-data-list__item--before--Top: 0;\n --pf-c-data-list__item--before--sm--Top: calc(var(--pf-c-data-list__item--BorderBottomWidth) * -1);\n --pf-c-data-list__item-row--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-data-list__item-row--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-data-list__item-row--xl--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-data-list__item-row--xl--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-data-list__item-content--md--PaddingBottom: var(--pf-global--spacer--lg);\n --pf-c-data-list__cell--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-data-list__cell--PaddingBottom: var(--pf-global--spacer--lg);\n --pf-c-data-list__cell--MarginRight: var(--pf-global--spacer--xl);\n --pf-c-data-list__cell--md--PaddingBottom: 0;\n --pf-c-data-list__cell--m-icon--MarginRight: var(--pf-global--spacer--md);\n --pf-c-data-list__cell--cell--PaddingTop: 0;\n --pf-c-data-list__cell--cell--md--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-data-list__cell--m-icon--cell--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-data-list--cell--MinWidth: initial;\n --pf-c-data-list--cell--Overflow: visible;\n --pf-c-data-list--cell--TextOverflow: clip;\n --pf-c-data-list--cell--WhiteSpace: normal;\n --pf-c-data-list--cell--WordBreak: normal;\n --pf-c-data-list--cell--m-truncate--MinWidth: 5ch;\n --pf-c-data-list__toggle--MarginLeft: calc(var(--pf-global--spacer--sm) * -1);\n --pf-c-data-list__toggle--MarginTop: calc(var(--pf-global--spacer--form-element) * -1);\n --pf-c-data-list__toggle-icon--Transition: .2s ease-in 0s;\n --pf-c-data-list__item--m-expanded__toggle-icon--Rotate: 90deg;\n --pf-c-data-list__item-draggable-button--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-data-list__item-draggable-button--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-data-list__item-draggable-button--MarginTop: calc(var(--pf-global--spacer--sm) * -1);\n --pf-c-data-list__item-draggable-button--MarginLeft: calc(var(--pf-global--spacer--md) * -1);\n --pf-c-data-list__item-draggable-button-icon--Color: var(--pf-global--icon--Color--light);\n --pf-c-data-list__item-draggable-button--m-disabled__draggable-icon--Color: var(--pf-global--disabled-color--200);\n --pf-c-data-list__item-draggable-button--hover__draggable-icon--Color: var(--pf-global--icon--Color--dark);\n --pf-c-data-list__item-draggable-button--focus__draggable-icon--Color: var(--pf-global--icon--Color--dark);\n --pf-c-data-list__item--m-ghost-row--after--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-data-list__item--m-ghost-row--after--Opacity: .6;\n --pf-c-data-list__item-control--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-data-list__item-control--PaddingBottom: var(--pf-global--spacer--lg);\n --pf-c-data-list__item-control--MarginRight: var(--pf-global--spacer--md);\n --pf-c-data-list__item-control--md--MarginRight: var(--pf-global--spacer--xl);\n --pf-c-data-list__item-control--not-last-child--MarginRight: var(--pf-global--spacer--md);\n --pf-c-data-list__item-action--Display: flex;\n --pf-c-data-list__item-action--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-data-list__item-action--PaddingBottom: var(--pf-global--spacer--lg);\n --pf-c-data-list__item-action--MarginLeft: var(--pf-global--spacer--md);\n --pf-c-data-list__item-action--md--MarginLeft: var(--pf-global--spacer--xl);\n --pf-c-data-list__item-action--not-last-child--MarginRight: var(--pf-global--spacer--md);\n --pf-c-data-list__action--MarginTop: calc(var(--pf-global--spacer--form-element) * -1);\n --pf-c-data-list__expandable-content--BorderTopWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-data-list__expandable-content--BorderTopColor: var(--pf-global--BorderColor--100);\n --pf-c-data-list__expandable-content--MarginRight: calc(var(--pf-c-data-list__expandable-content-body--PaddingRight) * -1);\n --pf-c-data-list__expandable-content--MarginLeft: calc(var(--pf-c-data-list__expandable-content-body--PaddingLeft) * -1);\n --pf-c-data-list__expandable-content--MaxHeight: 37.5rem;\n --pf-c-data-list__expandable-content--before--Top: calc(var(--pf-c-data-list__item--BorderBottomWidth) * -1);\n --pf-c-data-list__expandable-content-body--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-data-list__expandable-content-body--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-data-list__expandable-content-body--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-data-list__expandable-content-body--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-data-list__expandable-content-body--md--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-data-list__expandable-content-body--xl--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-data-list__expandable-content-body--md--PaddingBottom: var(--pf-global--spacer--lg);\n --pf-c-data-list__expandable-content-body--xl--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-data-list--m-compact--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-data-list--m-compact__check--FontSize: var(--pf-global--FontSize--md);\n --pf-c-data-list--m-compact__cell--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-data-list--m-compact__cell--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-data-list--m-compact__cell--md--PaddingBottom: 0;\n --pf-c-data-list--m-compact__cell-cell--PaddingTop: 0;\n --pf-c-data-list--m-compact__cell-cell--md--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-data-list--m-compact__cell--cell--MarginRight: var(--pf-global--spacer--md);\n --pf-c-data-list--m-compact__item-control--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-data-list--m-compact__item-control--PaddingBottom: 0;\n --pf-c-data-list--m-compact__item-control--MarginRight: var(--pf-global--spacer--md);\n --pf-c-data-list--m-compact__item-action--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-data-list--m-compact__item-action--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-data-list--m-compact__item-action--MarginLeft: var(--pf-global--spacer--md);\n --pf-c-data-list--m-compact__item-content--PaddingBottom: var(--pf-global--spacer--sm);\n color: var(--pf-global--Color--100);\n overflow-wrap: break-word;\n list-style-type: disc;\n border-top: var(--pf-c-data-list--BorderTopWidth) solid var(--pf-c-data-list--BorderTopColor); }\n @media screen and (min-width: 576px) {\n .pf-c-data-list {\n --pf-c-data-list--BorderTopColor: var(--pf-c-data-list--sm--BorderTopColor);\n --pf-c-data-list--BorderTopWidth: var(--pf-c-data-list--sm--BorderTopWidth); } }\n @media screen and (min-width: 576px) {\n .pf-c-data-list {\n --pf-c-data-list__item--BorderBottomWidth: var(--pf-c-data-list__item--sm--BorderBottomWidth);\n --pf-c-data-list__item--BorderBottomColor: var(--pf-c-data-list__item--sm--BorderBottomColor); } }\n @media (min-width: 576px) {\n .pf-c-data-list {\n --pf-c-data-list__item--before--Top: var(--pf-c-data-list__item--before--sm--Top); } }\n .pf-c-data-list.pf-m-compact {\n font-size: var(--pf-c-data-list--m-compact--FontSize);\n --pf-c-data-list__item-action--MarginLeft: var(--pf-c-data-list--m-compact__item-action--MarginLeft);\n --pf-c-data-list__item-action--PaddingTop: var(--pf-c-data-list--m-compact__item-action--PaddingTop);\n --pf-c-data-list__item-action--PaddingBottom: var(--pf-c-data-list--m-compact__item-action--PaddingBottom);\n --pf-c-data-list__item-control--MarginRight: var(--pf-c-data-list--m-compact__item-control--MarginRight);\n --pf-c-data-list__item-control--PaddingTop: var(--pf-c-data-list--m-compact__item-control--PaddingTop);\n --pf-c-data-list__item-control--PaddingBottom: var(--pf-c-data-list--m-compact__item-control--PaddingBottom);\n --pf-c-data-list__item-content--md--PaddingBottom: var(--pf-c-data-list--m-compact__item-content--PaddingBottom); }\n .pf-c-data-list.pf-m-compact .pf-c-data-list__cell {\n --pf-c-data-list__cell--PaddingTop: var(--pf-c-data-list--m-compact__cell--PaddingTop);\n --pf-c-data-list__cell--PaddingBottom: var(--pf-c-data-list--m-compact__cell--PaddingBottom);\n --pf-c-data-list__cell--MarginRight: var(--pf-c-data-list--m-compact__cell--cell--MarginRight);\n --pf-c-data-list__cell--cell--PaddingTop: var(--pf-c-data-list--m-compact__cell-cell--PaddingTop); }\n .pf-c-data-list.pf-m-compact .pf-c-data-list__check {\n font-size: var(--pf-c-data-list--m-compact__check--FontSize); }\n .pf-c-data-list.pf-m-drag-over {\n overflow-anchor: none; }\n\n.pf-c-data-list.pf-m-truncate,\n.pf-c-data-list__item-row.pf-m-truncate,\n.pf-c-data-list__cell.pf-m-truncate,\n.pf-c-data-list__text.pf-m-truncate {\n --pf-c-data-list--cell--MinWidth: var(--pf-c-data-list--cell--m-truncate--MinWidth);\n --pf-c-data-list--cell--Overflow: hidden;\n --pf-c-data-list--cell--TextOverflow: ellipsis;\n --pf-c-data-list--cell--WhiteSpace: nowrap; }\n\n.pf-c-data-list.pf-m-break-word,\n.pf-c-data-list__item-row.pf-m-break-word,\n.pf-c-data-list__cell.pf-m-break-word,\n.pf-c-data-list__text.pf-m-break-word {\n --pf-c-data-list--cell--WordBreak: break-word; }\n\n.pf-c-data-list.pf-m-nowrap,\n.pf-c-data-list__item-row.pf-m-nowrap,\n.pf-c-data-list__cell.pf-m-nowrap,\n.pf-c-data-list__text.pf-m-nowrap {\n --pf-c-data-list--cell--WhiteSpace: nowrap; }\n\n.pf-c-data-list__item {\n position: relative;\n display: flex;\n flex-direction: column;\n background-color: var(--pf-c-data-list__item--BackgroundColor);\n border-bottom: var(--pf-c-data-list__item--BorderBottomWidth) solid var(--pf-c-data-list__item--BorderBottomColor); }\n .pf-c-data-list__item::before {\n position: absolute;\n top: var(--pf-c-data-list__item--before--Top);\n bottom: 0;\n left: 0;\n width: var(--pf-c-data-list__item--before--Width);\n content: \"\";\n background-color: var(--pf-c-data-list__item--before--BackgroundColor);\n transition: var(--pf-c-data-list__item--before--Transition); }\n .pf-c-data-list__item.pf-m-selectable {\n cursor: pointer;\n outline-offset: var(--pf-c-data-list__item--m-selectable--OutlineOffset); }\n .pf-c-data-list__item.pf-m-selectable:hover, .pf-c-data-list__item.pf-m-selectable:focus {\n position: relative;\n z-index: var(--pf-c-data-list__item--m-selectable--hover--ZIndex); }\n .pf-c-data-list__item.pf-m-selectable:hover:not(.pf-m-selected):not(:last-child), .pf-c-data-list__item.pf-m-selectable:focus:not(.pf-m-selected):not(:last-child) {\n --pf-c-data-list__item--BorderBottomWidth: 0; }\n .pf-c-data-list__item.pf-m-selectable:hover:not(.pf-m-selected):not(:last-child) + .pf-c-data-list__item, .pf-c-data-list__item.pf-m-selectable:focus:not(.pf-m-selected):not(:last-child) + .pf-c-data-list__item {\n border-top: var(--pf-c-data-list__item--m-selectable--hover--item--BorderTopWidth) solid var(--pf-c-data-list__item--m-selectable--hover--item--BorderTopColor); }\n .pf-c-data-list__item.pf-m-selectable:hover {\n box-shadow: var(--pf-c-data-list__item--m-selectable--hover--BoxShadow); }\n .pf-c-data-list__item.pf-m-selectable:focus {\n box-shadow: var(--pf-c-data-list__item--m-selectable--focus--BoxShadow); }\n .pf-c-data-list__item.pf-m-selectable:active {\n box-shadow: var(--pf-c-data-list__item--m-selectable--active--BoxShadow); }\n .pf-c-data-list__item.pf-m-selected {\n --pf-c-data-list__item--before--BackgroundColor: var(--pf-c-data-list__item--m-selected--before--BackgroundColor);\n position: relative;\n z-index: var(--pf-c-data-list__item--m-selected--ZIndex);\n box-shadow: var(--pf-c-data-list__item--m-selected--BoxShadow); }\n .pf-c-data-list__item.pf-m-ghost-row::after {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n content: \"\";\n background-color: var(--pf-c-data-list__item--m-ghost-row--after--BackgroundColor);\n opacity: var(--pf-c-data-list__item--m-ghost-row--after--Opacity); }\n .pf-c-data-list__item.pf-m-expanded {\n --pf-c-data-list__item--before--BackgroundColor: var(--pf-c-data-list__item--m-expanded--before--BackgroundColor); }\n .pf-c-data-list__item.pf-m-expanded.pf-m-selectable:not(.pf-m-selected) {\n --pf-c-data-list__item--before--BackgroundColor: var(--pf-c-data-list__item--m-expanded--m-selectable--before--BackgroundColor); }\n\n.pf-c-data-list__item-row {\n display: flex;\n flex-wrap: nowrap;\n padding-right: var(--pf-c-data-list__item-row--PaddingRight);\n padding-left: var(--pf-c-data-list__item-row--PaddingLeft); }\n\n.pf-c-data-list__item-control {\n display: flex;\n flex-wrap: nowrap;\n padding-top: var(--pf-c-data-list__item-control--PaddingTop);\n padding-bottom: var(--pf-c-data-list__item-control--PaddingBottom);\n margin-right: var(--pf-c-data-list__item-control--MarginRight); }\n .pf-c-data-list__item-control > *:not(:last-child) {\n margin-right: var(--pf-c-data-list__item-control--not-last-child--MarginRight); }\n\n.pf-c-data-list__item-draggable-button {\n padding-right: var(--pf-c-data-list__item-draggable-button--PaddingRight);\n padding-left: var(--pf-c-data-list__item-draggable-button--PaddingLeft);\n margin-top: var(--pf-c-data-list__item-draggable-button--MarginTop);\n margin-left: var(--pf-c-data-list__item-draggable-button--MarginLeft);\n border: 0; }\n .pf-c-data-list__item-draggable-button:hover {\n --pf-c-data-list__item-draggable-button-icon--Color: var(--pf-c-data-list__item-draggable-button--hover__draggable-icon--Color);\n cursor: grab; }\n .pf-c-data-list__item-draggable-button:focus {\n --pf-c-data-list__item-draggable-button-icon--Color: var(--pf-c-data-list__item-draggable-button--focus__draggable-icon--Color); }\n .pf-c-data-list__item-draggable-button:active {\n cursor: grabbing; }\n .pf-c-data-list__item-draggable-button.pf-m-disabled {\n --pf-c-data-list__item-draggable-button-icon--Color: var(--pf-c-data-list__item-draggable-button--m-disabled__draggable-icon--Color);\n pointer-events: none;\n cursor: none; }\n .pf-c-data-list__item-draggable-button .pf-c-data-list__item-draggable-icon {\n color: var(--pf-c-data-list__item-draggable-button-icon--Color); }\n\n.pf-c-data-list__item-action {\n --pf-hidden-visible--visible--Display: var(--pf-c-data-list__item-action--Display);\n align-items: flex-start;\n align-content: flex-start;\n padding-top: var(--pf-c-data-list__item-action--PaddingTop);\n padding-bottom: var(--pf-c-data-list__item-action--PaddingBottom);\n margin-left: var(--pf-c-data-list__item-action--MarginLeft); }\n .pf-c-data-list__item-action > *:not(:last-child) {\n margin-right: var(--pf-c-data-list__item-action--not-last-child--MarginRight); }\n .pf-c-data-list__item-action .pf-c-data-list__action {\n margin-top: var(--pf-c-data-list__action--MarginTop); }\n\n.pf-c-data-list__toggle {\n margin-top: var(--pf-c-data-list__toggle--MarginTop);\n margin-left: var(--pf-c-data-list__toggle--MarginLeft); }\n\n.pf-c-data-list__toggle-icon {\n pointer-events: none;\n transition: var(--pf-c-data-list__toggle-icon--Transition); }\n .pf-c-data-list__item.pf-m-expanded .pf-c-data-list__toggle-icon {\n transform: rotate(var(--pf-c-data-list__item--m-expanded__toggle-icon--Rotate)); }\n\n.pf-c-data-list__item-content {\n display: grid;\n width: 100%;\n grid-template-columns: auto 1fr; }\n\n.pf-c-data-list__cell {\n flex: 1;\n grid-column: 1 / -1;\n padding-top: var(--pf-c-data-list__cell--PaddingTop);\n padding-bottom: var(--pf-c-data-list__cell--PaddingBottom); }\n .pf-c-data-list__cell + .pf-c-data-list__cell {\n flex: 1 0 100%;\n order: 1;\n padding-top: var(--pf-c-data-list__cell--cell--PaddingTop); }\n .pf-c-data-list__cell.pf-m-icon {\n flex-grow: 0;\n margin-right: var(--pf-c-data-list__cell--m-icon--MarginRight);\n grid-column: 1 / 2; }\n .pf-c-data-list__cell.pf-m-icon + .pf-c-data-list__cell {\n grid-column: 2 / 3;\n padding-top: var(--pf-c-data-list__cell--m-icon--cell--PaddingTop); }\n .pf-c-data-list__cell.pf-m-align-right {\n margin-left: 0; }\n\n.pf-c-data-list__text {\n display: inline-block; }\n\n.pf-c-data-list__text,\n.pf-c-data-list__cell {\n min-width: var(--pf-c-data-list--cell--MinWidth);\n max-width: 100%;\n overflow: var(--pf-c-data-list--cell--Overflow);\n text-overflow: var(--pf-c-data-list--cell--TextOverflow);\n word-break: var(--pf-c-data-list--cell--WordBreak);\n white-space: var(--pf-c-data-list--cell--WhiteSpace); }\n\n.pf-c-data-list__expandable-content {\n max-height: var(--pf-c-data-list__expandable-content--MaxHeight);\n overflow-y: auto;\n border-top: var(--pf-c-data-list__expandable-content--BorderTopWidth) solid var(--pf-c-data-list__expandable-content--BorderTopColor); }\n .pf-c-data-list__expandable-content .pf-c-data-list__expandable-content-body {\n padding: var(--pf-c-data-list__expandable-content-body--PaddingTop) var(--pf-c-data-list__expandable-content-body--PaddingRight) var(--pf-c-data-list__expandable-content-body--PaddingBottom) var(--pf-c-data-list__expandable-content-body--PaddingLeft); }\n .pf-c-data-list__expandable-content .pf-c-data-list__expandable-content-body.pf-m-no-padding {\n padding: 0; }\n\n.pf-c-description-list {\n --pf-c-description-list--RowGap: var(--pf-global--gutter--md);\n --pf-c-description-list--ColumnGap: var(--pf-global--spacer--lg);\n --pf-c-description-list--GridTemplateColumns--count: 1;\n --pf-c-description-list--GridTemplateColumns--width: 1fr;\n --pf-c-description-list--GridTemplateColumns: repeat(var(--pf-c-description-list--GridTemplateColumns--count), var(--pf-c-description-list--GridTemplateColumns--width));\n --pf-c-description-list__group--RowGap: var(--pf-global--spacer--sm);\n --pf-c-description-list__group--ColumnGap: var(--pf-global--spacer--md);\n --pf-c-description-list__group--GridTemplateColumns: auto;\n --pf-c-description-list__group--GridColumn: auto;\n --pf-c-description-list__term--FontWeight: var(--pf-global--FontWeight--bold);\n --pf-c-description-list__term--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-description-list--m-horizontal__term--width: 12ch;\n --pf-c-description-list--m-horizontal__description--width: minmax(10ch, auto);\n --pf-c-description-list--m-horizontal__group--GridTemplateColumns: var(--pf-c-description-list__term--width) var(--pf-c-description-list--m-horizontal__description--width);\n --pf-c-description-list--m-1-col--GridTemplateColumns--count: 1;\n --pf-c-description-list--m-auto-fit--GridTemplateColumns--min: 15.625rem;\n --pf-c-description-list--m-auto-fit--GridTemplateColumns--minmax--min: var(--pf-c-description-list--m-auto-fit--GridTemplateColumns--min);\n display: grid;\n align-items: baseline;\n row-gap: var(--pf-c-description-list--RowGap);\n column-gap: var(--pf-c-description-list--ColumnGap);\n grid-template-columns: var(--pf-c-description-list--GridTemplateColumns); }\n @media screen and (min-width: 768px) {\n .pf-c-description-list {\n --pf-c-description-list--m-2-col--GridTemplateColumns--count: 2;\n --pf-c-description-list--m-3-col--GridTemplateColumns--count: 3; } }\n .pf-c-description-list.pf-m-horizontal {\n --pf-c-description-list__group--GridTemplateColumns: var(--pf-c-description-list--m-horizontal__group--GridTemplateColumns);\n --pf-c-description-list__term--width: var(--pf-c-description-list--m-horizontal__term--width); }\n @media (min-width: 768px) {\n .pf-c-description-list.pf-m-horizontal {\n --pf-c-description-list__term--width: var(--pf-c-description-list--m-horizontal__term--width-on-md, var(--pf-c-description-list--m-horizontal__term--width)); } }\n @media (min-width: 992px) {\n .pf-c-description-list.pf-m-horizontal {\n --pf-c-description-list__term--width: var(--pf-c-description-list--m-horizontal__term--width-on-lg, var(--pf-c-description-list--m-horizontal__term--width-on-md, var(--pf-c-description-list--m-horizontal__term--width))); } }\n @media (min-width: 1200px) {\n .pf-c-description-list.pf-m-horizontal {\n --pf-c-description-list__term--width: var(--pf-c-description-list--m-horizontal__term--width-on-xl, var(--pf-c-description-list--m-horizontal__term--width-on-lg, var(--pf-c-description-list--m-horizontal__term--width-on-md, var(--pf-c-description-list--m-horizontal__term--width)))); } }\n @media (min-width: 1450px) {\n .pf-c-description-list.pf-m-horizontal {\n --pf-c-description-list__term--width: var(--pf-c-description-list--m-horizontal__term--width-on-2xl, var(--pf-c-description-list--m-horizontal__term--width-on-xl, var(--pf-c-description-list--m-horizontal__term--width-on-lg, var(--pf-c-description-list--m-horizontal__term--width-on-md, var(--pf-c-description-list--m-horizontal__term--width))))); } }\n .pf-c-description-list.pf-m-inline-grid {\n display: inline-grid; }\n .pf-c-description-list.pf-m-auto-column-widths {\n --pf-c-description-list--GridTemplateColumns--width: minmax(8ch, max-content); }\n .pf-c-description-list.pf-m-auto-fit {\n grid-template-columns: repeat(auto-fit, minmax(var(--pf-c-description-list--m-auto-fit--GridTemplateColumns--minmax--min), 1fr));\n --pf-c-description-list--GridTemplateColumns--minmax--min: var(--pf-c-description-list--GridTemplateColumns--min); }\n @media (min-width: 768px) {\n .pf-c-description-list.pf-m-auto-fit {\n --pf-c-description-list--GridTemplateColumns--minmax--min: var(--pf-c-description-list--GridTemplateColumns--min-on-md, var(--pf-c-description-list--GridTemplateColumns--min)); } }\n @media (min-width: 992px) {\n .pf-c-description-list.pf-m-auto-fit {\n --pf-c-description-list--GridTemplateColumns--minmax--min: var(--pf-c-description-list--GridTemplateColumns--min-on-lg, var(--pf-c-description-list--GridTemplateColumns--min-on-md, var(--pf-c-description-list--GridTemplateColumns--min))); } }\n @media (min-width: 1200px) {\n .pf-c-description-list.pf-m-auto-fit {\n --pf-c-description-list--GridTemplateColumns--minmax--min: var(--pf-c-description-list--GridTemplateColumns--min-on-xl, var(--pf-c-description-list--GridTemplateColumns--min-on-lg, var(--pf-c-description-list--GridTemplateColumns--min-on-md, var(--pf-c-description-list--GridTemplateColumns--min)))); } }\n @media (min-width: 1450px) {\n .pf-c-description-list.pf-m-auto-fit {\n --pf-c-description-list--GridTemplateColumns--minmax--min: var(--pf-c-description-list--GridTemplateColumns--min-on-2xl, var(--pf-c-description-list--GridTemplateColumns--min-on-xl, var(--pf-c-description-list--GridTemplateColumns--min-on-lg, var(--pf-c-description-list--GridTemplateColumns--min-on-md, var(--pf-c-description-list--GridTemplateColumns--min))))); } }\n\n.pf-c-description-list__group {\n display: grid;\n grid-column: var(--pf-c-description-list__group--GridColumn);\n row-gap: var(--pf-c-description-list__group--RowGap);\n column-gap: var(--pf-c-description-list__group--ColumnGap);\n grid-template-columns: var(--pf-c-description-list__group--GridTemplateColumns);\n align-items: baseline; }\n\n.pf-c-description-list__term,\n.pf-c-description-list__description {\n text-align: left; }\n\n.pf-c-description-list__term {\n font-size: var(--pf-c-description-list__term--FontSize);\n font-weight: var(--pf-c-description-list__term--FontWeight); }\n .pf-c-description-list__term .pf-c-description-list__text {\n display: inline; }\n\n.pf-c-description-list.pf-m-1-col {\n --pf-c-description-list--GridTemplateColumns--count: var(--pf-c-description-list--m-1-col--GridTemplateColumns--count); }\n\n.pf-c-description-list.pf-m-2-col {\n --pf-c-description-list--GridTemplateColumns--count: var(--pf-c-description-list--m-2-col--GridTemplateColumns--count); }\n\n.pf-c-description-list.pf-m-3-col {\n --pf-c-description-list--GridTemplateColumns--count: var(--pf-c-description-list--m-3-col--GridTemplateColumns--count); }\n\n@media (min-width: 768px) {\n .pf-c-description-list.pf-m-1-col-on-md {\n --pf-c-description-list--GridTemplateColumns--count: var(--pf-c-description-list--m-1-col--GridTemplateColumns--count); }\n .pf-c-description-list.pf-m-2-col-on-md {\n --pf-c-description-list--GridTemplateColumns--count: var(--pf-c-description-list--m-2-col--GridTemplateColumns--count); }\n .pf-c-description-list.pf-m-3-col-on-md {\n --pf-c-description-list--GridTemplateColumns--count: var(--pf-c-description-list--m-3-col--GridTemplateColumns--count); } }\n\n@media (min-width: 992px) {\n .pf-c-description-list.pf-m-1-col-on-lg {\n --pf-c-description-list--GridTemplateColumns--count: var(--pf-c-description-list--m-1-col--GridTemplateColumns--count); }\n .pf-c-description-list.pf-m-2-col-on-lg {\n --pf-c-description-list--GridTemplateColumns--count: var(--pf-c-description-list--m-2-col--GridTemplateColumns--count); }\n .pf-c-description-list.pf-m-3-col-on-lg {\n --pf-c-description-list--GridTemplateColumns--count: var(--pf-c-description-list--m-3-col--GridTemplateColumns--count); } }\n\n@media (min-width: 1200px) {\n .pf-c-description-list.pf-m-1-col-on-xl {\n --pf-c-description-list--GridTemplateColumns--count: var(--pf-c-description-list--m-1-col--GridTemplateColumns--count); }\n .pf-c-description-list.pf-m-2-col-on-xl {\n --pf-c-description-list--GridTemplateColumns--count: var(--pf-c-description-list--m-2-col--GridTemplateColumns--count); }\n .pf-c-description-list.pf-m-3-col-on-xl {\n --pf-c-description-list--GridTemplateColumns--count: var(--pf-c-description-list--m-3-col--GridTemplateColumns--count); } }\n\n@media (min-width: 1450px) {\n .pf-c-description-list.pf-m-1-col-on-2xl {\n --pf-c-description-list--GridTemplateColumns--count: var(--pf-c-description-list--m-1-col--GridTemplateColumns--count); }\n .pf-c-description-list.pf-m-2-col-on-2xl {\n --pf-c-description-list--GridTemplateColumns--count: var(--pf-c-description-list--m-2-col--GridTemplateColumns--count); }\n .pf-c-description-list.pf-m-3-col-on-2xl {\n --pf-c-description-list--GridTemplateColumns--count: var(--pf-c-description-list--m-3-col--GridTemplateColumns--count); } }\n\n.pf-c-dual-list-selector {\n --pf-c-dual-list-selector__header--GridArea: pane-header;\n --pf-c-dual-list-selector__tools--GridArea: pane-tools;\n --pf-c-dual-list-selector__status--GridArea: pane-status;\n --pf-c-dual-list-selector__menu--GridArea: pane-menu;\n --pf-c-dual-list-selector__controls--GridArea: controls;\n --pf-c-dual-list-selector--m-chosen__header--GridArea: pane-header-c;\n --pf-c-dual-list-selector--m-chosen__tools--GridArea: pane-tools-c;\n --pf-c-dual-list-selector--m-chosen__status--GridArea: pane-status-c;\n --pf-c-dual-list-selector--m-chosen__menu--GridArea: pane-menu-c;\n --pf-c-dual-list-selector--GridTemplateColumns--pane--MinMax--min: 12.5rem;\n --pf-c-dual-list-selector--GridTemplateColumns--pane--MinMax--max: 28.125rem;\n --pf-c-dual-list-selector__header--MarginBottom: var(--pf-global--spacer--sm);\n --pf-c-dual-list-selector__title-text--FontWeight: var(--pf-global--FontWeight--bold);\n --pf-c-dual-list-selector__tools--MarginBottom: var(--pf-global--spacer--md);\n --pf-c-dual-list-selector__tools-filter--tools-actions--MarginLeft: var(--pf-global--spacer--sm);\n --pf-c-dual-list-selector__menu--BorderWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-dual-list-selector__menu--BorderColor: var(--pf-global--BorderColor--100);\n --pf-c-dual-list-selector__menu--MinHeight: 12.5rem;\n --pf-c-dual-list-selector__menu--MaxHeight: 20rem;\n --pf-c-dual-list-selector__item--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-dual-list-selector__item--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-dual-list-selector__item--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-dual-list-selector__item--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-dual-list-selector__item--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-dual-list-selector__item--BackgroundColor: transparent;\n --pf-c-dual-list-selector__item--hover--BackgroundColor: var(--pf-global--BackgroundColor--light-300);\n --pf-c-dual-list-selector__item--focus-within--BackgroundColor: var(--pf-global--BackgroundColor--light-300);\n --pf-c-dual-list-selector__item--m-selected--BackgroundColor: var(--pf-global--BackgroundColor--light-300);\n --pf-c-dual-list-selector__item--m-expandable--PaddingLeft: 0;\n --pf-c-dual-list-selector__item--indent--base: calc(var(--pf-global--spacer--md) + var(--pf-global--spacer--sm) + var(--pf-c-dual-list-selector__item--FontSize));\n --pf-c-dual-list-selector__item--nested-indent--base: calc(var(--pf-c-dual-list-selector__item--indent--base) - var(--pf-global--spacer--md));\n --pf-c-dual-list-selector__item-text--Color: var(--pf-global--Color--100);\n --pf-c-dual-list-selector__item--m-selected__text--Color: var(--pf-global--active-color--100);\n --pf-c-dual-list-selector__item--m-selected__text--FontWeight: var(--pf-global--FontWeight--bold);\n --pf-c-dual-list-selector__status--MarginBottom: var(--pf-global--spacer--sm);\n --pf-c-dual-list-selector__status-text--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-dual-list-selector__status-text--Color: var(--pf-global--Color--200);\n --pf-c-dual-list-selector__controls--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-dual-list-selector__controls--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-dual-list-selector__item-toggle--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-dual-list-selector__item-toggle--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-dual-list-selector__item-toggle--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-dual-list-selector__item-toggle--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-dual-list-selector__item-toggle--MarginTop: calc(var(--pf-global--spacer--sm) * -1);\n --pf-c-dual-list-selector__item-toggle--MarginBottom: calc(var(--pf-global--spacer--sm) * -1);\n --pf-c-dual-list-selector__list__list__item-toggle--Left: 0;\n --pf-c-dual-list-selector__list__list__item-toggle--TranslateX: -100%;\n --pf-c-dual-list-selector__item-check--MarginRight: var(--pf-global--spacer--sm);\n --pf-c-dual-list-selector__item-count--Marginleft: var(--pf-global--spacer--sm);\n --pf-c-dual-list-selector__item--c-badge--m-read--BackgroundColor: var(--pf-global--disabled-color--200);\n --pf-c-dual-list-selector__item-toggle-icon--Rotate: 0;\n --pf-c-dual-list-selector__list-item--m-expanded__item-toggle-icon--Rotate: 90deg;\n --pf-c-dual-list-selector__item-toggle-icon--Transition: var(--pf-global--Transition);\n --pf-c-dual-list-selector__item-toggle-icon--MinWidth: var(--pf-c-dual-list-selector__item--FontSize);\n display: grid;\n grid-template-areas: \"pane-header . pane-header-c\" \"pane-tools . pane-tools-c\" \"pane-status . pane-status-c\" \"pane-menu controls pane-menu-c\";\n grid-template-columns: minmax(var(--pf-c-dual-list-selector--GridTemplateColumns--pane--MinMax--min), var(--pf-c-dual-list-selector--GridTemplateColumns--pane--MinMax--max)) min-content minmax(var(--pf-c-dual-list-selector--GridTemplateColumns--pane--MinMax--min), var(--pf-c-dual-list-selector--GridTemplateColumns--pane--MinMax--max));\n grid-template-rows: repeat(3, auto) auto; }\n\n.pf-c-dual-list-selector__pane {\n display: contents; }\n .pf-c-dual-list-selector__pane.pf-m-chosen {\n --pf-c-dual-list-selector__header--GridArea: var(--pf-c-dual-list-selector--m-chosen__header--GridArea);\n --pf-c-dual-list-selector__tools--GridArea: var(--pf-c-dual-list-selector--m-chosen__tools--GridArea);\n --pf-c-dual-list-selector__status--GridArea: var(--pf-c-dual-list-selector--m-chosen__status--GridArea);\n --pf-c-dual-list-selector__menu--GridArea: var(--pf-c-dual-list-selector--m-chosen__menu--GridArea); }\n\n.pf-c-dual-list-selector__header {\n grid-area: var(--pf-c-dual-list-selector__header--GridArea);\n margin-bottom: var(--pf-c-dual-list-selector__header--MarginBottom); }\n\n.pf-c-dual-list-selector__title-text {\n font-weight: var(--pf-c-dual-list-selector__title-text--FontWeight); }\n\n.pf-c-dual-list-selector__tools {\n display: flex;\n grid-area: var(--pf-c-dual-list-selector__tools--GridArea);\n margin-bottom: var(--pf-c-dual-list-selector__tools--MarginBottom); }\n\n.pf-c-dual-list-selector__tools-filter {\n flex-grow: 1; }\n\n.pf-c-dual-list-selector__tools-actions {\n display: flex; }\n .pf-c-dual-list-selector__tools-filter ~ .pf-c-dual-list-selector__tools-actions {\n margin-left: var(--pf-c-dual-list-selector__tools-filter--tools-actions--MarginLeft); }\n\n.pf-c-dual-list-selector__status {\n display: flex;\n grid-area: var(--pf-c-dual-list-selector__status--GridArea);\n margin-bottom: var(--pf-c-dual-list-selector__status--MarginBottom); }\n\n.pf-c-dual-list-selector__status-text {\n flex-grow: 1;\n font-size: var(--pf-c-dual-list-selector__status-text--FontSize);\n color: var(--pf-c-dual-list-selector__status-text--Color); }\n\n.pf-c-dual-list-selector__menu {\n grid-area: var(--pf-c-dual-list-selector__menu--GridArea);\n min-height: var(--pf-c-dual-list-selector__menu--MinHeight);\n max-height: var(--pf-c-dual-list-selector__menu--MaxHeight);\n overflow: auto;\n border: var(--pf-c-dual-list-selector__menu--BorderWidth) solid var(--pf-c-dual-list-selector__menu--BorderColor); }\n\n.pf-c-dual-list-selector__list {\n display: flex;\n flex-direction: column; }\n .pf-c-dual-list-selector__list .pf-c-dual-list-selector__list {\n --pf-c-dual-list-selector__item-toggle--MarginTop: 0;\n --pf-c-dual-list-selector__item-toggle--MarginBottom: 0; }\n .pf-c-dual-list-selector__list .pf-c-dual-list-selector__list .pf-c-dual-list-selector__item-toggle {\n position: absolute;\n top: 0;\n left: var(--pf-c-dual-list-selector__list__list__item-toggle--Left);\n transform: translateX(var(--pf-c-dual-list-selector__list__list__item-toggle--TranslateX)); }\n\n.pf-c-dual-list-selector__list-item.pf-m-expandable {\n --pf-c-dual-list-selector__item--PaddingLeft: var(--pf-c-dual-list-selector__item--m-expandable--PaddingLeft); }\n\n.pf-c-dual-list-selector__list-item.pf-m-expanded > .pf-c-dual-list-selector__item {\n --pf-c-dual-list-selector__item-toggle-icon--Rotate: var(--pf-c-dual-list-selector__list-item--m-expanded__item-toggle-icon--Rotate); }\n\n.pf-c-dual-list-selector__item,\n.pf-c-dual-list-selector__main {\n display: flex; }\n\n.pf-c-dual-list-selector__item,\n.pf-c-dual-list-selector__item-main {\n flex-basis: 100%; }\n\n.pf-c-dual-list-selector__item {\n position: relative;\n width: 100%;\n padding: var(--pf-c-dual-list-selector__item--PaddingTop) var(--pf-c-dual-list-selector__item--PaddingRight) var(--pf-c-dual-list-selector__item--PaddingBottom) var(--pf-c-dual-list-selector__item--PaddingLeft);\n font-size: var(--pf-c-dual-list-selector__item--FontSize);\n text-align: left;\n cursor: pointer;\n background-color: var(--pf-c-dual-list-selector__item--BackgroundColor);\n border: 0; }\n .pf-c-dual-list-selector__item:hover {\n --pf-c-dual-list-selector__item--BackgroundColor: var(--pf-c-dual-list-selector__item--hover--BackgroundColor); }\n .pf-c-dual-list-selector__item:focus-within {\n --pf-c-dual-list-selector__item--BackgroundColor: var(--pf-c-dual-list-selector__item--focus-within--BackgroundColor); }\n .pf-c-dual-list-selector__item.pf-m-selected {\n --pf-c-dual-list-selector__item--BackgroundColor: var(--pf-c-dual-list-selector__item--m-selected--BackgroundColor); }\n .pf-c-dual-list-selector__item.pf-m-selected .pf-c-dual-list-selector__item-text {\n --pf-c-dual-list-selector__item-text--Color: var(--pf-c-dual-list-selector__item--m-selected__text--Color);\n font-weight: var(--pf-c-dual-list-selector__item--m-selected__text--FontWeight); }\n .pf-c-dual-list-selector__item.pf-m-check {\n --pf-c-dual-list-selector__item--m-selected--BackgroundColor: transparent; }\n .pf-c-dual-list-selector__item .pf-c-dual-list-selector__item-count {\n margin-left: var(--pf-c-dual-list-selector__item-count--Marginleft); }\n .pf-c-dual-list-selector__item .pf-c-dual-list-selector__item-count .pf-c-badge.pf-m-read {\n --pf-c-badge--m-read--BackgroundColor: var(--pf-c-dual-list-selector__item--c-badge--m-read--BackgroundColor); }\n\n.pf-c-dual-list-selector__item-text {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n flex-grow: 1;\n color: var(--pf-c-dual-list-selector__item-text--Color); }\n\n.pf-c-dual-list-selector__controls {\n grid-area: var(--pf-c-dual-list-selector__controls--GridArea);\n align-self: center;\n padding-right: var(--pf-c-dual-list-selector__controls--PaddingRight);\n padding-left: var(--pf-c-dual-list-selector__controls--PaddingLeft); }\n\n.pf-c-dual-list-selector__item-main {\n display: flex;\n min-width: 0; }\n\n.pf-c-dual-list-selector__item-toggle {\n padding: var(--pf-c-dual-list-selector__item-toggle--PaddingTop) var(--pf-c-dual-list-selector__item-toggle--PaddingRight) var(--pf-c-dual-list-selector__item-toggle--PaddingBottom) var(--pf-c-dual-list-selector__item-toggle--PaddingLeft);\n margin-top: var(--pf-c-dual-list-selector__item-toggle--MarginTop);\n margin-bottom: var(--pf-c-dual-list-selector__item-toggle--MarginBottom); }\n\n.pf-c-dual-list-selector__item-check {\n display: flex;\n align-items: center;\n margin-right: var(--pf-c-dual-list-selector__item-check--MarginRight); }\n\n.pf-c-dual-list-selector__item-toggle-icon {\n display: inline-block;\n min-width: var(--pf-c-dual-list-selector__item-toggle-icon--MinWidth);\n text-align: center;\n transition: var(--pf-c-dual-list-selector__item-toggle-icon--Transition);\n transform: rotate(var(--pf-c-dual-list-selector__item-toggle-icon--Rotate)); }\n\n.pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item {\n --pf-c-dual-list-selector__item--PaddingLeft: calc(var(--pf-c-dual-list-selector__item--nested-indent--base) * 1 + var(--pf-c-dual-list-selector__item--indent--base));\n --pf-c-dual-list-selector__list__list__item-toggle--Left: var(--pf-c-dual-list-selector__item--PaddingLeft); }\n\n.pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item {\n --pf-c-dual-list-selector__item--PaddingLeft: calc(var(--pf-c-dual-list-selector__item--nested-indent--base) * 2 + var(--pf-c-dual-list-selector__item--indent--base));\n --pf-c-dual-list-selector__list__list__item-toggle--Left: var(--pf-c-dual-list-selector__item--PaddingLeft); }\n\n.pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item {\n --pf-c-dual-list-selector__item--PaddingLeft: calc(var(--pf-c-dual-list-selector__item--nested-indent--base) * 3 + var(--pf-c-dual-list-selector__item--indent--base));\n --pf-c-dual-list-selector__list__list__item-toggle--Left: var(--pf-c-dual-list-selector__item--PaddingLeft); }\n\n.pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item {\n --pf-c-dual-list-selector__item--PaddingLeft: calc(var(--pf-c-dual-list-selector__item--nested-indent--base) * 4 + var(--pf-c-dual-list-selector__item--indent--base));\n --pf-c-dual-list-selector__list__list__item-toggle--Left: var(--pf-c-dual-list-selector__item--PaddingLeft); }\n\n.pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item {\n --pf-c-dual-list-selector__item--PaddingLeft: calc(var(--pf-c-dual-list-selector__item--nested-indent--base) * 5 + var(--pf-c-dual-list-selector__item--indent--base));\n --pf-c-dual-list-selector__list__list__item-toggle--Left: var(--pf-c-dual-list-selector__item--PaddingLeft); }\n\n.pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item {\n --pf-c-dual-list-selector__item--PaddingLeft: calc(var(--pf-c-dual-list-selector__item--nested-indent--base) * 6 + var(--pf-c-dual-list-selector__item--indent--base));\n --pf-c-dual-list-selector__list__list__item-toggle--Left: var(--pf-c-dual-list-selector__item--PaddingLeft); }\n\n.pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item {\n --pf-c-dual-list-selector__item--PaddingLeft: calc(var(--pf-c-dual-list-selector__item--nested-indent--base) * 7 + var(--pf-c-dual-list-selector__item--indent--base));\n --pf-c-dual-list-selector__list__list__item-toggle--Left: var(--pf-c-dual-list-selector__item--PaddingLeft); }\n\n.pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item {\n --pf-c-dual-list-selector__item--PaddingLeft: calc(var(--pf-c-dual-list-selector__item--nested-indent--base) * 8 + var(--pf-c-dual-list-selector__item--indent--base));\n --pf-c-dual-list-selector__list__list__item-toggle--Left: var(--pf-c-dual-list-selector__item--PaddingLeft); }\n\n.pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item {\n --pf-c-dual-list-selector__item--PaddingLeft: calc(var(--pf-c-dual-list-selector__item--nested-indent--base) * 9 + var(--pf-c-dual-list-selector__item--indent--base));\n --pf-c-dual-list-selector__list__list__item-toggle--Left: var(--pf-c-dual-list-selector__item--PaddingLeft); }\n\n.pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item .pf-c-dual-list-selector__list-item {\n --pf-c-dual-list-selector__item--PaddingLeft: calc(var(--pf-c-dual-list-selector__item--nested-indent--base) * 10 + var(--pf-c-dual-list-selector__item--indent--base));\n --pf-c-dual-list-selector__list__list__item-toggle--Left: var(--pf-c-dual-list-selector__item--PaddingLeft); }\n\n.pf-c-toolbar {\n --pf-c-toolbar--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-toolbar--RowGap: var(--pf-global--spacer--lg);\n --pf-c-toolbar--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-toolbar--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-toolbar__content--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-toolbar--m-page-insets--inset: var(--pf-global--spacer--md);\n --pf-c-toolbar--m-page-insets--xl--inset: var(--pf-global--spacer--lg);\n --pf-c-toolbar__expandable-content--PaddingTop: var(--pf-c-toolbar--RowGap);\n --pf-c-toolbar__expandable-content--PaddingRight: var(--pf-c-toolbar__content--PaddingRight);\n --pf-c-toolbar__expandable-content--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-toolbar__expandable-content--PaddingLeft: var(--pf-c-toolbar__content--PaddingLeft);\n --pf-c-toolbar__expandable-content--lg--PaddingRight: 0;\n --pf-c-toolbar__expandable-content--lg--PaddingBottom: 0;\n --pf-c-toolbar__expandable-content--lg--PaddingLeft: 0;\n --pf-c-toolbar__expandable-content--ZIndex: var(--pf-global--ZIndex--xs);\n --pf-c-toolbar__expandable-content--BoxShadow: var(--pf-global--BoxShadow--md-bottom);\n --pf-c-toolbar__expandable-content--BackgroundColor: var(--pf-c-toolbar--BackgroundColor);\n --pf-c-toolbar__expandable-content--m-expanded--GridRowGap: var(--pf-global--gutter--md);\n --pf-c-toolbar__group--m-chip-container--MarginTop: calc(var(--pf-global--spacer--md) * -1);\n --pf-c-toolbar__group--m-chip-container__item--MarginTop: var(--pf-global--spacer--md);\n --pf-c-toolbar--spacer--base: var(--pf-global--spacer--md);\n --pf-c-toolbar__item--spacer: var(--pf-c-toolbar--spacer--base);\n --pf-c-toolbar__group--spacer: var(--pf-c-toolbar--spacer--base);\n --pf-c-toolbar__group--m-toggle-group--spacer: var(--pf-global--spacer--sm);\n --pf-c-toolbar__group--m-toggle-group--m-show--spacer: var(--pf-c-toolbar__group--spacer);\n --pf-c-toolbar__group--m-icon-button-group--spacer: var(--pf-c-toolbar__group--spacer);\n --pf-c-toolbar__group--m-icon-button-group--space-items: 0;\n --pf-c-toolbar__group--m-button-group--spacer: var(--pf-c-toolbar__group--spacer);\n --pf-c-toolbar__group--m-button-group--space-items: var(--pf-global--spacer--sm);\n --pf-c-toolbar__group--m-filter-group--spacer: var(--pf-c-toolbar__group--spacer);\n --pf-c-toolbar__group--m-filter-group--space-items: 0;\n --pf-c-toolbar__item--m-overflow-menu--spacer: var(--pf-c-toolbar__item--spacer);\n --pf-c-toolbar__item--m-bulk-select--spacer: var(--pf-global--spacer--lg);\n --pf-c-toolbar__expand-all-icon--Rotate: 0;\n --pf-c-toolbar__expand-all-icon--Transition: var(--pf-global--Transition);\n --pf-c-toolbar__item--m-expand-all--m-expanded__expand-all-icon--Rotate: 90deg;\n --pf-c-toolbar__item--m-search-filter--spacer: var(--pf-global--spacer--sm);\n --pf-c-toolbar__item--m-chip-group--spacer: var(--pf-global--spacer--sm);\n --pf-c-toolbar__item--m-label--spacer: var(--pf-c-toolbar__item--spacer);\n --pf-c-toolbar__item--m-label--FontWeight: var(--pf-global--FontWeight--bold);\n --pf-c-toolbar__toggle--m-expanded__c-button--m-plain--Color: var(--pf-global--Color--100);\n --pf-c-toolbar--c-divider--m-vertical--spacer: var(--pf-c-toolbar--spacer--base);\n position: relative;\n row-gap: var(--pf-c-toolbar--RowGap);\n display: grid;\n padding-top: var(--pf-c-toolbar--PaddingTop);\n padding-bottom: var(--pf-c-toolbar--PaddingBottom);\n background-color: var(--pf-c-toolbar--BackgroundColor); }\n @media screen and (min-width: 992px) {\n .pf-c-toolbar {\n --pf-c-toolbar__expandable-content--PaddingRight: var(--pf-c-toolbar__expandable-content--lg--PaddingRight);\n --pf-c-toolbar__expandable-content--PaddingBottom: var(--pf-c-toolbar__expandable-content--lg--PaddingBottom);\n --pf-c-toolbar__expandable-content--PaddingLeft: var(--pf-c-toolbar__expandable-content--lg--PaddingLeft); } }\n @media screen and (min-width: 1200px) {\n .pf-c-toolbar {\n --pf-c-toolbar--m-page-insets--inset: var(--pf-c-toolbar--m-page-insets--xl--inset); } }\n .pf-c-toolbar.pf-m-page-insets {\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--m-page-insets--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--m-page-insets--inset); }\n\n.pf-c-toolbar__content-section > .pf-c-divider,\n.pf-c-toolbar__group > .pf-c-divider {\n --pf-c-toolbar--spacer: var(--pf-c-toolbar--c-divider--m-vertical--spacer); }\n\n.pf-c-toolbar__content-section > .pf-c-divider.pf-m-vertical,\n.pf-c-toolbar__group > .pf-c-divider.pf-m-vertical {\n margin-right: var(--pf-c-toolbar--spacer); }\n .pf-c-toolbar__content-section > .pf-c-divider.pf-m-vertical:last-child,\n .pf-c-toolbar__group > .pf-c-divider.pf-m-vertical:last-child {\n --pf-c-toolbar--spacer: 0; }\n\n.pf-c-toolbar__group {\n --pf-c-toolbar--spacer: var(--pf-c-toolbar__group--spacer);\n display: flex;\n align-items: center;\n margin-right: var(--pf-c-toolbar--spacer); }\n .pf-c-toolbar__group.pf-m-button-group {\n --pf-c-toolbar--spacer: var(--pf-c-toolbar__group--m-button-group--spacer); }\n .pf-c-toolbar__group.pf-m-button-group > * {\n --pf-c-toolbar--spacer: var(--pf-c-toolbar__group--m-button-group--space-items); }\n .pf-c-toolbar__group.pf-m-icon-button-group {\n --pf-c-toolbar--spacer: var(--pf-c-toolbar__group--m-icon-button-group--spacer); }\n .pf-c-toolbar__group.pf-m-icon-button-group > * {\n --pf-c-toolbar--spacer: var(--pf-c-toolbar__group--m-icon-button-group--space-items); }\n .pf-c-toolbar__group.pf-m-filter-group {\n --pf-c-toolbar--spacer: var(--pf-c-toolbar__group--m-filter-group--spacer); }\n .pf-c-toolbar__group.pf-m-filter-group > * {\n --pf-c-toolbar--spacer: var(--pf-c-toolbar__group--m-filter-group--space-items); }\n .pf-c-toolbar__group.pf-m-filter-group > * + * {\n margin-left: -1px; }\n .pf-c-toolbar__group.pf-m-toggle-group {\n --pf-c-toolbar--spacer: var(--pf-c-toolbar__group--m-toggle-group--spacer); }\n .pf-c-toolbar__group.pf-m-toggle-group .pf-c-toolbar__group,\n .pf-c-toolbar__group.pf-m-toggle-group .pf-c-toolbar__item {\n display: none;\n visibility: hidden; }\n .pf-c-toolbar__group.pf-m-toggle-group .pf-c-toolbar__toggle {\n display: inline-block;\n visibility: visible; }\n .pf-c-toolbar__group:last-child {\n --pf-c-toolbar--spacer: 0; }\n\n.pf-c-toolbar__item {\n --pf-c-toolbar--spacer: var(--pf-c-toolbar__item--spacer);\n margin-right: var(--pf-c-toolbar--spacer); }\n .pf-c-toolbar__item.pf-m-overflow-menu {\n --pf-c-toolbar--spacer: var(--pf-c-toolbar__item--m-overflow-menu--spacer); }\n .pf-c-toolbar__item.pf-m-bulk-select {\n --pf-c-toolbar--spacer: var(--pf-c-toolbar__item--m-bulk-select--spacer); }\n .pf-c-toolbar__item.pf-m-expand-all.pf-m-expanded {\n --pf-c-toolbar__expand-all-icon--Rotate: var(--pf-c-toolbar__item--m-expand-all--m-expanded__expand-all-icon--Rotate); }\n .pf-c-toolbar__item.pf-m-search-filter {\n --pf-c-toolbar--spacer: var(--pf-c-toolbar__item--m-search-filter--spacer); }\n .pf-c-toolbar__item.pf-m-chip-group {\n --pf-c-toolbar--spacer: var(--pf-c-toolbar__item--m-chip-group--spacer); }\n .pf-c-toolbar__item.pf-m-label {\n --pf-c-toolbar--spacer: var(--pf-c-toolbar__item--m-label--spacer);\n font-weight: var(--pf-c-toolbar__item--m-label--FontWeight); }\n .pf-c-toolbar__item.pf-m-pagination {\n margin-left: auto; }\n .pf-c-toolbar__item.pf-m-pagination .pf-c-pagination {\n flex-wrap: nowrap; }\n .pf-c-toolbar__item:last-child {\n --pf-c-toolbar--spacer: 0; }\n\n.pf-c-toolbar__expand-all-icon {\n display: inline-block;\n transition: var(--pf-c-toolbar__expand-all-icon--Transition);\n transform: rotate(var(--pf-c-toolbar__expand-all-icon--Rotate)); }\n\n.pf-c-toolbar__content,\n.pf-c-toolbar__content-section {\n display: flex;\n flex-wrap: wrap;\n align-items: center; }\n\n.pf-c-toolbar__content {\n position: relative;\n padding-right: var(--pf-c-toolbar__content--PaddingRight);\n padding-left: var(--pf-c-toolbar__content--PaddingLeft); }\n\n.pf-c-toolbar__content-section {\n width: 100%; }\n\n.pf-c-toolbar__expandable-content {\n position: absolute;\n top: 100%;\n right: 0;\n left: 0;\n z-index: var(--pf-c-toolbar__expandable-content--ZIndex);\n display: none;\n width: 100%;\n padding: var(--pf-c-toolbar__expandable-content--PaddingTop) var(--pf-c-toolbar__expandable-content--PaddingRight) var(--pf-c-toolbar__expandable-content--PaddingBottom) var(--pf-c-toolbar__expandable-content--PaddingLeft);\n visibility: hidden;\n background-color: var(--pf-c-toolbar__expandable-content--BackgroundColor);\n box-shadow: var(--pf-c-toolbar__expandable-content--BoxShadow); }\n @media screen and (min-width: 992px) {\n .pf-c-toolbar__expandable-content {\n position: static;\n box-shadow: none; } }\n .pf-c-toolbar__expandable-content.pf-m-expanded {\n display: grid;\n grid-row-gap: var(--pf-c-toolbar__expandable-content--m-expanded--GridRowGap);\n visibility: visible; }\n .pf-c-toolbar__expandable-content .pf-c-toolbar__group,\n .pf-c-toolbar__expandable-content .pf-c-toolbar__item {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar__expandable-content .pf-c-toolbar__group {\n display: grid;\n grid-row-gap: var(--pf-c-toolbar__expandable-content--m-expanded--GridRowGap); }\n .pf-c-toolbar__expandable-content .pf-m-label {\n display: none;\n visibility: hidden; }\n\n.pf-c-toolbar__content.pf-m-chip-container,\n.pf-c-toolbar__group.pf-m-chip-container {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n margin-top: var(--pf-c-toolbar__group--m-chip-container--MarginTop);\n grid-row-gap: 0; }\n .pf-c-toolbar__content.pf-m-chip-container .pf-c-toolbar__item,\n .pf-c-toolbar__group.pf-m-chip-container .pf-c-toolbar__item {\n --pf-c-toolbar--spacer: var(--pf-c-toolbar__item--spacer);\n margin-top: var(--pf-c-toolbar__group--m-chip-container__item--MarginTop); }\n .pf-c-toolbar__content.pf-m-chip-container .pf-c-toolbar__group,\n .pf-c-toolbar__group.pf-m-chip-container .pf-c-toolbar__group {\n --pf-c-toolbar--spacer: var(--pf-c-toolbar__group--spacer);\n display: flex;\n flex-wrap: wrap;\n grid-row-gap: 0; }\n .pf-c-toolbar__content.pf-m-chip-container .pf-c-toolbar__group:last-child,\n .pf-c-toolbar__content.pf-m-chip-container .pf-c-toolbar__item:last-child,\n .pf-c-toolbar__group.pf-m-chip-container .pf-c-toolbar__group:last-child,\n .pf-c-toolbar__group.pf-m-chip-container .pf-c-toolbar__item:last-child {\n --pf-c-toolbar--spacer: 0; }\n\n.pf-c-toolbar .pf-c-chip-group:last-child {\n --pf-c-chip-group--MarginRight: 0; }\n\n.pf-c-toolbar .pf-c-chip-group li:last-child {\n --pf-c-chip-group__li--m-toolbar--MarginRight: 0; }\n\n.pf-c-toolbar__toggle.pf-m-expanded .pf-c-button.pf-m-plain {\n color: var(--pf-c-toolbar__toggle--m-expanded__c-button--m-plain--Color); }\n\n.pf-m-toggle-group.pf-m-show {\n --pf-c-toolbar--spacer: var(--pf-c-toolbar__group--m-toggle-group--m-show--spacer); }\n .pf-m-toggle-group.pf-m-show .pf-c-toolbar__group,\n .pf-m-toggle-group.pf-m-show .pf-c-toolbar__item {\n display: flex;\n flex: 0 1 auto;\n visibility: visible; }\n .pf-m-toggle-group.pf-m-show .pf-c-toolbar__toggle {\n display: none;\n visibility: hidden; }\n\n@media (min-width: 576px) {\n .pf-m-toggle-group.pf-m-show-on-sm {\n --pf-c-toolbar--spacer: var(--pf-c-toolbar__group--m-toggle-group--m-show--spacer); }\n .pf-m-toggle-group.pf-m-show-on-sm .pf-c-toolbar__group,\n .pf-m-toggle-group.pf-m-show-on-sm .pf-c-toolbar__item {\n display: flex;\n flex: 0 1 auto;\n visibility: visible; }\n .pf-m-toggle-group.pf-m-show-on-sm .pf-c-toolbar__toggle {\n display: none;\n visibility: hidden; } }\n\n@media (min-width: 768px) {\n .pf-m-toggle-group.pf-m-show-on-md {\n --pf-c-toolbar--spacer: var(--pf-c-toolbar__group--m-toggle-group--m-show--spacer); }\n .pf-m-toggle-group.pf-m-show-on-md .pf-c-toolbar__group,\n .pf-m-toggle-group.pf-m-show-on-md .pf-c-toolbar__item {\n display: flex;\n flex: 0 1 auto;\n visibility: visible; }\n .pf-m-toggle-group.pf-m-show-on-md .pf-c-toolbar__toggle {\n display: none;\n visibility: hidden; } }\n\n@media (min-width: 992px) {\n .pf-m-toggle-group.pf-m-show-on-lg {\n --pf-c-toolbar--spacer: var(--pf-c-toolbar__group--m-toggle-group--m-show--spacer); }\n .pf-m-toggle-group.pf-m-show-on-lg .pf-c-toolbar__group,\n .pf-m-toggle-group.pf-m-show-on-lg .pf-c-toolbar__item {\n display: flex;\n flex: 0 1 auto;\n visibility: visible; }\n .pf-m-toggle-group.pf-m-show-on-lg .pf-c-toolbar__toggle {\n display: none;\n visibility: hidden; } }\n\n@media (min-width: 1200px) {\n .pf-m-toggle-group.pf-m-show-on-xl {\n --pf-c-toolbar--spacer: var(--pf-c-toolbar__group--m-toggle-group--m-show--spacer); }\n .pf-m-toggle-group.pf-m-show-on-xl .pf-c-toolbar__group,\n .pf-m-toggle-group.pf-m-show-on-xl .pf-c-toolbar__item {\n display: flex;\n flex: 0 1 auto;\n visibility: visible; }\n .pf-m-toggle-group.pf-m-show-on-xl .pf-c-toolbar__toggle {\n display: none;\n visibility: hidden; } }\n\n@media (min-width: 1450px) {\n .pf-m-toggle-group.pf-m-show-on-2xl {\n --pf-c-toolbar--spacer: var(--pf-c-toolbar__group--m-toggle-group--m-show--spacer); }\n .pf-m-toggle-group.pf-m-show-on-2xl .pf-c-toolbar__group,\n .pf-m-toggle-group.pf-m-show-on-2xl .pf-c-toolbar__item {\n display: flex;\n flex: 0 1 auto;\n visibility: visible; }\n .pf-m-toggle-group.pf-m-show-on-2xl .pf-c-toolbar__toggle {\n display: none;\n visibility: hidden; } }\n\n.pf-c-toolbar .pf-c-toolbar__item.pf-m-align-right,\n.pf-c-toolbar .pf-c-toolbar__group.pf-m-align-right {\n margin-left: auto; }\n .pf-c-toolbar .pf-c-toolbar__item.pf-m-align-right ~ .pf-m-pagination,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-align-right ~ .pf-m-pagination {\n margin-left: 0; }\n\n.pf-c-toolbar .pf-c-toolbar__item.pf-m-align-left,\n.pf-c-toolbar .pf-c-toolbar__group.pf-m-align-left {\n margin-left: 0; }\n .pf-c-toolbar .pf-c-toolbar__item.pf-m-align-left ~ .pf-m-pagination,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-align-left ~ .pf-m-pagination {\n margin-left: auto; }\n\n.pf-c-toolbar .pf-m-hidden {\n display: none;\n visibility: hidden; }\n\n.pf-c-toolbar .pf-m-visible {\n display: flex;\n visibility: visible; }\n\n.pf-c-toolbar .pf-c-toolbar__content-section.pf-m-nowrap,\n.pf-c-toolbar .pf-c-toolbar__group.pf-m-nowrap {\n flex-wrap: nowrap; }\n\n.pf-c-toolbar .pf-c-toolbar__content-section.pf-m-wrap,\n.pf-c-toolbar .pf-c-toolbar__group.pf-m-wrap {\n flex-wrap: wrap; }\n\n@media (min-width: 576px) {\n .pf-c-toolbar .pf-c-toolbar__item.pf-m-align-right-on-sm,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-align-right-on-sm {\n margin-left: auto; }\n .pf-c-toolbar .pf-c-toolbar__item.pf-m-align-right-on-sm ~ .pf-m-pagination,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-align-right-on-sm ~ .pf-m-pagination {\n margin-left: 0; }\n .pf-c-toolbar .pf-c-toolbar__item.pf-m-align-left-on-sm,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-align-left-on-sm {\n margin-left: 0; }\n .pf-c-toolbar .pf-c-toolbar__item.pf-m-align-left-on-sm ~ .pf-m-pagination,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-align-left-on-sm ~ .pf-m-pagination {\n margin-left: auto; }\n .pf-c-toolbar .pf-m-hidden-on-sm {\n display: none;\n visibility: hidden; }\n .pf-c-toolbar .pf-m-visible-on-sm {\n display: flex;\n visibility: visible; }\n .pf-c-toolbar .pf-c-toolbar__content-section.pf-m-nowrap-on-sm,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-nowrap-on-sm {\n flex-wrap: nowrap; }\n .pf-c-toolbar .pf-c-toolbar__content-section.pf-m-wrap-on-sm,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-wrap-on-sm {\n flex-wrap: wrap; } }\n\n@media (min-width: 768px) {\n .pf-c-toolbar .pf-c-toolbar__item.pf-m-align-right-on-md,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-align-right-on-md {\n margin-left: auto; }\n .pf-c-toolbar .pf-c-toolbar__item.pf-m-align-right-on-md ~ .pf-m-pagination,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-align-right-on-md ~ .pf-m-pagination {\n margin-left: 0; }\n .pf-c-toolbar .pf-c-toolbar__item.pf-m-align-left-on-md,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-align-left-on-md {\n margin-left: 0; }\n .pf-c-toolbar .pf-c-toolbar__item.pf-m-align-left-on-md ~ .pf-m-pagination,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-align-left-on-md ~ .pf-m-pagination {\n margin-left: auto; }\n .pf-c-toolbar .pf-m-hidden-on-md {\n display: none;\n visibility: hidden; }\n .pf-c-toolbar .pf-m-visible-on-md {\n display: flex;\n visibility: visible; }\n .pf-c-toolbar .pf-c-toolbar__content-section.pf-m-nowrap-on-md,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-nowrap-on-md {\n flex-wrap: nowrap; }\n .pf-c-toolbar .pf-c-toolbar__content-section.pf-m-wrap-on-md,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-wrap-on-md {\n flex-wrap: wrap; } }\n\n@media (min-width: 992px) {\n .pf-c-toolbar .pf-c-toolbar__item.pf-m-align-right-on-lg,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-align-right-on-lg {\n margin-left: auto; }\n .pf-c-toolbar .pf-c-toolbar__item.pf-m-align-right-on-lg ~ .pf-m-pagination,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-align-right-on-lg ~ .pf-m-pagination {\n margin-left: 0; }\n .pf-c-toolbar .pf-c-toolbar__item.pf-m-align-left-on-lg,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-align-left-on-lg {\n margin-left: 0; }\n .pf-c-toolbar .pf-c-toolbar__item.pf-m-align-left-on-lg ~ .pf-m-pagination,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-align-left-on-lg ~ .pf-m-pagination {\n margin-left: auto; }\n .pf-c-toolbar .pf-m-hidden-on-lg {\n display: none;\n visibility: hidden; }\n .pf-c-toolbar .pf-m-visible-on-lg {\n display: flex;\n visibility: visible; }\n .pf-c-toolbar .pf-c-toolbar__content-section.pf-m-nowrap-on-lg,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-nowrap-on-lg {\n flex-wrap: nowrap; }\n .pf-c-toolbar .pf-c-toolbar__content-section.pf-m-wrap-on-lg,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-wrap-on-lg {\n flex-wrap: wrap; } }\n\n@media (min-width: 1200px) {\n .pf-c-toolbar .pf-c-toolbar__item.pf-m-align-right-on-xl,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-align-right-on-xl {\n margin-left: auto; }\n .pf-c-toolbar .pf-c-toolbar__item.pf-m-align-right-on-xl ~ .pf-m-pagination,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-align-right-on-xl ~ .pf-m-pagination {\n margin-left: 0; }\n .pf-c-toolbar .pf-c-toolbar__item.pf-m-align-left-on-xl,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-align-left-on-xl {\n margin-left: 0; }\n .pf-c-toolbar .pf-c-toolbar__item.pf-m-align-left-on-xl ~ .pf-m-pagination,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-align-left-on-xl ~ .pf-m-pagination {\n margin-left: auto; }\n .pf-c-toolbar .pf-m-hidden-on-xl {\n display: none;\n visibility: hidden; }\n .pf-c-toolbar .pf-m-visible-on-xl {\n display: flex;\n visibility: visible; }\n .pf-c-toolbar .pf-c-toolbar__content-section.pf-m-nowrap-on-xl,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-nowrap-on-xl {\n flex-wrap: nowrap; }\n .pf-c-toolbar .pf-c-toolbar__content-section.pf-m-wrap-on-xl,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-wrap-on-xl {\n flex-wrap: wrap; } }\n\n@media (min-width: 1450px) {\n .pf-c-toolbar .pf-c-toolbar__item.pf-m-align-right-on-2xl,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-align-right-on-2xl {\n margin-left: auto; }\n .pf-c-toolbar .pf-c-toolbar__item.pf-m-align-right-on-2xl ~ .pf-m-pagination,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-align-right-on-2xl ~ .pf-m-pagination {\n margin-left: 0; }\n .pf-c-toolbar .pf-c-toolbar__item.pf-m-align-left-on-2xl,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-align-left-on-2xl {\n margin-left: 0; }\n .pf-c-toolbar .pf-c-toolbar__item.pf-m-align-left-on-2xl ~ .pf-m-pagination,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-align-left-on-2xl ~ .pf-m-pagination {\n margin-left: auto; }\n .pf-c-toolbar .pf-m-hidden-on-2xl {\n display: none;\n visibility: hidden; }\n .pf-c-toolbar .pf-m-visible-on-2xl {\n display: flex;\n visibility: visible; }\n .pf-c-toolbar .pf-c-toolbar__content-section.pf-m-nowrap-on-2xl,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-nowrap-on-2xl {\n flex-wrap: nowrap; }\n .pf-c-toolbar .pf-c-toolbar__content-section.pf-m-wrap-on-2xl,\n .pf-c-toolbar .pf-c-toolbar__group.pf-m-wrap-on-2xl {\n flex-wrap: wrap; } }\n\n.pf-c-toolbar .pf-m-space-items-none > * {\n --pf-c-toolbar--spacer: 0; }\n\n.pf-c-toolbar .pf-m-space-items-none > :last-child {\n --pf-c-toolbar--spacer: 0; }\n\n.pf-c-toolbar .pf-m-space-items-sm > * {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--sm); }\n\n.pf-c-toolbar .pf-m-space-items-sm > :last-child {\n --pf-c-toolbar--spacer: 0; }\n\n.pf-c-toolbar .pf-m-space-items-md > * {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--md); }\n\n.pf-c-toolbar .pf-m-space-items-md > :last-child {\n --pf-c-toolbar--spacer: 0; }\n\n.pf-c-toolbar .pf-m-space-items-lg > * {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--lg); }\n\n.pf-c-toolbar .pf-m-space-items-lg > :last-child {\n --pf-c-toolbar--spacer: 0; }\n\n@media (min-width: 576px) {\n .pf-c-toolbar .pf-m-space-items-none-on-sm > * {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-space-items-none-on-sm > :last-child {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-space-items-sm-on-sm > * {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--sm); }\n .pf-c-toolbar .pf-m-space-items-sm-on-sm > :last-child {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-space-items-md-on-sm > * {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--md); }\n .pf-c-toolbar .pf-m-space-items-md-on-sm > :last-child {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-space-items-lg-on-sm > * {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--lg); }\n .pf-c-toolbar .pf-m-space-items-lg-on-sm > :last-child {\n --pf-c-toolbar--spacer: 0; } }\n\n@media (min-width: 768px) {\n .pf-c-toolbar .pf-m-space-items-none-on-md > * {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-space-items-none-on-md > :last-child {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-space-items-sm-on-md > * {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--sm); }\n .pf-c-toolbar .pf-m-space-items-sm-on-md > :last-child {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-space-items-md-on-md > * {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--md); }\n .pf-c-toolbar .pf-m-space-items-md-on-md > :last-child {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-space-items-lg-on-md > * {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--lg); }\n .pf-c-toolbar .pf-m-space-items-lg-on-md > :last-child {\n --pf-c-toolbar--spacer: 0; } }\n\n@media (min-width: 992px) {\n .pf-c-toolbar .pf-m-space-items-none-on-lg > * {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-space-items-none-on-lg > :last-child {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-space-items-sm-on-lg > * {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--sm); }\n .pf-c-toolbar .pf-m-space-items-sm-on-lg > :last-child {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-space-items-md-on-lg > * {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--md); }\n .pf-c-toolbar .pf-m-space-items-md-on-lg > :last-child {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-space-items-lg-on-lg > * {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--lg); }\n .pf-c-toolbar .pf-m-space-items-lg-on-lg > :last-child {\n --pf-c-toolbar--spacer: 0; } }\n\n@media (min-width: 1200px) {\n .pf-c-toolbar .pf-m-space-items-none-on-xl > * {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-space-items-none-on-xl > :last-child {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-space-items-sm-on-xl > * {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--sm); }\n .pf-c-toolbar .pf-m-space-items-sm-on-xl > :last-child {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-space-items-md-on-xl > * {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--md); }\n .pf-c-toolbar .pf-m-space-items-md-on-xl > :last-child {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-space-items-lg-on-xl > * {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--lg); }\n .pf-c-toolbar .pf-m-space-items-lg-on-xl > :last-child {\n --pf-c-toolbar--spacer: 0; } }\n\n@media (min-width: 1450px) {\n .pf-c-toolbar .pf-m-space-items-none-on-2xl > * {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-space-items-none-on-2xl > :last-child {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-space-items-sm-on-2xl > * {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--sm); }\n .pf-c-toolbar .pf-m-space-items-sm-on-2xl > :last-child {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-space-items-md-on-2xl > * {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--md); }\n .pf-c-toolbar .pf-m-space-items-md-on-2xl > :last-child {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-space-items-lg-on-2xl > * {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--lg); }\n .pf-c-toolbar .pf-m-space-items-lg-on-2xl > :last-child {\n --pf-c-toolbar--spacer: 0; } }\n\n.pf-c-toolbar .pf-m-spacer-none {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-spacer-none:last-child {\n --pf-c-toolbar--spacer: 0; }\n\n.pf-c-toolbar .pf-m-spacer-sm {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--sm); }\n .pf-c-toolbar .pf-m-spacer-sm:last-child {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--sm); }\n\n.pf-c-toolbar .pf-m-spacer-md {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--md); }\n .pf-c-toolbar .pf-m-spacer-md:last-child {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--md); }\n\n.pf-c-toolbar .pf-m-spacer-lg {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--lg); }\n .pf-c-toolbar .pf-m-spacer-lg:last-child {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--lg); }\n\n@media (min-width: 576px) {\n .pf-c-toolbar .pf-m-spacer-none-on-sm {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-spacer-none-on-sm:last-child {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-spacer-sm-on-sm {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--sm); }\n .pf-c-toolbar .pf-m-spacer-sm-on-sm:last-child {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--sm); }\n .pf-c-toolbar .pf-m-spacer-md-on-sm {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--md); }\n .pf-c-toolbar .pf-m-spacer-md-on-sm:last-child {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--md); }\n .pf-c-toolbar .pf-m-spacer-lg-on-sm {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--lg); }\n .pf-c-toolbar .pf-m-spacer-lg-on-sm:last-child {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--lg); } }\n\n@media (min-width: 768px) {\n .pf-c-toolbar .pf-m-spacer-none-on-md {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-spacer-none-on-md:last-child {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-spacer-sm-on-md {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--sm); }\n .pf-c-toolbar .pf-m-spacer-sm-on-md:last-child {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--sm); }\n .pf-c-toolbar .pf-m-spacer-md-on-md {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--md); }\n .pf-c-toolbar .pf-m-spacer-md-on-md:last-child {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--md); }\n .pf-c-toolbar .pf-m-spacer-lg-on-md {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--lg); }\n .pf-c-toolbar .pf-m-spacer-lg-on-md:last-child {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--lg); } }\n\n@media (min-width: 992px) {\n .pf-c-toolbar .pf-m-spacer-none-on-lg {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-spacer-none-on-lg:last-child {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-spacer-sm-on-lg {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--sm); }\n .pf-c-toolbar .pf-m-spacer-sm-on-lg:last-child {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--sm); }\n .pf-c-toolbar .pf-m-spacer-md-on-lg {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--md); }\n .pf-c-toolbar .pf-m-spacer-md-on-lg:last-child {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--md); }\n .pf-c-toolbar .pf-m-spacer-lg-on-lg {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--lg); }\n .pf-c-toolbar .pf-m-spacer-lg-on-lg:last-child {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--lg); } }\n\n@media (min-width: 1200px) {\n .pf-c-toolbar .pf-m-spacer-none-on-xl {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-spacer-none-on-xl:last-child {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-spacer-sm-on-xl {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--sm); }\n .pf-c-toolbar .pf-m-spacer-sm-on-xl:last-child {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--sm); }\n .pf-c-toolbar .pf-m-spacer-md-on-xl {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--md); }\n .pf-c-toolbar .pf-m-spacer-md-on-xl:last-child {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--md); }\n .pf-c-toolbar .pf-m-spacer-lg-on-xl {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--lg); }\n .pf-c-toolbar .pf-m-spacer-lg-on-xl:last-child {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--lg); } }\n\n@media (min-width: 1450px) {\n .pf-c-toolbar .pf-m-spacer-none-on-2xl {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-spacer-none-on-2xl:last-child {\n --pf-c-toolbar--spacer: 0; }\n .pf-c-toolbar .pf-m-spacer-sm-on-2xl {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--sm); }\n .pf-c-toolbar .pf-m-spacer-sm-on-2xl:last-child {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--sm); }\n .pf-c-toolbar .pf-m-spacer-md-on-2xl {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--md); }\n .pf-c-toolbar .pf-m-spacer-md-on-2xl:last-child {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--md); }\n .pf-c-toolbar .pf-m-spacer-lg-on-2xl {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--lg); }\n .pf-c-toolbar .pf-m-spacer-lg-on-2xl:last-child {\n --pf-c-toolbar--spacer: var(--pf-global--spacer--lg); } }\n\n.pf-c-toolbar.pf-m-inset-none {\n --pf-c-toolbar--inset: 0;\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n\n.pf-c-toolbar.pf-m-inset-sm {\n --pf-c-toolbar--inset: var(--pf-global--spacer--sm);\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n\n.pf-c-toolbar.pf-m-inset-md {\n --pf-c-toolbar--inset: var(--pf-global--spacer--md);\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n\n.pf-c-toolbar.pf-m-inset-lg {\n --pf-c-toolbar--inset: var(--pf-global--spacer--lg);\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n\n.pf-c-toolbar.pf-m-inset-xl {\n --pf-c-toolbar--inset: var(--pf-global--spacer--xl);\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n\n.pf-c-toolbar.pf-m-inset-2xl {\n --pf-c-toolbar--inset: var(--pf-global--spacer--2xl);\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n\n@media (min-width: 576px) {\n .pf-c-toolbar.pf-m-inset-none-on-sm {\n --pf-c-toolbar--inset: 0;\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n .pf-c-toolbar.pf-m-inset-sm-on-sm {\n --pf-c-toolbar--inset: var(--pf-global--spacer--sm);\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n .pf-c-toolbar.pf-m-inset-md-on-sm {\n --pf-c-toolbar--inset: var(--pf-global--spacer--md);\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n .pf-c-toolbar.pf-m-inset-lg-on-sm {\n --pf-c-toolbar--inset: var(--pf-global--spacer--lg);\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n .pf-c-toolbar.pf-m-inset-xl-on-sm {\n --pf-c-toolbar--inset: var(--pf-global--spacer--xl);\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n .pf-c-toolbar.pf-m-inset-2xl-on-sm {\n --pf-c-toolbar--inset: var(--pf-global--spacer--2xl);\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); } }\n\n@media (min-width: 768px) {\n .pf-c-toolbar.pf-m-inset-none-on-md {\n --pf-c-toolbar--inset: 0;\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n .pf-c-toolbar.pf-m-inset-sm-on-md {\n --pf-c-toolbar--inset: var(--pf-global--spacer--sm);\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n .pf-c-toolbar.pf-m-inset-md-on-md {\n --pf-c-toolbar--inset: var(--pf-global--spacer--md);\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n .pf-c-toolbar.pf-m-inset-lg-on-md {\n --pf-c-toolbar--inset: var(--pf-global--spacer--lg);\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n .pf-c-toolbar.pf-m-inset-xl-on-md {\n --pf-c-toolbar--inset: var(--pf-global--spacer--xl);\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n .pf-c-toolbar.pf-m-inset-2xl-on-md {\n --pf-c-toolbar--inset: var(--pf-global--spacer--2xl);\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); } }\n\n@media (min-width: 992px) {\n .pf-c-toolbar.pf-m-inset-none-on-lg {\n --pf-c-toolbar--inset: 0;\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n .pf-c-toolbar.pf-m-inset-sm-on-lg {\n --pf-c-toolbar--inset: var(--pf-global--spacer--sm);\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n .pf-c-toolbar.pf-m-inset-md-on-lg {\n --pf-c-toolbar--inset: var(--pf-global--spacer--md);\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n .pf-c-toolbar.pf-m-inset-lg-on-lg {\n --pf-c-toolbar--inset: var(--pf-global--spacer--lg);\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n .pf-c-toolbar.pf-m-inset-xl-on-lg {\n --pf-c-toolbar--inset: var(--pf-global--spacer--xl);\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n .pf-c-toolbar.pf-m-inset-2xl-on-lg {\n --pf-c-toolbar--inset: var(--pf-global--spacer--2xl);\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); } }\n\n@media (min-width: 1200px) {\n .pf-c-toolbar.pf-m-inset-none-on-xl {\n --pf-c-toolbar--inset: 0;\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n .pf-c-toolbar.pf-m-inset-sm-on-xl {\n --pf-c-toolbar--inset: var(--pf-global--spacer--sm);\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n .pf-c-toolbar.pf-m-inset-md-on-xl {\n --pf-c-toolbar--inset: var(--pf-global--spacer--md);\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n .pf-c-toolbar.pf-m-inset-lg-on-xl {\n --pf-c-toolbar--inset: var(--pf-global--spacer--lg);\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n .pf-c-toolbar.pf-m-inset-xl-on-xl {\n --pf-c-toolbar--inset: var(--pf-global--spacer--xl);\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n .pf-c-toolbar.pf-m-inset-2xl-on-xl {\n --pf-c-toolbar--inset: var(--pf-global--spacer--2xl);\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); } }\n\n@media (min-width: 1450px) {\n .pf-c-toolbar.pf-m-inset-none-on-2xl {\n --pf-c-toolbar--inset: 0;\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n .pf-c-toolbar.pf-m-inset-sm-on-2xl {\n --pf-c-toolbar--inset: var(--pf-global--spacer--sm);\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n .pf-c-toolbar.pf-m-inset-md-on-2xl {\n --pf-c-toolbar--inset: var(--pf-global--spacer--md);\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n .pf-c-toolbar.pf-m-inset-lg-on-2xl {\n --pf-c-toolbar--inset: var(--pf-global--spacer--lg);\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n .pf-c-toolbar.pf-m-inset-xl-on-2xl {\n --pf-c-toolbar--inset: var(--pf-global--spacer--xl);\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); }\n .pf-c-toolbar.pf-m-inset-2xl-on-2xl {\n --pf-c-toolbar--inset: var(--pf-global--spacer--2xl);\n --pf-c-toolbar__content--PaddingRight: var(--pf-c-toolbar--inset);\n --pf-c-toolbar__content--PaddingLeft: var(--pf-c-toolbar--inset); } }\n\n.pf-c-toolbar__content-section > :last-child {\n --pf-c-toolbar--spacer: 0; }\n\n.pf-c-date-picker {\n --pf-c-date-picker--m-top__calendar--Top: 0;\n --pf-c-date-picker--m-top__calendar--TranslateY: calc(-100% - var(--pf-global--spacer--xs));\n --pf-c-date-picker__helper-text--MarginTop: var(--pf-global--spacer--xs);\n --pf-c-date-picker__helper-text--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-date-picker__helper-text--Color: var(--pf-global--Color--100);\n --pf-c-date-picker__helper-text--m-error--Color: var(--pf-global--danger-color--100);\n --pf-c-date-picker__input--c-form-control--Width: calc(var(--pf-c-date-picker__input--c-form-control--width-chars) * 1ch + var(--pf-c-date-picker__input--c-form-control--width-base));\n --pf-c-date-picker__input--c-form-control--width-base: calc(var(--pf-global--spacer--xl) + var(--pf-global--spacer--sm));\n --pf-c-date-picker__input--c-form-control--width-chars: 10;\n --pf-c-date-picker__calendar--BackgroundColor: var(--pf-global--BackgroundColor--light-100);\n --pf-c-date-picker__calendar--BoxShadow: var(--pf-global--BoxShadow--md);\n --pf-c-date-picker__calendar--ZIndex: var(--pf-global--ZIndex--sm);\n --pf-c-date-picker__calendar--Top: calc(100% + var(--pf-global--spacer--xs));\n --pf-c-date-picker__calendar--Right: auto;\n --pf-c-date-picker__calendar--Left: 0;\n --pf-c-date-picker__calendar--m-align-right--Right: 0;\n --pf-c-date-picker__calendar--m-align-right--Left: auto;\n position: relative;\n display: inline-block; }\n\n.pf-c-date-picker__helper-text {\n margin-top: var(--pf-c-date-picker__helper-text--MarginTop);\n font-size: var(--pf-c-date-picker__helper-text--FontSize);\n color: var(--pf-c-date-picker__helper-text--Color); }\n .pf-c-date-picker__helper-text.pf-m-error {\n --pf-c-date-picker__helper-text--Color: var(--pf-c-date-picker__helper-text--m-error--Color); }\n\n.pf-c-date-picker__input .pf-c-form-control {\n width: var(--pf-c-date-picker__input--c-form-control--Width); }\n\n.pf-c-date-picker__calendar {\n position: absolute;\n top: var(--pf-c-date-picker__calendar--Top);\n right: var(--pf-c-date-picker__calendar--Right);\n left: var(--pf-c-date-picker__calendar--Left);\n z-index: var(--pf-c-date-picker__calendar--ZIndex);\n background-color: var(--pf-c-date-picker__calendar--BackgroundColor);\n box-shadow: var(--pf-c-date-picker__calendar--BoxShadow); }\n .pf-c-date-picker__calendar.pf-m-align-right {\n --pf-c-date-picker__calendar--Right: var(--pf-c-date-picker__calendar--m-align-right--Right);\n --pf-c-date-picker__calendar--Left: var(--pf-c-date-picker__calendar--m-align-right--Left); }\n .pf-c-date-picker.pf-m-top .pf-c-date-picker__calendar {\n --pf-c-date-picker__calendar--Top: var(--pf-c-date-picker--m-top__calendar--Top);\n transform: translateY(var(--pf-c-date-picker--m-top__calendar--TranslateY)); }\n\n.pf-c-divider {\n --pf-c-divider--Height: var(--pf-global--BorderWidth--sm);\n --pf-c-divider--BackgroundColor: var(--pf-global--BorderColor--100);\n --pf-c-divider--after--Height: var(--pf-c-divider--Height);\n --pf-c-divider--after--BackgroundColor: var(--pf-c-divider--BackgroundColor);\n --pf-c-divider--after--FlexBasis: 100%;\n --pf-c-divider--after--Inset: 0%;\n --pf-c-divider--m-vertical--after--FlexBasis: 100%;\n --pf-c-divider--m-vertical--after--Width: var(--pf-global--BorderWidth--sm);\n display: flex;\n align-items: center;\n align-self: stretch;\n justify-content: center;\n width: 100%;\n border: 0; }\n .pf-c-divider::after {\n flex-basis: calc(var(--pf-c-divider--after--FlexBasis) - calc(var(--pf-c-divider--after--Inset) * 2));\n align-self: stretch;\n height: var(--pf-c-divider--after--Height);\n content: \"\";\n background-color: var(--pf-c-divider--after--BackgroundColor);\n justify-self: center; }\n .pf-c-divider.pf-m-vertical {\n display: inline-flex;\n flex-direction: column;\n width: auto;\n height: inherit;\n min-height: 100%;\n max-height: 100%; }\n .pf-c-divider.pf-m-vertical::after {\n flex-basis: calc(var(--pf-c-divider--m-vertical--after--FlexBasis) - var(--pf-c-divider--after--Inset));\n width: var(--pf-c-divider--m-vertical--after--Width); }\n .pf-c-divider.pf-m-inset-none {\n --pf-c-divider--after--Inset: 0%; }\n .pf-c-divider.pf-m-inset-xs {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--xs); }\n .pf-c-divider.pf-m-inset-sm {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--sm); }\n .pf-c-divider.pf-m-inset-md {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--md); }\n .pf-c-divider.pf-m-inset-lg {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--lg); }\n .pf-c-divider.pf-m-inset-xl {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--xl); }\n .pf-c-divider.pf-m-inset-2xl {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--2xl); }\n .pf-c-divider.pf-m-inset-3xl {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--3xl); }\n @media (min-width: 576px) {\n .pf-c-divider.pf-m-inset-none-on-sm {\n --pf-c-divider--after--Inset: 0%; }\n .pf-c-divider.pf-m-inset-xs-on-sm {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--xs); }\n .pf-c-divider.pf-m-inset-sm-on-sm {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--sm); }\n .pf-c-divider.pf-m-inset-md-on-sm {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--md); }\n .pf-c-divider.pf-m-inset-lg-on-sm {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--lg); }\n .pf-c-divider.pf-m-inset-xl-on-sm {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--xl); }\n .pf-c-divider.pf-m-inset-2xl-on-sm {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--2xl); }\n .pf-c-divider.pf-m-inset-3xl-on-sm {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--3xl); } }\n @media (min-width: 768px) {\n .pf-c-divider.pf-m-inset-none-on-md {\n --pf-c-divider--after--Inset: 0%; }\n .pf-c-divider.pf-m-inset-xs-on-md {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--xs); }\n .pf-c-divider.pf-m-inset-sm-on-md {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--sm); }\n .pf-c-divider.pf-m-inset-md-on-md {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--md); }\n .pf-c-divider.pf-m-inset-lg-on-md {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--lg); }\n .pf-c-divider.pf-m-inset-xl-on-md {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--xl); }\n .pf-c-divider.pf-m-inset-2xl-on-md {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--2xl); }\n .pf-c-divider.pf-m-inset-3xl-on-md {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--3xl); } }\n @media (min-width: 992px) {\n .pf-c-divider.pf-m-inset-none-on-lg {\n --pf-c-divider--after--Inset: 0%; }\n .pf-c-divider.pf-m-inset-xs-on-lg {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--xs); }\n .pf-c-divider.pf-m-inset-sm-on-lg {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--sm); }\n .pf-c-divider.pf-m-inset-md-on-lg {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--md); }\n .pf-c-divider.pf-m-inset-lg-on-lg {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--lg); }\n .pf-c-divider.pf-m-inset-xl-on-lg {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--xl); }\n .pf-c-divider.pf-m-inset-2xl-on-lg {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--2xl); }\n .pf-c-divider.pf-m-inset-3xl-on-lg {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--3xl); } }\n @media (min-width: 1200px) {\n .pf-c-divider.pf-m-inset-none-on-xl {\n --pf-c-divider--after--Inset: 0%; }\n .pf-c-divider.pf-m-inset-xs-on-xl {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--xs); }\n .pf-c-divider.pf-m-inset-sm-on-xl {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--sm); }\n .pf-c-divider.pf-m-inset-md-on-xl {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--md); }\n .pf-c-divider.pf-m-inset-lg-on-xl {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--lg); }\n .pf-c-divider.pf-m-inset-xl-on-xl {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--xl); }\n .pf-c-divider.pf-m-inset-2xl-on-xl {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--2xl); }\n .pf-c-divider.pf-m-inset-3xl-on-xl {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--3xl); } }\n @media (min-width: 1450px) {\n .pf-c-divider.pf-m-inset-none-on-2xl {\n --pf-c-divider--after--Inset: 0%; }\n .pf-c-divider.pf-m-inset-xs-on-2xl {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--xs); }\n .pf-c-divider.pf-m-inset-sm-on-2xl {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--sm); }\n .pf-c-divider.pf-m-inset-md-on-2xl {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--md); }\n .pf-c-divider.pf-m-inset-lg-on-2xl {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--lg); }\n .pf-c-divider.pf-m-inset-xl-on-2xl {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--xl); }\n .pf-c-divider.pf-m-inset-2xl-on-2xl {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--2xl); }\n .pf-c-divider.pf-m-inset-3xl-on-2xl {\n --pf-c-divider--after--Inset: var(--pf-global--spacer--3xl); } }\n\n.pf-c-drawer {\n --pf-c-drawer__section--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-drawer__content--FlexBasis: 100%;\n --pf-c-drawer__content--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-drawer__content--ZIndex: var(--pf-global--ZIndex--xs);\n --pf-c-drawer__panel--FlexBasis: 100%;\n --pf-c-drawer__panel--md--FlexBasis: 50%;\n --pf-c-drawer__panel--MinWidth: 50%;\n --pf-c-drawer__panel--MaxHeight: auto;\n --pf-c-drawer--m-panel-bottom__panel--md--MinHeight: 50%;\n --pf-c-drawer__panel--xl--MinWidth: 28.125rem;\n --pf-c-drawer__panel--xl--FlexBasis: 28.125rem;\n --pf-c-drawer--m-panel-bottom__panel--xl--MinHeight: 18.75rem;\n --pf-c-drawer--m-panel-bottom__panel--xl--FlexBasis: 18.75rem;\n --pf-c-drawer__panel--ZIndex: var(--pf-global--ZIndex--sm);\n --pf-c-drawer__panel--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-drawer__panel--TransitionDuration: var(--pf-global--TransitionDuration);\n --pf-c-drawer__panel--TransitionProperty: margin, transform, box-shadow, flex-basis;\n --pf-c-drawer__panel--m-resizable--PaddingLeft: var(--pf-c-drawer__splitter--m-vertical--Width);\n --pf-c-drawer--m-panel-left__panel--m-resizable--PaddingRight: var(--pf-c-drawer__splitter--m-vertical--Width);\n --pf-c-drawer--m-panel-bottom__panel--m-resizable--PaddingTop: var(--pf-c-drawer__splitter--Height);\n --pf-c-drawer--child--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-drawer--child--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-drawer--child--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-drawer--child--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-drawer--child--md--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-drawer--child--md--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-drawer--child--md--PaddingBottom: var(--pf-global--spacer--lg);\n --pf-c-drawer--child--md--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-drawer--child--m-padding--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-drawer--child--m-padding--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-drawer--child--m-padding--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-drawer--child--m-padding--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-drawer--child--m-padding--md--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-drawer--child--m-padding--md--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-drawer--child--m-padding--md--PaddingBottom: var(--pf-global--spacer--lg);\n --pf-c-drawer--child--m-padding--md--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-drawer__content--child--PaddingTop: 0;\n --pf-c-drawer__content--child--PaddingRight: 0;\n --pf-c-drawer__content--child--PaddingBottom: 0;\n --pf-c-drawer__content--child--PaddingLeft: 0;\n --pf-c-drawer__splitter--Top: 0;\n --pf-c-drawer__splitter--Right: auto;\n --pf-c-drawer__splitter--Bottom: 0;\n --pf-c-drawer__splitter--Left: 0;\n --pf-c-drawer__splitter--Height: 0.5625rem;\n --pf-c-drawer__splitter--Width: 100%;\n --pf-c-drawer__splitter--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-drawer__splitter--Cursor: row-resize;\n --pf-c-drawer__splitter--m-vertical--Height: 100%;\n --pf-c-drawer__splitter--m-vertical--Width: 0.5625rem;\n --pf-c-drawer__splitter--m-vertical--Cursor: col-resize;\n --pf-c-drawer--m-inline__splitter--focus--OutlineOffset: -0.0625rem;\n --pf-c-drawer__splitter--after--BorderColor: var(--pf-global--BorderColor--100);\n --pf-c-drawer__splitter--after--border-width--base: var(--pf-global--BorderWidth--sm);\n --pf-c-drawer__splitter--after--BorderTopWidth: 0;\n --pf-c-drawer__splitter--after--BorderRightWidth: var(--pf-c-drawer__splitter--after--border-width--base);\n --pf-c-drawer__splitter--after--BorderBottomWidth: 0;\n --pf-c-drawer__splitter--after--BorderLeftWidth: 0;\n --pf-c-drawer--m-panel-left__splitter--after--BorderLeftWidth: var(--pf-c-drawer__splitter--after--border-width--base);\n --pf-c-drawer--m-panel-bottom__splitter--after--BorderBottomWidth: var(--pf-c-drawer__splitter--after--border-width--base);\n --pf-c-drawer--m-inline__splitter--m-vertical--Width: 0.625rem;\n --pf-c-drawer--m-inline__splitter-handle--Left: 50%;\n --pf-c-drawer--m-inline__splitter--after--BorderRightWidth: var(--pf-c-drawer__splitter--after--border-width--base);\n --pf-c-drawer--m-inline__splitter--after--BorderLeftWidth: var(--pf-c-drawer__splitter--after--border-width--base);\n --pf-c-drawer--m-inline--m-panel-bottom__splitter--Height: 0.625rem;\n --pf-c-drawer--m-inline--m-panel-bottom__splitter-handle--Top: 50%;\n --pf-c-drawer--m-inline--m-panel-bottom__splitter--after--BorderTopWidth: var(--pf-c-drawer__splitter--after--border-width--base);\n --pf-c-drawer__splitter-handle--Top: 50%;\n --pf-c-drawer__splitter-handle--Left: calc(50% - var(--pf-c-drawer__splitter--after--border-width--base));\n --pf-c-drawer--m-panel-left__splitter-handle--Left: 50%;\n --pf-c-drawer--m-panel-bottom__splitter-handle--Top: calc(50% - var(--pf-c-drawer__splitter--after--border-width--base));\n --pf-c-drawer__splitter-handle--after--BorderColor: var(--pf-global--Color--200);\n --pf-c-drawer__splitter-handle--after--BorderTopWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-drawer__splitter-handle--after--BorderRightWidth: 0;\n --pf-c-drawer__splitter-handle--after--BorderBottomWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-drawer__splitter-handle--after--BorderLeftWidth: 0;\n --pf-c-drawer__splitter--hover__splitter-handle--after--BorderColor: var(--pf-global--Color--100);\n --pf-c-drawer__splitter--focus__splitter-handle--after--BorderColor: var(--pf-global--Color--100);\n --pf-c-drawer__splitter--m-vertical__splitter-handle--after--BorderTopWidth: 0;\n --pf-c-drawer__splitter--m-vertical__splitter-handle--after--BorderRightWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-drawer__splitter--m-vertical__splitter-handle--after--BorderBottomWidth: 0;\n --pf-c-drawer__splitter--m-vertical__splitter-handle--after--BorderLeftWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-drawer__splitter-handle--after--Width: 0.75rem;\n --pf-c-drawer__splitter-handle--after--Height: 0.25rem;\n --pf-c-drawer__splitter--m-vertical__splitter-handle--after--Width: 0.25rem;\n --pf-c-drawer__splitter--m-vertical__splitter-handle--after--Height: 0.75rem;\n --pf-c-drawer__actions--MarginTop: calc(var(pf-global--spacer--form-element) * -1);\n --pf-c-drawer__actions--MarginRight: calc(var(pf-global--spacer--form-element) * -1);\n --pf-c-drawer__panel--BoxShadow: none;\n --pf-c-drawer--m-expanded__panel--BoxShadow: var(--pf-global--BoxShadow--lg-left);\n --pf-c-drawer--m-expanded--m-panel-left__panel--BoxShadow: var(--pf-global--BoxShadow--lg-right);\n --pf-c-drawer--m-expanded--m-panel-bottom__panel--BoxShadow: var(--pf-global--BoxShadow--lg-top);\n --pf-c-drawer__panel--after--Width: var(--pf-global--BorderWidth--sm);\n --pf-c-drawer--m-panel-bottom__panel--after--Height: var(--pf-global--BorderWidth--sm);\n --pf-c-drawer__panel--after--BackgroundColor: transparent;\n --pf-c-drawer--m-inline--m-expanded__panel--after--BackgroundColor: var(--pf-global--BorderColor--100);\n --pf-c-drawer--m-inline__panel--PaddingLeft: var(--pf-c-drawer__panel--after--Width);\n --pf-c-drawer--m-panel-left--m-inline__panel--PaddingRight: var(--pf-c-drawer__panel--after--Width);\n --pf-c-drawer--m-panel-bottom--m-inline__panel--PaddingTop: var(--pf-c-drawer__panel--after--Width);\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow-x: hidden; }\n @media screen and (min-width: 768px) {\n .pf-c-drawer {\n --pf-c-drawer__panel--FlexBasis: var(--pf-c-drawer__panel--md--FlexBasis);\n --pf-c-drawer--child--PaddingTop: var(--pf-c-drawer--child--md--PaddingTop);\n --pf-c-drawer--child--PaddingRight: var(--pf-c-drawer--child--md--PaddingRight);\n --pf-c-drawer--child--PaddingBottom: var(--pf-c-drawer--child--md--PaddingBottom);\n --pf-c-drawer--child--PaddingLeft: var(--pf-c-drawer--child--md--PaddingLeft);\n --pf-c-drawer--child--m-padding--PaddingTop: var(--pf-c-drawer--child--m-padding--md--PaddingTop);\n --pf-c-drawer--child--m-padding--PaddingRight: var(--pf-c-drawer--child--m-padding--md--PaddingRight);\n --pf-c-drawer--child--m-padding--PaddingBottom: var(--pf-c-drawer--child--m-padding--md--PaddingBottom);\n --pf-c-drawer--child--m-padding--PaddingLeft: var(--pf-c-drawer--child--m-padding--md--PaddingLeft); } }\n @media screen and (min-width: 1200px) {\n .pf-c-drawer {\n --pf-c-drawer__panel--FlexBasis: var(--pf-c-drawer__panel--xl--FlexBasis);\n --pf-c-drawer__panel--MinWidth: var(--pf-c-drawer__panel--xl--MinWidth); }\n .pf-c-drawer.pf-m-panel-bottom {\n --pf-c-drawer__panel--MinWidth: auto;\n --pf-c-drawer__panel--FlexBasis: var(--pf-c-drawer--m-panel-bottom__panel--xl--FlexBasis);\n --pf-c-drawer__panel--MinHeight: var(--pf-c-drawer--m-panel-bottom__panel--xl--MinHeight); } }\n .pf-c-drawer.pf-m-inline > .pf-c-drawer__main > .pf-c-drawer__panel , .pf-c-drawer.pf-m-static > .pf-c-drawer__main > .pf-c-drawer__panel {\n padding-left: var(--pf-c-drawer--m-inline__panel--PaddingLeft); }\n .pf-c-drawer.pf-m-panel-left > .pf-c-drawer__main > .pf-c-drawer__panel {\n order: 0;\n margin-right: calc(var(--pf-c-drawer__panel--FlexBasis) * -1);\n transform: translateX(-100%); }\n .pf-c-drawer.pf-m-panel-left > .pf-c-drawer__main > .pf-c-drawer__content {\n order: 1; }\n .pf-c-drawer.pf-m-panel-bottom > .pf-c-drawer__main {\n flex-direction: column; }\n .pf-c-drawer.pf-m-expanded > .pf-c-drawer__main > .pf-c-drawer__panel {\n transform: translateX(-100%); }\n .pf-c-drawer.pf-m-expanded.pf-m-panel-left > .pf-c-drawer__main > .pf-c-drawer__panel {\n transform: translateX(0); }\n .pf-c-drawer.pf-m-expanded.pf-m-panel-bottom > .pf-c-drawer__main > .pf-c-drawer__panel {\n transform: translate(0, -100%); }\n\n.pf-c-drawer__section {\n flex-grow: 0;\n background-color: var(--pf-c-drawer__section--BackgroundColor); }\n .pf-c-drawer__section.pf-m-no-background {\n background-color: transparent; }\n\n.pf-c-drawer__main {\n display: flex;\n flex-grow: 1;\n overflow: hidden; }\n\n.pf-c-drawer__content,\n.pf-c-drawer__panel {\n display: flex;\n flex-direction: column;\n flex-shrink: 0;\n overflow: auto; }\n\n.pf-c-drawer__content {\n z-index: var(--pf-c-drawer__content--ZIndex);\n flex-basis: var(--pf-c-drawer__content--FlexBasis);\n order: 0;\n background-color: var(--pf-c-drawer__content--BackgroundColor); }\n .pf-c-drawer__content > .pf-c-drawer__body {\n padding: var(--pf-c-drawer__content--child--PaddingTop) var(--pf-c-drawer__content--child--PaddingRight) var(--pf-c-drawer__content--child--PaddingBottom) var(--pf-c-drawer__content--child--PaddingLeft); }\n .pf-c-drawer__content.pf-m-no-background {\n background-color: transparent; }\n\n.pf-c-drawer__panel {\n position: relative;\n z-index: var(--pf-c-drawer__panel--ZIndex);\n flex-basis: var(--pf-c-drawer__panel--FlexBasis);\n order: 1;\n max-height: var(--pf-c-drawer__panel--MaxHeight);\n overflow: auto;\n background-color: var(--pf-c-drawer__panel--BackgroundColor);\n box-shadow: var(--pf-c-drawer__panel--BoxShadow);\n transition-duration: var(--pf-c-drawer__panel--TransitionDuration);\n transition-property: var(--pf-c-drawer__panel--TransitionProperty);\n -webkit-overflow-scrolling: touch; }\n .pf-c-drawer__panel::after {\n position: absolute;\n top: 0;\n left: 0;\n width: var(--pf-c-drawer__panel--after--Width);\n height: 100%;\n content: \"\";\n background-color: var(--pf-c-drawer__panel--after--BackgroundColor); }\n .pf-c-drawer__panel.pf-m-no-background {\n background-color: transparent; }\n\n@keyframes pf-remove-tab-focus {\n to {\n visibility: hidden; } }\n\n.pf-c-drawer__panel[hidden] {\n animation-name: pf-remove-tab-focus;\n animation-delay: var(--pf-c-drawer__panel--TransitionDuration);\n animation-fill-mode: forwards; }\n\n.pf-c-drawer__head {\n display: grid;\n grid-template-columns: auto;\n grid-auto-columns: max-content; }\n .pf-c-drawer__head > * {\n grid-column: 1; }\n\n.pf-c-drawer__actions {\n grid-column: 2;\n grid-row: 1;\n display: flex;\n align-self: baseline;\n margin-top: var(--pf-c-drawer__actions--MarginTop);\n margin-right: var(--pf-c-drawer__actions--MarginRight); }\n\n.pf-c-drawer__body {\n min-height: 0;\n padding: var(--pf-c-drawer--child--PaddingTop) var(--pf-c-drawer--child--PaddingRight) var(--pf-c-drawer--child--PaddingBottom) var(--pf-c-drawer--child--PaddingLeft); }\n .pf-c-drawer__body.pf-m-no-padding {\n padding: 0; }\n .pf-c-drawer__body.pf-m-no-padding > .pf-c-drawer__actions,\n .pf-c-drawer__body.pf-m-no-padding > .pf-c-drawer__head > .pf-c-drawer__actions {\n margin-top: 0;\n margin-right: 0; }\n .pf-c-drawer__body.pf-m-padding {\n padding: var(--pf-c-drawer--child--m-padding--PaddingTop) var(--pf-c-drawer--child--m-padding--PaddingRight) var(--pf-c-drawer--child--m-padding--PaddingBottom) var(--pf-c-drawer--child--m-padding--PaddingLeft); }\n .pf-c-drawer__body:not(.pf-m-no-padding) + * {\n padding-top: 0; }\n .pf-c-drawer__body:last-child {\n flex: 1 1; }\n\n.pf-c-drawer__body > .pf-c-page__main {\n min-height: 100%; }\n\n.pf-c-drawer__splitter {\n position: absolute;\n top: var(--pf-c-drawer__splitter--Top);\n right: var(--pf-c-drawer__splitter--Right);\n bottom: var(--pf-c-drawer__splitter--Bottom);\n left: var(--pf-c-drawer__splitter--Left);\n display: none;\n width: var(--pf-c-drawer__splitter--Width);\n height: var(--pf-c-drawer__splitter--Height);\n cursor: var(--pf-c-drawer__splitter--Cursor);\n visibility: hidden;\n background-color: var(--pf-c-drawer__splitter--BackgroundColor); }\n .pf-c-drawer__splitter.pf-m-vertical {\n --pf-c-drawer__splitter--Height: var(--pf-c-drawer__splitter--m-vertical--Height);\n --pf-c-drawer__splitter--Width: var(--pf-c-drawer__splitter--m-vertical--Width);\n --pf-c-drawer__splitter--Cursor: var(--pf-c-drawer__splitter--m-vertical--Cursor);\n --pf-c-drawer__splitter-handle--after--Width: var(--pf-c-drawer__splitter--m-vertical__splitter-handle--after--Width);\n --pf-c-drawer__splitter-handle--after--Height: var(--pf-c-drawer__splitter--m-vertical__splitter-handle--after--Height);\n --pf-c-drawer__splitter-handle--after--BorderTopWidth: var(--pf-c-drawer__splitter--m-vertical__splitter-handle--after--BorderTopWidth);\n --pf-c-drawer__splitter-handle--after--BorderRightWidth: var(--pf-c-drawer__splitter--m-vertical__splitter-handle--after--BorderRightWidth);\n --pf-c-drawer__splitter-handle--after--BorderBottomWidth: var(--pf-c-drawer__splitter--m-vertical__splitter-handle--after--BorderBottomWidth);\n --pf-c-drawer__splitter-handle--after--BorderLeftWidth: var(--pf-c-drawer__splitter--m-vertical__splitter-handle--after--BorderLeftWidth); }\n .pf-c-drawer__splitter:hover {\n --pf-c-drawer__splitter-handle--after--BorderColor: var(--pf-c-drawer__splitter--hover__splitter-handle--after--BorderColor); }\n .pf-c-drawer__splitter:focus {\n --pf-c-drawer__splitter-handle--after--BorderColor: var(--pf-c-drawer__splitter--focus__splitter-handle--after--BorderColor); }\n .pf-c-drawer__splitter::after {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n content: \"\";\n border: solid var(--pf-c-drawer__splitter--after--BorderColor);\n border-width: var(--pf-c-drawer__splitter--after--BorderTopWidth) var(--pf-c-drawer__splitter--after--BorderRightWidth) var(--pf-c-drawer__splitter--after--BorderBottomWidth) var(--pf-c-drawer__splitter--after--BorderLeftWidth); }\n\n.pf-c-drawer__splitter-handle {\n position: absolute;\n top: var(--pf-c-drawer__splitter-handle--Top);\n left: var(--pf-c-drawer__splitter-handle--Left);\n transform: translate(-50%, -50%); }\n .pf-c-drawer__splitter-handle::after {\n display: block;\n width: var(--pf-c-drawer__splitter-handle--after--Width);\n height: var(--pf-c-drawer__splitter-handle--after--Height);\n content: \"\";\n border-color: var(--pf-c-drawer__splitter-handle--after--BorderColor);\n border-style: solid;\n border-width: var(--pf-c-drawer__splitter-handle--after--BorderTopWidth) var(--pf-c-drawer__splitter-handle--after--BorderRightWidth) var(--pf-c-drawer__splitter-handle--after--BorderBottomWidth) var(--pf-c-drawer__splitter-handle--after--BorderLeftWidth); }\n\n@media screen and (min-width: 768px) {\n .pf-c-drawer {\n min-width: var(--pf-c-drawer__panel--MinWidth); }\n .pf-c-drawer.pf-m-expanded > .pf-c-drawer__main > .pf-c-drawer__panel {\n box-shadow: var(--pf-c-drawer--m-expanded__panel--BoxShadow); }\n .pf-c-drawer > .pf-c-drawer__main > .pf-c-drawer__panel.pf-m-resizable {\n padding-left: var(--pf-c-drawer__panel--m-resizable--PaddingLeft); }\n .pf-c-drawer > .pf-c-drawer__main > .pf-c-drawer__panel.pf-m-resizable::after {\n width: 0;\n height: 0; }\n .pf-c-drawer.pf-m-panel-left {\n --pf-c-drawer--m-expanded__panel--BoxShadow: var(--pf-c-drawer--m-expanded--m-panel-left__panel--BoxShadow); }\n .pf-c-drawer.pf-m-panel-left.pf-m-inline > .pf-c-drawer__main > .pf-c-drawer__panel , .pf-c-drawer.pf-m-panel-left.pf-m-static > .pf-c-drawer__main > .pf-c-drawer__panel {\n padding-right: var(--pf-c-drawer--m-panel-left--m-inline__panel--PaddingRight);\n padding-left: 0; }\n .pf-c-drawer.pf-m-panel-left.pf-m-expanded > .pf-c-drawer__main > .pf-c-drawer__panel {\n transform: translateX(0); }\n .pf-c-drawer.pf-m-panel-left > .pf-c-drawer__main > .pf-c-drawer__panel::after {\n right: 0;\n left: auto; }\n .pf-c-drawer.pf-m-panel-left > .pf-c-drawer__main > .pf-c-drawer__panel.pf-m-resizable {\n padding-right: var(--pf-c-drawer--m-panel-left__panel--m-resizable--PaddingRight);\n padding-left: 0; }\n .pf-c-drawer.pf-m-panel-left > .pf-c-drawer__main > .pf-c-drawer__panel.pf-m-resizable > .pf-c-drawer__splitter {\n --pf-c-drawer__splitter--Right: 0;\n --pf-c-drawer__splitter--Left: auto;\n --pf-c-drawer__splitter-handle--Left: var(--pf-c-drawer--m-panel-left__splitter-handle--Left);\n --pf-c-drawer__splitter--after--BorderRightWidth: 0;\n --pf-c-drawer__splitter--after--BorderLeftWidth: var(--pf-c-drawer--m-panel-left__splitter--after--BorderLeftWidth); }\n .pf-c-drawer.pf-m-panel-bottom {\n --pf-c-drawer--m-expanded__panel--BoxShadow: var(--pf-c-drawer--m-expanded--m-panel-bottom__panel--BoxShadow);\n --pf-c-drawer__panel--MaxHeight: 100%;\n min-width: auto;\n min-height: var(--pf-c-drawer--m-panel-bottom__panel--md--MinHeight); }\n .pf-c-drawer.pf-m-panel-bottom.pf-m-inline > .pf-c-drawer__main > .pf-c-drawer__panel , .pf-c-drawer.pf-m-panel-bottom.pf-m-static > .pf-c-drawer__main > .pf-c-drawer__panel {\n padding-top: var(--pf-c-drawer--m-panel-bottom--m-inline__panel--PaddingTop);\n padding-left: 0; }\n .pf-c-drawer.pf-m-panel-bottom > .pf-c-drawer__main > .pf-c-drawer__panel::after {\n top: 0;\n left: auto;\n width: 100%;\n height: var(--pf-c-drawer--m-panel-bottom__panel--after--Height); }\n .pf-c-drawer.pf-m-panel-bottom > .pf-c-drawer__main > .pf-c-drawer__panel.pf-m-resizable {\n padding-top: var(--pf-c-drawer--m-panel-bottom__panel--m-resizable--PaddingTop);\n padding-left: 0; }\n .pf-c-drawer.pf-m-panel-bottom > .pf-c-drawer__main > .pf-c-drawer__panel.pf-m-resizable > .pf-c-drawer__splitter {\n --pf-c-drawer__splitter--Top: 0;\n --pf-c-drawer__splitter--Right: 0;\n --pf-c-drawer__splitter--Bottom: auto;\n --pf-c-drawer__splitter-handle--Top: var(--pf-c-drawer--m-panel-bottom__splitter-handle--Top);\n --pf-c-drawer__splitter--after--BorderRightWidth: 0;\n --pf-c-drawer__splitter--after--BorderBottomWidth: var(--pf-c-drawer--m-panel-bottom__splitter--after--BorderBottomWidth); }\n .pf-c-drawer.pf-m-inline > .pf-c-drawer__main > .pf-c-drawer__panel.pf-m-resizable > .pf-c-drawer__splitter {\n --pf-c-drawer__splitter--m-vertical--Width: var(--pf-c-drawer--m-inline__splitter--m-vertical--Width);\n --pf-c-drawer__splitter-handle--Left: var(--pf-c-drawer--m-inline__splitter-handle--Left);\n --pf-c-drawer__splitter--after--BorderRightWidth: var(--pf-c-drawer--m-inline__splitter--after--BorderRightWidth);\n --pf-c-drawer__splitter--after--BorderLeftWidth: var(--pf-c-drawer--m-inline__splitter--after--BorderLeftWidth);\n outline-offset: var(--pf-c-drawer--m-inline__splitter--focus--OutlineOffset); }\n .pf-c-drawer.pf-m-inline.pf-m-panel-bottom > .pf-c-drawer__main > .pf-c-drawer__panel.pf-m-resizable > .pf-c-drawer__splitter {\n --pf-c-drawer__splitter--Height: var(--pf-c-drawer--m-inline--m-panel-bottom__splitter--Height);\n --pf-c-drawer__splitter-handle--Top: var(--pf-c-drawer--m-inline--m-panel-bottom__splitter-handle--Top);\n --pf-c-drawer__splitter--after--BorderTopWidth: var(--pf-c-drawer--m-inline--m-panel-bottom__splitter--after--BorderTopWidth);\n --pf-c-drawer__splitter--after--BorderRightWidth: 0;\n --pf-c-drawer__splitter--after--BorderLeftWidth: 0; }\n .pf-c-drawer > .pf-c-drawer__main > .pf-c-drawer__panel.pf-m-no-border,\n .pf-c-drawer.pf-m-panel-left > .pf-c-drawer__main > .pf-c-drawer__panel.pf-m-no-border {\n --pf-c-drawer--m-expanded__panel--BoxShadow: none; }\n .pf-c-drawer__splitter {\n display: block;\n visibility: visible; } }\n\n@media (min-width: 768px) {\n .pf-c-drawer__panel.pf-m-width-25 {\n --pf-c-drawer__panel--FlexBasis: 25%; }\n .pf-c-drawer__panel.pf-m-width-33 {\n --pf-c-drawer__panel--FlexBasis: 33%; }\n .pf-c-drawer__panel.pf-m-width-50 {\n --pf-c-drawer__panel--FlexBasis: 50%; }\n .pf-c-drawer__panel.pf-m-width-66 {\n --pf-c-drawer__panel--FlexBasis: 66%; }\n .pf-c-drawer__panel.pf-m-width-75 {\n --pf-c-drawer__panel--FlexBasis: 75%; }\n .pf-c-drawer__panel.pf-m-width-100 {\n --pf-c-drawer__panel--FlexBasis: 100%; } }\n\n@media (min-width: 992px) {\n .pf-c-drawer__panel.pf-m-width-25-on-lg {\n --pf-c-drawer__panel--FlexBasis: 25%; }\n .pf-c-drawer__panel.pf-m-width-33-on-lg {\n --pf-c-drawer__panel--FlexBasis: 33%; }\n .pf-c-drawer__panel.pf-m-width-50-on-lg {\n --pf-c-drawer__panel--FlexBasis: 50%; }\n .pf-c-drawer__panel.pf-m-width-66-on-lg {\n --pf-c-drawer__panel--FlexBasis: 66%; }\n .pf-c-drawer__panel.pf-m-width-75-on-lg {\n --pf-c-drawer__panel--FlexBasis: 75%; }\n .pf-c-drawer__panel.pf-m-width-100-on-lg {\n --pf-c-drawer__panel--FlexBasis: 100%; } }\n\n@media (min-width: 1200px) {\n .pf-c-drawer__panel.pf-m-width-25-on-xl {\n --pf-c-drawer__panel--FlexBasis: 25%; }\n .pf-c-drawer__panel.pf-m-width-33-on-xl {\n --pf-c-drawer__panel--FlexBasis: 33%; }\n .pf-c-drawer__panel.pf-m-width-50-on-xl {\n --pf-c-drawer__panel--FlexBasis: 50%; }\n .pf-c-drawer__panel.pf-m-width-66-on-xl {\n --pf-c-drawer__panel--FlexBasis: 66%; }\n .pf-c-drawer__panel.pf-m-width-75-on-xl {\n --pf-c-drawer__panel--FlexBasis: 75%; }\n .pf-c-drawer__panel.pf-m-width-100-on-xl {\n --pf-c-drawer__panel--FlexBasis: 100%; } }\n\n@media (min-width: 1450px) {\n .pf-c-drawer__panel.pf-m-width-25-on-2xl {\n --pf-c-drawer__panel--FlexBasis: 25%; }\n .pf-c-drawer__panel.pf-m-width-33-on-2xl {\n --pf-c-drawer__panel--FlexBasis: 33%; }\n .pf-c-drawer__panel.pf-m-width-50-on-2xl {\n --pf-c-drawer__panel--FlexBasis: 50%; }\n .pf-c-drawer__panel.pf-m-width-66-on-2xl {\n --pf-c-drawer__panel--FlexBasis: 66%; }\n .pf-c-drawer__panel.pf-m-width-75-on-2xl {\n --pf-c-drawer__panel--FlexBasis: 75%; }\n .pf-c-drawer__panel.pf-m-width-100-on-2xl {\n --pf-c-drawer__panel--FlexBasis: 100%; } }\n\n@media (min-width: 768px) {\n .pf-c-drawer.pf-m-inline > .pf-c-drawer__main > .pf-c-drawer__content,\n .pf-c-drawer.pf-m-static > .pf-c-drawer__main > .pf-c-drawer__content {\n flex-shrink: 1; }\n .pf-c-drawer.pf-m-inline > .pf-c-drawer__main > .pf-c-drawer__panel,\n .pf-c-drawer.pf-m-static > .pf-c-drawer__main > .pf-c-drawer__panel {\n --pf-c-drawer--m-expanded__panel--BoxShadow: none; }\n .pf-c-drawer.pf-m-inline > .pf-c-drawer__main > .pf-c-drawer__panel:not(.pf-m-no-border)::after,\n .pf-c-drawer.pf-m-static > .pf-c-drawer__main > .pf-c-drawer__panel:not(.pf-m-no-border)::after {\n background-color: var(--pf-c-drawer--m-inline--m-expanded__panel--after--BackgroundColor); }\n .pf-c-drawer.pf-m-inline > .pf-c-drawer__main > .pf-c-drawer__content {\n overflow-x: auto; }\n .pf-c-drawer.pf-m-inline > .pf-c-drawer__main > .pf-c-drawer__panel {\n margin-left: calc(var(--pf-c-drawer__panel--FlexBasis) * -1);\n transform: translateX(100%); }\n .pf-c-drawer.pf-m-inline.pf-m-expanded > .pf-c-drawer__main > .pf-c-drawer__panel {\n margin-left: 0;\n transform: translateX(0); }\n .pf-c-drawer.pf-m-inline > .pf-c-drawer__main > .pf-c-drawer__panel > .pf-c-drawer__body > .pf-c-drawer__head .pf-c-drawer__close {\n display: unset;\n visibility: visible; }\n .pf-c-drawer.pf-m-inline.pf-m-panel-left > .pf-c-drawer__main > .pf-c-drawer__panel {\n margin-right: calc(var(--pf-c-drawer__panel--FlexBasis) * -1);\n margin-left: 0;\n transform: translateX(-100%); }\n .pf-c-drawer.pf-m-inline.pf-m-panel-left.pf-m-expanded > .pf-c-drawer__main > .pf-c-drawer__panel {\n margin-right: 0;\n transform: translateX(0); }\n .pf-c-drawer.pf-m-inline.pf-m-panel-left > .pf-c-drawer__main > .pf-c-drawer__panel > .pf-c-drawer__body > .pf-c-drawer__head .pf-c-drawer__close {\n display: unset;\n visibility: visible; }\n .pf-c-drawer.pf-m-static > .pf-c-drawer__main > .pf-c-drawer__panel {\n transform: translateX(0); }\n .pf-c-drawer.pf-m-static.pf-m-panel-left > .pf-c-drawer__main > .pf-c-drawer__panel {\n margin-right: 0;\n transform: translateX(0); }\n .pf-c-drawer.pf-m-static.pf-m-panel-bottom > .pf-c-drawer__main > .pf-c-drawer__panel {\n transform: translateX(0); }\n .pf-c-drawer.pf-m-static > .pf-c-drawer__main > .pf-c-drawer__panel > .pf-c-drawer__body > .pf-c-drawer__head .pf-c-drawer__close {\n display: none;\n visibility: hidden; } }\n\n@media (min-width: 992px) {\n .pf-c-drawer.pf-m-inline-on-lg > .pf-c-drawer__main > .pf-c-drawer__content,\n .pf-c-drawer.pf-m-static-on-lg > .pf-c-drawer__main > .pf-c-drawer__content {\n flex-shrink: 1; }\n .pf-c-drawer.pf-m-inline-on-lg > .pf-c-drawer__main > .pf-c-drawer__panel,\n .pf-c-drawer.pf-m-static-on-lg > .pf-c-drawer__main > .pf-c-drawer__panel {\n --pf-c-drawer--m-expanded__panel--BoxShadow: none; }\n .pf-c-drawer.pf-m-inline-on-lg > .pf-c-drawer__main > .pf-c-drawer__panel:not(.pf-m-no-border)::after,\n .pf-c-drawer.pf-m-static-on-lg > .pf-c-drawer__main > .pf-c-drawer__panel:not(.pf-m-no-border)::after {\n background-color: var(--pf-c-drawer--m-inline--m-expanded__panel--after--BackgroundColor); }\n .pf-c-drawer.pf-m-inline-on-lg > .pf-c-drawer__main > .pf-c-drawer__content {\n overflow-x: auto; }\n .pf-c-drawer.pf-m-inline-on-lg > .pf-c-drawer__main > .pf-c-drawer__panel {\n margin-left: calc(var(--pf-c-drawer__panel--FlexBasis) * -1);\n transform: translateX(100%); }\n .pf-c-drawer.pf-m-inline-on-lg.pf-m-expanded > .pf-c-drawer__main > .pf-c-drawer__panel {\n margin-left: 0;\n transform: translateX(0); }\n .pf-c-drawer.pf-m-inline-on-lg > .pf-c-drawer__main > .pf-c-drawer__panel > .pf-c-drawer__body > .pf-c-drawer__head .pf-c-drawer__close {\n display: unset;\n visibility: visible; }\n .pf-c-drawer.pf-m-inline-on-lg.pf-m-panel-left > .pf-c-drawer__main > .pf-c-drawer__panel {\n margin-right: calc(var(--pf-c-drawer__panel--FlexBasis) * -1);\n margin-left: 0;\n transform: translateX(-100%); }\n .pf-c-drawer.pf-m-inline-on-lg.pf-m-panel-left.pf-m-expanded > .pf-c-drawer__main > .pf-c-drawer__panel {\n margin-right: 0;\n transform: translateX(0); }\n .pf-c-drawer.pf-m-inline-on-lg.pf-m-panel-left > .pf-c-drawer__main > .pf-c-drawer__panel > .pf-c-drawer__body > .pf-c-drawer__head .pf-c-drawer__close {\n display: unset;\n visibility: visible; }\n .pf-c-drawer.pf-m-static-on-lg > .pf-c-drawer__main > .pf-c-drawer__panel {\n transform: translateX(0); }\n .pf-c-drawer.pf-m-static-on-lg.pf-m-panel-left > .pf-c-drawer__main > .pf-c-drawer__panel {\n margin-right: 0;\n transform: translateX(0); }\n .pf-c-drawer.pf-m-static-on-lg.pf-m-panel-bottom > .pf-c-drawer__main > .pf-c-drawer__panel {\n transform: translateX(0); }\n .pf-c-drawer.pf-m-static-on-lg > .pf-c-drawer__main > .pf-c-drawer__panel > .pf-c-drawer__body > .pf-c-drawer__head .pf-c-drawer__close {\n display: none;\n visibility: hidden; } }\n\n@media (min-width: 1200px) {\n .pf-c-drawer.pf-m-inline-on-xl > .pf-c-drawer__main > .pf-c-drawer__content,\n .pf-c-drawer.pf-m-static-on-xl > .pf-c-drawer__main > .pf-c-drawer__content {\n flex-shrink: 1; }\n .pf-c-drawer.pf-m-inline-on-xl > .pf-c-drawer__main > .pf-c-drawer__panel,\n .pf-c-drawer.pf-m-static-on-xl > .pf-c-drawer__main > .pf-c-drawer__panel {\n --pf-c-drawer--m-expanded__panel--BoxShadow: none; }\n .pf-c-drawer.pf-m-inline-on-xl > .pf-c-drawer__main > .pf-c-drawer__panel:not(.pf-m-no-border)::after,\n .pf-c-drawer.pf-m-static-on-xl > .pf-c-drawer__main > .pf-c-drawer__panel:not(.pf-m-no-border)::after {\n background-color: var(--pf-c-drawer--m-inline--m-expanded__panel--after--BackgroundColor); }\n .pf-c-drawer.pf-m-inline-on-xl > .pf-c-drawer__main > .pf-c-drawer__content {\n overflow-x: auto; }\n .pf-c-drawer.pf-m-inline-on-xl > .pf-c-drawer__main > .pf-c-drawer__panel {\n margin-left: calc(var(--pf-c-drawer__panel--FlexBasis) * -1);\n transform: translateX(100%); }\n .pf-c-drawer.pf-m-inline-on-xl.pf-m-expanded > .pf-c-drawer__main > .pf-c-drawer__panel {\n margin-left: 0;\n transform: translateX(0); }\n .pf-c-drawer.pf-m-inline-on-xl > .pf-c-drawer__main > .pf-c-drawer__panel > .pf-c-drawer__body > .pf-c-drawer__head .pf-c-drawer__close {\n display: unset;\n visibility: visible; }\n .pf-c-drawer.pf-m-inline-on-xl.pf-m-panel-left > .pf-c-drawer__main > .pf-c-drawer__panel {\n margin-right: calc(var(--pf-c-drawer__panel--FlexBasis) * -1);\n margin-left: 0;\n transform: translateX(-100%); }\n .pf-c-drawer.pf-m-inline-on-xl.pf-m-panel-left.pf-m-expanded > .pf-c-drawer__main > .pf-c-drawer__panel {\n margin-right: 0;\n transform: translateX(0); }\n .pf-c-drawer.pf-m-inline-on-xl.pf-m-panel-left > .pf-c-drawer__main > .pf-c-drawer__panel > .pf-c-drawer__body > .pf-c-drawer__head .pf-c-drawer__close {\n display: unset;\n visibility: visible; }\n .pf-c-drawer.pf-m-static-on-xl > .pf-c-drawer__main > .pf-c-drawer__panel {\n transform: translateX(0); }\n .pf-c-drawer.pf-m-static-on-xl.pf-m-panel-left > .pf-c-drawer__main > .pf-c-drawer__panel {\n margin-right: 0;\n transform: translateX(0); }\n .pf-c-drawer.pf-m-static-on-xl.pf-m-panel-bottom > .pf-c-drawer__main > .pf-c-drawer__panel {\n transform: translateX(0); }\n .pf-c-drawer.pf-m-static-on-xl > .pf-c-drawer__main > .pf-c-drawer__panel > .pf-c-drawer__body > .pf-c-drawer__head .pf-c-drawer__close {\n display: none;\n visibility: hidden; } }\n\n@media (min-width: 1450px) {\n .pf-c-drawer.pf-m-inline-on-2xl > .pf-c-drawer__main > .pf-c-drawer__content,\n .pf-c-drawer.pf-m-static-on-2xl > .pf-c-drawer__main > .pf-c-drawer__content {\n flex-shrink: 1; }\n .pf-c-drawer.pf-m-inline-on-2xl > .pf-c-drawer__main > .pf-c-drawer__panel,\n .pf-c-drawer.pf-m-static-on-2xl > .pf-c-drawer__main > .pf-c-drawer__panel {\n --pf-c-drawer--m-expanded__panel--BoxShadow: none; }\n .pf-c-drawer.pf-m-inline-on-2xl > .pf-c-drawer__main > .pf-c-drawer__panel:not(.pf-m-no-border)::after,\n .pf-c-drawer.pf-m-static-on-2xl > .pf-c-drawer__main > .pf-c-drawer__panel:not(.pf-m-no-border)::after {\n background-color: var(--pf-c-drawer--m-inline--m-expanded__panel--after--BackgroundColor); }\n .pf-c-drawer.pf-m-inline-on-2xl > .pf-c-drawer__main > .pf-c-drawer__content {\n overflow-x: auto; }\n .pf-c-drawer.pf-m-inline-on-2xl > .pf-c-drawer__main > .pf-c-drawer__panel {\n margin-left: calc(var(--pf-c-drawer__panel--FlexBasis) * -1);\n transform: translateX(100%); }\n .pf-c-drawer.pf-m-inline-on-2xl.pf-m-expanded > .pf-c-drawer__main > .pf-c-drawer__panel {\n margin-left: 0;\n transform: translateX(0); }\n .pf-c-drawer.pf-m-inline-on-2xl > .pf-c-drawer__main > .pf-c-drawer__panel > .pf-c-drawer__body > .pf-c-drawer__head .pf-c-drawer__close {\n display: unset;\n visibility: visible; }\n .pf-c-drawer.pf-m-inline-on-2xl.pf-m-panel-left > .pf-c-drawer__main > .pf-c-drawer__panel {\n margin-right: calc(var(--pf-c-drawer__panel--FlexBasis) * -1);\n margin-left: 0;\n transform: translateX(-100%); }\n .pf-c-drawer.pf-m-inline-on-2xl.pf-m-panel-left.pf-m-expanded > .pf-c-drawer__main > .pf-c-drawer__panel {\n margin-right: 0;\n transform: translateX(0); }\n .pf-c-drawer.pf-m-inline-on-2xl.pf-m-panel-left > .pf-c-drawer__main > .pf-c-drawer__panel > .pf-c-drawer__body > .pf-c-drawer__head .pf-c-drawer__close {\n display: unset;\n visibility: visible; }\n .pf-c-drawer.pf-m-static-on-2xl > .pf-c-drawer__main > .pf-c-drawer__panel {\n transform: translateX(0); }\n .pf-c-drawer.pf-m-static-on-2xl.pf-m-panel-left > .pf-c-drawer__main > .pf-c-drawer__panel {\n margin-right: 0;\n transform: translateX(0); }\n .pf-c-drawer.pf-m-static-on-2xl.pf-m-panel-bottom > .pf-c-drawer__main > .pf-c-drawer__panel {\n transform: translateX(0); }\n .pf-c-drawer.pf-m-static-on-2xl > .pf-c-drawer__main > .pf-c-drawer__panel > .pf-c-drawer__body > .pf-c-drawer__head .pf-c-drawer__close {\n display: none;\n visibility: hidden; } }\n\n.pf-c-dropdown {\n --pf-c-dropdown__toggle--PaddingTop: var(--pf-global--spacer--form-element);\n --pf-c-dropdown__toggle--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-dropdown__toggle--PaddingBottom: var(--pf-global--spacer--form-element);\n --pf-c-dropdown__toggle--PaddingLeft: var(--pf-global--spacer--sm);\n --pf-c-dropdown__toggle--MinWidth: var(--pf-global--target-size--MinWidth);\n --pf-c-dropdown__toggle--FontSize: var(--pf-global--FontSize--md);\n --pf-c-dropdown__toggle--FontWeight: var(--pf-global--FontWeight--normal);\n --pf-c-dropdown__toggle--Color: var(--pf-global--Color--100);\n --pf-c-dropdown__toggle--LineHeight: var(--pf-global--LineHeight--md);\n --pf-c-dropdown__toggle--BackgroundColor: transparent;\n --pf-c-dropdown__toggle--before--BorderWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-dropdown__toggle--before--BorderTopColor: var(--pf-global--BorderColor--300);\n --pf-c-dropdown__toggle--before--BorderRightColor: var(--pf-global--BorderColor--300);\n --pf-c-dropdown__toggle--before--BorderBottomColor: var(--pf-global--BorderColor--200);\n --pf-c-dropdown__toggle--before--BorderLeftColor: var(--pf-global--BorderColor--300);\n --pf-c-dropdown__toggle--hover--before--BorderBottomColor: var(--pf-global--active-color--100);\n --pf-c-dropdown__toggle--active--before--BorderBottomWidth: var(--pf-global--BorderWidth--md);\n --pf-c-dropdown__toggle--active--before--BorderBottomColor: var(--pf-global--active-color--100);\n --pf-c-dropdown__toggle--focus--before--BorderBottomWidth: var(--pf-global--BorderWidth--md);\n --pf-c-dropdown__toggle--focus--before--BorderBottomColor: var(--pf-global--active-color--100);\n --pf-c-dropdown--m-expanded__toggle--before--BorderBottomWidth: var(--pf-global--BorderWidth--md);\n --pf-c-dropdown--m-expanded__toggle--before--BorderBottomColor: var(--pf-global--active-color--100);\n --pf-c-dropdown__toggle--disabled--BackgroundColor: var(--pf-global--disabled-color--300);\n --pf-c-dropdown__toggle--m-plain--Color: var(--pf-global--Color--200);\n --pf-c-dropdown__toggle--m-plain--hover--Color: var(--pf-global--Color--100);\n --pf-c-dropdown__toggle--m-plain--disabled--Color: var(--pf-global--disabled-color--200);\n --pf-c-dropdown__toggle--m-plain--child--LineHeight: normal;\n --pf-c-dropdown__toggle--m-primary--Color: var(--pf-global--Color--light-100);\n --pf-c-dropdown__toggle--m-primary--BorderRadius: var(--pf-global--BorderRadius--sm);\n --pf-c-dropdown__toggle--m-primary--BackgroundColor: var(--pf-global--primary-color--100);\n --pf-c-dropdown__toggle--m-primary--hover--BackgroundColor: var(--pf-global--primary-color--200);\n --pf-c-dropdown__toggle--m-primary--active--BackgroundColor: var(--pf-global--primary-color--200);\n --pf-c-dropdown__toggle--m-primary--focus--BackgroundColor: var(--pf-global--primary-color--200);\n --pf-c-dropdown--m-expanded__toggle--m-primary--BackgroundColor: var(--pf-global--primary-color--200);\n --pf-c-dropdown__toggle-button--Color: var(--pf-global--Color--100);\n --pf-c-dropdown__toggle--m-split-button--child--PaddingTop: var(--pf-global--spacer--form-element);\n --pf-c-dropdown__toggle--m-split-button--child--PaddingRight: var(--pf-global--spacer--xs);\n --pf-c-dropdown__toggle--m-split-button--child--PaddingBottom: var(--pf-global--spacer--form-element);\n --pf-c-dropdown__toggle--m-split-button--child--PaddingLeft: var(--pf-global--spacer--xs);\n --pf-c-dropdown__toggle--m-split-button--child--BackgroundColor: transparent;\n --pf-c-dropdown__toggle--m-split-button--first-child--PaddingLeft: var(--pf-global--spacer--sm);\n --pf-c-dropdown__toggle--m-split-button--last-child--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-dropdown__toggle--m-split-button--m-action--child--PaddingLeft: var(--pf-global--spacer--sm);\n --pf-c-dropdown__toggle--m-split-button--m-action--child--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-dropdown__toggle--m-split-button--m-action__toggle-button--MarginRight: calc(-1 * var(--pf-global--BorderWidth--sm));\n --pf-c-dropdown__toggle--m-split-button__toggle-check__input--TranslateY: -0.0625rem;\n --pf-c-dropdown__toggle--m-split-button__toggle-text--MarginLeft: var(--pf-global--spacer--sm);\n --pf-c-dropdown__toggle-icon--LineHeight: var(--pf-global--LineHeight--md);\n --pf-c-dropdown__toggle-icon--MarginRight: var(--pf-global--spacer--sm);\n --pf-c-dropdown__toggle-icon--MarginLeft: var(--pf-global--spacer--md);\n --pf-c-dropdown--m-top--m-expanded__toggle-icon--Rotate: 180deg;\n --pf-c-dropdown__menu--BackgroundColor: var(--pf-global--BackgroundColor--light-100);\n --pf-c-dropdown__menu--BoxShadow: var(--pf-global--BoxShadow--md);\n --pf-c-dropdown__menu--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-dropdown__menu--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-dropdown__menu--Top: calc(100% + var(--pf-global--spacer--xs));\n --pf-c-dropdown__menu--ZIndex: var(--pf-global--ZIndex--sm);\n --pf-c-dropdown--m-top__menu--Top: 0;\n --pf-c-dropdown--m-top__menu--TranslateY: calc(-100% - var(--pf-global--spacer--xs));\n --pf-c-dropdown__menu-item--BackgroundColor: transparent;\n --pf-c-dropdown__menu-item--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-dropdown__menu-item--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-dropdown__menu-item--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-dropdown__menu-item--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-dropdown__menu-item--FontSize: var(--pf-global--FontSize--md);\n --pf-c-dropdown__menu-item--FontWeight: var(--pf-global--FontWeight--normal);\n --pf-c-dropdown__menu-item--LineHeight: var(--pf-global--LineHeight--md);\n --pf-c-dropdown__menu-item--Color: var(--pf-global--Color--dark-100);\n --pf-c-dropdown__menu-item--hover--Color: var(--pf-global--Color--dark-100);\n --pf-c-dropdown__menu-item--disabled--Color: var(--pf-global--Color--dark-200);\n --pf-c-dropdown__menu-item--hover--BackgroundColor: var(--pf-global--BackgroundColor--light-300);\n --pf-c-dropdown__menu-item--disabled--BackgroundColor: transparent;\n --pf-c-dropdown__menu-item--m-text--Color: var(--pf-global--Color--dark-200);\n --pf-c-dropdown__menu-item-icon--MarginRight: var(--pf-global--spacer--sm);\n --pf-c-dropdown__menu-item-icon--Width: var(--pf-global--icon--FontSize--lg);\n --pf-c-dropdown__menu-item-icon--Height: var(--pf-global--icon--FontSize--lg);\n --pf-c-dropdown__menu-item-description--FontSize: var(--pf-global--FontSize--xs);\n --pf-c-dropdown__menu-item-description--Color: var(--pf-global--Color--dark-200);\n --pf-c-dropdown__group--group--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-dropdown__group-title--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-dropdown__group-title--PaddingRight: var(--pf-c-dropdown__menu-item--PaddingRight);\n --pf-c-dropdown__group-title--PaddingBottom: var(--pf-c-dropdown__menu-item--PaddingBottom);\n --pf-c-dropdown__group-title--PaddingLeft: var(--pf-c-dropdown__menu-item--PaddingLeft);\n --pf-c-dropdown__group-title--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-dropdown__group-title--FontWeight: var(--pf-global--FontWeight--semi-bold);\n --pf-c-dropdown__group-title--Color: var(--pf-global--Color--dark-200);\n --pf-c-dropdown__toggle-image--MarginTop: var(--pf-global--spacer--xs);\n --pf-c-dropdown__toggle-image--MarginBottom: var(--pf-global--spacer--xs);\n --pf-c-dropdown__toggle-image--MarginRight: var(--pf-global--spacer--sm);\n --pf-c-dropdown--c-divider--MarginTop: var(--pf-global--spacer--sm);\n --pf-c-dropdown--c-divider--MarginBottom: var(--pf-global--spacer--sm);\n position: relative;\n display: inline-block;\n max-width: 100%; }\n .pf-c-dropdown .pf-c-divider {\n margin-top: var(--pf-c-dropdown--c-divider--MarginTop);\n margin-bottom: var(--pf-c-dropdown--c-divider--MarginBottom); }\n .pf-c-dropdown .pf-c-divider:last-child {\n --pf-c-dropdown--c-divider--MarginBottom: 0; }\n\n.pf-c-dropdown__toggle {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: space-between;\n min-width: var(--pf-c-dropdown__toggle--MinWidth);\n max-width: 100%;\n padding: var(--pf-c-dropdown__toggle--PaddingTop) var(--pf-c-dropdown__toggle--PaddingRight) var(--pf-c-dropdown__toggle--PaddingBottom) var(--pf-c-dropdown__toggle--PaddingLeft);\n font-size: var(--pf-c-dropdown__toggle--FontSize);\n font-weight: var(--pf-c-dropdown__toggle--FontWeight);\n line-height: var(--pf-c-dropdown__toggle--LineHeight);\n color: var(--pf-c-dropdown__toggle--Color);\n background-color: var(--pf-c-dropdown__toggle--BackgroundColor);\n border: none; }\n .pf-c-dropdown__toggle::before,\n .pf-c-dropdown__toggle.pf-m-action .pf-c-dropdown__toggle-button::before {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n content: \"\";\n border: var(--pf-c-dropdown__toggle--before--BorderWidth) solid;\n border-color: var(--pf-c-dropdown__toggle--before--BorderTopColor) var(--pf-c-dropdown__toggle--before--BorderRightColor) var(--pf-c-dropdown__toggle--before--BorderBottomColor) var(--pf-c-dropdown__toggle--before--BorderLeftColor); }\n .pf-c-dropdown__toggle.pf-m-disabled, .pf-c-dropdown__toggle:disabled {\n pointer-events: none; }\n .pf-c-dropdown__toggle.pf-m-disabled:not(.pf-m-plain), .pf-c-dropdown__toggle:disabled:not(.pf-m-plain) {\n --pf-c-dropdown__toggle--BackgroundColor: var(--pf-c-dropdown__toggle--disabled--BackgroundColor); }\n .pf-c-dropdown__toggle.pf-m-disabled:not(.pf-m-plain)::before, .pf-c-dropdown__toggle:disabled:not(.pf-m-plain)::before {\n border: 0; }\n .pf-c-dropdown__toggle.pf-m-split-button {\n padding: 0; }\n .pf-c-dropdown__toggle.pf-m-split-button > * {\n position: relative;\n padding-top: var(--pf-c-dropdown__toggle--m-split-button--child--PaddingTop);\n padding-right: var(--pf-c-dropdown__toggle--m-split-button--child--PaddingRight);\n padding-bottom: var(--pf-c-dropdown__toggle--m-split-button--child--PaddingBottom);\n padding-left: var(--pf-c-dropdown__toggle--m-split-button--child--PaddingLeft);\n background-color: var(--pf-c-dropdown__toggle--m-split-button--child--BackgroundColor); }\n .pf-c-dropdown__toggle.pf-m-split-button > *:first-child {\n --pf-c-dropdown__toggle--m-split-button--child--PaddingLeft: var(--pf-c-dropdown__toggle--m-split-button--first-child--PaddingLeft); }\n .pf-c-dropdown__toggle.pf-m-split-button > *:last-child {\n --pf-c-dropdown__toggle--m-split-button--child--PaddingRight: var(--pf-c-dropdown__toggle--m-split-button--last-child--PaddingRight); }\n .pf-c-dropdown__toggle.pf-m-split-button.pf-m-action {\n --pf-c-dropdown__toggle--m-split-button--child--PaddingRight: var(--pf-c-dropdown__toggle--m-split-button--m-action--child--PaddingRight);\n --pf-c-dropdown__toggle--m-split-button--child--PaddingLeft: var(--pf-c-dropdown__toggle--m-split-button--m-action--child--PaddingLeft); }\n .pf-c-dropdown__toggle.pf-m-split-button.pf-m-action .pf-c-dropdown__toggle-button {\n margin-right: var(--pf-c-dropdown__toggle--m-split-button--m-action__toggle-button--MarginRight); }\n .pf-c-dropdown__toggle.pf-m-split-button.pf-m-action .pf-c-dropdown__toggle-button::before {\n border-left: 0; }\n .pf-c-dropdown__toggle.pf-m-split-button.pf-m-action .pf-c-dropdown__toggle-button:last-child {\n --pf-c-dropdown__toggle--m-split-button--m-action__toggle-button--MarginRight: 0; }\n .pf-c-dropdown__toggle.pf-m-split-button .pf-c-dropdown__toggle-check {\n display: flex;\n align-items: center;\n cursor: pointer; }\n .pf-c-dropdown__toggle.pf-m-split-button .pf-c-dropdown__toggle-check input {\n transform: translateY(var(--pf-c-dropdown__toggle--m-split-button__toggle-check__input--TranslateY)); }\n .pf-c-dropdown__toggle.pf-m-split-button .pf-c-dropdown__toggle-button {\n color: var(--pf-c-dropdown__toggle-button--Color);\n border: 0; }\n .pf-c-dropdown__toggle.pf-m-split-button .pf-c-dropdown__toggle-text {\n margin-left: var(--pf-c-dropdown__toggle--m-split-button__toggle-text--MarginLeft); }\n .pf-c-dropdown__toggle:not(.pf-m-action):hover::before,\n .pf-c-dropdown__toggle.pf-m-action .pf-c-dropdown__toggle-button:hover::before {\n --pf-c-dropdown__toggle--before--BorderBottomColor: var(--pf-c-dropdown__toggle--hover--before--BorderBottomColor); }\n .pf-c-dropdown__toggle:not(.pf-m-action):active::before, .pf-c-dropdown__toggle:not(.pf-m-action).pf-m-active::before,\n .pf-c-dropdown__toggle.pf-m-action .pf-c-dropdown__toggle-button:active::before {\n --pf-c-dropdown__toggle--before--BorderBottomColor: var(--pf-c-dropdown__toggle--active--before--BorderBottomColor);\n border-bottom-width: var(--pf-c-dropdown__toggle--active--before--BorderBottomWidth); }\n .pf-c-dropdown__toggle:not(.pf-m-action):focus::before,\n .pf-c-dropdown__toggle.pf-m-action .pf-c-dropdown__toggle-button:focus::before {\n --pf-c-dropdown__toggle--before--BorderBottomColor: var(--pf-c-dropdown__toggle--focus--before--BorderBottomColor);\n border-bottom-width: var(--pf-c-dropdown__toggle--focus--before--BorderBottomWidth); }\n .pf-m-expanded > .pf-c-dropdown__toggle:not(.pf-m-action)::before,\n .pf-m-expanded > .pf-c-dropdown__toggle.pf-m-action .pf-c-dropdown__toggle-button::before {\n --pf-c-dropdown__toggle--before--BorderBottomColor: var(--pf-c-dropdown--m-expanded__toggle--before--BorderBottomColor);\n border-bottom-width: var(--pf-c-dropdown--m-expanded__toggle--before--BorderBottomWidth); }\n .pf-c-dropdown__toggle.pf-m-plain {\n display: inline-block;\n color: var(--pf-c-dropdown__toggle--m-plain--Color); }\n .pf-c-dropdown__toggle.pf-m-plain > * {\n line-height: var(--pf-c-dropdown__toggle--m-plain--child--LineHeight); }\n .pf-c-dropdown__toggle.pf-m-plain::before {\n border: 0; }\n .pf-c-dropdown__toggle.pf-m-plain:hover, .pf-c-dropdown__toggle.pf-m-plain:active, .pf-c-dropdown__toggle.pf-m-plain.pf-m-active, .pf-c-dropdown__toggle.pf-m-plain:focus,\n .pf-m-expanded > .pf-c-dropdown__toggle.pf-m-plain {\n --pf-c-dropdown__toggle--m-plain--Color: var(--pf-c-dropdown__toggle--m-plain--hover--Color); }\n .pf-c-dropdown__toggle.pf-m-plain.pf-m-disabled, .pf-c-dropdown__toggle.pf-m-plain:disabled {\n --pf-c-dropdown__toggle--m-plain--Color: var(--pf-c-dropdown__toggle--m-plain--disabled--Color); }\n .pf-c-dropdown__toggle.pf-m-primary {\n --pf-c-dropdown__toggle--Color: var(--pf-c-dropdown__toggle--m-primary--Color);\n --pf-c-dropdown__toggle--BackgroundColor: var(--pf-c-dropdown__toggle--m-primary--BackgroundColor);\n border-radius: var(--pf-c-dropdown__toggle--m-primary--BorderRadius); }\n .pf-c-dropdown__toggle.pf-m-primary::before {\n border: 0; }\n .pf-c-dropdown__toggle.pf-m-primary:hover {\n --pf-c-dropdown__toggle--BackgroundColor: var(--pf-c-dropdown__toggle--m-primary--hover--BackgroundColor); }\n .pf-c-dropdown__toggle.pf-m-primary:active, .pf-c-dropdown__toggle.pf-m-primary.pf-m-active {\n --pf-c-dropdown__toggle--BackgroundColor: var(--pf-c-dropdown__toggle--m-primary--active--BackgroundColor); }\n .pf-c-dropdown__toggle.pf-m-primary:focus {\n --pf-c-dropdown__toggle--BackgroundColor: var(--pf-c-dropdown__toggle--m-primary--focus--BackgroundColor); }\n .pf-m-expanded > .pf-c-dropdown__toggle.pf-m-primary {\n --pf-c-dropdown__toggle--BackgroundColor: var(--pf-c-dropdown--m-expanded__toggle--m-primary--BackgroundColor); }\n .pf-c-dropdown__toggle .pf-c-dropdown__toggle-text {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap; }\n\n.pf-c-dropdown__toggle-icon {\n margin-right: var(--pf-c-dropdown__toggle-icon--MarginRight);\n margin-left: var(--pf-c-dropdown__toggle-icon--MarginLeft);\n line-height: var(--pf-c-dropdown__toggle-icon--LineHeight); }\n .pf-c-dropdown.pf-m-top.pf-m-expanded .pf-c-dropdown__toggle-icon {\n transform: rotate(var(--pf-c-dropdown--m-top--m-expanded__toggle-icon--Rotate)); }\n\n.pf-c-dropdown__toggle-image {\n display: inline-flex;\n margin-top: var(--pf-c-dropdown__toggle-image--MarginTop);\n margin-right: var(--pf-c-dropdown__toggle-image--MarginRight);\n margin-bottom: var(--pf-c-dropdown__toggle-image--MarginBottom); }\n .pf-c-dropdown__toggle-image:last-child {\n --pf-c-dropdown__toggle-image--MarginRight: 0; }\n\n.pf-c-dropdown__menu {\n position: absolute;\n top: var(--pf-c-dropdown__menu--Top);\n z-index: var(--pf-c-dropdown__menu--ZIndex);\n min-width: 100%;\n padding-top: var(--pf-c-dropdown__menu--PaddingTop);\n padding-bottom: var(--pf-c-dropdown__menu--PaddingBottom);\n background: var(--pf-c-dropdown__menu--BackgroundColor);\n background-clip: padding-box;\n box-shadow: var(--pf-c-dropdown__menu--BoxShadow); }\n .pf-c-dropdown__menu.pf-m-align-right {\n right: 0; }\n .pf-c-dropdown.pf-m-top .pf-c-dropdown__menu {\n --pf-c-dropdown__menu--Top: var(--pf-c-dropdown--m-top__menu--Top);\n transform: translateY(var(--pf-c-dropdown--m-top__menu--TranslateY)); }\n\n.pf-c-dropdown__menu-item {\n display: block;\n width: 100%;\n padding: var(--pf-c-dropdown__menu-item--PaddingTop) var(--pf-c-dropdown__menu-item--PaddingRight) var(--pf-c-dropdown__menu-item--PaddingBottom) var(--pf-c-dropdown__menu-item--PaddingLeft);\n font-size: var(--pf-c-dropdown__menu-item--FontSize);\n font-weight: var(--pf-c-dropdown__menu-item--FontWeight);\n line-height: var(--pf-c-dropdown__menu-item--LineHeight);\n color: var(--pf-c-dropdown__menu-item--Color);\n text-align: left;\n white-space: nowrap;\n background-color: var(--pf-c-dropdown__menu-item--BackgroundColor);\n border: none; }\n .pf-c-dropdown__menu-item:hover, .pf-c-dropdown__menu-item:focus {\n --pf-c-dropdown__menu-item--Color: var(--pf-c-dropdown__menu-item--hover--Color);\n --pf-c-dropdown__menu-item--BackgroundColor: var(--pf-c-dropdown__menu-item--hover--BackgroundColor);\n text-decoration: none; }\n .pf-c-dropdown__menu-item:disabled, .pf-c-dropdown__menu-item.pf-m-disabled {\n --pf-c-dropdown__menu-item--Color: var(--pf-c-dropdown__menu-item--disabled--Color);\n --pf-c-dropdown__menu-item--BackgroundColor: var(--pf-c-dropdown__menu-item--disabled--BackgroundColor);\n pointer-events: none; }\n .pf-c-dropdown__menu-item.pf-m-icon {\n display: flex;\n align-items: center; }\n .pf-c-dropdown__menu-item.pf-m-icon.pf-m-description {\n flex-direction: column;\n align-items: start; }\n .pf-c-dropdown__menu-item.pf-m-icon .pf-c-dropdown__menu-item-main {\n display: flex;\n align-items: center; }\n .pf-c-dropdown__menu-item.pf-m-text {\n --pf-c-dropdown__menu-item--Color: var(--pf-c-dropdown__menu-item--m-text--Color); }\n .pf-c-dropdown__menu-item.pf-m-text:hover, .pf-c-dropdown__menu-item.pf-m-text:focus {\n --pf-c-dropdown__menu-item--BackgroundColor: transparent; }\n\n.pf-c-dropdown__menu-item-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--pf-c-dropdown__menu-item-icon--Width);\n height: var(--pf-c-dropdown__menu-item-icon--Height);\n margin-right: var(--pf-c-dropdown__menu-item-icon--MarginRight); }\n .pf-c-dropdown__menu-item-icon > * {\n max-width: 100%;\n max-height: 100%; }\n\n.pf-c-dropdown__menu-item-description {\n font-size: var(--pf-c-dropdown__menu-item-description--FontSize);\n color: var(--pf-c-dropdown__menu-item-description--Color); }\n\n.pf-c-dropdown__group + .pf-c-dropdown__group {\n padding-top: var(--pf-c-dropdown__group--group--PaddingTop); }\n\n.pf-c-dropdown__group-title {\n padding-top: var(--pf-c-dropdown__group-title--PaddingTop);\n padding-right: var(--pf-c-dropdown__group-title--PaddingRight);\n padding-bottom: var(--pf-c-dropdown__group-title--PaddingBottom);\n padding-left: var(--pf-c-dropdown__group-title--PaddingLeft);\n font-size: var(--pf-c-dropdown__group-title--FontSize);\n font-weight: var(--pf-c-dropdown__group-title--FontWeight);\n color: var(--pf-c-dropdown__group-title--Color); }\n\n.pf-c-empty-state {\n --pf-c-empty-state--PaddingTop: var(--pf-global--spacer--xl);\n --pf-c-empty-state--PaddingRight: var(--pf-global--spacer--xl);\n --pf-c-empty-state--PaddingBottom: var(--pf-global--spacer--xl);\n --pf-c-empty-state--PaddingLeft: var(--pf-global--spacer--xl);\n --pf-c-empty-state__content--MaxWidth: none;\n --pf-c-empty-state__icon--MarginBottom: var(--pf-global--spacer--lg);\n --pf-c-empty-state__icon--FontSize: var(--pf-global--icon--FontSize--xl);\n --pf-c-empty-state__icon--Color: var(--pf-global--icon--Color--light);\n --pf-c-empty-state__content--c-title--m-lg--FontSize: var(--pf-global--FontSize--xl);\n --pf-c-empty-state__body--MarginTop: var(--pf-global--spacer--md);\n --pf-c-empty-state__body--Color: var(--pf-global--Color--200);\n --pf-c-empty-state__primary--MarginTop: var(--pf-global--spacer--xl);\n --pf-c-empty-state__primary--secondary--MarginTop: var(--pf-global--spacer--sm);\n --pf-c-empty-state__secondary--MarginTop: var(--pf-global--spacer--xl);\n --pf-c-empty-state__secondary--MarginBottom: calc(var(--pf-global--spacer--xs) * -1);\n --pf-c-empty-state__secondary--child--MarginRight: calc(var(--pf-global--spacer--xs) / 2);\n --pf-c-empty-state__secondary--child--MarginBottom: var(--pf-global--spacer--xs);\n --pf-c-empty-state__secondary--child--MarginLeft: calc(var(--pf-global--spacer--xs) / 2);\n --pf-c-empty-state--m-xs__content--MaxWidth: 21.875rem;\n --pf-c-empty-state--m-xs__body--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-empty-state--m-xs--button--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-empty-state--m-xs--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-empty-state--m-xs--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-empty-state--m-xs--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-empty-state--m-xs--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-empty-state--m-xs__icon--MarginBottom: var(--pf-global--spacer--md);\n --pf-c-empty-state--m-xs__body--MarginTop: var(--pf-global--spacer--md);\n --pf-c-empty-state--m-xs__primary--MarginTop: var(--pf-global--spacer--md);\n --pf-c-empty-state--m-xs__secondary--MarginTop: var(--pf-global--spacer--md);\n --pf-c-empty-state--m-sm__content--MaxWidth: 25rem;\n --pf-c-empty-state--m-lg__content--MaxWidth: 37.5rem;\n --pf-c-empty-state--m-xl__body--FontSize: var(--pf-global--FontSize--xl);\n --pf-c-empty-state--m-xl__body--MarginTop: var(--pf-global--spacer--lg);\n --pf-c-empty-state--m-xl__icon--MarginBottom: var(--pf-global--spacer--xl);\n --pf-c-empty-state--m-xl__icon--FontSize: 6.25rem;\n --pf-c-empty-state--m-xl--c-button__secondary--MarginTop: var(--pf-global--spacer--md);\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--pf-c-empty-state--PaddingTop) var(--pf-c-empty-state--PaddingRight) var(--pf-c-empty-state--PaddingBottom) var(--pf-c-empty-state--PaddingLeft);\n text-align: center; }\n .pf-c-empty-state.pf-m-xs {\n --pf-c-empty-state--PaddingTop: var(--pf-c-empty-state--m-xs--PaddingTop);\n --pf-c-empty-state--PaddingRight: var(--pf-c-empty-state--m-xs--PaddingRight);\n --pf-c-empty-state--PaddingBottom: var(--pf-c-empty-state--m-xs--PaddingBottom);\n --pf-c-empty-state--PaddingLeft: var(--pf-c-empty-state--m-xs--PaddingLeft);\n --pf-c-empty-state__content--MaxWidth: var(--pf-c-empty-state--m-xs__content--MaxWidth);\n --pf-c-empty-state__icon--MarginBottom: var(--pf-c-empty-state--m-xs__icon--MarginBottom);\n --pf-c-empty-state__body--MarginTop: var(--pf-c-empty-state--m-xs__body--MarginTop);\n --pf-c-empty-state__primary--MarginTop: var(--pf-c-empty-state--m-xs__primary--MarginTop);\n --pf-c-empty-state__secondary--MarginTop: var(--pf-c-empty-state--m-xs__secondary--MarginTop); }\n .pf-c-empty-state.pf-m-xs .pf-c-empty-state__body {\n font-size: var(--pf-c-empty-state--m-xs__body--FontSize); }\n .pf-c-empty-state.pf-m-xs .pf-c-button {\n --pf-c-button--FontSize: var(--pf-c-empty-state--m-xs--button--FontSize); }\n .pf-c-empty-state.pf-m-sm {\n --pf-c-empty-state__content--MaxWidth: var(--pf-c-empty-state--m-sm__content--MaxWidth); }\n .pf-c-empty-state.pf-m-lg {\n --pf-c-empty-state__content--MaxWidth: var(--pf-c-empty-state--m-lg__content--MaxWidth); }\n .pf-c-empty-state.pf-m-xl {\n --pf-c-empty-state__body--MarginTop: var(--pf-c-empty-state--m-xl__body--MarginTop);\n --pf-c-empty-state__icon--MarginBottom: var(--pf-c-empty-state--m-xl__icon--MarginBottom);\n --pf-c-empty-state__icon--FontSize: var(--pf-c-empty-state--m-xl__icon--FontSize);\n --pf-c-empty-state--c-button__secondary--MarginTop: var(--pf-c-empty-state--m-xl--c-button__secondary--MarginTop); }\n .pf-c-empty-state.pf-m-xl .pf-c-empty-state__body {\n font-size: var(--pf-c-empty-state--m-xl__body--FontSize); }\n .pf-c-empty-state.pf-m-full-height {\n height: 100%; }\n\n.pf-c-empty-state__content {\n max-width: var(--pf-c-empty-state__content--MaxWidth); }\n .pf-c-empty-state__content > .pf-c-title.pf-m-lg {\n font-size: var(--pf-c-empty-state__content--c-title--m-lg--FontSize); }\n\n.pf-c-empty-state__icon {\n margin-bottom: var(--pf-c-empty-state__icon--MarginBottom);\n font-size: var(--pf-c-empty-state__icon--FontSize);\n color: var(--pf-c-empty-state__icon--Color); }\n\n.pf-c-empty-state__body {\n margin-top: var(--pf-c-empty-state__body--MarginTop);\n color: var(--pf-c-empty-state__body--Color); }\n\n.pf-c-empty-state__content > .pf-c-button.pf-m-primary,\n.pf-c-empty-state__primary {\n margin-top: var(--pf-c-empty-state__primary--MarginTop); }\n .pf-c-empty-state__content > .pf-c-button.pf-m-primary + .pf-c-empty-state__secondary,\n .pf-c-empty-state__primary + .pf-c-empty-state__secondary {\n margin-top: var(--pf-c-empty-state__primary--secondary--MarginTop); }\n\n.pf-c-empty-state__secondary {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n margin-top: var(--pf-c-empty-state__secondary--MarginTop);\n margin-bottom: var(--pf-c-empty-state__secondary--MarginBottom); }\n .pf-c-empty-state__secondary > * {\n margin-right: var(--pf-c-empty-state__secondary--child--MarginRight);\n margin-bottom: var(--pf-c-empty-state__secondary--child--MarginBottom);\n margin-left: var(--pf-c-empty-state__secondary--child--MarginLeft); }\n\n.pf-m-overpass-font .pf-c-empty-state .pf-c-empty-state__content > .pf-c-title.pf-m-lg {\n font-size: var(--pf-global--FontSize--lg); }\n\n.pf-c-expandable-section {\n --pf-c-expandable-section__toggle--PaddingTop: var(--pf-global--spacer--form-element);\n --pf-c-expandable-section__toggle--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-expandable-section__toggle--PaddingBottom: var(--pf-global--spacer--form-element);\n --pf-c-expandable-section__toggle--PaddingLeft: 0;\n --pf-c-expandable-section__toggle--Color: var(--pf-global--link--Color);\n --pf-c-expandable-section__toggle--hover--Color: var(--pf-global--link--Color--hover);\n --pf-c-expandable-section__toggle--active--Color: var(--pf-global--link--Color--hover);\n --pf-c-expandable-section__toggle--focus--Color: var(--pf-global--link--Color--hover);\n --pf-c-expandable-section__toggle--m-expanded--Color: var(--pf-global--link--Color--hover);\n --pf-c-expandable-section__toggle-icon--Color: var(--pf-global--Color--100);\n --pf-c-expandable-section__toggle-icon--Transition: .2s ease-in 0s;\n --pf-c-expandable-section__toggle-icon--Rotate: 0;\n --pf-c-expandable-section--m-expanded__toggle-icon--Rotate: 90deg;\n --pf-c-expandable-section__toggle-text--MarginLeft: calc(var(--pf-global--spacer--xs) + var(--pf-global--spacer--sm));\n --pf-c-expandable-section__content--MarginTop: var(--pf-global--spacer--md); }\n .pf-c-expandable-section.pf-m-expanded {\n --pf-c-expandable-section__toggle--Color: var(--pf-c-expandable-section__toggle--m-expanded--Color);\n --pf-c-expandable-section__toggle-icon--Rotate: var(--pf-c-expandable-section--m-expanded__toggle-icon--Rotate); }\n\n.pf-c-expandable-section__toggle {\n display: flex;\n padding: var(--pf-c-expandable-section__toggle--PaddingTop) var(--pf-c-expandable-section__toggle--PaddingRight) var(--pf-c-expandable-section__toggle--PaddingBottom) var(--pf-c-expandable-section__toggle--PaddingLeft);\n color: var(--pf-c-expandable-section__toggle--Color);\n border: none; }\n .pf-c-expandable-section__toggle:hover {\n --pf-c-expandable-section__toggle--Color: var(--pf-c-expandable-section__toggle--hover--Color); }\n .pf-c-expandable-section__toggle:active, .pf-c-expandable-section__toggle.pf-m-active {\n --pf-c-expandable-section__toggle--Color: var(--pf-c-expandable-section__toggle--active--Color); }\n .pf-c-expandable-section__toggle:focus {\n --pf-c-expandable-section__toggle--Color: var(--pf-c-expandable-section__toggle--focus--Color); }\n\n.pf-c-expandable-section__toggle-icon {\n color: var(--pf-c-expandable-section__toggle-icon--Color);\n transition: var(--pf-c-expandable-section__toggle-icon--Transition);\n transform: rotate(var(--pf-c-expandable-section__toggle-icon--Rotate)); }\n\n.pf-c-expandable-section__toggle-text {\n margin-left: var(--pf-c-expandable-section__toggle-text--MarginLeft); }\n\n.pf-c-expandable-section__content {\n margin-top: var(--pf-c-expandable-section__content--MarginTop); }\n\n.pf-m-overpass-font .pf-c-expandable-section__toggle {\n font-weight: var(--pf-global--FontWeight--semi-bold); }\n\n.pf-c-file-upload {\n --pf-c-file-upload--m-loading__file-details--before--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-file-upload--m-loading__file-details--before--Left: var(--pf-global--BorderWidth--sm);\n --pf-c-file-upload--m-loading__file-details--before--Right: var(--pf-global--BorderWidth--sm);\n --pf-c-file-upload--m-loading__file-details--before--Bottom: var(--pf-global--BorderWidth--sm);\n --pf-c-file-upload--m-drag-hover--before--BorderWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-file-upload--m-drag-hover--before--BorderColor: var(--pf-global--primary-color--100);\n --pf-c-file-upload--m-drag-hover--before--ZIndex: var(--pf-global--ZIndex--xs);\n --pf-c-file-upload--m-drag-hover--after--BackgroundColor: var(--pf-global--primary-color--100);\n --pf-c-file-upload--m-drag-hover--after--Opacity: .1;\n --pf-c-file-upload__file-details__c-form-control--MinHeight: calc(var(--pf-global--spacer--3xl) * 2);\n --pf-c-file-upload__file-select__c-button--m-control--OutlineOffset: calc(-1 * var(--pf-global--spacer--xs));\n position: relative;\n display: flex;\n flex-direction: column; }\n .pf-c-file-upload.pf-m-drag-hover::before {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: var(--pf-c-file-upload--m-drag-hover--before--ZIndex);\n content: \"\";\n border: var(--pf-c-file-upload--m-drag-hover--before--BorderWidth) solid var(--pf-c-file-upload--m-drag-hover--before--BorderColor); }\n .pf-c-file-upload.pf-m-drag-hover::after {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n content: \"\";\n background-color: var(--pf-c-file-upload--m-drag-hover--after--BackgroundColor);\n opacity: var(--pf-c-file-upload--m-drag-hover--after--Opacity); }\n .pf-c-file-upload.pf-m-loading .pf-c-file-upload__file-details {\n position: relative; }\n .pf-c-file-upload.pf-m-loading .pf-c-file-upload__file-details::before {\n position: absolute;\n top: 0;\n right: var(--pf-c-file-upload--m-loading__file-details--before--Left);\n bottom: var(--pf-c-file-upload--m-loading__file-details--before--Left);\n left: var(--pf-c-file-upload--m-loading__file-details--before--Left);\n content: \"\";\n background-color: var(--pf-c-file-upload--m-loading__file-details--before--BackgroundColor); }\n\n.pf-c-file-upload__file-select .pf-c-button.pf-m-control {\n outline-offset: var(--pf-c-file-upload__file-select__c-button--m-control--OutlineOffset); }\n\n.pf-c-file-upload__file-details {\n position: relative;\n display: flex; }\n .pf-c-file-upload__file-details .pf-c-form-control {\n flex: 1 1 auto;\n min-height: var(--pf-c-file-upload__file-details__c-form-control--MinHeight);\n border-top: 0; }\n\n.pf-c-file-upload__file-details-spinner {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%); }\n\n.pf-c-form {\n --pf-c-form--GridGap: var(--pf-global--gutter--md);\n --pf-c-form__group--m-action--MarginTop: var(--pf-global--spacer--xl);\n --pf-c-form--m-horizontal__group-label--md--GridColumnWidth: 9.375rem;\n --pf-c-form--m-horizontal__group-label--md--GridColumnGap: var(--pf-global--spacer--md);\n --pf-c-form--m-horizontal__group-control--md--GridColumnWidth: 1fr;\n --pf-c-form--m-limit-width--MaxWidth: 31.25rem;\n --pf-c-form--m-horizontal__group-label--md--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-form__group-label--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-form__label--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-form__label--LineHeight: var(--pf-global--LineHeight--sm);\n --pf-c-form__label--m-disabled--Color: var(--pf-global--disabled-color--100);\n --pf-c-form__label-text--FontWeight: var(--pf-global--FontWeight--bold);\n --pf-c-form__label-required--MarginLeft: var(--pf-global--spacer--xs);\n --pf-c-form__label-required--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-form__label-required--Color: var(--pf-global--danger-color--100);\n --pf-c-form__group-label-help--PaddingTop: var(--pf-global--spacer--xs);\n --pf-c-form__group-label-help--PaddingRight: var(--pf-global--spacer--xs);\n --pf-c-form__group-label-help--PaddingBottom: var(--pf-global--spacer--xs);\n --pf-c-form__group-label-help--PaddingLeft: var(--pf-global--spacer--xs);\n --pf-c-form__group-label-help--MarginTop: calc(var(--pf-c-form__group-label-help--PaddingTop) * -1);\n --pf-c-form__group-label-help--MarginRight: calc(var(--pf-c-form__group-label-help--PaddingRight) * -1);\n --pf-c-form__group-label-help--MarginBottom: calc(var(--pf-c-form__group-label-help--PaddingBottom) * -1);\n --pf-c-form__group-label-help--MarginLeft: calc(var(--pf-c-form__group-label-help--PaddingLeft) * -1 + var(--pf-global--spacer--xs));\n --pf-c-form__group-label-help--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-form__group-label-help--TranslateY: 0.125rem;\n --pf-c-form__group-control--m-inline--child--MarginRight: var(--pf-global--spacer--lg);\n --pf-c-form__group-control__helper-text--MarginBottom: var(--pf-global--spacer--xs);\n --pf-c-form__actions--child--MarginTop: var(--pf-global--spacer--sm);\n --pf-c-form__actions--child--MarginRight: var(--pf-global--spacer--sm);\n --pf-c-form__actions--child--MarginBottom: var(--pf-global--spacer--sm);\n --pf-c-form__actions--child--MarginLeft: var(--pf-global--spacer--sm);\n --pf-c-form__actions--MarginTop: calc(var(--pf-c-form__actions--child--MarginTop) * -1);\n --pf-c-form__actions--MarginRight: calc(var(--pf-c-form__actions--child--MarginRight) * -1);\n --pf-c-form__actions--MarginBottom: calc(var(--pf-c-form__actions--child--MarginBottom) * -1);\n --pf-c-form__actions--MarginLeft: calc(var(--pf-c-form__actions--child--MarginLeft) * -1);\n --pf-c-form__helper-text--MarginTop: var(--pf-global--spacer--xs);\n --pf-c-form__helper-text--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-form__helper-text--Color: var(--pf-global--Color--100);\n --pf-c-form__helper-text-icon--FontSize: var(--pf-global--FontSize--md);\n --pf-c-form__helper-text-icon--MarginRight: var(--pf-global--spacer--xs);\n --pf-c-form__helper-text--m-success--Color: var(--pf-global--success-color--200);\n --pf-c-form__helper-text--m-warning--Color: var(--pf-global--warning-color--200);\n --pf-c-form__helper-text--m-error--Color: var(--pf-global--danger-color--100);\n --pf-c-form__section--MarginTop: var(--pf-global--spacer--xl);\n --pf-c-form__section--Gap: var(--pf-global--gutter--md);\n --pf-c-form__field-group--border-width-base: var(--pf-global--BorderWidth--sm);\n --pf-c-form__field-group--BorderTopWidth: var(--pf-c-form__field-group--border-width-base);\n --pf-c-form__field-group--BorderTopColor: var(--pf-global--BorderColor--100);\n --pf-c-form__field-group--BorderBottomWidth: var(--pf-c-form__field-group--border-width-base);\n --pf-c-form__field-group--BorderBottomColor: var(--pf-global--BorderColor--100);\n --pf-c-form__field-group--field-group--MarginTop: calc(var(--pf-c-form--GridGap) * -1);\n --pf-c-form__field-group--GridTemplateColumns--toggle: calc(var(--pf-global--spacer--md) * 2 + var(--pf-c-form__field-group-toggle-icon--MinWidth) + var(--pf-global--spacer--xs));\n --pf-c-form__field-group-toggle--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-form__field-group-toggle--PaddingRight: var(--pf-global--spacer--xs);\n --pf-c-form__field-group__field-group__field-group-toggle--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-form__field-group-header-toggle--BorderWidth--base: var(--pf-global--BorderWidth--sm);\n --pf-c-form__field-group__field-group--field-group__field-group-toggle--after--BorderTopWidth: var(--pf-c-form__field-group-header-toggle--BorderWidth--base);\n --pf-c-form__field-group-toggle-button--MarginTop: calc(var(--pf-global--spacer--form-element) * -1);\n --pf-c-form__field-group-toggle-button--MarginBottom: calc(var(--pf-global--spacer--form-element) * -1);\n --pf-c-form__field-group-toggle-icon--Transition: var(--pf-global--Transition);\n --pf-c-form__field-group-toggle-icon--MinWidth: var(--pf-global--FontSize--md);\n --pf-c-form__field-group-toggle-icon--Rotate: 0;\n --pf-c-form__field-group--m-expanded__toggle-icon--Rotate: 90deg;\n --pf-c-form__field-group-header--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-form__field-group-header--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-form__field-group-header--GridColumn: 1 / 3;\n --pf-c-form__field-group__field-group__field-group-header--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-form__field-group__field-group__field-group-header--PaddingBottom: var(--pf-global--spacer--lg);\n --pf-c-form__field-group-toggle--field-group-header--GridColumn: 2 / 3;\n --pf-c-form__field-group__field-group--field-group__field-group-header--after--BorderTopWidth: var(--pf-c-form__field-group-header-toggle--BorderWidth--base);\n --pf-c-form__field-group-header-description--MarginTop: var(--pf-global--spacer--xs);\n --pf-c-form__field-group-header-description--Color: var(--pf-global--Color--200);\n --pf-c-form__field-group-header-actions--MarginTop: calc(var(--pf-global--spacer--form-element) * -1);\n --pf-c-form__field-group-header-actions--MarginBottom: calc(var(--pf-global--spacer--form-element) * -1);\n --pf-c-form__field-group-header-actions--MarginLeft: var(--pf-global--spacer--sm);\n --pf-c-form__field-group-body--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-form__field-group-body--PaddingBottom: var(--pf-global--spacer--lg);\n --pf-c-form__field-group-body--Gap: var(--pf-c-form--GridGap);\n --pf-c-form__field-group-body--GridColumn: 2 / 3;\n --pf-c-form__field-group__field-group__field-group-body--GridColumn: 1 / 3;\n --pf-c-form__field-group__field-group__field-group-toggle--field-group-body--GridColumn: 2 / 3;\n --pf-c-form__field-group__field-group--not--m-expandable__field-group--not-m-expandable__field-group-header--GridColumn: 2 / 3;\n --pf-c-form__field-group__field-group--not--m-expandable__field-group--not-m-expandable__field-group-body--GridColumn: 2 / 3;\n --pf-c-form__field-group-body__field-group--last-child--MarginBottom: calc(var(--pf-c-form__field-group-body--PaddingBottom) * -1);\n display: grid;\n grid-gap: var(--pf-c-form--GridGap); }\n .pf-c-form.pf-m-horizontal {\n --pf-c-form__group-label--PaddingBottom: 0; }\n .pf-c-form.pf-m-horizontal.pf-m-align-right .pf-c-form__label {\n text-align: right; }\n @media (min-width: 768px) {\n .pf-c-form.pf-m-horizontal .pf-c-form__group {\n display: grid;\n grid-column-gap: var(--pf-c-form--m-horizontal__group-label--md--GridColumnGap);\n grid-template-columns: var(--pf-c-form--m-horizontal__group-label--md--GridColumnWidth) var(--pf-c-form--m-horizontal__group-control--md--GridColumnWidth); }\n .pf-c-form.pf-m-horizontal .pf-c-form__group-label {\n padding-top: var(--pf-c-form--m-horizontal__group-label--md--PaddingTop); }\n .pf-c-form.pf-m-horizontal .pf-c-form__group-label.pf-m-no-padding-top {\n --pf-c-form--m-horizontal__group-label--md--PaddingTop: 0; }\n .pf-c-form.pf-m-horizontal .pf-c-form__group-control {\n grid-column: 2; } }\n .pf-c-form.pf-m-limit-width {\n max-width: var(--pf-c-form--m-limit-width--MaxWidth); }\n\n.pf-c-form__group.pf-m-action {\n margin-top: var(--pf-c-form__group--m-action--MarginTop);\n overflow: hidden; }\n\n.pf-c-form__section {\n display: grid;\n gap: var(--pf-c-form__section--Gap); }\n .pf-c-form__section + .pf-c-form__group:not(.pf-m-action), .pf-c-form__section:not(:first-child) {\n margin-top: var(--pf-c-form__section--MarginTop); }\n\n.pf-c-form__group-label {\n --pf-c-form__helper-text--MarginTop: 0;\n padding-bottom: var(--pf-c-form__group-label--PaddingBottom); }\n\n.pf-c-form__label {\n font-size: var(--pf-c-form__label--FontSize);\n line-height: var(--pf-c-form__label--LineHeight); }\n .pf-c-form__label::selection {\n background-color: none; }\n .pf-c-form__label:not(.pf-m-disabled):hover {\n cursor: pointer; }\n .pf-c-form__label.pf-m-disabled {\n color: var(--pf-c-form__label--m-disabled--Color); }\n .pf-c-form__label.pf-m-disabled:hover {\n cursor: not-allowed; }\n\n.pf-c-form__label-text {\n font-weight: var(--pf-c-form__label-text--FontWeight); }\n\n.pf-c-form__label-required {\n margin-left: var(--pf-c-form__label-required--MarginLeft);\n font-size: var(--pf-c-form__label-required--FontSize);\n color: var(--pf-c-form__label-required--Color); }\n\n.pf-c-form__group-label-help {\n padding-top: var(--pf-c-form__group-label-help--PaddingTop);\n padding-right: var(--pf-c-form__group-label-help--PaddingRight);\n padding-bottom: var(--pf-c-form__group-label-help--PaddingBottom);\n padding-left: var(--pf-c-form__group-label-help--PaddingLeft);\n margin-top: var(--pf-c-form__group-label-help--MarginTop);\n margin-right: var(--pf-c-form__group-label-help--MarginRight);\n margin-bottom: var(--pf-c-form__group-label-help--MarginBottom);\n margin-left: var(--pf-c-form__group-label-help--MarginLeft);\n font-size: var(--pf-c-form__group-label-help--FontSize);\n line-height: 1;\n border: 0;\n transform: translateY(var(--pf-c-form__group-label-help--TranslateY)); }\n\n.pf-c-form__group-control.pf-m-inline {\n display: flex;\n flex-flow: row wrap; }\n .pf-c-form__group-control.pf-m-inline > * {\n margin-right: var(--pf-c-form__group-control--m-inline--child--MarginRight); }\n\n.pf-c-form__group-control .pf-c-form__helper-text:first-child {\n --pf-c-form__helper-text--MarginTop: 0;\n margin-bottom: var(--pf-c-form__group-control__helper-text--MarginBottom); }\n\n.pf-c-form__helper-text {\n margin-top: var(--pf-c-form__helper-text--MarginTop);\n font-size: var(--pf-c-form__helper-text--FontSize);\n color: var(--pf-c-form__helper-text--Color); }\n .pf-c-form__helper-text.pf-m-error {\n --pf-c-form__helper-text--Color: var(--pf-c-form__helper-text--m-error--Color); }\n .pf-c-form__helper-text.pf-m-success {\n --pf-c-form__helper-text--Color: var(--pf-c-form__helper-text--m-success--Color); }\n .pf-c-form__helper-text.pf-m-warning {\n --pf-c-form__helper-text--Color: var(--pf-c-form__helper-text--m-warning--Color); }\n .pf-c-form__helper-text.pf-m-inactive {\n display: none;\n visibility: hidden; }\n .pf-c-form__helper-text.pf-m-hidden {\n visibility: hidden;\n opacity: 0; }\n\n.pf-c-form__helper-text-icon {\n margin-right: var(--pf-c-form__helper-text-icon--MarginRight);\n font-size: var(--pf-c-form__helper-text-icon--FontSize); }\n\n.pf-c-form__fieldset {\n border: 0; }\n\n.pf-c-form__actions {\n display: flex;\n flex-wrap: wrap;\n margin-top: var(--pf-c-form__actions--MarginTop);\n margin-right: var(--pf-c-form__actions--MarginRight);\n margin-bottom: var(--pf-c-form__actions--MarginBottom);\n margin-left: var(--pf-c-form__actions--MarginLeft); }\n .pf-c-form__actions > * {\n margin-top: var(--pf-c-form__actions--child--MarginTop);\n margin-right: var(--pf-c-form__actions--child--MarginRight);\n margin-bottom: var(--pf-c-form__actions--child--MarginBottom);\n margin-left: var(--pf-c-form__actions--child--MarginLeft); }\n\n.pf-c-form__field-group {\n --pf-c-form__field-group--BorderTopWidth: var(--pf-c-form__field-group--border-width-base);\n --pf-c-form__field-group--BorderTopWidth: var(--pf-c-form__field-group--border-width-base);\n display: grid;\n grid-template-columns: minmax(var(--pf-c-form__field-group--GridTemplateColumns--toggle), max-content) 1fr;\n border-top: var(--pf-c-form__field-group--BorderTopWidth) solid var(--pf-c-form__field-group--BorderTopColor);\n border-bottom: var(--pf-c-form__field-group--BorderBottomWidth) solid var(--pf-c-form__field-group--BorderBottomColor); }\n .pf-c-form__field-group:last-child {\n --pf-c-form__field-group--BorderBottomWidth: 0; }\n .pf-c-form__field-group + .pf-c-form__field-group, .pf-c-form__field-group:first-child {\n --pf-c-form__field-group--BorderTopWidth: 0; }\n .pf-c-form__field-group + .pf-c-form__field-group {\n margin-top: var(--pf-c-form__field-group--field-group--MarginTop); }\n .pf-c-form__field-group .pf-c-form__field-group {\n --pf-c-form__field-group-body--GridColumn: var(--pf-c-form__field-group__field-group__field-group-body--GridColumn);\n --pf-c-form__field-group-toggle--PaddingTop: var(--pf-c-form__field-group__field-group__field-group-toggle--PaddingTop);\n --pf-c-form__field-group-header--PaddingTop: var(--pf-c-form__field-group__field-group__field-group-header--PaddingTop);\n --pf-c-form__field-group-header--PaddingBottom: var(--pf-c-form__field-group__field-group__field-group-header--PaddingBottom);\n --pf-c-form__field-group-body--PaddingTop: 0; }\n .pf-c-form__field-group .pf-c-form__field-group .pf-c-form__field-group-toggle ~ .pf-c-form__field-group-body {\n --pf-c-form__field-group-body--GridColumn: var(--pf-c-form__field-group__field-group__field-group-toggle--field-group-body--GridColumn); }\n .pf-c-form__field-group.pf-m-expanded > .pf-c-form__field-group-toggle {\n --pf-c-form__field-group-toggle-icon--Rotate: var(--pf-c-form__field-group--m-expanded__toggle-icon--Rotate); }\n\n.pf-c-form__field-group-toggle {\n grid-column: 1 / 2;\n grid-row: 1 / 2;\n padding-top: var(--pf-c-form__field-group-toggle--PaddingTop);\n padding-right: var(--pf-c-form__field-group-toggle--PaddingRight); }\n .pf-c-form__field-group-toggle + .pf-c-form__field-group-header {\n --pf-c-form__field-group-header--GridColumn: var(--pf-c-form__field-group-toggle--field-group-header--GridColumn); }\n\n.pf-c-form__field-group-toggle-button {\n margin-top: var(--pf-c-form__field-group-toggle-button--MarginTop);\n margin-bottom: var(--pf-c-form__field-group-toggle-button--MarginBottom); }\n\n.pf-c-form__field-group-toggle-icon {\n display: inline-block;\n min-width: var(--pf-c-form__field-group-toggle-icon--MinWidth);\n text-align: center;\n transition: var(--pf-c-form__field-group-toggle-icon--Transition);\n transform: rotate(var(--pf-c-form__field-group-toggle-icon--Rotate)); }\n\n.pf-c-form__field-group-header {\n grid-column: var(--pf-c-form__field-group-header--GridColumn);\n grid-row: 1 / 2;\n display: flex;\n align-items: flex-start;\n padding-top: var(--pf-c-form__field-group-header--PaddingTop);\n padding-bottom: var(--pf-c-form__field-group-header--PaddingBottom); }\n\n.pf-c-form__field-group-header-main {\n display: flex;\n flex-direction: column;\n flex-grow: 1; }\n\n.pf-c-form__field-group-header-title {\n display: flex; }\n\n.pf-c-form__field-group-header-title-text {\n flex-grow: 1; }\n\n.pf-c-form__field-group-header-description {\n margin-top: var(--pf-c-form__field-group-header-description--MarginTop);\n color: var(--pf-c-form__field-group-header-description--Color); }\n\n.pf-c-form__field-group-header-actions {\n margin-top: var(--pf-c-form__field-group-header-actions--MarginTop);\n margin-bottom: var(--pf-c-form__field-group-header-actions--MarginBottom);\n margin-left: var(--pf-c-form__field-group-header-actions--MarginLeft);\n white-space: nowrap; }\n\n.pf-c-form__field-group-body {\n grid-column: var(--pf-c-form__field-group-body--GridColumn);\n display: grid;\n gap: var(--pf-c-form__field-group-body--Gap);\n padding-top: var(--pf-c-form__field-group-body--PaddingTop);\n padding-bottom: var(--pf-c-form__field-group-body--PaddingBottom); }\n .pf-c-form__field-group-body > .pf-c-form__field-group:first-child {\n --pf-c-form__field-group-toggle--PaddingTop: 0;\n --pf-c-form__field-group-header--PaddingTop: 0; }\n .pf-c-form__field-group-body > .pf-c-form__field-group:last-child {\n margin-bottom: var(--pf-c-form__field-group-body__field-group--last-child--MarginBottom); }\n\n.pf-c-form-control {\n --pf-c-form-control--FontSize: var(--pf-global--FontSize--md);\n --pf-c-form-control--LineHeight: var(--pf-global--LineHeight--md);\n --pf-c-form-control--BorderWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-form-control--BorderTopColor: var(--pf-global--BorderColor--300);\n --pf-c-form-control--BorderRightColor: var(--pf-global--BorderColor--300);\n --pf-c-form-control--BorderBottomColor: var(--pf-global--BorderColor--200);\n --pf-c-form-control--BorderLeftColor: var(--pf-global--BorderColor--300);\n --pf-c-form-control--BorderRadius: 0;\n --pf-c-form-control--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-form-control--Height: calc(var(--pf-c-form-control--FontSize) * var(--pf-c-form-control--LineHeight) + var(--pf-c-form-control--BorderWidth) * 2 + var(--pf-c-form-control--PaddingTop) + var(--pf-c-form-control--PaddingBottom));\n --pf-c-form-control--inset--base: var(--pf-global--spacer--sm);\n --pf-c-form-control--PaddingTop: calc(var(--pf-global--spacer--form-element) - var(--pf-global--BorderWidth--sm));\n --pf-c-form-control--PaddingBottom: calc(var(--pf-global--spacer--form-element) - var(--pf-global--BorderWidth--sm));\n --pf-c-form-control--PaddingRight: var(--pf-c-form-control--inset--base);\n --pf-c-form-control--PaddingLeft: var(--pf-c-form-control--inset--base);\n --pf-c-form-control--hover--BorderBottomColor: var(--pf-global--primary-color--100);\n --pf-c-form-control--focus--BorderBottomWidth: var(--pf-global--BorderWidth--md);\n --pf-c-form-control--focus--PaddingBottom: calc(var(--pf-global--spacer--form-element) - var(--pf-c-form-control--focus--BorderBottomWidth));\n --pf-c-form-control--focus--BorderBottomColor: var(--pf-global--primary-color--100);\n --pf-c-form-control--m-expanded--BorderBottomWidth: var(--pf-global--BorderWidth--md);\n --pf-c-form-control--m-expanded--PaddingBottom: calc(var(--pf-global--spacer--form-element) - var(--pf-c-form-control--focus--BorderBottomWidth));\n --pf-c-form-control--m-expanded--BorderBottomColor: var(--pf-global--primary-color--100);\n --pf-c-form-control--placeholder--Color: var(--pf-global--Color--dark-200);\n --pf-c-form-control--disabled--Color: var(--pf-global--disabled-color--100);\n --pf-c-form-control--disabled--BackgroundColor: var(--pf-global--disabled-color--300);\n --pf-c-form-control--disabled--BorderColor: transparent;\n --pf-c-form-control--readonly--BackgroundColor: var(--pf-global--disabled-color--300);\n --pf-c-form-control--readonly--hover--BorderBottomColor: var(--pf-global--BorderColor--200);\n --pf-c-form-control--readonly--focus--PaddingBottom: calc(var(--pf-global--spacer--form-element) - var(--pf-global--BorderWidth--sm));\n --pf-c-form-control--readonly--focus--BorderBottomWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-form-control--readonly--focus--BorderBottomColor: var(--pf-global--BorderColor--200);\n --pf-c-form-control--success--BorderBottomWidth: var(--pf-global--BorderWidth--md);\n --pf-c-form-control--success--PaddingBottom: calc(var(--pf-global--spacer--form-element) - var(--pf-c-form-control--success--BorderBottomWidth));\n --pf-c-form-control--success--BorderBottomColor: var(--pf-global--success-color--100);\n --pf-c-form-control--success--PaddingRight: var(--pf-global--spacer--xl);\n --pf-c-form-control--success--BackgroundPositionX: calc(100% - var(--pf-c-form-control--PaddingLeft));\n --pf-c-form-control--success--BackgroundPositionY: center;\n --pf-c-form-control--success--BackgroundPosition: var(--pf-c-form-control--success--BackgroundPositionX) var(--pf-c-form-control--success--BackgroundPositionY);\n --pf-c-form-control--success--BackgroundSizeX: var(--pf-c-form-control--FontSize);\n --pf-c-form-control--success--BackgroundSizeY: var(--pf-c-form-control--FontSize);\n --pf-c-form-control--success--BackgroundSize: var(--pf-c-form-control--success--BackgroundSizeX) var(--pf-c-form-control--success--BackgroundSizeY);\n --pf-c-form-control--success--BackgroundUrl: url(\"data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='%233e8635' d='M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z'/%3E%3C/svg%3E\");\n --pf-c-form-control--m-warning--BorderBottomWidth: var(--pf-global--BorderWidth--md);\n --pf-c-form-control--m-warning--PaddingBottom: calc(var(--pf-global--spacer--form-element) - var(--pf-c-form-control--m-warning--BorderBottomWidth));\n --pf-c-form-control--m-warning--BorderBottomColor: var(--pf-global--warning-color--100);\n --pf-c-form-control--m-warning--PaddingRight: var(--pf-global--spacer--xl);\n --pf-c-form-control--m-warning--BackgroundPositionX: calc(100% - calc(var(--pf-c-form-control--PaddingLeft) - 0.0625rem));\n --pf-c-form-control--m-warning--BackgroundPositionY: center;\n --pf-c-form-control--m-warning--BackgroundPosition: var(--pf-c-form-control--m-warning--BackgroundPositionX) var(--pf-c-form-control--m-warning--BackgroundPositionY);\n --pf-c-form-control--m-warning--BackgroundSizeX: 1.25rem;\n --pf-c-form-control--m-warning--BackgroundSizeY: var(--pf-c-form-control--FontSize);\n --pf-c-form-control--m-warning--BackgroundSize: var(--pf-c-form-control--m-warning--BackgroundSizeX) var(--pf-c-form-control--m-warning--BackgroundSizeY);\n --pf-c-form-control--m-warning--BackgroundUrl: url(\"data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='%23f0ab00' d='M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z'/%3E%3C/svg%3E\");\n --pf-c-form-control--invalid--BorderBottomWidth: var(--pf-global--BorderWidth--md);\n --pf-c-form-control--invalid--PaddingBottom: calc(var(--pf-global--spacer--form-element) - var(--pf-c-form-control--invalid--BorderBottomWidth));\n --pf-c-form-control--invalid--BorderBottomColor: var(--pf-global--danger-color--100);\n --pf-c-form-control--invalid--PaddingRight: var(--pf-global--spacer--xl);\n --pf-c-form-control--invalid--BackgroundPositionX: calc(100% - var(--pf-c-form-control--PaddingLeft));\n --pf-c-form-control--invalid--BackgroundPositionY: center;\n --pf-c-form-control--invalid--BackgroundPosition: var(--pf-c-form-control--invalid--BackgroundPositionX) var(--pf-c-form-control--invalid--BackgroundPositionY);\n --pf-c-form-control--invalid--BackgroundSizeX: var(--pf-c-form-control--FontSize);\n --pf-c-form-control--invalid--BackgroundSizeY: var(--pf-c-form-control--FontSize);\n --pf-c-form-control--invalid--BackgroundSize: var(--pf-c-form-control--invalid--BackgroundSizeX) var(--pf-c-form-control--invalid--BackgroundSizeY);\n --pf-c-form-control--invalid--BackgroundUrl: url(\"data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='%23c9190b' d='M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zm-248 50c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z'/%3E%3C/svg%3E\");\n --pf-c-form-control--invalid--exclamation--Background: var(--pf-c-form-control--invalid--BackgroundUrl) var(--pf-c-form-control--invalid--BackgroundPosition) / var(--pf-c-form-control--invalid--BackgroundSize) no-repeat;\n --pf-c-form-control--invalid--Background: var(--pf-c-form-control--BackgroundColor) var(--pf-c-form-control--invalid--exclamation--Background);\n --pf-c-form-control--m-search--PaddingLeft: var(--pf-global--spacer--xl);\n --pf-c-form-control--m-search--BackgroundPosition: var(--pf-c-form-control--PaddingRight);\n --pf-c-form-control--m-search--BackgroundSize: var(--pf-c-form-control--FontSize) var(--pf-c-form-control--FontSize);\n --pf-c-form-control--m-search--BackgroundUrl: url(\"data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='%236a6e73' d='M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 336c-70.7 0-128-57.2-128-128 0-70.7 57.2-128 128-128 70.7 0 128 57.2 128 128 0 70.7-57.2 128-128 128z'/%3E%3C/svg%3E\");\n --pf-c-form-control--m-icon--PaddingRight: calc(var(--pf-c-form-control--inset--base) + var(--pf-c-form-control--m-icon--BackgroundSizeX) + var(--pf-c-form-control--m-icon--icon--spacer));\n --pf-c-form-control--m-icon--BackgroundUrl: none;\n --pf-c-form-control--m-icon--BackgroundPositionX: calc(100% - var(--pf-c-form-control--inset--base));\n --pf-c-form-control--m-icon--BackgroundPositionY: center;\n --pf-c-form-control--m-icon--BackgroundSizeX: var(--pf-c-form-control--FontSize);\n --pf-c-form-control--m-icon--BackgroundSizeY: var(--pf-c-form-control--FontSize);\n --pf-c-form-control--m-icon--icon--spacer: var(--pf-global--spacer--sm);\n --pf-c-form-control--m-icon--icon--PaddingRight: calc(var(--pf-c-form-control--inset--base) + var(--pf-c-form-control--invalid--BackgroundSizeX) + var(--pf-c-form-control--m-icon--icon--spacer) + var(--pf-c-form-control--m-icon--BackgroundSizeX) + var(--pf-c-form-control--m-icon--icon--spacer));\n --pf-c-form-control--m-icon--icon--BackgroundPositionX: calc(var(--pf-c-form-control--m-icon--BackgroundPositionX) - var(--pf-c-form-control--m-icon--icon--spacer) - var(--pf-c-form-control--invalid--BackgroundSizeX));\n --pf-c-form-control--m-icon--invalid--BackgroundUrl: var(--pf-c-form-control--invalid--BackgroundUrl), var(--pf-c-form-control--m-icon--BackgroundUrl);\n --pf-c-form-control--m-icon--invalid--BackgroundPosition: var(--pf-c-form-control--invalid--BackgroundPosition), var(--pf-c-form-control--m-icon--icon--BackgroundPositionX) var(--pf-c-form-control--m-icon--BackgroundPositionY);\n --pf-c-form-control--m-icon--invalid--BackgroundSize: var(--pf-c-form-control--invalid--BackgroundSize), var(--pf-c-form-control--m-icon--BackgroundSizeX) var(--pf-c-form-control--m-icon--BackgroundSizeY);\n --pf-c-form-control--m-icon--success--BackgroundUrl: var(--pf-c-form-control--success--BackgroundUrl), var(--pf-c-form-control--m-icon--BackgroundUrl);\n --pf-c-form-control--m-icon--success--BackgroundPosition: var(--pf-c-form-control--success--BackgroundPosition), var(--pf-c-form-control--m-icon--icon--BackgroundPositionX) var(--pf-c-form-control--m-icon--BackgroundPositionY);\n --pf-c-form-control--m-icon--success--BackgroundSize: var(--pf-c-form-control--success--BackgroundSize), var(--pf-c-form-control--m-icon--BackgroundSizeX) var(--pf-c-form-control--m-icon--BackgroundSizeY);\n --pf-c-form-control--m-icon--m-warning--BackgroundUrl: var(--pf-c-form-control--m-warning--BackgroundUrl), var(--pf-c-form-control--m-icon--BackgroundUrl);\n --pf-c-form-control--m-icon--m-warning--BackgroundPosition: var(--pf-c-form-control--m-warning--BackgroundPosition), var(--pf-c-form-control--m-icon--icon--BackgroundPositionX) var(--pf-c-form-control--m-icon--BackgroundPositionY);\n --pf-c-form-control--m-icon--m-warning--BackgroundSize: var(--pf-c-form-control--m-warning--BackgroundSize), var(--pf-c-form-control--m-icon--BackgroundSizeX) var(--pf-c-form-control--m-icon--BackgroundSizeY);\n --pf-c-form-control--m-calendar--BackgroundUrl: url(\"data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='%236a6e73' d='M0 464c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V192H0v272zm320-196c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40zm0 128c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40zM192 268c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40zm0 128c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40zM64 268c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12H76c-6.6 0-12-5.4-12-12v-40zm0 128c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12H76c-6.6 0-12-5.4-12-12v-40zM400 64h-48V16c0-8.8-7.2-16-16-16h-32c-8.8 0-16 7.2-16 16v48H160V16c0-8.8-7.2-16-16-16h-32c-8.8 0-16 7.2-16 16v48H48C21.5 64 0 85.5 0 112v48h448v-48c0-26.5-21.5-48-48-48z'/%3E%3C/svg%3E\");\n --pf-c-form-control--m-clock--BackgroundUrl: url(\"data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='%236a6e73' d='M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm61.8-104.4l-84.9-61.7c-3.1-2.3-4.9-5.9-4.9-9.7V116c0-6.6 5.4-12 12-12h32c6.6 0 12 5.4 12 12v141.7l66.8 48.6c5.4 3.9 6.5 11.4 2.6 16.8L334.6 349c-3.9 5.3-11.4 6.5-16.8 2.6z'/%3E%3C/svg%3E\");\n --pf-c-form-control__select--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-form-control__select--BackgroundUrl: url(\"data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 512'%3E%3Cpath fill='%23urrentColor' d='M31.3 192h257.3c17.8 0 26.7 21.5 14.1 34.1L174.1 354.8c-7.8 7.8-20.5 7.8-28.3 0L17.2 226.1C4.6 213.5 13.5 192 31.3 192z'/%3E%3C/svg%3E\");\n --pf-c-form-control__select--BackgroundSize: .625em;\n --pf-c-form-control__select--BackgroundPositionX: calc(100% - var(--pf-global--spacer--md) + 1px);\n --pf-c-form-control__select--BackgroundPositionY: center;\n --pf-c-form-control__select--BackgroundPosition: var(--pf-c-form-control__select--BackgroundPositionX) var(--pf-c-form-control__select--BackgroundPositionY);\n --pf-c-form-control__select--success--PaddingRight: var(--pf-global--spacer--3xl);\n --pf-c-form-control__select--success--BackgroundPosition: calc(var(--pf-c-form-control__select--BackgroundPositionX) - var(--pf-global--spacer--lg));\n --pf-c-form-control__select--m-warning--PaddingRight: var(--pf-global--spacer--3xl);\n --pf-c-form-control__select--m-warning--BackgroundPosition: calc(var(--pf-c-form-control__select--BackgroundPositionX) - var(--pf-global--spacer--lg) + 0.0625rem);\n --pf-c-form-control__select--invalid--PaddingRight: var(--pf-global--spacer--3xl);\n --pf-c-form-control__select--invalid--BackgroundPosition: calc(var(--pf-c-form-control__select--BackgroundPositionX) - var(--pf-global--spacer--lg));\n --pf-c-form-control--textarea--success--BackgroundPositionY: var(--pf-c-form-control--PaddingLeft);\n --pf-c-form-control--textarea--m-warning--BackgroundPositionY: var(--pf-c-form-control--PaddingLeft);\n --pf-c-form-control--textarea--invalid--BackgroundPositionY: var(--pf-c-form-control--PaddingLeft);\n color: var(--pf-global--Color--100);\n width: 100%;\n padding: var(--pf-c-form-control--PaddingTop) var(--pf-c-form-control--PaddingRight) var(--pf-c-form-control--PaddingBottom) var(--pf-c-form-control--PaddingLeft);\n font-size: var(--pf-c-form-control--FontSize);\n line-height: var(--pf-c-form-control--LineHeight);\n background-color: var(--pf-c-form-control--BackgroundColor);\n background-repeat: no-repeat;\n border: var(--pf-c-form-control--BorderWidth) solid;\n border-color: var(--pf-c-form-control--BorderTopColor) var(--pf-c-form-control--BorderRightColor) var(--pf-c-form-control--BorderBottomColor) var(--pf-c-form-control--BorderLeftColor);\n border-radius: var(--pf-c-form-control--BorderRadius);\n -moz-appearance: none;\n -webkit-appearance: none; }\n .pf-c-form-control::placeholder {\n color: var(--pf-c-form-control--placeholder--Color); }\n .pf-c-form-control:not(textarea) {\n height: var(--pf-c-form-control--Height);\n text-overflow: ellipsis; }\n .pf-c-form-control[readonly] {\n background-color: var(--pf-c-form-control--readonly--BackgroundColor); }\n .pf-c-form-control[readonly]:not(.pf-m-success):not([aria-invalid=\"true\"]):hover {\n --pf-c-form-control--BorderBottomColor: var(--pf-c-form-control--readonly--hover--BorderBottomColor); }\n .pf-c-form-control[readonly]:not(.pf-m-success):not([aria-invalid=\"true\"]):focus {\n --pf-c-form-control--focus--PaddingBottom: var(--pf-c-form-control--readonly--focus--PaddingBottom);\n --pf-c-form-control--focus--BorderBottomWidth: var(--pf-c-form-control--readonly--focus--BorderBottomWidth);\n --pf-c-form-control--focus--BorderBottomColor: var(--pf-c-form-control--readonly--focus--BorderBottomColor); }\n .pf-c-form-control:hover {\n --pf-c-form-control--BorderBottomColor: var(--pf-c-form-control--hover--BorderBottomColor); }\n .pf-c-form-control:focus {\n --pf-c-form-control--BorderBottomColor: var(--pf-c-form-control--focus--BorderBottomColor);\n padding-bottom: var(--pf-c-form-control--focus--PaddingBottom);\n border-bottom-width: var(--pf-c-form-control--focus--BorderBottomWidth); }\n .pf-c-form-control.pf-m-expanded {\n --pf-c-form-control--BorderBottomColor: var(--pf-c-form-control--m-expanded--BorderBottomColor);\n padding-bottom: var(--pf-c-form-control--m-expanded--PaddingBottom);\n border-bottom-width: var(--pf-c-form-control--m-expanded--BorderBottomWidth); }\n .pf-c-form-control:disabled {\n --pf-c-form-control--Color: var(--pf-c-form-control--disabled--Color);\n --pf-c-form-control--BackgroundColor: var(--pf-c-form-control--disabled--BackgroundColor);\n cursor: not-allowed;\n border-color: var(--pf-c-form-control--disabled--BorderColor); }\n .pf-c-form-control[aria-invalid=\"true\"] {\n --pf-c-form-control--PaddingRight: var(--pf-c-form-control--invalid--PaddingRight);\n --pf-c-form-control--BorderBottomColor: var(--pf-c-form-control--invalid--BorderBottomColor);\n padding-bottom: var(--pf-c-form-control--invalid--PaddingBottom);\n background-image: var(--pf-c-form-control--invalid--BackgroundUrl);\n background-position: var(--pf-c-form-control--invalid--BackgroundPosition);\n background-size: var(--pf-c-form-control--invalid--BackgroundSize);\n border-bottom-width: var(--pf-c-form-control--invalid--BorderBottomWidth); }\n .pf-c-form-control[aria-invalid=\"true\"].pf-m-icon {\n --pf-c-form-control--PaddingRight: var(--pf-c-form-control--m-icon--icon--PaddingRight);\n background-image: var(--pf-c-form-control--m-icon--invalid--BackgroundUrl);\n background-position: var(--pf-c-form-control--m-icon--invalid--BackgroundPosition);\n background-size: var(--pf-c-form-control--m-icon--invalid--BackgroundSize); }\n .pf-c-form-control.pf-m-success {\n --pf-c-form-control--PaddingRight: var(--pf-c-form-control--success--PaddingRight);\n --pf-c-form-control--BorderBottomColor: var(--pf-c-form-control--success--BorderBottomColor);\n padding-bottom: var(--pf-c-form-control--success--PaddingBottom);\n background-image: var(--pf-c-form-control--success--BackgroundUrl);\n background-position: var(--pf-c-form-control--success--BackgroundPosition);\n background-size: var(--pf-c-form-control--success--BackgroundSize);\n border-bottom-width: var(--pf-c-form-control--success--BorderBottomWidth); }\n .pf-c-form-control.pf-m-success.pf-m-icon {\n --pf-c-form-control--PaddingRight: var(--pf-c-form-control--m-icon--icon--PaddingRight);\n background-image: var(--pf-c-form-control--m-icon--success--BackgroundUrl);\n background-position: var(--pf-c-form-control--m-icon--success--BackgroundPosition);\n background-size: var(--pf-c-form-control--m-icon--success--BackgroundSize); }\n .pf-c-form-control.pf-m-warning {\n --pf-c-form-control--PaddingRight: var(--pf-c-form-control--m-warning--PaddingRight);\n --pf-c-form-control--BorderBottomColor: var(--pf-c-form-control--m-warning--BorderBottomColor);\n padding-bottom: var(--pf-c-form-control--m-warning--PaddingBottom);\n background-image: var(--pf-c-form-control--m-warning--BackgroundUrl);\n background-position: var(--pf-c-form-control--m-warning--BackgroundPosition);\n background-size: var(--pf-c-form-control--m-warning--BackgroundSize);\n border-bottom-width: var(--pf-c-form-control--m-warning--BorderBottomWidth); }\n .pf-c-form-control.pf-m-warning.pf-m-icon {\n --pf-c-form-control--PaddingRight: var(--pf-c-form-control--m-icon--icon--PaddingRight);\n background-image: var(--pf-c-form-control--m-icon--m-warning--BackgroundUrl);\n background-position: var(--pf-c-form-control--m-icon--m-warning--BackgroundPosition);\n background-size: var(--pf-c-form-control--m-icon--m-warning--BackgroundSize); }\n .pf-c-form-control.pf-m-search {\n --pf-c-form-control--PaddingLeft: var(--pf-c-form-control--m-search--PaddingLeft);\n background-image: var(--pf-c-form-control--m-search--BackgroundUrl);\n background-position: var(--pf-c-form-control--m-search--BackgroundPosition);\n background-size: var(--pf-c-form-control--m-search--BackgroundSize); }\n .pf-c-form-control.pf-m-icon {\n --pf-c-form-control--PaddingRight: var(--pf-c-form-control--m-icon--PaddingRight);\n background-image: var(--pf-c-form-control--m-icon--BackgroundUrl);\n background-position: var(--pf-c-form-control--m-icon--BackgroundPositionX) var(--pf-c-form-control--m-icon--BackgroundPositionY);\n background-size: var(--pf-c-form-control--m-icon--BackgroundSizeX) var(--pf-c-form-control--m-icon--BackgroundSizeY); }\n .pf-c-form-control.pf-m-icon.pf-m-calendar {\n --pf-c-form-control--m-icon--BackgroundUrl: var(--pf-c-form-control--m-calendar--BackgroundUrl); }\n .pf-c-form-control.pf-m-icon.pf-m-clock {\n --pf-c-form-control--m-icon--BackgroundUrl: var(--pf-c-form-control--m-clock--BackgroundUrl); }\n select.pf-c-form-control {\n --pf-c-form-control--PaddingRight: var(--pf-c-form-control__select--PaddingRight);\n background-image: var(--pf-c-form-control__select--BackgroundUrl);\n background-position: var(--pf-c-form-control__select--BackgroundPosition);\n background-size: var(--pf-c-form-control__select--BackgroundSize); }\n select.pf-c-form-control[aria-invalid=\"true\"] {\n --pf-c-form-control--PaddingRight: var(--pf-c-form-control__select--invalid--PaddingRight);\n --pf-c-form-control--invalid--BackgroundPosition: var(--pf-c-form-control__select--invalid--BackgroundPosition);\n background-image: var(--pf-c-form-control__select--BackgroundUrl), var(--pf-c-form-control--invalid--BackgroundUrl);\n background-position: var(--pf-c-form-control__select--BackgroundPosition), var(--pf-c-form-control--invalid--BackgroundPosition);\n background-size: var(--pf-c-form-control__select--BackgroundSize), var(--pf-c-form-control--invalid--BackgroundSize); }\n select.pf-c-form-control.pf-m-success {\n --pf-c-form-control--PaddingRight: var(--pf-c-form-control__select--success--PaddingRight);\n --pf-c-form-control--success--BackgroundPosition: var(--pf-c-form-control__select--success--BackgroundPosition);\n background-image: var(--pf-c-form-control__select--BackgroundUrl), var(--pf-c-form-control--success--BackgroundUrl);\n background-position: var(--pf-c-form-control__select--BackgroundPosition), var(--pf-c-form-control--success--BackgroundPosition);\n background-size: var(--pf-c-form-control__select--BackgroundSize), var(--pf-c-form-control--success--BackgroundSize); }\n select.pf-c-form-control.pf-m-warning {\n --pf-c-form-control--PaddingRight: var(--pf-c-form-control__select--m-warning--PaddingRight);\n background-image: var(--pf-c-form-control__select--BackgroundUrl), var(--pf-c-form-control--m-warning--BackgroundUrl);\n background-position: var(--pf-c-form-control__select--BackgroundPosition), var(--pf-c-form-control__select--m-warning--BackgroundPosition);\n background-size: var(--pf-c-form-control__select--BackgroundSize), var(--pf-c-form-control--m-warning--BackgroundSize); }\n textarea.pf-c-form-control {\n --pf-c-form-control--success--BackgroundPositionY: var(--pf-c-form-control--textarea--success--BackgroundPositionY);\n --pf-c-form-control--invalid--BackgroundPositionY: var(--pf-c-form-control--textarea--invalid--BackgroundPositionY);\n --pf-c-form-control--m-warning--BackgroundPositionY: var(--pf-c-form-control--textarea--m-warning--BackgroundPositionY); }\n .pf-c-form-control.pf-m-resize-vertical {\n resize: vertical; }\n .pf-c-form-control.pf-m-resize-horizontal {\n resize: horizontal; }\n\n.pf-c-hint {\n --pf-c-hint--GridRowGap: var(--pf-global--spacer--md);\n --pf-c-hint--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-hint--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-hint--PaddingBottom: var(--pf-global--spacer--lg);\n --pf-c-hint--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-hint--BackgroundColor: var(--pf-global--palette--blue-50);\n --pf-c-hint--BorderColor: var(--pf-global--palette--blue-100);\n --pf-c-hint--BorderWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-hint--BoxShadow: var(--pf-global--BoxShadow--sm);\n --pf-c-hint--Color: var(--pf-global--Color--100);\n --pf-c-hint__title--FontSize: var(--pf-global--FontSize--lg);\n --pf-c-hint__body--FontSize: var(--pf-global--FontSize--md);\n --pf-c-hint__footer--child--MarginRight: var(--pf-global--spacer--md);\n --pf-c-hint__actions--MarginLeft: var(--pf-global--spacer--2xl);\n --pf-c-hint__actions--c-dropdown--MarginTop: calc(var(--pf-global--spacer--form-element) * -1);\n display: grid;\n grid-template-columns: 1fr auto;\n grid-row-gap: var(--pf-c-hint--GridRowGap);\n padding: var(--pf-c-hint--PaddingTop) var(--pf-c-hint--PaddingRight) var(--pf-c-hint--PaddingBottom) var(--pf-c-hint--PaddingLeft);\n color: var(--pf-c-hint--Color);\n background-color: var(--pf-c-hint--BackgroundColor);\n border: var(--pf-c-hint--BorderWidth) solid var(--pf-c-hint--BorderColor);\n box-shadow: var(--pf-c-hint--BoxShadow); }\n .pf-c-hint .pf-c-button.pf-m-link.pf-m-inline {\n text-align: left;\n white-space: normal; }\n\n.pf-c-hint__actions {\n display: inline-grid;\n grid-auto-flow: column;\n margin-left: var(--pf-c-hint__actions--MarginLeft);\n text-align: right;\n grid-column: 2;\n grid-row: 1; }\n .pf-c-hint__actions .pf-c-dropdown .pf-c-dropdown__toggle.pf-m-plain {\n margin-top: var(--pf-c-hint__actions--c-dropdown--MarginTop); }\n .pf-c-hint__actions + .pf-c-hint__body {\n grid-column: 1; }\n\n.pf-c-hint__title {\n font-size: var(--pf-c-hint__title--FontSize); }\n\n.pf-c-hint__body {\n grid-column: 1 / -1;\n font-size: var(--pf-c-hint__body--FontSize); }\n\n.pf-c-hint__footer {\n grid-column: 1 / -1; }\n .pf-c-hint__footer > :not(:last-child) {\n margin-right: var(--pf-c-hint__footer--child--MarginRight); }\n\n.pf-c-inline-edit {\n --pf-c-inline-edit__group--item--MarginRight: var(--pf-global--spacer--sm);\n --pf-c-inline-edit__action--c-button--m-valid--m-plain--Color: var(--pf-global--link--Color);\n --pf-c-inline-edit__action--c-button--m-valid--m-plain--hover--Color: var(--pf-global--link--Color--hover);\n --pf-c-inline-edit__action--m-icon-group--item--MarginRight: 0;\n --pf-c-inline-edit__group--m-footer--MarginTop: var(--pf-global--spacer--xl);\n --pf-c-inline-edit__label--m-bold--FontWeight: var(--pf-global--FontWeight--semi-bold); }\n\n.pf-c-inline-edit__group {\n display: flex;\n align-items: baseline; }\n .pf-c-inline-edit__group > * {\n margin-right: var(--pf-c-inline-edit__group--item--MarginRight); }\n .pf-c-inline-edit__group.pf-m-icon-group {\n --pf-c-inline-edit__group--item--MarginRight: var(--pf-c-inline-edit__action--m-icon-group--item--MarginRight); }\n .pf-c-inline-edit__group.pf-m-footer {\n margin-top: var(--pf-c-inline-edit__group--m-footer--MarginTop); }\n .pf-c-inline-edit__group.pf-m-column {\n --pf-c-inline-edit__group--item--MarginRight: 0;\n flex-direction: column; }\n .pf-c-inline-edit__group > :last-child {\n --pf-c-inline-edit__group--item--MarginRight: 0; }\n\n.pf-c-inline-edit__input {\n flex: 1; }\n\n.pf-c-inline-edit__action.pf-m-valid .pf-c-button.pf-m-plain {\n --pf-c-button--m-plain--Color: var(--pf-c-inline-edit__action--c-button--m-valid--m-plain--Color); }\n .pf-c-inline-edit__action.pf-m-valid .pf-c-button.pf-m-plain:hover {\n --pf-c-button--m-plain--Color: var(--pf-c-inline-edit__action--c-button--m-valid--m-plain--hover--Color); }\n\n.pf-c-inline-edit__input,\n.pf-c-inline-edit__action,\n.pf-c-inline-edit__group.pf-m-action-group {\n display: none;\n visibility: hidden; }\n\n.pf-c-inline-edit__action.pf-m-enable-editable {\n display: inline-block;\n visibility: visible; }\n\n.pf-c-inline-edit.pf-m-inline-editable .pf-c-inline-edit__input,\n.pf-c-inline-edit.pf-m-inline-editable .pf-c-inline-edit__action,\n.pf-c-inline-edit.pf-m-inline-editable .pf-c-inline-edit__group.pf-m-action-group,\n.pf-c-inline-edit .pf-m-inline-editable .pf-c-inline-edit__input,\n.pf-c-inline-edit .pf-m-inline-editable .pf-c-inline-edit__action,\n.pf-c-inline-edit .pf-m-inline-editable .pf-c-inline-edit__group.pf-m-action-group {\n visibility: visible; }\n\n.pf-c-inline-edit.pf-m-inline-editable .pf-c-inline-edit__input,\n.pf-c-inline-edit .pf-m-inline-editable .pf-c-inline-edit__input {\n display: block; }\n\n.pf-c-inline-edit.pf-m-inline-editable .pf-c-inline-edit__action,\n.pf-c-inline-edit .pf-m-inline-editable .pf-c-inline-edit__action {\n display: inline-block; }\n\n.pf-c-inline-edit.pf-m-inline-editable .pf-c-inline-edit__group.pf-m-action-group,\n.pf-c-inline-edit .pf-m-inline-editable .pf-c-inline-edit__group.pf-m-action-group {\n display: inline-flex; }\n\n.pf-c-inline-edit.pf-m-inline-editable .pf-c-inline-edit__value,\n.pf-c-inline-edit.pf-m-inline-editable .pf-c-inline-edit__action.pf-m-enable-editable,\n.pf-c-inline-edit .pf-m-inline-editable .pf-c-inline-edit__value,\n.pf-c-inline-edit .pf-m-inline-editable .pf-c-inline-edit__action.pf-m-enable-editable {\n display: none;\n visibility: hidden; }\n\n.pf-c-inline-edit__label + .pf-c-inline-edit__action.pf-m-enable > .pf-c-button {\n margin-top: calc(var(--pf-c-button--PaddingTop) * -1);\n margin-bottom: calc(var(--pf-c-button--PaddingBottom) * -1); }\n\n.pf-c-inline-edit__label.pf-m-bold {\n font-weight: var(--pf-c-inline-edit__label--m-bold--FontWeight); }\n\n.pf-c-input-group {\n --pf-c-input-group--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-input-group__text--FontSize: var(--pf-global--FontSize--md);\n --pf-c-input-group__text--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-input-group__text--PaddingLeft: var(--pf-global--spacer--sm);\n --pf-c-input-group__text--Color: var(--pf-global--Color--dark-200);\n --pf-c-input-group__text--BorderWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-input-group__text--BorderTopColor: var(--pf-global--BorderColor--300);\n --pf-c-input-group__text--BorderRightColor: var(--pf-global--BorderColor--300);\n --pf-c-input-group__text--BorderBottomColor: var(--pf-global--BorderColor--200);\n --pf-c-input-group__text--BorderLeftColor: var(--pf-global--BorderColor--300);\n --pf-c-input-group__text--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-input-group__textarea--MinHeight: var(--pf-global--spacer--xl);\n --pf-c-input-group--c-form-control--invalid--ZIndex: var(--pf-global--ZIndex--xs);\n --pf-c-input-group--c-form-control--MarginRight: 0;\n color: var(--pf-global--Color--100);\n display: flex;\n width: 100%;\n background-color: var(--pf-c-input-group--BackgroundColor); }\n .pf-c-input-group > * + * {\n margin-left: -1px; }\n .pf-c-input-group .pf-c-form-control[aria-invalid=\"true\"]:not(:last-child) {\n margin-right: var(--pf-c-input-group--c-form-control--MarginRight); }\n .pf-c-input-group input:not([type=\"checkbox\"]):not([type=\"radio\"]),\n .pf-c-input-group textarea {\n flex: 2;\n min-width: 0; }\n .pf-c-input-group textarea {\n min-height: var(--pf-c-input-group__textarea--MinHeight); }\n\n.pf-c-input-group__text {\n display: flex;\n align-items: center;\n padding-right: var(--pf-c-input-group__text--PaddingRight);\n padding-left: var(--pf-c-input-group__text--PaddingLeft);\n font-size: var(--pf-c-input-group__text--FontSize);\n color: var(--pf-c-input-group__text--Color);\n text-align: center;\n background-color: var(--pf-c-input-group__text--BackgroundColor);\n border: var(--pf-c-input-group__text--BorderWidth) solid;\n border-color: var(--pf-c-input-group__text--BorderTopColor) var(--pf-c-input-group__text--BorderRightColor) var(--pf-c-input-group__text--BorderBottomColor) var(--pf-c-input-group__text--BorderLeftColor); }\n label.pf-c-input-group__text {\n cursor: pointer; }\n .pf-c-input-group__text.pf-m-plain {\n --pf-c-input-group__text--BorderWidth: 0;\n margin-left: 0; }\n\n.pf-c-jump-links {\n --pf-c-jump-links__list--PaddingTop: 0;\n --pf-c-jump-links__list--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-jump-links__list--PaddingBottom: 0;\n --pf-c-jump-links__list--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-jump-links--m-vertical__list--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-jump-links--m-vertical__list--PaddingRight: 0;\n --pf-c-jump-links--m-vertical__list--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-jump-links--m-vertical__list--PaddingLeft: 0;\n --pf-c-jump-links__list--FlexDirection: row;\n --pf-c-jump-links--m-vertical__list--FlexDirection: column;\n --pf-c-jump-links__list--before--BorderColor: var(--pf-global--BorderColor--100);\n --pf-c-jump-links__list--before--BorderTopWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-jump-links__list--before--BorderRightWidth: 0;\n --pf-c-jump-links__list--before--BorderBottomWidth: 0;\n --pf-c-jump-links__list--before--BorderLeftWidth: 0;\n --pf-c-jump-links--m-vertical__list--before--BorderLeftWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-jump-links--m-vertical__list--before--BorderTopWidth: 0;\n --pf-c-jump-links__list__list--MarginTop: calc(var(--pf-global--spacer--sm) * -1);\n --pf-c-jump-links__link--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-jump-links__link--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-jump-links__link--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-jump-links__link--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-jump-links__list__list__link--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-jump-links__list__list__link--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-jump-links__list__list__link--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-jump-links__link--OutlineOffset: calc(-1 * var(--pf-global--spacer--sm));\n --pf-c-jump-links__link--before--BorderTopWidth: 0;\n --pf-c-jump-links__link--before--BorderRightWidth: 0;\n --pf-c-jump-links__link--before--BorderBottomWidth: 0;\n --pf-c-jump-links__link--before--BorderLeftWidth: 0;\n --pf-c-jump-links__link--before--BorderColor: transparent;\n --pf-c-jump-links__link--focus--before--BorderTopWidth: var(--pf-global--BorderWidth--lg);\n --pf-c-jump-links__link--focus--before--BorderLeftWidth: 0;\n --pf-c-jump-links__link--focus--before--BorderColor: var(--pf-global--primary-color--100);\n --pf-c-jump-links__item--m-current__link--before--BorderTopWidth: var(--pf-global--BorderWidth--lg);\n --pf-c-jump-links__item--m-current__link--before--BorderLeftWidth: 0;\n --pf-c-jump-links__item--m-current__link--before--BorderColor: var(--pf-global--primary-color--100);\n --pf-c-jump-links--m-vertical__link--focus--before--BorderTopWidth: 0;\n --pf-c-jump-links--m-vertical__link--focus--before--BorderLeftWidth: var(--pf-global--BorderWidth--lg);\n --pf-c-jump-links--m-vertical__item--m-current__link--before--BorderTopWidth: 0;\n --pf-c-jump-links--m-vertical__item--m-current__link--before--BorderLeftWidth: var(--pf-global--BorderWidth--lg);\n --pf-c-jump-links__link-text--Color: var(--pf-global--Color--200);\n --pf-c-jump-links__link--hover__link-text--Color: var(--pf-global--Color--100);\n --pf-c-jump-links__link--focus__link-text--Color: var(--pf-global--Color--100);\n --pf-c-jump-links__item--m-current__link-text--Color: var(--pf-global--Color--100);\n --pf-c-jump-links__label--MarginBottom: var(--pf-global--spacer--md);\n display: flex; }\n .pf-c-jump-links.pf-m-center {\n justify-content: center; }\n .pf-c-jump-links.pf-m-center .pf-c-jump-links__main {\n align-items: center; }\n .pf-c-jump-links.pf-m-vertical {\n --pf-c-jump-links__list--PaddingTop: var(--pf-c-jump-links--m-vertical__list--PaddingTop);\n --pf-c-jump-links__list--PaddingRight: var(--pf-c-jump-links--m-vertical__list--PaddingRight);\n --pf-c-jump-links__list--PaddingBottom: var(--pf-c-jump-links--m-vertical__list--PaddingBottom);\n --pf-c-jump-links__list--PaddingLeft: var(--pf-c-jump-links--m-vertical__list--PaddingLeft);\n --pf-c-jump-links__list--before--BorderTopWidth: var(--pf-c-jump-links--m-vertical__list--before--BorderTopWidth);\n --pf-c-jump-links__list--before--BorderLeftWidth: var(--pf-c-jump-links--m-vertical__list--before--BorderLeftWidth);\n --pf-c-jump-links__link--focus--before--BorderTopWidth: var(--pf-c-jump-links--m-vertical__link--focus--before--BorderTopWidth);\n --pf-c-jump-links__link--focus--before--BorderLeftWidth: var(--pf-c-jump-links--m-vertical__link--focus--before--BorderLeftWidth);\n --pf-c-jump-links__item--m-current__link--before--BorderTopWidth: var(--pf-c-jump-links--m-vertical__item--m-current__link--before--BorderTopWidth);\n --pf-c-jump-links__item--m-current__link--before--BorderLeftWidth: var(--pf-c-jump-links--m-vertical__item--m-current__link--before--BorderLeftWidth);\n --pf-c-jump-links__list--FlexDirection: var(--pf-c-jump-links--m-vertical__list--FlexDirection);\n flex-direction: column; }\n\n.pf-c-jump-links__list {\n position: relative;\n display: flex;\n flex-direction: var(--pf-c-jump-links__list--FlexDirection);\n padding-top: var(--pf-c-jump-links__list--PaddingTop);\n padding-right: var(--pf-c-jump-links__list--PaddingRight);\n padding-bottom: var(--pf-c-jump-links__list--PaddingBottom);\n padding-left: var(--pf-c-jump-links__list--PaddingLeft); }\n .pf-c-jump-links__list::before {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n pointer-events: none;\n content: \"\";\n border: solid var(--pf-c-jump-links__list--before--BorderColor);\n border-width: var(--pf-c-jump-links__list--before--BorderTopWidth) var(--pf-c-jump-links__list--before--BorderRightWidth) var(--pf-c-jump-links__list--before--BorderBottomWidth) var(--pf-c-jump-links__list--before--BorderLeftWidth); }\n .pf-c-jump-links__list .pf-c-jump-links__list {\n --pf-c-jump-links__list--PaddingTop: 0;\n --pf-c-jump-links__list--PaddingBottom: 0;\n --pf-c-jump-links__link--PaddingTop: var(--pf-c-jump-links__list__list__link--PaddingTop);\n --pf-c-jump-links__link--PaddingBottom: var(--pf-c-jump-links__list__list__link--PaddingBottom);\n --pf-c-jump-links__link--PaddingLeft: var(--pf-c-jump-links__list__list__link--PaddingLeft);\n margin-top: var(--pf-c-jump-links__list__list--MarginTop); }\n\n.pf-c-jump-links__link {\n position: relative;\n display: flex;\n flex: 1;\n padding-top: var(--pf-c-jump-links__link--PaddingTop);\n padding-right: var(--pf-c-jump-links__link--PaddingRight);\n padding-bottom: var(--pf-c-jump-links__link--PaddingBottom);\n padding-left: var(--pf-c-jump-links__link--PaddingLeft);\n text-decoration: none;\n outline-offset: var(--pf-c-jump-links__link--OutlineOffset); }\n .pf-c-jump-links__link:hover {\n --pf-c-jump-links__link-text--Color: var(--pf-c-jump-links__link--hover__link-text--Color); }\n .pf-c-jump-links__link:focus {\n --pf-c-jump-links__link-text--Color: var(--pf-c-jump-links__link--focus__link-text--Color);\n --pf-c-jump-links__link--before--BorderTopWidth: var(--pf-c-jump-links__link--focus--before--BorderTopWidth);\n --pf-c-jump-links__link--before--BorderLeftWidth: var(--pf-c-jump-links__link--focus--before--BorderLeftWidth);\n --pf-c-jump-links__link--before--BorderColor: var(--pf-c-jump-links__link--focus--before--BorderColor); }\n .pf-c-jump-links__link::before {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n pointer-events: none;\n content: \"\";\n border-color: var(--pf-c-jump-links__link--before--BorderColor);\n border-style: solid;\n border-width: var(--pf-c-jump-links__link--before--BorderTopWidth) var(--pf-c-jump-links__link--before--BorderRightWidth) var(--pf-c-jump-links__link--before--BorderBottomWidth) var(--pf-c-jump-links__link--before--BorderLeftWidth); }\n\n.pf-c-jump-links__item {\n --pf-c-jump-links__list--before--BorderColor: transparent; }\n .pf-c-jump-links__item.pf-m-current > .pf-c-jump-links__link {\n --pf-c-jump-links__link--before--BorderTopWidth: var(--pf-c-jump-links__item--m-current__link--before--BorderTopWidth);\n --pf-c-jump-links__link--before--BorderLeftWidth: var(--pf-c-jump-links__item--m-current__link--before--BorderLeftWidth);\n --pf-c-jump-links__link--before--BorderColor: var(--pf-c-jump-links__item--m-current__link--before--BorderColor);\n --pf-c-jump-links__link-text--Color: var(--pf-c-jump-links__item--m-current__link-text--Color); }\n\n.pf-c-jump-links__link-text {\n color: var(--pf-c-jump-links__link-text--Color); }\n\n.pf-c-jump-links__label {\n margin-bottom: var(--pf-c-jump-links__label--MarginBottom); }\n\n.pf-c-jump-links__main {\n display: flex;\n flex-direction: column; }\n\n.pf-c-label {\n --pf-c-label--PaddingTop: var(--pf-global--spacer--xs);\n --pf-c-label--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-label--PaddingBottom: var(--pf-global--spacer--xs);\n --pf-c-label--PaddingLeft: var(--pf-global--spacer--sm);\n --pf-c-label--BorderRadius: var(--pf-global--BorderRadius--lg);\n --pf-c-label--BackgroundColor: var(--pf-global--BackgroundColor--200);\n --pf-c-label--Color: var(--pf-global--Color--100);\n --pf-c-label--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-label__content--before--BorderWidth: 0;\n --pf-c-label__content--before--BorderColor: transparent;\n --pf-c-label--m-outline--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-label--m-outline__content--before--BorderWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-label--m-outline__content--before--BorderColor: var(--pf-global--BorderColor--100);\n --pf-c-label__content--link--hover--before--BorderWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-label__content--link--focus--before--BorderWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-label__content--link--hover--before--BorderColor: var(--pf-global--BorderColor--200);\n --pf-c-label__content--link--focus--before--BorderColor: var(--pf-global--BorderColor--200);\n --pf-c-label--m-outline__content--link--hover--before--BorderWidth: var(--pf-global--BorderWidth--md);\n --pf-c-label--m-outline__content--link--focus--before--BorderWidth: var(--pf-global--BorderWidth--md);\n --pf-c-label--m-outline__content--link--hover--before--BorderColor: var(--pf-global--BorderColor--100);\n --pf-c-label--m-outline__content--link--focus--before--BorderColor: var(--pf-global--BorderColor--100);\n --pf-c-label--m-blue--BackgroundColor: var(--pf-global--palette--blue-50);\n --pf-c-label--m-blue__content--Color: var(--pf-global--info-color--200);\n --pf-c-label--m-blue__icon--Color: var(--pf-global--primary-color--100);\n --pf-c-label--m-blue__content--link--hover--before--BorderColor: var(--pf-global--primary-color--100);\n --pf-c-label--m-blue__content--link--focus--before--BorderColor: var(--pf-global--primary-color--100);\n --pf-c-label--m-outline--m-blue__content--before--BorderColor: var(--pf-global--active-color--200);\n --pf-c-label--m-outline--m-blue__content--link--hover--before--BorderColor: var(--pf-global--active-color--200);\n --pf-c-label--m-outline--m-blue__content--link--focus--before--BorderColor: var(--pf-global--active-color--200);\n --pf-c-label--m-green--BackgroundColor: var(--pf-global--palette--green-50);\n --pf-c-label--m-green__content--Color: var(--pf-global--success-color--200);\n --pf-c-label--m-green__icon--Color: var(--pf-global--success-color--100);\n --pf-c-label--m-green__content--link--hover--before--BorderColor: var(--pf-global--success-color--100);\n --pf-c-label--m-green__content--link--focus--before--BorderColor: var(--pf-global--success-color--100);\n --pf-c-label--m-outline--m-green__content--before--BorderColor: var(--pf-global--palette--green-100);\n --pf-c-label--m-outline--m-green__content--link--hover--before--BorderColor: var(--pf-global--palette--green-100);\n --pf-c-label--m-outline--m-green__content--link--focus--before--BorderColor: var(--pf-global--palette--green-100);\n --pf-c-label--m-orange--BackgroundColor: var(--pf-global--palette--gold-50);\n --pf-c-label--m-orange__content--Color: var(--pf-global--palette--gold-700);\n --pf-c-label--m-orange__icon--Color: var(--pf-global--palette--orange-300);\n --pf-c-label--m-orange__content--link--hover--before--BorderColor: var(--pf-global--palette--orange-300);\n --pf-c-label--m-orange__content--link--focus--before--BorderColor: var(--pf-global--palette--orange-300);\n --pf-c-label--m-outline--m-orange__content--before--BorderColor: var(--pf-global--palette--gold-100);\n --pf-c-label--m-outline--m-orange__content--link--hover--before--BorderColor: var(--pf-global--palette--gold-100);\n --pf-c-label--m-outline--m-orange__content--link--focus--before--BorderColor: var(--pf-global--palette--gold-100);\n --pf-c-label--m-red--BackgroundColor: var(--pf-global--palette--red-50);\n --pf-c-label--m-red__content--Color: var(--pf-global--palette--red-300);\n --pf-c-label--m-red__icon--Color: var(--pf-global--danger-color--100);\n --pf-c-label--m-red__content--link--hover--before--BorderColor: var(--pf-global--danger-color--100);\n --pf-c-label--m-red__content--link--focus--before--BorderColor: var(--pf-global--danger-color--100);\n --pf-c-label--m-outline--m-red__content--before--BorderColor: var(--pf-global--danger-color--100);\n --pf-c-label--m-outline--m-red__content--link--hover--before--BorderColor: var(--pf-global--danger-color--100);\n --pf-c-label--m-outline--m-red__content--link--focus--before--BorderColor: var(--pf-global--danger-color--100);\n --pf-c-label--m-purple--BackgroundColor: var(--pf-global--palette--purple-50);\n --pf-c-label--m-purple__content--Color: var(--pf-global--palette--purple-700);\n --pf-c-label--m-purple__icon--Color: var(--pf-global--palette--purple-500);\n --pf-c-label--m-purple__content--link--hover--before--BorderColor: var(--pf-global--palette--purple-500);\n --pf-c-label--m-purple__content--link--focus--before--BorderColor: var(--pf-global--palette--purple-500);\n --pf-c-label--m-outline--m-purple__content--before--BorderColor: var(--pf-global--palette--purple-100);\n --pf-c-label--m-outline--m-purple__content--link--hover--before--BorderColor: var(--pf-global--palette--purple-100);\n --pf-c-label--m-outline--m-purple__content--link--focus--before--BorderColor: var(--pf-global--palette--purple-100);\n --pf-c-label--m-cyan--BackgroundColor: var(--pf-global--palette--cyan-50);\n --pf-c-label--m-cyan__content--Color: var(--pf-global--default-color--300);\n --pf-c-label--m-cyan__icon--Color: var(--pf-global--default-color--200);\n --pf-c-label--m-cyan__content--link--hover--before--BorderColor: var(--pf-global--default-color--200);\n --pf-c-label--m-cyan__content--link--focus--before--BorderColor: var(--pf-global--default-color--200);\n --pf-c-label--m-outline--m-cyan__content--before--BorderColor: var(--pf-global--palette--cyan-100);\n --pf-c-label--m-outline--m-cyan__content--link--hover--before--BorderColor: var(--pf-global--palette--cyan-100);\n --pf-c-label--m-outline--m-cyan__content--link--focus--before--BorderColor: var(--pf-global--palette--cyan-100);\n --pf-c-label--m-overflow__content--Color: var(--pf-global--link--Color);\n --pf-c-label--m-overflow__content--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-label--m-overflow__content--before--BorderWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-label--m-overflow__content--before--BorderColor: var(--pf-global--BorderColor--300);\n --pf-c-label--m-overflow__content--link--hover--before--BorderWidth: var(--pf-global--BorderWidth--md);\n --pf-c-label--m-overflow__content--link--hover--before--BorderColor: var(--pf-global--BorderColor--300);\n --pf-c-label--m-overflow__content--link--focus--before--BorderWidth: var(--pf-global--BorderWidth--md);\n --pf-c-label--m-overflow__content--link--focus--before--BorderColor: var(--pf-global--BorderColor--300);\n --pf-c-label__content--Color: var(--pf-global--Color--100);\n --pf-c-label__text--MaxWidth: 16ch;\n --pf-c-label__icon--Color: var(--pf-global--Color--100);\n --pf-c-label__icon--MarginRight: var(--pf-global--spacer--xs);\n --pf-c-label__c-button--FontSize: var(--pf-global--FontSize--xs);\n --pf-c-label__c-button--MarginTop: calc(var(--pf-global--spacer--form-element) * -1);\n --pf-c-label__c-button--MarginRight: calc(var(--pf-global--spacer--form-element) * -1);\n --pf-c-label__c-button--MarginBottom: calc(var(--pf-global--spacer--form-element) * -1);\n --pf-c-label__c-button--MarginLeft: var(--pf-global--spacer--xs);\n --pf-c-label__c-button--PaddingTop: var(--pf-global--spacer--xs);\n --pf-c-label__c-button--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-label__c-button--PaddingBottom: var(--pf-global--spacer--xs);\n --pf-c-label__c-button--PaddingLeft: var(--pf-global--spacer--sm);\n position: relative;\n padding: var(--pf-c-label--PaddingTop) var(--pf-c-label--PaddingRight) var(--pf-c-label--PaddingBottom) var(--pf-c-label--PaddingLeft);\n font-size: var(--pf-c-label--FontSize);\n color: var(--pf-c-label--Color);\n white-space: nowrap;\n background-color: var(--pf-c-label--BackgroundColor);\n border: 0;\n border-radius: var(--pf-c-label--BorderRadius); }\n .pf-c-label.pf-m-blue {\n --pf-c-label--BackgroundColor: var(--pf-c-label--m-blue--BackgroundColor);\n --pf-c-label__content--Color: var(--pf-c-label--m-blue__content--Color);\n --pf-c-label__icon--Color: var(--pf-c-label--m-blue__icon--Color);\n --pf-c-label--m-outline__content--before--BorderColor: var(--pf-c-label--m-outline--m-blue__content--before--BorderColor);\n --pf-c-label__content--link--hover--before--BorderColor: var(--pf-c-label--m-blue__content--link--hover--before--BorderColor);\n --pf-c-label__content--link--focus--before--BorderColor: var(--pf-c-label--m-blue__content--link--focus--before--BorderColor);\n --pf-c-label--m-outline__content--link--hover--before--BorderColor: var(--pf-c-label--m-outline--m-blue__content--link--hover--before--BorderColor);\n --pf-c-label--m-outline__content--link--focus--before--BorderColor: var(--pf-c-label--m-outline--m-blue__content--link--focus--before--BorderColor); }\n .pf-c-label.pf-m-green {\n --pf-c-label--BackgroundColor: var(--pf-c-label--m-green--BackgroundColor);\n --pf-c-label__content--Color: var(--pf-c-label--m-green__content--Color);\n --pf-c-label__icon--Color: var(--pf-c-label--m-green__icon--Color);\n --pf-c-label--m-outline__content--before--BorderColor: var(--pf-c-label--m-outline--m-green__content--before--BorderColor);\n --pf-c-label__content--link--hover--before--BorderColor: var(--pf-c-label--m-green__content--link--hover--before--BorderColor);\n --pf-c-label__content--link--focus--before--BorderColor: var(--pf-c-label--m-green__content--link--focus--before--BorderColor);\n --pf-c-label--m-outline__content--link--hover--before--BorderColor: var(--pf-c-label--m-outline--m-green__content--link--hover--before--BorderColor);\n --pf-c-label--m-outline__content--link--focus--before--BorderColor: var(--pf-c-label--m-outline--m-green__content--link--focus--before--BorderColor); }\n .pf-c-label.pf-m-orange {\n --pf-c-label--BackgroundColor: var(--pf-c-label--m-orange--BackgroundColor);\n --pf-c-label__content--Color: var(--pf-c-label--m-orange__content--Color);\n --pf-c-label__icon--Color: var(--pf-c-label--m-orange__icon--Color);\n --pf-c-label--m-outline__content--before--BorderColor: var(--pf-c-label--m-outline--m-orange__content--before--BorderColor);\n --pf-c-label__content--link--hover--before--BorderColor: var(--pf-c-label--m-orange__content--link--hover--before--BorderColor);\n --pf-c-label__content--link--focus--before--BorderColor: var(--pf-c-label--m-orange__content--link--focus--before--BorderColor);\n --pf-c-label--m-outline__content--link--hover--before--BorderColor: var(--pf-c-label--m-outline--m-orange__content--link--hover--before--BorderColor);\n --pf-c-label--m-outline__content--link--focus--before--BorderColor: var(--pf-c-label--m-outline--m-orange__content--link--focus--before--BorderColor); }\n .pf-c-label.pf-m-red {\n --pf-c-label--BackgroundColor: var(--pf-c-label--m-red--BackgroundColor);\n --pf-c-label__content--Color: var(--pf-c-label--m-red__content--Color);\n --pf-c-label__icon--Color: var(--pf-c-label--m-red__icon--Color);\n --pf-c-label--m-outline__content--before--BorderColor: var(--pf-c-label--m-outline--m-red__content--before--BorderColor);\n --pf-c-label__content--link--hover--before--BorderColor: var(--pf-c-label--m-red__content--link--hover--before--BorderColor);\n --pf-c-label__content--link--focus--before--BorderColor: var(--pf-c-label--m-red__content--link--focus--before--BorderColor);\n --pf-c-label--m-outline__content--link--hover--before--BorderColor: var(--pf-c-label--m-outline--m-red__content--link--hover--before--BorderColor);\n --pf-c-label--m-outline__content--link--focus--before--BorderColor: var(--pf-c-label--m-outline--m-red__content--link--focus--before--BorderColor); }\n .pf-c-label.pf-m-purple {\n --pf-c-label--BackgroundColor: var(--pf-c-label--m-purple--BackgroundColor);\n --pf-c-label__content--Color: var(--pf-c-label--m-purple__content--Color);\n --pf-c-label__icon--Color: var(--pf-c-label--m-purple__icon--Color);\n --pf-c-label--m-outline__content--before--BorderColor: var(--pf-c-label--m-outline--m-purple__content--before--BorderColor);\n --pf-c-label__content--link--hover--before--BorderColor: var(--pf-c-label--m-purple__content--link--hover--before--BorderColor);\n --pf-c-label__content--link--focus--before--BorderColor: var(--pf-c-label--m-purple__content--link--focus--before--BorderColor);\n --pf-c-label--m-outline__content--link--hover--before--BorderColor: var(--pf-c-label--m-outline--m-purple__content--link--hover--before--BorderColor);\n --pf-c-label--m-outline__content--link--focus--before--BorderColor: var(--pf-c-label--m-outline--m-purple__content--link--focus--before--BorderColor); }\n .pf-c-label.pf-m-cyan {\n --pf-c-label--BackgroundColor: var(--pf-c-label--m-cyan--BackgroundColor);\n --pf-c-label__content--Color: var(--pf-c-label--m-cyan__content--Color);\n --pf-c-label__icon--Color: var(--pf-c-label--m-cyan__icon--Color);\n --pf-c-label--m-outline__content--before--BorderColor: var(--pf-c-label--m-outline--m-cyan__content--before--BorderColor);\n --pf-c-label__content--link--hover--before--BorderColor: var(--pf-c-label--m-cyan__content--link--hover--before--BorderColor);\n --pf-c-label__content--link--focus--before--BorderColor: var(--pf-c-label--m-cyan__content--link--focus--before--BorderColor);\n --pf-c-label--m-outline__content--link--hover--before--BorderColor: var(--pf-c-label--m-outline--m-cyan__content--link--hover--before--BorderColor);\n --pf-c-label--m-outline__content--link--focus--before--BorderColor: var(--pf-c-label--m-outline--m-cyan__content--link--focus--before--BorderColor); }\n .pf-c-label.pf-m-outline {\n --pf-c-label__content--before--BorderWidth: var(--pf-c-label--m-outline__content--before--BorderWidth);\n --pf-c-label__content--before--BorderColor: var(--pf-c-label--m-outline__content--before--BorderColor);\n --pf-c-label--BackgroundColor: var(--pf-c-label--m-outline--BackgroundColor); }\n .pf-c-label.pf-m-overflow:hover, .pf-c-label.pf-m-outline a.pf-c-label__content:hover,\n .pf-c-label.pf-m-outline button.pf-c-label__content:hover {\n --pf-c-label__content--before--BorderWidth: var(--pf-c-label--m-outline__content--link--hover--before--BorderWidth);\n --pf-c-label__content--before--BorderColor: var(--pf-c-label--m-outline__content--link--hover--before--BorderColor); }\n .pf-c-label.pf-m-overflow:focus, .pf-c-label.pf-m-outline a.pf-c-label__content:focus,\n .pf-c-label.pf-m-outline button.pf-c-label__content:focus {\n --pf-c-label__content--before--BorderWidth: var(--pf-c-label--m-outline__content--link--focus--before--BorderWidth);\n --pf-c-label__content--before--BorderColor: var(--pf-c-label--m-outline__content--link--focus--before--BorderColor); }\n .pf-c-label .pf-c-button {\n --pf-c-button--FontSize: var(--pf-c-label__c-button--FontSize);\n --pf-c-button--PaddingTop: var(--pf-c-label__c-button--PaddingTop);\n --pf-c-button--PaddingRight: var(--pf-c-label__c-button--PaddingRight);\n --pf-c-button--PaddingBottom: var(--pf-c-label__c-button--PaddingBottom);\n --pf-c-button--PaddingLeft: var(--pf-c-label__c-button--PaddingLeft);\n margin-top: var(--pf-c-label__c-button--MarginTop);\n margin-right: var(--pf-c-label__c-button--MarginRight);\n margin-bottom: var(--pf-c-label__c-button--MarginBottom);\n margin-left: var(--pf-c-label__c-button--MarginLeft); }\n .pf-c-label.pf-m-overflow {\n --pf-c-label__content--Color: var(--pf-c-label--m-overflow__content--Color);\n --pf-c-label--BackgroundColor: var(--pf-c-label--m-overflow__content--BackgroundColor);\n --pf-c-label__content--before--BorderWidth: var(--pf-c-label--m-overflow__content--before--BorderWidth);\n --pf-c-label__content--before--BorderColor: var(--pf-c-label--m-overflow__content--before--BorderColor);\n --pf-c-label__content--link--hover--before--BorderWidth: var(--pf-c-label--m-overflow__content--link--hover--before--BorderWidth);\n --pf-c-label__content--link--hover--before--BorderColor: var(--pf-c-label--m-overflow__content--link--hover--before--BorderColor);\n --pf-c-label__content--link--focus--before--BorderWidth: var(--pf-c-label--m-overflow__content--link--focus--before--BorderWidth);\n --pf-c-label__content--link--focus--before--BorderColor: var(--pf-c-label--m-overflow__content--link--focus--before--BorderColor); }\n\n.pf-c-label,\n.pf-c-label__content {\n display: inline-flex;\n align-items: center; }\n\n.pf-c-label__text {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n max-width: var(--pf-c-label__text--MaxWidth); }\n\n.pf-c-label__content {\n color: var(--pf-c-label__content--Color);\n border: 0; }\n .pf-c-label__content::before {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n content: \"\";\n border: var(--pf-c-label__content--before--BorderWidth) solid var(--pf-c-label__content--before--BorderColor);\n border-radius: var(--pf-c-label--BorderRadius); }\n a.pf-c-label__content,\n button.pf-c-label__content {\n cursor: pointer;\n border: none; }\n a.pf-c-label__content, a.pf-c-label__content:hover, a.pf-c-label__content:focus,\n button.pf-c-label__content,\n button.pf-c-label__content:hover,\n button.pf-c-label__content:focus {\n text-decoration: none; }\n a.pf-c-label__content:hover,\n button.pf-c-label__content:hover {\n --pf-c-label__content--before--BorderWidth: var(--pf-c-label__content--link--hover--before--BorderWidth);\n --pf-c-label__content--before--BorderColor: var(--pf-c-label__content--link--hover--before--BorderColor); }\n a.pf-c-label__content:focus,\n button.pf-c-label__content:focus {\n --pf-c-label__content--before--BorderWidth: var(--pf-c-label__content--link--focus--before--BorderWidth);\n --pf-c-label__content--before--BorderColor: var(--pf-c-label__content--link--focus--before--BorderColor); }\n\n.pf-c-label__icon {\n margin-right: var(--pf-c-label__icon--MarginRight);\n color: var(--pf-c-label__icon--Color); }\n\n.pf-c-label-group {\n --pf-c-label-group__list--MarginBottom: calc(var(--pf-global--spacer--xs) * -1);\n --pf-c-label-group__list--MarginRight: calc(var(--pf-global--spacer--xs) * -1);\n --pf-c-label-group--m-category--PaddingTop: var(--pf-global--spacer--xs);\n --pf-c-label-group--m-category--PaddingRight: var(--pf-global--spacer--xs);\n --pf-c-label-group--m-category--PaddingBottom: var(--pf-global--spacer--xs);\n --pf-c-label-group--m-category--PaddingLeft: var(--pf-global--spacer--sm);\n --pf-c-label-group--m-vertical--m-category--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-label-group--m-category--BorderRadius: var(--pf-global--BorderRadius--sm);\n --pf-c-label-group--m-category--BorderWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-label-group--m-category--BorderColor: var(--pf-global--BorderColor--300);\n --pf-c-label-group--m-category--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-label-group__label--MarginRight: var(--pf-global--spacer--sm);\n --pf-c-label-group__label--MarginBottom: 0;\n --pf-c-label-group--m-vertical__label--MarginBottom: var(--pf-global--spacer--sm);\n --pf-c-label-group__label--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-label-group__label--MaxWidth: 18ch;\n --pf-c-label-group__close--MarginTop: calc(var(--pf-global--spacer--xs) * -1);\n --pf-c-label-group__close--MarginBottom: calc(var(--pf-global--spacer--xs) * -1);\n --pf-c-label-group--m-vertical__close--MarginTop: calc(var(--pf-global--spacer--form-element) * -1);\n --pf-c-label-group--m-vertical__close--MarginRight: calc(var(--pf-global--spacer--form-element) * -1);\n --pf-c-label-group--m-vertical__close--MarginLeft: var(--pf-global--spacer--sm);\n --pf-c-label-group--m-vertical__close--c-button--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-label-group--m-vertical__close--c-button--PaddingLeft: var(--pf-global--spacer--sm);\n --pf-c-label-group__list-item--MarginRight: var(--pf-global--spacer--xs);\n --pf-c-label-group__list-item--MarginBottom: var(--pf-global--spacer--xs);\n display: inline-flex; }\n .pf-c-label-group.pf-m-category {\n padding-top: var(--pf-c-label-group--m-category--PaddingTop);\n padding-right: var(--pf-c-label-group--m-category--PaddingRight);\n padding-bottom: var(--pf-c-label-group--m-category--PaddingBottom);\n padding-left: var(--pf-c-label-group--m-category--PaddingLeft);\n background-color: var(--pf-c-label-group--m-category--BackgroundColor);\n border: var(--pf-c-label-group--m-category--BorderWidth) solid var(--pf-c-label-group--m-category--BorderColor);\n border-radius: var(--pf-c-label-group--m-category--BorderRadius); }\n .pf-c-label-group.pf-m-vertical {\n --pf-c-label-group__list--MarginRight: 0;\n --pf-c-label-group__list--MarginBottom: 0;\n --pf-c-label-group__list-item--MarginRight: 0;\n --pf-c-label-group__label--MarginRight: 0;\n --pf-c-label-group__label--MarginBottom: var(--pf-c-label-group--m-vertical__label--MarginBottom);\n --pf-c-label-group__close--MarginTop: var(--pf-c-label-group--m-vertical__close--MarginTop);\n --pf-c-label-group__close--MarginLeft: var(--pf-c-label-group--m-vertical__close--MarginLeft);\n --pf-c-label-group__close--MarginBottom: 0;\n --pf-c-label-group__close--MarginRight: var(--pf-c-label-group--m-vertical__close--MarginRight);\n --pf-c-label-group--m-category--PaddingRight: var(--pf-c-label-group--m-vertical--m-category--PaddingRight); }\n .pf-c-label-group.pf-m-vertical.pf-c-label-group {\n align-items: flex-start; }\n .pf-c-label-group.pf-m-vertical .pf-c-label-group__list {\n flex-direction: column;\n align-items: flex-start; }\n .pf-c-label-group.pf-m-vertical .pf-c-label-group__main {\n flex-direction: column; }\n .pf-c-label-group.pf-m-vertical .pf-c-label-group__list-item:last-child {\n --pf-c-label-group__list-item--MarginBottom: 0; }\n .pf-c-label-group.pf-m-vertical .pf-c-label-group__close .pf-c-button {\n --pf-c-button--PaddingLeft: var(--pf-c-label-group--m-vertical__close--c-button--PaddingLeft);\n --pf-c-button--PaddingRight: var(--pf-c-label-group--m-vertical__close--c-button--PaddingRight); }\n\n.pf-c-label-group__main {\n display: flex;\n flex: 1;\n flex-wrap: wrap;\n align-items: baseline; }\n\n.pf-c-label-group__list {\n display: inline-flex;\n flex-wrap: wrap;\n margin-right: var(--pf-c-label-group__list--MarginRight);\n margin-bottom: var(--pf-c-label-group__list--MarginBottom); }\n\n.pf-c-label-group__list-item {\n display: inline-flex;\n margin-right: var(--pf-c-label-group__list-item--MarginRight);\n margin-bottom: var(--pf-c-label-group__list-item--MarginBottom); }\n\n.pf-c-label-group__label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n max-width: var(--pf-c-label-group__label--MaxWidth);\n margin-right: var(--pf-c-label-group__label--MarginRight);\n margin-bottom: var(--pf-c-label-group__label--MarginBottom);\n font-size: var(--pf-c-label-group__label--FontSize); }\n\n.pf-c-label-group__close {\n margin-top: var(--pf-c-label-group__close--MarginTop);\n margin-right: var(--pf-c-label-group__close--MarginRight);\n margin-bottom: var(--pf-c-label-group__close--MarginBottom);\n margin-left: var(--pf-c-label-group__close--MarginLeft); }\n\n.pf-c-list {\n --pf-c-list--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-list--nested--MarginTop: var(--pf-global--spacer--sm);\n --pf-c-list--nested--MarginLeft: var(--pf-global--spacer--sm);\n --pf-c-list--ul--ListStyle: var(--pf-global--ListStyle);\n --pf-c-list--li--MarginTop: var(--pf-global--spacer--sm);\n --pf-c-list--m-inline--li--MarginRight: var(--pf-global--spacer--lg);\n padding-left: var(--pf-c-list--PaddingLeft); }\n .pf-c-list ol,\n .pf-c-list ul {\n margin-top: var(--pf-c-list--nested--MarginTop);\n margin-left: var(--pf-c-list--nested--MarginLeft); }\n .pf-c-list li + li {\n margin-top: var(--pf-c-list--li--MarginTop); }\n ul.pf-c-list:not(.pf-m-inline) {\n list-style: var(--pf-c-list--ul--ListStyle); }\n .pf-c-list.pf-m-inline {\n --pf-c-list--PaddingLeft: 0;\n display: flex;\n flex-wrap: wrap; }\n .pf-c-list.pf-m-inline li {\n --pf-c-list--li--MarginTop: 0; }\n .pf-c-list.pf-m-inline li:not(:last-child) {\n margin-right: var(--pf-c-list--m-inline--li--MarginRight); }\n\n.pf-c-login {\n --pf-c-login--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-login--PaddingBottom: var(--pf-global--spacer--lg);\n --pf-c-login--xl--BackgroundImage: none;\n --pf-c-login__container--xl--GridColumnGap: var(--pf-global--spacer--3xl);\n --pf-c-login__container--MaxWidth: 31.25rem;\n --pf-c-login__container--xl--MaxWidth: none;\n --pf-c-login__container--PaddingLeft: 6.125rem;\n --pf-c-login__container--PaddingRight: 6.125rem;\n --pf-c-login__container--xl--GridTemplateColumns: 34rem minmax(auto, 34rem);\n --pf-c-login__header--MarginBottom: var(--pf-global--spacer--md);\n --pf-c-login__header--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-login__header--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-login__header--xl--MarginBottom: var(--pf-global--spacer--2xl);\n --pf-c-login__header--xl--MarginTop: var(--pf-global--spacer--3xl);\n --pf-c-login__header--c-brand--MarginBottom: var(--pf-global--spacer--lg);\n --pf-c-login__header--c-brand--xl--MarginBottom: var(--pf-global--spacer--2xl);\n --pf-c-login__main--BackgroundColor: var(--pf-global--BackgroundColor--light-100);\n --pf-c-login__main--MarginBottom: var(--pf-global--spacer--lg);\n --pf-c-login__main-header--PaddingTop: var(--pf-global--spacer--2xl);\n --pf-c-login__main-header--PaddingRight: var(--pf-global--spacer--xl);\n --pf-c-login__main-header--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-login__main-header--PaddingLeft: var(--pf-global--spacer--xl);\n --pf-c-login__main-header--md--PaddingRight: var(--pf-global--spacer--2xl);\n --pf-c-login__main-header--md--PaddingLeft: var(--pf-global--spacer--2xl);\n --pf-c-login__main-header--ColumnGap: var(--pf-global--spacer--md);\n --pf-c-login__main-header--RowGap: var(--pf-global--spacer--md);\n --pf-c-login__main-header-desc--MarginBottom: var(--pf-global--spacer--sm);\n --pf-c-login__main-header-desc--md--MarginBottom: 0;\n --pf-c-login__main-header-desc--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-login__main-body--PaddingRight: var(--pf-global--spacer--xl);\n --pf-c-login__main-body--PaddingBottom: var(--pf-global--spacer--xl);\n --pf-c-login__main-body--PaddingLeft: var(--pf-global--spacer--xl);\n --pf-c-login__main-body--md--PaddingRight: var(--pf-global--spacer--2xl);\n --pf-c-login__main-body--md--PaddingLeft: var(--pf-global--spacer--2xl);\n --pf-c-login__main-footer--PaddingBottom: var(--pf-global--spacer--3xl);\n --pf-c-login__main-footer--c-title--MarginBottom: var(--pf-global--spacer--md);\n --pf-c-login__main-footer-links--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-login__main-footer-links--PaddingRight: var(--pf-global--spacer--3xl);\n --pf-c-login__main-footer-links--PaddingBottom: var(--pf-global--spacer--xl);\n --pf-c-login__main-footer-links--PaddingLeft: var(--pf-global--spacer--3xl);\n --pf-c-login__main-footer-links-item--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-login__main-footer-links-item--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-login__main-footer-links-item--MarginBottom: var(--pf-global--spacer--sm);\n --pf-c-login__main-footer-links-item-link-svg--Fill: var(--pf-global--icon--Color--light);\n --pf-c-login__main-footer-links-item-link-svg--Width: var(--pf-global--icon--FontSize--lg);\n --pf-c-login__main-footer-links-item-link-svg--Height: var(--pf-global--icon--FontSize--lg);\n --pf-c-login__main-footer-links-item-link-svg--hover--Fill: var(--pf-global--icon--Color--dark);\n --pf-c-login__main-footer-band--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-login__main-footer-band--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-login__main-footer-band--PaddingBottom: var(--pf-global--spacer--lg);\n --pf-c-login__main-footer-band--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-login__main-footer-band--BackgroundColor: var(--pf-global--BackgroundColor--200);\n --pf-c-login__main-footer-band-item--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-login__footer--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-login__footer--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-login__footer--c-list--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-login__footer--c-list--xl--PaddingTop: var(--pf-global--spacer--2xl);\n display: flex;\n justify-content: center;\n min-height: 100vh;\n padding-top: var(--pf-c-login--PaddingTop);\n padding-bottom: var(--pf-c-login--PaddingBottom); }\n @media (min-width: 1200px) {\n .pf-c-login {\n --pf-c-login__container--MaxWidth: var(--pf-c-login__container--xl--MaxWidth); } }\n @media (min-width: 576px) {\n .pf-c-login {\n --pf-c-login__header--PaddingRight: 0;\n --pf-c-login__header--PaddingLeft: 0; } }\n @media (min-width: 1200px) {\n .pf-c-login {\n --pf-c-login__header--MarginBottom: var(--pf-c-login__header--xl--MarginBottom);\n --pf-c-login__header--c-brand--MarginBottom: var(--pf-c-login__header--c-brand--xl--MarginBottom); } }\n @media (min-width: 1200px) {\n .pf-c-login {\n --pf-c-login__main--MarginBottom: 0; } }\n @media (min-width: 768px) {\n .pf-c-login {\n --pf-c-login__main-header--PaddingRight: var(--pf-c-login__main-header--md--PaddingRight);\n --pf-c-login__main-header--PaddingLeft: var(--pf-c-login__main-header--md--PaddingLeft);\n --pf-c-login__main-header-desc--MarginBottom: var(--pf-c-login__main-header-desc--md--MarginBottom); } }\n @media (min-width: 768px) {\n .pf-c-login {\n --pf-c-login__main-body--PaddingRight: var(--pf-c-login__main-body--md--PaddingRight);\n --pf-c-login__main-body--PaddingLeft: var(--pf-c-login__main-body--md--PaddingLeft); } }\n @media (min-width: 576px) {\n .pf-c-login {\n --pf-c-login__footer--PaddingRight: 0;\n --pf-c-login__footer--PaddingLeft: 0; } }\n @media (min-width: 1200px) {\n .pf-c-login {\n --pf-c-login__footer--c-list--PaddingTop: var(--pf-c-login__footer--c-list--xl--PaddingTop); } }\n @media (min-width: 1200px) {\n .pf-c-login {\n background-image: var(--pf-c-login--xl--BackgroundImage); } }\n @media (min-width: 576px) {\n .pf-c-login {\n align-items: center; } }\n\n.pf-c-login__container {\n width: 100%;\n max-width: var(--pf-c-login__container--MaxWidth); }\n @media (min-width: 1200px) {\n .pf-c-login__container {\n display: grid;\n justify-content: center;\n grid-column-gap: var(--pf-c-login__container--xl--GridColumnGap);\n grid-template-columns: var(--pf-c-login__container--xl--GridTemplateColumns);\n grid-template-areas: \"main header\" \"main footer\" \"main .\";\n padding-right: var(--pf-c-login__container--PaddingRight);\n padding-left: var(--pf-c-login__container--PaddingLeft); } }\n\n.pf-c-login__header {\n color: var(--pf-global--Color--100);\n grid-area: header;\n padding-right: var(--pf-c-login__header--PaddingRight);\n padding-left: var(--pf-c-login__header--PaddingLeft); }\n @media (min-width: 1200px) {\n .pf-c-login__header {\n margin-top: var(--pf-c-login__header--xl--MarginTop); } }\n .pf-c-login__header .pf-c-brand {\n margin-bottom: var(--pf-c-login__header--c-brand--MarginBottom); }\n\n.pf-c-login__main {\n margin-bottom: var(--pf-c-login__main--MarginBottom);\n background-color: var(--pf-c-login__main--BackgroundColor);\n grid-area: main; }\n .pf-c-login__main > :first-child:not(.pf-c-login__main-header) {\n padding-top: var(--pf-c-login__main-header--PaddingTop); }\n .pf-c-login__main > :last-child:not(.pf-c-login__main-footer) {\n padding-bottom: var(--pf-c-login__main-footer--PaddingBottom); }\n\n.pf-c-login__main-header {\n display: grid;\n grid-template-columns: 100%;\n column-gap: var(--pf-c-login__main-header--ColumnGap);\n row-gap: var(--pf-c-login__main-header--RowGap);\n align-items: center;\n padding: var(--pf-c-login__main-header--PaddingTop) var(--pf-c-login__main-header--PaddingRight) var(--pf-c-login__main-header--PaddingBottom) var(--pf-c-login__main-header--PaddingLeft); }\n @media (min-width: 768px) {\n .pf-c-login__main-header {\n grid-template-columns: 1fr auto; } }\n .pf-c-login__main-header .pf-c-dropdown {\n grid-column: auto;\n grid-row: auto; }\n @media (min-width: 768px) {\n .pf-c-login__main-header .pf-c-dropdown {\n grid-column: 2 / 3;\n grid-row: 1; } }\n\n.pf-c-login__main-header-desc {\n margin-bottom: var(--pf-c-login__main-header-desc--MarginBottom);\n font-size: var(--pf-c-login__main-header-desc--FontSize);\n grid-column: 1 / -1; }\n\n.pf-c-login__main-body {\n padding-right: var(--pf-c-login__main-body--PaddingRight);\n padding-bottom: var(--pf-c-login__main-body--PaddingBottom);\n padding-left: var(--pf-c-login__main-body--PaddingLeft); }\n\n.pf-c-login__main-footer {\n display: flex;\n flex-wrap: wrap; }\n .pf-c-login__main-footer .pf-c-title {\n margin-bottom: var(--pf-c-login__main-footer--c-title--MarginBottom);\n text-align: center; }\n .pf-c-login__main-footer > * {\n flex-basis: 100%; }\n\n.pf-c-login__main-footer-links {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n padding: var(--pf-c-login__main-footer-links--PaddingTop) var(--pf-c-login__main-footer-links--PaddingRight) var(--pf-c-login__main-footer-links--PaddingBottom) var(--pf-c-login__main-footer-links--PaddingLeft); }\n\n.pf-c-login__main-footer-links-item {\n padding-right: var(--pf-c-login__main-footer-links-item--PaddingRight);\n padding-left: var(--pf-c-login__main-footer-links-item--PaddingLeft);\n margin-bottom: var(--pf-c-login__main-footer-links-item--MarginBottom); }\n\n.pf-c-login__main-footer-links-item-link svg {\n fill: var(--pf-c-login__main-footer-links-item-link-svg--Fill);\n width: 100%;\n max-width: var(--pf-c-login__main-footer-links-item-link-svg--Width);\n height: 100%;\n max-height: var(--pf-c-login__main-footer-links-item-link-svg--Height); }\n\n.pf-c-login__main-footer-links-item-link:hover svg {\n fill: var(--pf-c-login__main-footer-links-item-link-svg--hover--Fill); }\n\n.pf-c-login__main-footer-band {\n padding: var(--pf-c-login__main-footer-band--PaddingTop) var(--pf-c-login__main-footer-band--PaddingRight) var(--pf-c-login__main-footer-band--PaddingBottom) var(--pf-c-login__main-footer-band--PaddingLeft);\n text-align: center;\n background-color: var(--pf-c-login__main-footer-band--BackgroundColor); }\n .pf-c-login__main-footer-band > * + * {\n padding-top: var(--pf-c-login__main-footer-band-item--PaddingTop); }\n\n.pf-c-login__footer {\n color: var(--pf-global--Color--100);\n grid-area: footer;\n padding-right: var(--pf-c-login__footer--PaddingRight);\n padding-left: var(--pf-c-login__footer--PaddingLeft); }\n .pf-c-login__footer .pf-c-list a {\n color: unset; }\n .pf-c-login__footer .pf-c-list:not(:only-child) {\n padding-top: var(--pf-c-login__footer--c-list--PaddingTop); }\n\n.pf-c-menu {\n color: var(--pf-global--Color--100);\n --pf-c-menu--BackgroundColor: var(--pf-global--BackgroundColor--light-100);\n --pf-c-menu--BoxShadow: var(--pf-global--BoxShadow--md);\n --pf-c-menu--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-menu--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-menu--m-flyout__menu--Top: calc(var(--pf-c-menu--PaddingTop) * -1);\n --pf-c-menu--c-divider--MarginTop: var(--pf-global--spacer--sm);\n --pf-c-menu--c-divider--MarginBottom: var(--pf-global--spacer--sm);\n --pf-c-menu__search--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-menu__search--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-menu__search--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-menu__search--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-menu__list-item--Color: var(--pf-global--Color--100);\n --pf-c-menu__list-item--hover--Color: var(--pf-global--Color--100);\n --pf-c-menu__list-item--BackgroundColor: transparent;\n --pf-c-menu__list-item--hover--BackgroundColor: var(--pf-global--BackgroundColor--light-300);\n --pf-c-menu__item--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-menu__item--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-menu__item--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-menu__item--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-menu__item--OutlineOffset: calc(0.125rem * -1);\n --pf-c-menu__item--FontSize: var(--pf-global--FontSize--md);\n --pf-c-menu__item--FontWeight: var(--pf-global--FontWeight--normal);\n --pf-c-menu__item--LineHeight: var(--pf-global--LineHeight--md);\n --pf-c-menu__item--disabled--Color: var(--pf-global--Color--dark-200);\n --pf-c-menu__group-title--PaddingTop: var(--pf-c-menu__item--PaddingTop);\n --pf-c-menu__group-title--PaddingRight: var(--pf-c-menu__item--PaddingRight);\n --pf-c-menu__group-title--PaddingBottom: var(--pf-c-menu__item--PaddingBottom);\n --pf-c-menu__group-title--PaddingLeft: var(--pf-c-menu__item--PaddingLeft);\n --pf-c-menu__group-title--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-menu__group-title--FontWeight: var(--pf-global--FontWeight--semi-bold);\n --pf-c-menu__group-title--Color: var(--pf-global--Color--dark-200);\n --pf-c-menu__item-description--FontSize: var(--pf-global--FontSize--xs);\n --pf-c-menu__item-description--Color: var(--pf-global--Color--200);\n --pf-c-menu__item-icon--MarginRight: var(--pf-global--spacer--sm);\n --pf-c-menu__item-toggle-icon--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-menu__item-toggle-icon--PaddingLeft: var(--pf-global--spacer--sm);\n --pf-c-menu__item-text--item-toggle-icon--MarginLeft: var(--pf-global--spacer--sm);\n --pf-c-menu__item-toggle-icon--item-text--MarginLeft: var(--pf-global--spacer--sm);\n --pf-c-menu__item-select-icon--MarginLeft: var(--pf-global--spacer--sm);\n --pf-c-menu__item-select-icon--Color: var(--pf-global--active-color--100);\n --pf-c-menu__item-select-icon--FontSize: var(--pf-global--icon--FontSize--sm);\n --pf-c-menu__item-main__external-icon--MarginLeft: var(--pf-global--spacer--sm);\n --pf-c-menu__item-main__external-icon--Color: var(--pf-global--link--Color);\n --pf-c-menu__item-main__external-icon--FontSize: var(--pf-global--icon--FontSize--sm);\n --pf-c-menu__item-action--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-menu__item-action--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-menu__item-action--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-menu__item-action--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-menu__item-action-icon--Color: var(--pf-global--Color--dark-200);\n --pf-c-menu__item-action-icon--Height: calc(var(--pf-c-menu__item--FontSize) * var(--pf-c-menu__item--LineHeight));\n --pf-c-menu__item-action--hover__icon--Color: var(--pf-global--Color--dark-100);\n --pf-c-menu__item-action--m-favorite__icon--Color: var(--pf-global--disabled-color--200);\n --pf-c-menu__item-action--m-favorite__icon--FontSize: var(--pf-global--icon--FontSize--sm);\n --pf-c-menu__item-action--m-favorite--m-favorited__icon--Color: var(--pf-global--palette--gold-400);\n --pf-c-menu--m-drilldown--Width: auto;\n --pf-c-menu--m-drilldown--Height: auto;\n --pf-c-menu--m-drilldown--TransitionDuration--transform: var(--pf-global--TransitionDuration);\n --pf-c-menu--m-drilldown--TransitionDuration--height: var(--pf-global--TransitionDuration);\n --pf-c-menu--m-drilldown--Transition: transform var(--pf-c-menu--m-drilldown--TransitionDuration--transform), height var(--pf-c-menu--m-drilldown--TransitionDuration--height);\n --pf-c-menu--m-drilldown--c-menu--Top: calc(var(--pf-c-menu--PaddingTop) * -1);\n --pf-c-menu--m-drilldown--c-menu--TransitionDuration--transform: var(--pf-global--TransitionDuration);\n --pf-c-menu--m-drilldown--c-menu--TransitionDuration--visibility: var(--pf-global--TransitionDuration);\n --pf-c-menu--m-drilldown--c-menu--Transition: transform var(--pf-c-menu--m-drilldown--c-menu--TransitionDuration--transform), visibility var(--pf-c-menu--m-drilldown--c-menu--TransitionDuration--visibility);\n --pf-c-menu--m-drilldown__list--TransitionDuration--transform: var(--pf-global--TransitionDuration);\n --pf-c-menu--m-drilldown__list--Transition: transform var(--pf-c-menu--m-drilldown__list--TransitionDuration--transform);\n --pf-c-menu--m-drilled-in--c-menu__list-item--m-current-path--c-menu--ZIndex: var(--pf-global--ZIndex--2xl);\n padding-top: var(--pf-c-menu--PaddingTop);\n padding-bottom: var(--pf-c-menu--PaddingBottom);\n background-color: var(--pf-c-menu--BackgroundColor);\n box-shadow: var(--pf-c-menu--BoxShadow); }\n .pf-c-menu.pf-m-flyout .pf-c-menu {\n position: absolute;\n top: var(--pf-c-menu--m-flyout__menu--Top);\n left: 100%; }\n .pf-c-menu.pf-m-flyout .pf-c-menu__list-item {\n position: relative; }\n .pf-c-menu.pf-m-drilldown {\n width: var(--pf-c-menu--m-drilldown--Width);\n height: var(--pf-c-menu--m-drilldown--Height);\n overflow: hidden;\n transition: var(--pf-c-menu--m-drilldown--Transition); }\n .pf-c-menu.pf-m-drilldown.pf-m-drilled-in > .pf-c-menu__content > .pf-c-menu__list,\n .pf-c-menu.pf-m-drilldown.pf-m-drilled-in > .pf-c-menu__list {\n transform: translateX(-100%); }\n .pf-c-menu.pf-m-drilldown .pf-c-menu {\n --pf-c-menu--BoxShadow: none;\n position: absolute;\n top: var(--pf-c-menu--m-drilldown--c-menu--Top);\n left: 100%;\n width: 100%;\n transition: var(--pf-c-menu--m-drilldown--c-menu--Transition); }\n .pf-c-menu.pf-m-drilldown .pf-c-menu.pf-m-drilled-in {\n transform: translateX(-100%); }\n .pf-c-menu.pf-m-drilldown .pf-c-menu__list {\n position: relative;\n transition: var(--pf-c-menu--m-drilldown__list--Transition); }\n .pf-c-menu.pf-m-drilldown .pf-c-menu__list-item.pf-m-current-path .pf-c-menu {\n z-index: var(--pf-c-menu--m-drilled-in--c-menu__list-item--m-current-path--c-menu--ZIndex); }\n .pf-c-menu.pf-m-drilldown .pf-c-menu__list-item:not(.pf-m-current-path) .pf-c-menu {\n visibility: hidden; }\n .pf-c-menu.pf-m-drilldown .pf-c-menu__item {\n outline-offset: var(--pf-c-menu__item--OutlineOffset); }\n .pf-c-menu .pf-c-divider {\n margin-top: var(--pf-c-menu--c-divider--MarginTop);\n margin-bottom: var(--pf-c-menu--c-divider--MarginBottom); }\n\n.pf-c-menu__search {\n padding-top: var(--pf-c-menu__search--PaddingTop);\n padding-right: var(--pf-c-menu__search--PaddingRight);\n padding-bottom: var(--pf-c-menu__search--PaddingBottom);\n padding-left: var(--pf-c-menu__search--PaddingLeft); }\n\n.pf-c-menu__list-item {\n display: flex;\n color: var(--pf-c-menu__list-item--Color);\n background-color: var(--pf-c-menu__list-item--BackgroundColor); }\n .pf-c-menu__list-item:hover:not(.pf-m-disabled), .pf-c-menu__list-item:focus-within:not(.pf-m-disabled) {\n --pf-c-menu__list-item--Color: var(--pf-c-menu__list-item--hover--Color);\n --pf-c-menu__list-item--BackgroundColor: var(--pf-c-menu__list-item--hover--BackgroundColor); }\n .pf-c-menu__list-item:hover:not(.pf-m-disabled) .pf-c-menu__item-external-icon, .pf-c-menu__list-item:focus-within:not(.pf-m-disabled) .pf-c-menu__item-external-icon {\n opacity: 1; }\n .pf-c-menu__list-item.pf-m-disabled .pf-c-menu__item {\n --pf-c-menu__item--Color: var(--pf-c-menu__item--disabled--Color);\n pointer-events: none; }\n\n.pf-c-menu__item {\n display: flex;\n flex-basis: 100%;\n flex-direction: column;\n min-width: 0;\n padding-top: var(--pf-c-menu__item--PaddingTop);\n padding-right: var(--pf-c-menu__item--PaddingRight);\n padding-bottom: var(--pf-c-menu__item--PaddingBottom);\n padding-left: var(--pf-c-menu__item--PaddingLeft);\n font-size: var(--pf-c-menu__item--FontSize);\n font-weight: var(--pf-c-menu__item--FontWeight);\n line-height: var(--pf-c-menu__item--LineHeight);\n color: var(--pf-c-menu__item--Color);\n text-align: left;\n background-color: var(--pf-c-menu__item--BackgroundColor);\n border: none; }\n .pf-c-menu__item:hover {\n text-decoration: none; }\n .pf-c-menu__item:disabled {\n --pf-c-menu__item--Color: var(--pf-c-menu__item--disabled--Color);\n pointer-events: none; }\n .pf-c-menu__item.pf-m-selected .pf-c-menu__item-select-icon {\n opacity: 1; }\n\n.pf-c-menu__item-main {\n display: flex;\n align-items: center;\n width: 100%; }\n .pf-c-menu__item-main .pf-c-menu__item-external-icon {\n margin-left: var(--pf-c-menu__item-main__external-icon--MarginLeft);\n font-size: var(--pf-c-menu__item-main__external-icon--FontSize);\n color: var(--pf-c-menu__item-main__external-icon--Color);\n opacity: 0; }\n\n.pf-c-menu__item-text {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n flex-grow: 1; }\n\n.pf-c-menu__group-title {\n padding-top: var(--pf-c-menu__group-title--PaddingTop);\n padding-right: var(--pf-c-menu__group-title--PaddingRight);\n padding-bottom: var(--pf-c-menu__group-title--PaddingBottom);\n padding-left: var(--pf-c-menu__group-title--PaddingLeft);\n font-size: var(--pf-c-menu__group-title--FontSize);\n font-weight: var(--pf-c-menu__group-title--FontWeight);\n color: var(--pf-c-menu__group-title--Color); }\n\n.pf-c-menu__item-description {\n font-size: var(--pf-c-menu__item-description--FontSize);\n color: var(--pf-c-menu__item-description--Color);\n word-break: break-all; }\n\n.pf-c-menu__item-icon {\n margin-right: var(--pf-c-menu__item-icon--MarginRight); }\n\n.pf-c-menu__item-toggle-icon {\n padding-right: var(--pf-c-menu__item-toggle-icon--PaddingRight);\n padding-left: var(--pf-c-menu__item-toggle-icon--PaddingLeft); }\n\n.pf-c-menu__item-text + .pf-c-menu__item-toggle-icon {\n margin-left: var(--pf-c-menu__item-text--item-toggle-icon--MarginLeft); }\n\n.pf-c-menu__item-toggle-icon + .pf-c-menu__item-text {\n margin-left: var(--pf-c-menu__item-toggle-icon--item-text--MarginLeft); }\n\n.pf-c-menu__item-select-icon {\n margin-left: var(--pf-c-menu__item-select-icon--MarginLeft);\n font-size: var(--pf-c-menu__item-select-icon--FontSize);\n color: var(--pf-c-menu__item-select-icon--Color);\n opacity: 0; }\n\n.pf-c-menu__item-action {\n display: flex;\n padding-top: var(--pf-c-menu__item-action--PaddingTop);\n padding-right: var(--pf-c-menu__item-action--PaddingRight);\n padding-bottom: var(--pf-c-menu__item-action--PaddingBottom);\n padding-left: var(--pf-c-menu__item-action--PaddingLeft);\n border: none; }\n .pf-c-menu__item-action:hover, .pf-c-menu__item-action:focus {\n --pf-c-menu__item-action-icon--Color: var(--pf-c-menu__item-action--hover__icon--Color); }\n .pf-c-menu__item-action.pf-m-favorite {\n --pf-c-menu__item-action-icon--Color: var(--pf-c-menu__item-action--m-favorite__icon--Color); }\n .pf-c-menu__item-action.pf-m-favorite.pf-m-favorited {\n --pf-c-menu__item-action-icon--Color: var(--pf-c-menu__item-action--m-favorite--m-favorited__icon--Color); }\n .pf-c-menu__item-action.pf-m-favorite .pf-c-menu__item-action-icon {\n font-size: var(--pf-c-menu__item-action--m-favorite__icon--FontSize); }\n\n.pf-c-menu__item-action-icon {\n display: flex;\n align-items: center;\n height: var(--pf-c-menu__item-action-icon--Height);\n color: var(--pf-c-menu__item-action-icon--Color); }\n\n.pf-c-modal-box {\n --pf-c-modal-box--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-modal-box--BoxShadow: var(--pf-global--BoxShadow--xl);\n --pf-c-modal-box--ZIndex: var(--pf-global--ZIndex--xl);\n --pf-c-modal-box--Width: 100%;\n --pf-c-modal-box--MaxWidth: calc(100% - var(--pf-global--spacer--xl));\n --pf-c-modal-box--m-sm--sm--MaxWidth: 35rem;\n --pf-c-modal-box--m-md--Width: 52.5rem;\n --pf-c-modal-box--m-lg--lg--MaxWidth: 70rem;\n --pf-c-modal-box--MaxHeight: calc(100% - var(--pf-global--spacer--2xl));\n --pf-c-modal-box--m-align-top--spacer: var(--pf-global--spacer--sm);\n --pf-c-modal-box--m-align-top--xl--spacer: var(--pf-global--spacer--xl);\n --pf-c-modal-box--m-align-top--MarginTop: var(--pf-c-modal-box--m-align-top--spacer);\n --pf-c-modal-box--m-align-top--MaxHeight: calc(100% - min(var(--pf-c-modal-box--m-align-top--spacer), var(--pf-global--spacer--2xl)) - var(--pf-c-modal-box--m-align-top--spacer));\n --pf-c-modal-box--m-align-top--MaxWidth: calc(100% - min(var(--pf-c-modal-box--m-align-top--spacer) * 2, var(--pf-global--spacer--xl)));\n --pf-c-modal-box--m-danger__title-icon--Color: var(--pf-global--danger-color--100);\n --pf-c-modal-box--m-warning__title-icon--Color: var(--pf-global--warning-color--100);\n --pf-c-modal-box--m-success__title-icon--Color: var(--pf-global--success-color--100);\n --pf-c-modal-box--m-info__title-icon--Color: var(--pf-global--info-color--100);\n --pf-c-modal-box--m-default__title-icon--Color: var(--pf-global--default-color--200);\n --pf-c-modal-box__header--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-modal-box__header--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-modal-box__header--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-modal-box__header--last-child--PaddingBottom: var(--pf-global--spacer--lg);\n --pf-c-modal-box__title--LineHeight: var(--pf-global--LineHeight--sm);\n --pf-c-modal-box__title--FontFamily: var(--pf-global--FontFamily--heading--sans-serif);\n --pf-c-modal-box__title--FontSize: var(--pf-global--FontSize--2xl);\n --pf-c-modal-box__title-icon--MarginRight: var(--pf-global--spacer--sm);\n --pf-c-modal-box__title-icon--Color: var(--pf-global--Color--100);\n --pf-c-modal-box__description--PaddingTop: var(--pf-global--spacer--xs);\n --pf-c-modal-box__body--MinHeight: calc(var(--pf-global--FontSize--md) * var(--pf-global--LineHeight--md));\n --pf-c-modal-box__body--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-modal-box__body--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-modal-box__body--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-modal-box__body--last-child--PaddingBottom: var(--pf-global--spacer--lg);\n --pf-c-modal-box__header--body--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-modal-box--c-button--Top: calc(var(--pf-global--spacer--lg));\n --pf-c-modal-box--c-button--Right: var(--pf-global--spacer--md);\n --pf-c-modal-box--c-button--sibling--MarginRight: calc(var(--pf-global--spacer--xl) + var(--pf-global--spacer--sm));\n --pf-c-modal-box__footer--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-modal-box__footer--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-modal-box__footer--PaddingBottom: var(--pf-global--spacer--lg);\n --pf-c-modal-box__footer--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-modal-box__footer--c-button--MarginRight: var(--pf-global--spacer--md);\n --pf-c-modal-box__footer--c-button--sm--MarginRight: calc(var(--pf-c-modal-box__footer--c-button--MarginRight) / 2);\n position: relative;\n z-index: var(--pf-c-modal-box--ZIndex);\n display: flex;\n flex-direction: column;\n width: var(--pf-c-modal-box--Width);\n max-width: var(--pf-c-modal-box--MaxWidth);\n max-height: var(--pf-c-modal-box--MaxHeight);\n background-color: var(--pf-c-modal-box--BackgroundColor);\n box-shadow: var(--pf-c-modal-box--BoxShadow); }\n @media (min-width: 1200px) {\n .pf-c-modal-box {\n --pf-c-modal-box--m-align-top--spacer: var(--pf-c-modal-box--m-align-top--xl--spacer); } }\n .pf-c-modal-box.pf-m-sm {\n --pf-c-modal-box--Width: var(--pf-c-modal-box--m-sm--sm--MaxWidth); }\n .pf-c-modal-box.pf-m-md {\n --pf-c-modal-box--Width: var(--pf-c-modal-box--m-md--Width); }\n .pf-c-modal-box.pf-m-lg {\n --pf-c-modal-box--Width: var(--pf-c-modal-box--m-lg--lg--MaxWidth); }\n .pf-c-modal-box.pf-m-align-top {\n top: var(--pf-c-modal-box--m-align-top--MarginTop);\n align-self: flex-start;\n max-width: var(--pf-c-modal-box--m-align-top--MaxWidth);\n max-height: var(--pf-c-modal-box--m-align-top--MaxHeight); }\n .pf-c-modal-box.pf-m-danger {\n --pf-c-modal-box__title-icon--Color: var(--pf-c-modal-box--m-danger__title-icon--Color); }\n .pf-c-modal-box.pf-m-warning {\n --pf-c-modal-box__title-icon--Color: var(--pf-c-modal-box--m-warning__title-icon--Color); }\n .pf-c-modal-box.pf-m-success {\n --pf-c-modal-box__title-icon--Color: var(--pf-c-modal-box--m-success__title-icon--Color); }\n .pf-c-modal-box.pf-m-default {\n --pf-c-modal-box__title-icon--Color: var(--pf-c-modal-box--m-default__title-icon--Color); }\n .pf-c-modal-box.pf-m-info {\n --pf-c-modal-box__title-icon--Color: var(--pf-c-modal-box--m-info__title-icon--Color); }\n .pf-c-modal-box > .pf-c-button {\n position: absolute;\n top: var(--pf-c-modal-box--c-button--Top);\n right: var(--pf-c-modal-box--c-button--Right); }\n .pf-c-modal-box > .pf-c-button + * {\n margin-right: var(--pf-c-modal-box--c-button--sibling--MarginRight); }\n\n.pf-c-modal-box__header {\n display: flex;\n flex-direction: column;\n padding-top: var(--pf-c-modal-box__header--PaddingTop);\n padding-right: var(--pf-c-modal-box__header--PaddingRight);\n padding-left: var(--pf-c-modal-box__header--PaddingLeft); }\n .pf-c-modal-box__header.pf-m-help {\n display: flex;\n flex-direction: row; }\n .pf-c-modal-box__header:last-child {\n padding-bottom: var(--pf-c-modal-box__header--last-child--PaddingBottom); }\n .pf-c-modal-box__header + .pf-c-modal-box__body {\n --pf-c-modal-box__body--PaddingTop: var(--pf-c-modal-box__header--body--PaddingTop); }\n\n.pf-c-modal-box__header-main {\n flex-grow: 1;\n min-width: 0; }\n\n.pf-c-modal-box__title,\n.pf-c-modal-box__title-text {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap; }\n\n.pf-c-modal-box__title {\n flex: 0 0 auto;\n font-family: var(--pf-c-modal-box__title--FontFamily);\n font-size: var(--pf-c-modal-box__title--FontSize);\n line-height: var(--pf-c-modal-box__title--LineHeight); }\n .pf-c-modal-box__title.pf-m-icon {\n display: flex; }\n\n.pf-c-modal-box__title-icon {\n margin-right: var(--pf-c-modal-box__title-icon--MarginRight);\n color: var(--pf-c-modal-box__title-icon--Color); }\n\n.pf-c-modal-box__description {\n padding-top: var(--pf-c-modal-box__description--PaddingTop); }\n\n.pf-c-modal-box__body {\n flex: 1 1 auto;\n min-height: var(--pf-c-modal-box__body--MinHeight);\n padding-top: var(--pf-c-modal-box__body--PaddingTop);\n padding-right: var(--pf-c-modal-box__body--PaddingRight);\n padding-left: var(--pf-c-modal-box__body--PaddingLeft);\n overflow-x: hidden;\n overflow-y: auto;\n overscroll-behavior: contain;\n word-break: break-word;\n -webkit-overflow-scrolling: touch; }\n .pf-c-modal-box__body:last-child {\n padding-bottom: var(--pf-c-modal-box__body--last-child--PaddingBottom); }\n\n.pf-c-modal-box__footer {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n padding-top: var(--pf-c-modal-box__footer--PaddingTop);\n padding-right: var(--pf-c-modal-box__footer--PaddingRight);\n padding-bottom: var(--pf-c-modal-box__footer--PaddingBottom);\n padding-left: var(--pf-c-modal-box__footer--PaddingLeft); }\n .pf-c-modal-box__footer > .pf-c-button:not(:last-child) {\n margin-right: var(--pf-c-modal-box__footer--c-button--MarginRight); }\n @media screen and (min-width: 576px) {\n .pf-c-modal-box__footer > .pf-c-button:not(:last-child) {\n --pf-c-modal-box__footer--c-button--MarginRight: var(--pf-c-modal-box__footer--c-button--sm--MarginRight); } }\n\n.pf-c-nav {\n --pf-c-nav--Transition: var(--pf-global--Transition);\n --pf-c-nav__item--m-expanded__toggle-icon--Rotate: 90deg;\n --pf-c-nav--m-light__item--before--BorderColor: var(--pf-global--BorderColor--300);\n --pf-c-nav--m-light__item--m-current--not--m-expanded__link--BackgroundColor: var(--pf-global--BackgroundColor--light-300);\n --pf-c-nav--m-light__link--Color: var(--pf-global--Color--dark-100);\n --pf-c-nav--m-light__link--hover--Color: var(--pf-global--Color--dark-100);\n --pf-c-nav--m-light__link--focus--Color: var(--pf-global--Color--dark-100);\n --pf-c-nav--m-light__link--active--Color: var(--pf-global--Color--dark-100);\n --pf-c-nav--m-light__link--m-current--Color: var(--pf-global--Color--dark-100);\n --pf-c-nav--m-light__link--hover--BackgroundColor: var(--pf-global--BackgroundColor--light-300);\n --pf-c-nav--m-light__link--focus--BackgroundColor: var(--pf-global--BackgroundColor--light-300);\n --pf-c-nav--m-light__link--active--BackgroundColor: var(--pf-global--BackgroundColor--light-300);\n --pf-c-nav--m-light__link--m-current--BackgroundColor: var(--pf-global--BackgroundColor--light-300);\n --pf-c-nav--m-light__link--before--BorderColor: var(--pf-global--BorderColor--300);\n --pf-c-nav--m-light__link--after--BorderColor: var(--pf-global--active-color--100);\n --pf-c-nav--m-light__link--m-current--after--BorderColor: var(--pf-global--active-color--100);\n --pf-c-nav--m-light__section-title--Color: var(--pf-global--Color--dark-200);\n --pf-c-nav--m-light__section-title--BorderBottomColor: var(--pf-global--BorderColor--300);\n --pf-c-nav--m-light--c-divider--BackgroundColor: var(--pf-global--BorderColor--300);\n --pf-c-nav--m-light__subnav__link--hover--after--BorderColor: var(--pf-global--BorderColor--dark-100);\n --pf-c-nav--m-light__subnav__link--focus--after--BorderColor: var(--pf-global--BorderColor--dark-100);\n --pf-c-nav--m-light__subnav__link--active--after--BorderColor: var(--pf-global--BorderColor--dark-100);\n --pf-c-nav--m-light__subnav__link--m-current--after--BorderColor: var(--pf-global--active-color--100);\n --pf-c-nav__item--MarginTop: 0;\n --pf-c-nav__item--m-current--not--m-expanded__link--BackgroundColor: var(--pf-global--BackgroundColor--dark-400);\n --pf-c-nav__link--m-current--not--m-expanded__link--after--BorderWidth: var(--pf-global--BorderWidth--xl);\n --pf-c-nav__item--before--BorderColor: var(--pf-global--BackgroundColor--dark-200);\n --pf-c-nav__item--before--BorderWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-nav__link--FontSize: var(--pf-global--FontSize--md);\n --pf-c-nav__link--FontWeight: var(--pf-global--FontWeight--normal);\n --pf-c-nav__link--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-nav__link--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-nav__link--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-nav__link--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-nav__link--xl--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-nav__link--xl--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-nav__link--Color: var(--pf-global--Color--light-100);\n --pf-c-nav__link--hover--Color: var(--pf-global--Color--light-100);\n --pf-c-nav__link--focus--Color: var(--pf-global--Color--light-100);\n --pf-c-nav__link--active--Color: var(--pf-global--Color--light-100);\n --pf-c-nav__link--m-current--Color: var(--pf-global--Color--light-100);\n --pf-c-nav__link--BackgroundColor: transparent;\n --pf-c-nav__link--hover--BackgroundColor: var(--pf-global--BackgroundColor--dark-200);\n --pf-c-nav__link--focus--BackgroundColor: var(--pf-global--BackgroundColor--dark-200);\n --pf-c-nav__link--active--BackgroundColor: var(--pf-global--BackgroundColor--dark-200);\n --pf-c-nav__link--m-current--BackgroundColor: var(--pf-global--BackgroundColor--dark-400);\n --pf-c-nav__link--OutlineOffset: calc(var(--pf-global--spacer--xs) * -1);\n --pf-c-nav__link--before--BorderColor: var(--pf-global--BackgroundColor--dark-200);\n --pf-c-nav__link--before--BorderBottomWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-nav__link--hover--before--BorderBottomWidth: 0;\n --pf-c-nav__link--focus--before--BorderBottomWidth: 0;\n --pf-c-nav__link--active--before--BorderBottomWidth: 0;\n --pf-c-nav__link--m-current--before--BorderBottomWidth: 0;\n --pf-c-nav__link--after--BorderColor: var(--pf-global--active-color--400);\n --pf-c-nav__link--hover--after--BorderColor: var(--pf-global--active-color--400);\n --pf-c-nav__link--focus--after--BorderColor: var(--pf-global--active-color--400);\n --pf-c-nav__link--active--after--BorderColor: var(--pf-global--active-color--400);\n --pf-c-nav__link--m-current--after--BorderColor: var(--pf-global--active-color--400);\n --pf-c-nav__link--after--BorderLeftWidth: 0;\n --pf-c-nav__link--hover--after--BorderLeftWidth: 0;\n --pf-c-nav__link--focus--after--BorderLeftWidth: 0;\n --pf-c-nav__link--active--after--BorderLeftWidth: 0;\n --pf-c-nav__link--m-current--after--BorderLeftWidth: var(--pf-global--BorderWidth--xl);\n --pf-c-nav--m-horizontal__link--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-nav--m-horizontal__link--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-nav--m-horizontal__link--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-nav--m-horizontal__link--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-nav--m-horizontal__link--lg--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-nav--m-horizontal__link--lg--PaddingBottom: var(--pf-global--spacer--lg);\n --pf-c-nav--m-horizontal__link--Right: var(--pf-global--spacer--md);\n --pf-c-nav--m-horizontal__link--Left: var(--pf-global--spacer--md);\n --pf-c-nav--m-horizontal__link--Color: var(--pf-global--Color--light-300);\n --pf-c-nav--m-horizontal__link--hover--Color: var(--pf-global--active-color--400);\n --pf-c-nav--m-horizontal__link--focus--Color: var(--pf-global--active-color--400);\n --pf-c-nav--m-horizontal__link--active--Color: var(--pf-global--active-color--400);\n --pf-c-nav--m-horizontal__link--m-current--Color: var(--pf-global--active-color--400);\n --pf-c-nav--m-horizontal__link--BackgroundColor: transparent;\n --pf-c-nav--m-horizontal__link--hover--BackgroundColor: transparent;\n --pf-c-nav--m-horizontal__link--focus--BackgroundColor: transparent;\n --pf-c-nav--m-horizontal__link--active--BackgroundColor: transparent;\n --pf-c-nav--m-horizontal__link--m-current--BackgroundColor: transparent;\n --pf-c-nav--m-horizontal__link--before--BorderColor: var(--pf-global--active-color--400);\n --pf-c-nav--m-horizontal__link--before--BorderWidth: 0;\n --pf-c-nav--m-horizontal__link--hover--before--BorderWidth: var(--pf-global--BorderWidth--lg);\n --pf-c-nav--m-horizontal__link--focus--before--BorderWidth: var(--pf-global--BorderWidth--lg);\n --pf-c-nav--m-horizontal__link--active--before--BorderWidth: var(--pf-global--BorderWidth--lg);\n --pf-c-nav--m-horizontal__link--m-current--before--BorderWidth: var(--pf-global--BorderWidth--lg);\n --pf-c-nav--m-tertiary__link--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-nav--m-tertiary__link--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-nav--m-tertiary__link--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-nav--m-tertiary__link--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-nav--m-tertiary__link--Right: var(--pf-global--spacer--md);\n --pf-c-nav--m-tertiary__link--Left: var(--pf-global--spacer--md);\n --pf-c-nav--m-tertiary__link--Color: var(--pf-global--Color--dark-100);\n --pf-c-nav--m-tertiary__link--hover--Color: var(--pf-global--active-color--100);\n --pf-c-nav--m-tertiary__link--focus--Color: var(--pf-global--active-color--100);\n --pf-c-nav--m-tertiary__link--active--Color: var(--pf-global--active-color--100);\n --pf-c-nav--m-tertiary__link--m-current--Color: var(--pf-global--active-color--100);\n --pf-c-nav--m-tertiary__link--BackgroundColor: transparent;\n --pf-c-nav--m-tertiary__link--hover--BackgroundColor: transparent;\n --pf-c-nav--m-tertiary__link--focus--BackgroundColor: transparent;\n --pf-c-nav--m-tertiary__link--active--BackgroundColor: transparent;\n --pf-c-nav--m-tertiary__link--m-current--BackgroundColor: transparent;\n --pf-c-nav--m-tertiary__link--before--BorderColor: var(--pf-global--active-color--100);\n --pf-c-nav--m-tertiary__link--before--BorderWidth: 0;\n --pf-c-nav--m-tertiary__link--hover--before--BorderWidth: var(--pf-global--BorderWidth--lg);\n --pf-c-nav--m-tertiary__link--focus--before--BorderWidth: var(--pf-global--BorderWidth--lg);\n --pf-c-nav--m-tertiary__link--active--before--BorderWidth: var(--pf-global--BorderWidth--lg);\n --pf-c-nav--m-tertiary__link--m-current--before--BorderWidth: var(--pf-global--BorderWidth--lg);\n --pf-c-nav--m-tertiary__scroll-button--Color: var(--pf-global--Color--dark-100);\n --pf-c-nav--m-tertiary__scroll-button--hover--Color: var(--pf-global--active-color--100);\n --pf-c-nav--m-tertiary__scroll-button--focus--Color: var(--pf-global--active-color--100);\n --pf-c-nav--m-tertiary__scroll-button--active--Color: var(--pf-global--active-color--100);\n --pf-c-nav--m-tertiary__scroll-button--disabled--Color: var(--pf-global--disabled-color--200);\n --pf-c-nav--m-tertiary__scroll-button--before--BorderColor: var(--pf-global--BorderColor--300);\n --pf-c-nav--m-tertiary__scroll-button--disabled--before--BorderColor: var(--pf-global--disabled-color--300);\n --pf-c-nav__subnav--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-nav__subnav--xl--PaddingLeft: var(--pf-c-nav__link--PaddingLeft);\n --pf-c-nav__subnav__link--MarginTop: 0;\n --pf-c-nav__subnav__link--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-nav__subnav__link--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-nav__subnav__link--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-nav__subnav__link--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-nav__subnav__link--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-nav__subnav__link--hover--after--BorderColor: var(--pf-global--BorderColor--200);\n --pf-c-nav__subnav__link--focus--after--BorderColor: var(--pf-global--BorderColor--200);\n --pf-c-nav__subnav__link--active--after--BorderColor: var(--pf-global--BorderColor--200);\n --pf-c-nav__subnav__link--m-current--after--BorderColor: var(--pf-global--active-color--400);\n --pf-c-nav__subnav__link--hover--after--BorderWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-nav__subnav__link--focus--after--BorderWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-nav__subnav__link--active--after--BorderWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-nav__subnav__link--m-current--after--BorderWidth: var(--pf-global--BorderWidth--xl);\n --pf-c-nav__subnav--MaxHeight: 0;\n --pf-c-nav__item--m-expanded__subnav--MaxHeight: 100%;\n --pf-c-nav__subnav--c-divider--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-nav__subnav--c-divider--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-nav__section--MarginTop: var(--pf-global--spacer--sm);\n --pf-c-nav__section__item--MarginTop: var(--pf-global--spacer--sm);\n --pf-c-nav__section__link--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-nav__section__link--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-nav__section__link--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-nav__section__link--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-nav__section__link--xl--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-nav__section__link--xl--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-nav__section__link--FontSize: var(--pf-global--FontSize--md);\n --pf-c-nav__section__link--before--BorderBottomWidth: 0;\n --pf-c-nav__section__link--hover--after--BorderColor: transparent;\n --pf-c-nav__section__link--focus--after--BorderColor: transparent;\n --pf-c-nav__section__link--active--after--BorderColor: transparent;\n --pf-c-nav__section__link--m-current--after--BorderColor: var(--pf-global--active-color--400);\n --pf-c-nav__section__link--hover--after--BorderWidth: 0;\n --pf-c-nav__section__link--focus--after--BorderWidth: 0;\n --pf-c-nav__section__link--active--after--BorderWidth: 0;\n --pf-c-nav__section__link--m-current--after--BorderWidth: var(--pf-global--BorderWidth--xl);\n --pf-c-nav__section--section--MarginTop: var(--pf-global--spacer--xl);\n --pf-c-nav__section-title--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-nav__section-title--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-nav__section-title--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-nav__section-title--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-nav__section-title--xl--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-nav__section-title--xl--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-nav__section-title--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-nav__section-title--Color: var(--pf-global--Color--light-100);\n --pf-c-nav__section-title--BorderBottomColor: var(--pf-global--BackgroundColor--dark-200);\n --pf-c-nav__section-title--BorderBottomWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-nav__scroll-button--Color: var(--pf-global--Color--light-100);\n --pf-c-nav__scroll-button--hover--Color: var(--pf-global--active-color--400);\n --pf-c-nav__scroll-button--focus--Color: var(--pf-global--active-color--400);\n --pf-c-nav__scroll-button--active--Color: var(--pf-global--active-color--400);\n --pf-c-nav__scroll-button--disabled--Color: var(--pf-global--disabled-color--100);\n --pf-c-nav__scroll-button--BackgroundColor: transparent;\n --pf-c-nav__scroll-button--Width: var(--pf-global--target-size--MinWidth);\n --pf-c-nav__scroll-button--OutlineOffset: calc(-1 * var(--pf-global--spacer--xs));\n --pf-c-nav__scroll-button--Transition: margin .125s, transform .125s, opacity .125s;\n --pf-c-nav__scroll-button--before--BorderColor: var(--pf-global--BackgroundColor--dark-200);\n --pf-c-nav__scroll-button--before--BorderWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-nav__scroll-button--before--BorderRightWidth: 0;\n --pf-c-nav__scroll-button--before--BorderLeftWidth: 0;\n --pf-c-nav__scroll-button--disabled--before--BorderColor: transparent;\n --pf-c-nav__toggle--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-nav__toggle--PaddingLeft: var(--pf-global--spacer--sm);\n --pf-c-nav__toggle--FontSize: var(--pf-global--icon--FontSize--md);\n --pf-c-nav__toggle-icon--Transition: var(--pf-global--TransitionDuration);\n --pf-c-nav--c-divider--MarginTop: var(--pf-global--spacer--sm);\n --pf-c-nav--c-divider--MarginBottom: var(--pf-global--spacer--sm);\n --pf-c-nav--c-divider--PaddingRight: 0;\n --pf-c-nav--c-divider--PaddingLeft: 0;\n --pf-c-nav--c-divider--BackgroundColor: var(--pf-global--BackgroundColor--dark-200); }\n @media screen and (min-width: 1200px) {\n .pf-c-nav {\n --pf-c-nav__link--PaddingRight: var(--pf-c-nav__link--xl--PaddingRight);\n --pf-c-nav__link--PaddingLeft: var(--pf-c-nav__link--xl--PaddingLeft);\n --pf-c-nav__section__link--PaddingRight: var(--pf-c-nav__section__link--xl--PaddingRight);\n --pf-c-nav__section__link--PaddingLeft: var(--pf-c-nav__section__link--xl--PaddingLeft);\n --pf-c-nav__section-title--PaddingRight: var(--pf-c-nav__section-title--xl--PaddingRight);\n --pf-c-nav__section-title--PaddingLeft: var(--pf-c-nav__section-title--xl--PaddingLeft);\n --pf-c-nav__subnav--PaddingLeft: var(--pf-c-nav__subnav--xl--PaddingLeft); } }\n .pf-c-nav.pf-m-horizontal, .pf-c-nav.pf-m-tertiary {\n overflow: hidden; }\n .pf-c-nav.pf-m-horizontal,\n .pf-c-nav.pf-m-horizontal .pf-c-nav__list, .pf-c-nav.pf-m-tertiary,\n .pf-c-nav.pf-m-tertiary .pf-c-nav__list {\n position: relative;\n display: flex; }\n .pf-c-nav.pf-m-horizontal .pf-c-nav__list, .pf-c-nav.pf-m-tertiary .pf-c-nav__list {\n flex: 1;\n max-width: 100%;\n overflow-x: auto;\n white-space: nowrap;\n -webkit-overflow-scrolling: touch;\n scrollbar-width: none;\n -ms-overflow-style: -ms-autohiding-scrollbar; }\n .pf-c-nav.pf-m-horizontal .pf-c-nav__list::-webkit-scrollbar, .pf-c-nav.pf-m-tertiary .pf-c-nav__list::-webkit-scrollbar {\n display: none; }\n .pf-c-nav.pf-m-horizontal .pf-c-nav__item, .pf-c-nav.pf-m-tertiary .pf-c-nav__item {\n display: flex; }\n .pf-c-nav.pf-m-horizontal .pf-c-nav__link, .pf-c-nav.pf-m-tertiary .pf-c-nav__link {\n align-items: center;\n align-self: stretch;\n white-space: nowrap; }\n .pf-c-nav.pf-m-horizontal .pf-c-nav__link::before, .pf-c-nav.pf-m-tertiary .pf-c-nav__link::before {\n top: auto;\n bottom: 0; }\n .pf-c-nav.pf-m-horizontal .pf-c-nav__link::after, .pf-c-nav.pf-m-tertiary .pf-c-nav__link::after {\n content: none; }\n .pf-c-nav.pf-m-horizontal .pf-c-nav__link::before {\n right: var(--pf-c-nav--m-horizontal__link--Right);\n left: var(--pf-c-nav--m-horizontal__link--Left); }\n .pf-c-nav.pf-m-tertiary .pf-c-nav__link::before {\n right: var(--pf-c-nav--m-tertiary__link--Right);\n left: var(--pf-c-nav--m-tertiary__link--Left); }\n .pf-c-nav.pf-m-light {\n --pf-c-nav__item--before--BorderColor: var(--pf-c-nav--m-light__item--before--BorderColor);\n --pf-c-nav__item--m-current--not--m-expanded__link--BackgroundColor: var(--pf-c-nav--m-light__item--m-current--not--m-expanded__link--BackgroundColor);\n --pf-c-nav__link--Color: var(--pf-c-nav--m-light__link--Color);\n --pf-c-nav__link--hover--Color: var(--pf-c-nav--m-light__link--hover--Color);\n --pf-c-nav__link--focus--Color: var(--pf-c-nav--m-light__link--focus--Color);\n --pf-c-nav__link--active--Color: var(--pf-c-nav--m-light__link--active--Color);\n --pf-c-nav__link--m-current--Color: var(--pf-c-nav--m-light__link--m-current--Color);\n --pf-c-nav__link--hover--BackgroundColor: var(--pf-c-nav--m-light__link--hover--BackgroundColor);\n --pf-c-nav__link--focus--BackgroundColor: var(--pf-c-nav--m-light__link--focus--BackgroundColor);\n --pf-c-nav__link--active--BackgroundColor: var(--pf-c-nav--m-light__link--active--BackgroundColor);\n --pf-c-nav__link--m-current--BackgroundColor: var(--pf-c-nav--m-light__link--m-current--BackgroundColor);\n --pf-c-nav__link--before--BorderColor: var(--pf-c-nav--m-light__link--before--BorderColor);\n --pf-c-nav__link--after--BorderColor: var(--pf-c-nav--m-light__link--after--BorderColor);\n --pf-c-nav__link--m-current--after--BorderColor: var(--pf-c-nav--m-light__link--m-current--after--BorderColor);\n --pf-c-nav__subnav__link--hover--after--BorderColor: var(--pf-c-nav--m-light__subnav__link--hover--after--BorderColor);\n --pf-c-nav__subnav__link--focus--after--BorderColor: var(--pf-c-nav--m-light__subnav__link--focus--after--BorderColor);\n --pf-c-nav__subnav__link--active--after--BorderColor: var(--pf-c-nav--m-light__subnav__link--active--after--BorderColor);\n --pf-c-nav__subnav__link--m-current--after--BorderColor: var(--pf-c-nav--m-light__subnav__link--m-current--after--BorderColor);\n --pf-c-nav__section-title--Color: var(--pf-c-nav--m-light__section-title--Color);\n --pf-c-nav__section-title--BorderBottomColor: var(--pf-c-nav--m-light__section-title--BorderBottomColor); }\n .pf-c-nav.pf-m-light .pf-c-divider {\n --pf-c-divider--after--BackgroundColor: var(--pf-c-nav--m-light--c-divider--BackgroundColor); }\n .pf-c-nav.pf-m-horizontal {\n --pf-c-nav__link--PaddingTop: var(--pf-c-nav--m-horizontal__link--PaddingTop);\n --pf-c-nav__link--PaddingRight: var(--pf-c-nav--m-horizontal__link--PaddingRight);\n --pf-c-nav__link--PaddingBottom: var(--pf-c-nav--m-horizontal__link--PaddingBottom);\n --pf-c-nav__link--PaddingLeft: var(--pf-c-nav--m-horizontal__link--PaddingLeft);\n --pf-c-nav__link--Right: var(--pf-c-nav--m-horizontal__link--Right);\n --pf-c-nav__link--Left: var(--pf-c-nav--m-horizontal__link--Left);\n --pf-c-nav__link--Color: var(--pf-c-nav--m-horizontal__link--Color);\n --pf-c-nav__link--hover--Color: var(--pf-c-nav--m-horizontal__link--hover--Color);\n --pf-c-nav__link--active--Color: var(--pf-c-nav--m-horizontal__link--active--Color);\n --pf-c-nav__link--focus--Color: var(--pf-c-nav--m-horizontal__link--focus--Color);\n --pf-c-nav__link--m-current--Color: var(--pf-c-nav--m-horizontal__link--m-current--Color);\n --pf-c-nav__link--BackgroundColor: var(--pf-c-nav--m-horizontal__link--BackgroundColor);\n --pf-c-nav__link--hover--BackgroundColor: var(--pf-c-nav--m-horizontal__link--hover--BackgroundColor);\n --pf-c-nav__link--focus--BackgroundColor: var(--pf-c-nav--m-horizontal__link--focus--BackgroundColor);\n --pf-c-nav__link--active--BackgroundColor: var(--pf-c-nav--m-horizontal__link--active--BackgroundColor);\n --pf-c-nav__link--m-current--BackgroundColor: var(--pf-c-nav--m-horizontal__link--m-current--BackgroundColor);\n --pf-c-nav__link--before--BorderColor: var(--pf-c-nav--m-horizontal__link--before--BorderColor);\n --pf-c-nav__link--before--BorderBottomWidth: var(--pf-c-nav--m-horizontal__link--before--BorderWidth);\n --pf-c-nav__link--hover--before--BorderBottomWidth: var(--pf-c-nav--m-horizontal__link--hover--before--BorderWidth);\n --pf-c-nav__link--focus--before--BorderBottomWidth: var(--pf-c-nav--m-horizontal__link--focus--before--BorderWidth);\n --pf-c-nav__link--active--before--BorderBottomWidth: var(--pf-c-nav--m-horizontal__link--active--before--BorderWidth);\n --pf-c-nav__link--m-current--before--BorderBottomWidth: var(--pf-c-nav--m-horizontal__link--m-current--before--BorderWidth); }\n .pf-c-nav.pf-m-tertiary {\n --pf-c-nav__link--PaddingTop: var(--pf-c-nav--m-tertiary__link--PaddingTop);\n --pf-c-nav__link--PaddingRight: var(--pf-c-nav--m-tertiary__link--PaddingRight);\n --pf-c-nav__link--PaddingBottom: var(--pf-c-nav--m-tertiary__link--PaddingBottom);\n --pf-c-nav__link--PaddingLeft: var(--pf-c-nav--m-tertiary__link--PaddingLeft);\n --pf-c-nav__link--Right: var(--pf-c-nav--m-tertiary__link--Right);\n --pf-c-nav__link--Left: var(--pf-c-nav--m-tertiary__link--Left);\n --pf-c-nav__link--Color: var(--pf-c-nav--m-tertiary__link--Color);\n --pf-c-nav__link--hover--Color: var(--pf-c-nav--m-tertiary__link--hover--Color);\n --pf-c-nav__link--active--Color: var(--pf-c-nav--m-tertiary__link--active--Color);\n --pf-c-nav__link--focus--Color: var(--pf-c-nav--m-tertiary__link--focus--Color);\n --pf-c-nav__link--m-current--Color: var(--pf-c-nav--m-tertiary__link--m-current--Color);\n --pf-c-nav__link--BackgroundColor: var(--pf-c-nav--m-tertiary__link--BackgroundColor);\n --pf-c-nav__link--hover--BackgroundColor: var(--pf-c-nav--m-tertiary__link--hover--BackgroundColor);\n --pf-c-nav__link--focus--BackgroundColor: var(--pf-c-nav--m-tertiary__link--focus--BackgroundColor);\n --pf-c-nav__link--active--BackgroundColor: var(--pf-c-nav--m-tertiary__link--active--BackgroundColor);\n --pf-c-nav__link--m-current--BackgroundColor: var(--pf-c-nav--m-tertiary__link--m-current--BackgroundColor);\n --pf-c-nav__link--before--BorderColor: var(--pf-c-nav--m-tertiary__link--before--BorderColor);\n --pf-c-nav__link--before--BorderBottomWidth: var(--pf-c-nav--m-tertiary__link--before--BorderWidth);\n --pf-c-nav__link--hover--before--BorderBottomWidth: var(--pf-c-nav--m-tertiary__link--hover--before--BorderWidth);\n --pf-c-nav__link--focus--before--BorderBottomWidth: var(--pf-c-nav--m-tertiary__link--focus--before--BorderWidth);\n --pf-c-nav__link--active--before--BorderBottomWidth: var(--pf-c-nav--m-tertiary__link--active--before--BorderWidth);\n --pf-c-nav__link--m-current--before--BorderBottomWidth: var(--pf-c-nav--m-tertiary__link--m-current--before--BorderWidth);\n --pf-c-nav__scroll-button--Color: var(--pf-c-nav--m-tertiary__scroll-button--Color);\n --pf-c-nav__scroll-button--hover--Color: var(--pf-c-nav--m-tertiary__scroll-button--hover--Color);\n --pf-c-nav__scroll-button--focus--Color: var(--pf-c-nav--m-tertiary__scroll-button--focus--Color);\n --pf-c-nav__scroll-button--active--Color: var(--pf-c-nav--m-tertiary__scroll-button--active--Color);\n --pf-c-nav__scroll-button--disabled--Color: var(--pf-c-nav--m-tertiary__scroll-button--disabled--Color);\n --pf-c-nav__scroll-button--before--BorderColor: var(--pf-c-nav--m-tertiary__scroll-button--before--BorderColor);\n --pf-c-nav__scroll-button--disabled--before--BorderColor: var(--pf-c-nav--m-tertiary__scroll-button--disabled--before--BorderColor); }\n .pf-c-nav .pf-c-divider {\n --pf-c-divider--after--BackgroundColor: var(--pf-c-nav--c-divider--BackgroundColor);\n padding-right: var(--pf-c-nav--c-divider--PaddingRight);\n padding-left: var(--pf-c-nav--c-divider--PaddingLeft);\n margin-top: var(--pf-c-nav--c-divider--MarginTop);\n margin-bottom: var(--pf-c-nav--c-divider--MarginBottom); }\n .pf-c-nav.pf-m-scrollable .pf-c-nav__scroll-button {\n opacity: 1; }\n .pf-c-nav.pf-m-scrollable .pf-c-nav__scroll-button:nth-of-type(1) {\n margin-right: 0;\n transform: translateX(0); }\n .pf-c-nav.pf-m-scrollable .pf-c-nav__scroll-button:nth-of-type(2) {\n margin-left: 0;\n transform: translateX(0); }\n\n.pf-c-nav__list {\n display: block; }\n\n.pf-c-nav__item {\n position: relative;\n margin-top: var(--pf-c-nav__item--MarginTop); }\n .pf-c-nav__item.pf-m-expandable {\n --pf-c-nav__link--before--BorderBottomWidth: 0; }\n .pf-c-nav__item.pf-m-expandable::before {\n position: absolute;\n right: 0;\n bottom: calc(var(--pf-c-nav__item--before--BorderWidth) * -1);\n left: 0;\n content: \"\";\n border-bottom: var(--pf-c-nav__item--before--BorderWidth) solid var(--pf-c-nav__item--before--BorderColor); }\n\n.pf-c-nav__link {\n position: relative;\n display: flex;\n align-items: baseline;\n padding: var(--pf-c-nav__link--PaddingTop) var(--pf-c-nav__link--PaddingRight) var(--pf-c-nav__link--PaddingBottom) var(--pf-c-nav__link--PaddingLeft);\n font-size: var(--pf-c-nav__link--FontSize);\n font-weight: var(--pf-c-nav__link--FontWeight);\n color: var(--pf-c-nav__link--Color);\n background-color: var(--pf-c-nav__link--BackgroundColor);\n outline-offset: var(--pf-c-nav__link--OutlineOffset); }\n .pf-c-nav__link::after, .pf-c-nav__link::before {\n position: absolute;\n content: \"\";\n border: 0 solid; }\n .pf-c-nav__link::before {\n right: 0;\n bottom: calc(var(--pf-c-nav__link--before--BorderBottomWidth) * -1);\n left: 0;\n border-color: var(--pf-c-nav__link--before--BorderColor);\n border-bottom-width: var(--pf-c-nav__link--before--BorderBottomWidth); }\n .pf-c-nav__link::after {\n top: 0;\n bottom: 0;\n left: 0;\n border: 0 solid;\n border-color: var(--pf-c-nav__link--after--BorderColor);\n border-left-width: var(--pf-c-nav__link--after--BorderLeftWidth); }\n .pf-c-nav__link:hover {\n color: var(--pf-c-nav__link--hover--Color);\n background-color: var(--pf-c-nav__link--hover--BackgroundColor); }\n .pf-c-nav__link:hover::before {\n border-bottom-width: var(--pf-c-nav__link--hover--before--BorderBottomWidth); }\n .pf-c-nav__link:hover::after {\n border-color: var(--pf-c-nav__link--hover--after--BorderColor);\n border-left-width: var(--pf-c-nav__link--hover--after--BorderLeftWidth); }\n .pf-c-nav__link:focus {\n color: var(--pf-c-nav__link--focus--Color);\n background-color: var(--pf-c-nav__link--focus--BackgroundColor); }\n .pf-c-nav__link:focus::before {\n border-bottom-width: var(--pf-c-nav__link--focus--before--BorderBottomWidth); }\n .pf-c-nav__link:focus::after {\n border-color: var(--pf-c-nav__link--focus--after--BorderColor);\n border-left-width: var(--pf-c-nav__link--focus--after--BorderLeftWidth); }\n .pf-c-nav__link:active {\n color: var(--pf-c-nav__link--active--Color);\n background-color: var(--pf-c-nav__link--active--BackgroundColor); }\n .pf-c-nav__link:active::before {\n border-bottom-width: var(--pf-c-nav__link--active--before--BorderBottomWidth); }\n .pf-c-nav__link:active::after {\n border-color: var(--pf-c-nav__link--active--after--BorderColor);\n border-left-width: var(--pf-c-nav__link--active--after--BorderLeftWidth); }\n .pf-c-nav__link.pf-m-current, .pf-c-nav__link.pf-m-current:hover,\n .pf-c-nav__item.pf-m-current:not(.pf-m-expanded) .pf-c-nav__link {\n color: var(--pf-c-nav__link--m-current--Color);\n background-color: var(--pf-c-nav__link--m-current--BackgroundColor); }\n .pf-c-nav__link.pf-m-current::before, .pf-c-nav__link.pf-m-current:hover::before,\n .pf-c-nav__item.pf-m-current:not(.pf-m-expanded) .pf-c-nav__link::before {\n border-bottom-width: var(--pf-c-nav__link--m-current--before--BorderBottomWidth); }\n .pf-c-nav__link.pf-m-current::after, .pf-c-nav__link.pf-m-current:hover::after,\n .pf-c-nav__item.pf-m-current:not(.pf-m-expanded) .pf-c-nav__link::after {\n border-color: var(--pf-c-nav__link--m-current--after--BorderColor);\n border-left-width: var(--pf-c-nav__link--m-current--after--BorderLeftWidth); }\n .pf-c-nav__link, .pf-c-nav__link:hover, .pf-c-nav__link:focus, .pf-c-nav__link:active {\n width: 100%;\n text-decoration: none;\n border: none; }\n\n.pf-c-nav__subnav {\n --pf-c-nav__link--PaddingTop: var(--pf-c-nav__subnav__link--PaddingTop);\n --pf-c-nav__link--PaddingRight: var(--pf-c-nav__subnav__link--PaddingRight);\n --pf-c-nav__link--PaddingBottom: var(--pf-c-nav__subnav__link--PaddingBottom);\n --pf-c-nav__link--PaddingLeft: var(--pf-c-nav__subnav__link--PaddingLeft);\n --pf-c-nav__link--FontSize: var(--pf-c-nav__subnav__link--FontSize);\n --pf-c-nav__link--hover--after--BorderColor: var(--pf-c-nav__subnav__link--hover--after--BorderColor);\n --pf-c-nav__link--focus--after--BorderColor: var(--pf-c-nav__subnav__link--focus--after--BorderColor);\n --pf-c-nav__link--active--after--BorderColor: var(--pf-c-nav__subnav__link--active--after--BorderColor);\n --pf-c-nav__link--m-current--after--BorderColor: var(--pf-c-nav__subnav__link--m-current--after--BorderColor);\n --pf-c-nav__link--hover--after--BorderLeftWidth: var(--pf-c-nav__subnav__link--hover--after--BorderWidth);\n --pf-c-nav__link--focus--after--BorderLeftWidth: var(--pf-c-nav__subnav__link--focus--after--BorderWidth);\n --pf-c-nav__link--active--after--BorderLeftWidth: var(--pf-c-nav__subnav__link--active--after--BorderWidth);\n --pf-c-nav__link--m-current--after--BorderLeftWidth: var(--pf-c-nav__subnav__link--m-current--after--BorderWidth);\n --pf-c-nav--c-divider--PaddingRight: var(--pf-c-nav__subnav--c-divider--PaddingRight);\n --pf-c-nav--c-divider--PaddingLeft: var(--pf-c-nav__subnav--c-divider--PaddingLeft);\n max-height: var(--pf-c-nav__subnav--MaxHeight);\n padding-bottom: var(--pf-c-nav__subnav--PaddingBottom);\n padding-left: var(--pf-c-nav__subnav--PaddingLeft);\n transition: var(--pf-c-nav--Transition);\n scrollbar-width: none;\n -ms-overflow-style: -ms-autohiding-scrollbar; }\n .pf-c-nav__item.pf-m-expanded .pf-c-nav__subnav {\n --pf-c-nav__subnav--MaxHeight: var(--pf-c-nav__item--m-expanded__subnav--MaxHeight);\n overflow-y: auto;\n opacity: 1; }\n .pf-c-nav__subnav::-webkit-scrollbar {\n display: none; }\n\n.pf-c-nav__toggle {\n flex: none;\n padding-right: var(--pf-c-nav__toggle--PaddingRight);\n padding-left: var(--pf-c-nav__toggle--PaddingLeft);\n margin-left: auto;\n font-size: var(--pf-c-nav__toggle--FontSize);\n line-height: 1; }\n\n.pf-c-nav__toggle-icon {\n display: inline-block;\n transition: var(--pf-c-nav__toggle-icon--Transition); }\n .pf-c-nav__item.pf-m-expanded .pf-c-nav__toggle-icon {\n transform: rotate(var(--pf-c-nav__item--m-expanded__toggle-icon--Rotate)); }\n\n.pf-c-nav__section {\n --pf-c-nav__item--MarginTop: var(--pf-c-nav__section__item--MarginTop);\n --pf-c-nav__link--PaddingTop: var(--pf-c-nav__section__link--PaddingTop);\n --pf-c-nav__link--PaddingRight: var(--pf-c-nav__section__link--PaddingRight);\n --pf-c-nav__link--PaddingBottom: var(--pf-c-nav__section__link--PaddingBottom);\n --pf-c-nav__link--PaddingLeft: var(--pf-c-nav__section__link--PaddingLeft);\n --pf-c-nav__link--FontSize: var(--pf-c-nav__section__link--FontSize);\n --pf-c-nav__link--before--BorderBottomWidth: var(--pf-c-nav__section__link--before--BorderBottomWidth);\n --pf-c-nav__link--hover--after--BorderColor: var(--pf-c-nav__section__link--hover--after--BorderColor);\n --pf-c-nav__link--focus--after--BorderColor: var(--pf-c-nav__section__link--focus--after--BorderColor);\n --pf-c-nav__link--active--after--BorderColor: var(--pf-c-nav__section__link--active--after--BorderColor);\n --pf-c-nav__link--m-current--after--BorderColor: var(--pf-c-nav__section__link--m-current--after--BorderColor);\n --pf-c-nav__link--hover--after--BorderLeftWidth: var(--pf-c-nav__section__link--hover--after--BorderWidth);\n --pf-c-nav__link--focus--after--BorderLeftWidth: var(--pf-c-nav__section__link--focus--after--BorderWidth);\n --pf-c-nav__link--active--after--BorderLeftWidth: var(--pf-c-nav__section__link--active--after--BorderWidth);\n --pf-c-nav__link--m-current--after--BorderLeftWidth: var(--pf-c-nav__section__link--m-current--after--BorderWidth);\n margin-top: var(--pf-c-nav__section--MarginTop);\n --pf-c-nav--c-divider--MarginBottom: 0; }\n .pf-c-nav__section + .pf-c-nav__section {\n --pf-c-nav__section--MarginTop: var(--pf-c-nav__section--section--MarginTop); }\n\n.pf-c-nav__section-title {\n padding: var(--pf-c-nav__section-title--PaddingTop) var(--pf-c-nav__section-title--PaddingRight) var(--pf-c-nav__section-title--PaddingBottom) var(--pf-c-nav__section-title--PaddingLeft);\n font-size: var(--pf-c-nav__section-title--FontSize);\n color: var(--pf-c-nav__section-title--Color);\n border-bottom: var(--pf-c-nav__section-title--BorderBottomWidth) solid var(--pf-c-nav__section-title--BorderBottomColor); }\n\n.pf-c-nav__scroll-button {\n flex: none;\n width: var(--pf-c-nav__scroll-button--Width);\n color: var(--pf-c-nav__scroll-button--Color);\n background-color: var(--pf-c-nav__scroll-button--BackgroundColor);\n border: 0;\n outline-offset: var(--pf-c-nav__scroll-button--OutlineOffset);\n opacity: 0;\n transition: var(--pf-c-nav__scroll-button--Transition); }\n .pf-c-nav__scroll-button::before {\n position: absolute;\n top: 0;\n bottom: 0;\n content: \"\";\n border: solid var(--pf-c-nav__scroll-button--before--BorderColor);\n border-width: 0 var(--pf-c-nav__scroll-button--before--BorderRightWidth) 0 var(--pf-c-nav__scroll-button--before--BorderLeftWidth); }\n .pf-c-nav__scroll-button:hover {\n color: var(--pf-c-nav__scroll-button--hover--Color); }\n .pf-c-nav__scroll-button:focus {\n color: var(--pf-c-nav__scroll-button--focus--Color); }\n .pf-c-nav__scroll-button:active {\n color: var(--pf-c-nav__scroll-button--active--Color); }\n .pf-c-nav__scroll-button:disabled {\n color: var(--pf-c-nav__scroll-button--disabled--Color);\n border-color: var(--pf-c-nav__scroll-button--disabled--before--BorderColor); }\n .pf-c-nav__scroll-button:nth-of-type(1) {\n --pf-c-nav__scroll-button--before--BorderRightWidth: var(--pf-c-nav__scroll-button--before--BorderWidth);\n margin-right: calc(var(--pf-c-nav__scroll-button--Width) * -1);\n transform: translateX(-100%); }\n .pf-c-nav__scroll-button:nth-of-type(1)::before {\n right: 0; }\n .pf-c-nav__scroll-button:nth-of-type(2) {\n --pf-c-nav__scroll-button--before--BorderLeftWidth: var(--pf-c-nav__scroll-button--before--BorderWidth);\n margin-left: calc(var(--pf-c-nav__scroll-button--Width) * -1);\n transform: translateX(100%); }\n .pf-c-nav__scroll-button:nth-of-type(2)::before {\n left: 0; }\n\n.pf-c-notification-badge {\n --pf-c-notification-badge--PaddingTop: var(--pf-global--spacer--form-element);\n --pf-c-notification-badge--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-notification-badge--PaddingBottom: var(--pf-global--spacer--form-element);\n --pf-c-notification-badge--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-notification-badge--MarginTop: calc(-1 * var(--pf-global--spacer--form-element));\n --pf-c-notification-badge--MarginRight: calc(-1 * var(--pf-global--spacer--md));\n --pf-c-notification-badge--MarginBottom: calc(-1 * var(--pf-global--spacer--form-element));\n --pf-c-notification-badge--MarginLeft: calc(-1 * var(--pf-global--spacer--md));\n --pf-c-notification-badge--after--BorderColor: transparent;\n --pf-c-notification-badge--after--BorderRadius: var(--pf-global--BorderRadius--sm);\n --pf-c-notification-badge--after--BorderWidth: 0;\n --pf-c-notification-badge--after--Top: 0;\n --pf-c-notification-badge--after--Right: 0;\n --pf-c-notification-badge--after--Width: auto;\n --pf-c-notification-badge--after--Height: auto;\n --pf-c-notification-badge--after--BackgroundColor: transparent;\n --pf-c-notification-badge--after--TranslateX: 0;\n --pf-c-notification-badge--after--TranslateY: 0;\n --pf-c-notification-badge__i--Width: auto;\n --pf-c-notification-badge__i--Height: auto;\n --pf-c-notification-badge--m-read--after--BorderColor: transparent;\n --pf-c-notification-badge--m-read--after--BackgroundColor: transparent;\n --pf-c-notification-badge--m-unread--Color: var(--pf-global--Color--light-100);\n --pf-c-notification-badge--m-unread--after--BackgroundColor: var(--pf-global--active-color--100);\n --pf-c-notification-badge--m-unread--hover--after--BackgroundColor: var(--pf-global--primary-color--200);\n --pf-c-notification-badge--m-attention--Color: var(--pf-global--Color--light-100);\n --pf-c-notification-badge--m-attention--after--BackgroundColor: var(--pf-global--danger-color--100);\n --pf-c-notification-badge--m-attention--hover--after--BackgroundColor: var(--pf-global--danger-color--200);\n --pf-c-notification-badge__count--MarginLeft: var(--pf-global--spacer--xs);\n --pf-c-notification-badge--pf-icon-attention-bell--LineHeight: var(--pf-global--LineHeight--sm);\n position: relative;\n display: inline-block;\n padding: var(--pf-c-notification-badge--PaddingTop) var(--pf-c-notification-badge--PaddingRight) var(--pf-c-notification-badge--PaddingBottom) var(--pf-c-notification-badge--PaddingLeft);\n margin: var(--pf-c-notification-badge--MarginTop) var(--pf-c-notification-badge--MarginRight) var(--pf-c-notification-badge--MarginBottom) var(--pf-c-notification-badge--MarginLeft);\n background-color: var(--pf-c-notification-badge--after--BackgroundColor);\n border-radius: var(--pf-c-notification-badge--after--BorderRadius); }\n .pf-c-notification-badge::before {\n position: absolute;\n top: var(--pf-c-notification-badge--after--Top);\n right: var(--pf-c-notification-badge--after--Right);\n bottom: 0;\n left: 0;\n width: var(--pf-c-notification-badge--after--Width);\n height: var(--pf-c-notification-badge--after--Height);\n content: \"\";\n border: var(--pf-c-notification-badge--after--BorderWidth) solid var(--pf-c-notification-badge--after--BorderColor);\n border-radius: var(--pf-c-notification-badge--after--BorderRadius);\n transform: translate(var(--pf-c-notification-badge--after--TranslateX), var(--pf-c-notification-badge--after--TranslateY)); }\n .pf-c-notification-badge > i {\n width: var(--pf-c-notification-badge__i--Width);\n height: var(--pf-c-notification-badge__i--Height); }\n .pf-c-notification-badge > * {\n position: relative; }\n .pf-c-notification-badge .pf-icon-attention-bell,\n .pf-c-notification-badge .pf-icon-bell {\n display: inline-block;\n line-height: var(--pf-c-notification-badge--pf-icon-attention-bell--LineHeight); }\n .pf-c-notification-badge .pf-icon-attention-bell::before,\n .pf-c-notification-badge .pf-icon-bell::before {\n vertical-align: bottom; }\n .pf-c-notification-badge.pf-m-read {\n --pf-c-notification-badge--after--BackgroundColor: var(--pf-c-notification-badge--m-read--after--BackgroundColor);\n --pf-c-notification-badge--after--BorderColor: var(--pf-c-notification-badge--m-read--after--BorderColor); }\n .pf-c-notification-badge.pf-m-unread {\n --pf-c-notification-badge--after--BackgroundColor: var(--pf-c-notification-badge--m-unread--after--BackgroundColor);\n color: var(--pf-c-notification-badge--m-unread--Color); }\n .pf-c-notification-badge.pf-m-unread:hover {\n --pf-c-notification-badge--after--BackgroundColor: var(--pf-c-notification-badge--m-unread--hover--after--BackgroundColor); }\n .pf-c-notification-badge.pf-m-attention {\n --pf-c-notification-badge--after--BackgroundColor: var(--pf-c-notification-badge--m-attention--after--BackgroundColor);\n color: var(--pf-c-notification-badge--m-attention--Color); }\n .pf-c-notification-badge.pf-m-attention:hover {\n --pf-c-notification-badge--after--BackgroundColor: var(--pf-c-notification-badge--m-attention--hover--after--BackgroundColor); }\n\n.pf-c-notification-badge__count {\n margin-left: var(--pf-c-notification-badge__count--MarginLeft); }\n\n.pf-c-notification-drawer {\n --pf-c-notification-drawer--BackgroundColor: var(--pf-global--BackgroundColor--200);\n --pf-c-notification-drawer__header--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-notification-drawer__header--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-notification-drawer__header--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-notification-drawer__header--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-notification-drawer__header--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-notification-drawer__header--BoxShadow: var(--pf-global--BoxShadow--sm-bottom);\n --pf-c-notification-drawer__header--ZIndex: var(--pf-global--ZIndex--sm);\n --pf-c-notification-drawer__header-title--FontSize: var(--pf-global--FontSize--xl);\n --pf-c-notification-drawer__header-status--MarginLeft: var(--pf-global--spacer--md);\n --pf-c-notification-drawer__body--ZIndex: var(--pf-global--ZIndex--xs);\n --pf-c-notification-drawer__list-item--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-notification-drawer__list-item--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-notification-drawer__list-item--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-notification-drawer__list-item--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-notification-drawer__list-item--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-notification-drawer__list-item--BoxShadow: inset var(--pf-global--BoxShadow--sm-bottom);\n --pf-c-notification-drawer__list-item--BorderBottomWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-notification-drawer__list-item--BorderBottomColor: transparent;\n --pf-c-notification-drawer__list-item--OutlineOffset: -0.25rem;\n --pf-c-notification-drawer__list-item--before--Width: var(--pf-global--BorderWidth--lg);\n --pf-c-notification-drawer__list-item--before--Top: 0;\n --pf-c-notification-drawer__list-item--before--Bottom: calc(var(--pf-c-notification-drawer__list-item--BorderBottomWidth) * -1);\n --pf-c-notification-drawer__list-item--m-info__list-item-header-icon--Color: var(--pf-global--info-color--100);\n --pf-c-notification-drawer__list-item--m-info__list-item--before--BackgroundColor: var(--pf-global--info-color--100);\n --pf-c-notification-drawer__list-item--m-warning__list-item-header-icon--Color: var(--pf-global--warning-color--100);\n --pf-c-notification-drawer__list-item--m-warning__list-item--before--BackgroundColor: var(--pf-global--warning-color--100);\n --pf-c-notification-drawer__list-item--m-danger__list-item-header-icon--Color: var(--pf-global--danger-color--100);\n --pf-c-notification-drawer__list-item--m-danger__list-item--before--BackgroundColor: var(--pf-global--danger-color--100);\n --pf-c-notification-drawer__list-item--m-success__list-item-header-icon--Color: var(--pf-global--success-color--100);\n --pf-c-notification-drawer__list-item--m-success__list-item--before--BackgroundColor: var(--pf-global--success-color--100);\n --pf-c-notification-drawer__list-item--m-default__list-item-header-icon--Color: var(--pf-global--default-color--200);\n --pf-c-notification-drawer__list-item--m-default__list-item--before--BackgroundColor: var(--pf-global--default-color--200);\n --pf-c-notification-drawer__list-item--m-read--BackgroundColor: var(--pf-global--BackgroundColor--200);\n --pf-c-notification-drawer__list-item--m-read--BorderBottomColor: var(--pf-global--BorderColor--100);\n --pf-c-notification-drawer__list-item--m-read--before--Top: calc(var(--pf-c-notification-drawer__list-item--BorderBottomWidth) * -1);\n --pf-c-notification-drawer__list-item--m-read--before--Bottom: 0;\n --pf-c-notification-drawer__list-item--m-read--before--BackgroundColor: transparent;\n --pf-c-notification-drawer__list-item--list-item--m-read--before--Top: 0;\n --pf-c-notification-drawer__list-item--list-item--m-read--BoxShadow: inset var(--pf-global--BoxShadow--sm-bottom);\n --pf-c-notification-drawer__list-item--m-hoverable--hover--ZIndex: var(--pf-global--ZIndex--xs);\n --pf-c-notification-drawer__list-item--m-hoverable--hover--BoxShadow: var(--pf-global--BoxShadow--md-top), var(--pf-global--BoxShadow--md-bottom);\n --pf-c-notification-drawer__list-item-header--MarginBottom: var(--pf-global--spacer--xs);\n --pf-c-notification-drawer__list-item-header-icon--Color: inherit;\n --pf-c-notification-drawer__list-item-header-icon--MarginRight: var(--pf-global--spacer--sm);\n --pf-c-notification-drawer__list-item-header-title--FontWeight: var(--pf-global--FontWeight--bold);\n --pf-c-notification-drawer__list-item-header-title--max-lines: 1;\n --pf-c-notification-drawer__list-item--m-read__list-item-header-title--FontWeight: var(--pf-global--FontWeight--normal);\n --pf-c-notification-drawer__list-item-description--MarginBottom: var(--pf-global--spacer--sm);\n --pf-c-notification-drawer__list-item-timestamp--Color: var(--pf-global--Color--200);\n --pf-c-notification-drawer__list-item-timestamp--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-notification-drawer__group--m-expanded--group--BorderTopWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-notification-drawer__group--m-expanded--group--BorderTopColor: var(--pf-global--BorderColor--100);\n --pf-c-notification-drawer__group--m-expanded--MinHeight: 0;\n --pf-c-notification-drawer__group-toggle--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-notification-drawer__group-toggle--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-notification-drawer__group-toggle--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-notification-drawer__group-toggle--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-notification-drawer__group-toggle--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-notification-drawer__group-toggle--BorderColor: var(--pf-global--BorderColor--100);\n --pf-c-notification-drawer__group-toggle--BorderBottomWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-notification-drawer__group-toggle--OutlineOffset: -0.25rem;\n --pf-c-notification-drawer__group-toggle-title--MarginRight: var(--pf-global--spacer--md);\n --pf-c-notification-drawer__group-toggle-title--max-lines: 1;\n --pf-c-notification-drawer__group-toggle-count--MarginRight: var(--pf-global--spacer--md);\n --pf-c-notification-drawer__group-toggle-icon--MarginRight: var(--pf-global--spacer--md);\n --pf-c-notification-drawer__group-toggle-icon--Color: var(--pf-global--Color--200);\n --pf-c-notification-drawer__group-toggle-icon--Transition: .2s ease-in 0s;\n --pf-c-notification-drawer__group--m-expanded__group-toggle-icon--Rotate: 90deg;\n display: flex;\n flex-direction: column;\n height: 100%;\n background-color: var(--pf-c-notification-drawer--BackgroundColor); }\n\n.pf-c-notification-drawer__header {\n position: relative;\n z-index: var(--pf-c-notification-drawer__header--ZIndex);\n display: flex;\n flex-shrink: 0;\n align-items: baseline;\n padding: var(--pf-c-notification-drawer__header--PaddingTop) var(--pf-c-notification-drawer__header--PaddingRight) var(--pf-c-notification-drawer__header--PaddingBottom) var(--pf-c-notification-drawer__header--PaddingLeft);\n background-color: var(--pf-c-notification-drawer__header--BackgroundColor);\n box-shadow: var(--pf-c-notification-drawer__header--BoxShadow); }\n\n.pf-c-notification-drawer__header-title {\n font-size: var(--pf-c-notification-drawer__header-title--FontSize); }\n\n.pf-c-notification-drawer__header-status {\n margin-left: var(--pf-c-notification-drawer__header-status--MarginLeft); }\n\n.pf-c-notification-drawer__header-action {\n display: flex;\n align-items: center;\n margin-left: auto; }\n\n.pf-c-notification-drawer__body {\n overflow-y: auto;\n box-shadow: var(--pf-c-notification-drawer__body--ZIndex); }\n\n.pf-c-notification-drawer__list-item {\n position: relative;\n display: grid;\n grid-template-columns: 1fr auto;\n padding: var(--pf-c-notification-drawer__list-item--PaddingTop) var(--pf-c-notification-drawer__list-item--PaddingRight) var(--pf-c-notification-drawer__list-item--PaddingBottom) var(--pf-c-notification-drawer__list-item--PaddingLeft);\n background-color: var(--pf-c-notification-drawer__list-item--BackgroundColor);\n border-bottom: var(--pf-c-notification-drawer__list-item--BorderBottomWidth) solid var(--pf-c-notification-drawer__list-item--BorderBottomColor);\n outline-offset: var(--pf-c-notification-drawer__list-item--OutlineOffset);\n box-shadow: var(--pf-c-notification-drawer__list-item--BoxShadow); }\n .pf-c-notification-drawer__list-item.pf-m-read, .pf-c-notification-drawer__list-item:first-child {\n --pf-c-notification-drawer__list-item--BoxShadow: none; }\n .pf-c-notification-drawer__list-item:not(.pf-m-read) + .pf-c-notification-drawer__list-item.pf-m-read {\n --pf-c-notification-drawer__list-item--BoxShadow: var(--pf-c-notification-drawer__list-item--list-item--m-read--BoxShadow);\n --pf-c-notification-drawer__list-item--before--Top: var(--pf-c-notification-drawer__list-item--list-item--m-read--before--Top); }\n .pf-c-notification-drawer__list-item::before {\n position: absolute;\n top: var(--pf-c-notification-drawer__list-item--before--Top);\n bottom: var(--pf-c-notification-drawer__list-item--before--Bottom);\n width: var(--pf-c-notification-drawer__list-item--before--Width);\n content: \"\";\n background-color: var(--pf-c-notification-drawer__list-item--before--BackgroundColor); }\n .pf-c-notification-drawer__list-item.pf-m-info {\n --pf-c-notification-drawer__list-item--before--BackgroundColor: var(--pf-c-notification-drawer__list-item--m-info__list-item--before--BackgroundColor);\n --pf-c-notification-drawer__list-item-header-icon--Color: var(--pf-c-notification-drawer__list-item--m-info__list-item-header-icon--Color); }\n .pf-c-notification-drawer__list-item.pf-m-warning {\n --pf-c-notification-drawer__list-item--before--BackgroundColor: var(--pf-c-notification-drawer__list-item--m-warning__list-item--before--BackgroundColor);\n --pf-c-notification-drawer__list-item-header-icon--Color: var(--pf-c-notification-drawer__list-item--m-warning__list-item-header-icon--Color); }\n .pf-c-notification-drawer__list-item.pf-m-danger {\n --pf-c-notification-drawer__list-item--before--BackgroundColor: var(--pf-c-notification-drawer__list-item--m-danger__list-item--before--BackgroundColor);\n --pf-c-notification-drawer__list-item-header-icon--Color: var(--pf-c-notification-drawer__list-item--m-danger__list-item-header-icon--Color); }\n .pf-c-notification-drawer__list-item.pf-m-success {\n --pf-c-notification-drawer__list-item--before--BackgroundColor: var(--pf-c-notification-drawer__list-item--m-success__list-item--before--BackgroundColor);\n --pf-c-notification-drawer__list-item-header-icon--Color: var(--pf-c-notification-drawer__list-item--m-success__list-item-header-icon--Color); }\n .pf-c-notification-drawer__list-item.pf-m-default {\n --pf-c-notification-drawer__list-item--before--BackgroundColor: var(--pf-c-notification-drawer__list-item--m-default__list-item--before--BackgroundColor);\n --pf-c-notification-drawer__list-item-header-icon--Color: var(--pf-c-notification-drawer__list-item--m-default__list-item-header-icon--Color); }\n .pf-c-notification-drawer__list-item.pf-m-read {\n --pf-c-notification-drawer__list-item--BorderBottomColor: var(--pf-c-notification-drawer__list-item--m-read--BorderBottomColor);\n --pf-c-notification-drawer__list-item--BackgroundColor: var(--pf-c-notification-drawer__list-item--m-read--BackgroundColor);\n --pf-c-notification-drawer__list-item--before--Top: var(--pf-c-notification-drawer__list-item--m-read--before--Top);\n --pf-c-notification-drawer__list-item--before--Bottom: var(--pf-c-notification-drawer__list-item--m-read--before--Bottom);\n --pf-c-notification-drawer__list-item--before--BackgroundColor: var(--pf-c-notification-drawer__list-item--m-read--before--BackgroundColor);\n --pf-c-notification-drawer__list-item-header-title--FontWeight: var(--pf-c-notification-drawer__list-item--m-read__list-item-header-title--FontWeight);\n position: relative; }\n .pf-c-notification-drawer__list-item.pf-m-hoverable {\n cursor: pointer; }\n .pf-c-notification-drawer__list-item.pf-m-hoverable:hover {\n z-index: var(--pf-c-notification-drawer__list-item--m-hoverable--hover--ZIndex);\n box-shadow: var(--pf-c-notification-drawer__list-item--m-hoverable--hover--BoxShadow); }\n\n.pf-c-notification-drawer__list-item-header {\n display: flex;\n align-items: baseline;\n grid-column: 1 / 2;\n grid-row: 1 / 2;\n margin-bottom: var(--pf-c-notification-drawer__list-item-header--MarginBottom); }\n\n.pf-c-notification-drawer__list-item-header-icon {\n margin-right: var(--pf-c-notification-drawer__list-item-header-icon--MarginRight);\n color: var(--pf-c-notification-drawer__list-item-header-icon--Color); }\n\n.pf-c-notification-drawer__list-item-header-title {\n font-weight: var(--pf-c-notification-drawer__list-item-header-title--FontWeight);\n word-break: break-word; }\n .pf-c-notification-drawer__list-item-header-title.pf-m-truncate {\n display: -webkit-box;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: var(--pf-c-notification-drawer__list-item-header-title--max-lines);\n overflow: hidden; }\n\n.pf-c-notification-drawer__list-item-action {\n grid-column: 2 / 3;\n grid-row: 1 / 3; }\n\n.pf-c-notification-drawer__list-item-description {\n grid-row: 2 / 3;\n grid-column: 1 / 2;\n margin-bottom: var(--pf-c-notification-drawer__list-item-description--MarginBottom);\n word-break: break-word; }\n\n.pf-c-notification-drawer__list-item-timestamp {\n grid-row: 3 / 4;\n grid-column: 1 / 2;\n font-size: var(--pf-c-notification-drawer__list-item-timestamp--FontSize);\n color: var(--pf-c-notification-drawer__list-item-timestamp--Color); }\n\n.pf-c-notification-drawer__group-list {\n display: flex;\n flex-direction: column; }\n\n.pf-c-notification-drawer__group.pf-m-expanded {\n min-height: var(--pf-c-notification-drawer__group--m-expanded--MinHeight); }\n .pf-c-notification-drawer__group.pf-m-expanded + .pf-c-notification-drawer__group {\n border-top: var(--pf-c-notification-drawer__group--m-expanded--group--BorderTopWidth) solid var(--pf-c-notification-drawer__group--m-expanded--group--BorderTopColor); }\n\n.pf-c-notification-drawer__group .pf-c-notification-drawer__list-item:last-child {\n --pf-c-notification-drawer__list-item--BorderBottomWidth: 0;\n --pf-c-notification-drawer__list-item--before--Bottom: 0; }\n\n.pf-c-notification-drawer__group-toggle {\n display: flex;\n align-items: baseline;\n width: 100%;\n padding: var(--pf-c-notification-drawer__group-toggle--PaddingTop) var(--pf-c-notification-drawer__group-toggle--PaddingRight) var(--pf-c-notification-drawer__group-toggle--PaddingBottom) var(--pf-c-notification-drawer__group-toggle--PaddingLeft);\n background-color: var(--pf-c-notification-drawer__group-toggle--BackgroundColor);\n border: solid var(--pf-c-notification-drawer__group-toggle--BorderColor);\n border-width: 0 0 var(--pf-c-notification-drawer__group-toggle--BorderBottomWidth) 0;\n outline-offset: var(--pf-c-notification-drawer__group-toggle--OutlineOffset); }\n\n.pf-c-notification-drawer__group-toggle-title {\n display: -webkit-box;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: var(--pf-c-notification-drawer__group-toggle-title--max-lines);\n overflow: hidden;\n margin-right: var(--pf-c-notification-drawer__group-toggle-title--MarginRight);\n text-align: left;\n word-break: break-word; }\n\n.pf-c-notification-drawer__group-toggle-count {\n margin-right: var(--pf-c-notification-drawer__group-toggle-count--MarginRight);\n margin-left: auto; }\n\n.pf-c-notification-drawer__group-toggle-icon {\n margin-right: var(--pf-c-notification-drawer__group-toggle-icon--MarginRight);\n color: var(--pf-c-notification-drawer__group-toggle-icon--Color);\n transition: var(--pf-c-notification-drawer__group-toggle-icon--Transition); }\n .pf-c-notification-drawer__group.pf-m-expanded .pf-c-notification-drawer__group-toggle-icon {\n transform: rotate(var(--pf-c-notification-drawer__group--m-expanded__group-toggle-icon--Rotate)); }\n\n.pf-c-options-menu {\n --pf-c-options-menu__toggle--BackgroundColor: transparent;\n --pf-c-options-menu__toggle--PaddingTop: var(--pf-global--spacer--form-element);\n --pf-c-options-menu__toggle--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-options-menu__toggle--PaddingBottom: var(--pf-global--spacer--form-element);\n --pf-c-options-menu__toggle--PaddingLeft: var(--pf-global--spacer--sm);\n --pf-c-options-menu__toggle--MinWidth: var(--pf-global--target-size--MinWidth);\n --pf-c-options-menu__toggle--LineHeight: var(--pf-global--LineHeight--md);\n --pf-c-options-menu__toggle--BorderWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-options-menu__toggle--BorderTopColor: var(--pf-global--BorderColor--300);\n --pf-c-options-menu__toggle--BorderRightColor: var(--pf-global--BorderColor--300);\n --pf-c-options-menu__toggle--BorderBottomColor: var(--pf-global--BorderColor--200);\n --pf-c-options-menu__toggle--BorderLeftColor: var(--pf-global--BorderColor--300);\n --pf-c-options-menu__toggle--Color: var(--pf-global--Color--100);\n --pf-c-options-menu__toggle--hover--BorderBottomColor: var(--pf-global--active-color--100);\n --pf-c-options-menu__toggle--active--BorderBottomWidth: var(--pf-global--BorderWidth--md);\n --pf-c-options-menu__toggle--active--BorderBottomColor: var(--pf-global--active-color--100);\n --pf-c-options-menu__toggle--focus--BorderBottomWidth: var(--pf-global--BorderWidth--md);\n --pf-c-options-menu__toggle--focus--BorderBottomColor: var(--pf-global--active-color--100);\n --pf-c-options-menu__toggle--expanded--BorderBottomWidth: var(--pf-global--BorderWidth--md);\n --pf-c-options-menu__toggle--expanded--BorderBottomColor: var(--pf-global--active-color--100);\n --pf-c-options-menu__toggle--disabled--BackgroundColor: var(--pf-global--disabled-color--300);\n --pf-c-options-menu__toggle--m-plain--Color: var(--pf-global--Color--200);\n --pf-c-options-menu__toggle--m-plain--hover--Color: var(--pf-global--Color--100);\n --pf-c-options-menu__toggle--m-plain--disabled--Color: var(--pf-global--disabled-color--200);\n --pf-c-options-menu__toggle-icon--MarginRight: var(--pf-global--spacer--sm);\n --pf-c-options-menu__toggle-icon--MarginLeft: var(--pf-global--spacer--md);\n --pf-c-options-menu--m-top--m-expanded__toggle-icon--Rotate: 180deg;\n --pf-c-options-menu__toggle-button--BackgroundColor: transparent;\n --pf-c-options-menu__toggle-button--PaddingTop: var(--pf-global--spacer--form-element);\n --pf-c-options-menu__toggle-button--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-options-menu__toggle-button--PaddingBottom: var(--pf-global--spacer--form-element);\n --pf-c-options-menu__toggle-button--PaddingLeft: var(--pf-global--spacer--sm);\n --pf-c-options-menu__menu--BackgroundColor: var(--pf-global--BackgroundColor--light-100);\n --pf-c-options-menu__menu--BoxShadow: var(--pf-global--BoxShadow--md);\n --pf-c-options-menu__menu--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-options-menu__menu--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-options-menu__menu--Top: calc(100% + var(--pf-global--spacer--xs));\n --pf-c-options-menu__menu--ZIndex: var(--pf-global--ZIndex--sm);\n --pf-c-options-menu--m-top__menu--Top: 0;\n --pf-c-options-menu--m-top__menu--TranslateY: calc(-100% - var(--pf-global--spacer--xs));\n --pf-c-options-menu__menu-item--BackgroundColor: transparent;\n --pf-c-options-menu__menu-item--Color: var(--pf-global--Color--100);\n --pf-c-options-menu__menu-item--FontSize: var(--pf-global--FontSize--md);\n --pf-c-options-menu__menu-item--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-options-menu__menu-item--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-options-menu__menu-item--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-options-menu__menu-item--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-options-menu__menu-item--disabled--Color: var(--pf-global--Color--dark-200);\n --pf-c-options-menu__menu-item--hover--BackgroundColor: var(--pf-global--BackgroundColor--light-300);\n --pf-c-options-menu__menu-item--disabled--BackgroundColor: transparent;\n --pf-c-options-menu__menu-item-icon--Color: var(--pf-global--active-color--100);\n --pf-c-options-menu__menu-item-icon--FontSize: var(--pf-global--icon--FontSize--sm);\n --pf-c-options-menu__menu-item-icon--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-options-menu__group--group--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-options-menu__group-title--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-options-menu__group-title--PaddingRight: var(--pf-c-options-menu__menu-item--PaddingRight);\n --pf-c-options-menu__group-title--PaddingBottom: var(--pf-c-options-menu__menu-item--PaddingBottom);\n --pf-c-options-menu__group-title--PaddingLeft: var(--pf-c-options-menu__menu-item--PaddingLeft);\n --pf-c-options-menu__group-title--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-options-menu__group-title--FontWeight: var(--pf-global--FontWeight--semi-bold);\n --pf-c-options-menu__group-title--Color: var(--pf-global--Color--dark-200);\n --pf-c-options-menu--c-divider--MarginTop: var(--pf-global--spacer--sm);\n --pf-c-options-menu--c-divider--MarginBottom: var(--pf-global--spacer--sm);\n position: relative;\n display: inline-block;\n max-width: 100%; }\n .pf-c-options-menu .pf-c-divider {\n margin-top: var(--pf-c-options-menu--c-divider--MarginTop);\n margin-bottom: var(--pf-c-options-menu--c-divider--MarginBottom); }\n .pf-c-options-menu .pf-c-divider:last-child {\n --pf-c-options-menu--c-divider--MarginBottom: 0; }\n\n.pf-c-options-menu__toggle:not(.pf-m-plain)::before,\n.pf-c-options-menu.pf-m-text:not(.pf-m-plain) .pf-c-options-menu__toggle-button::before {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n content: \"\";\n border: var(--pf-c-options-menu__toggle--BorderWidth) solid;\n border-color: var(--pf-c-options-menu__toggle--BorderTopColor) var(--pf-c-options-menu__toggle--BorderRightColor) var(--pf-c-options-menu__toggle--BorderBottomColor) var(--pf-c-options-menu__toggle--BorderLeftColor); }\n\n.pf-c-options-menu__toggle:not(.pf-m-plain):hover::before,\n.pf-c-options-menu.pf-m-text:not(.pf-m-plain) .pf-c-options-menu__toggle-button:hover::before {\n --pf-c-options-menu__toggle--BorderBottomColor: var(--pf-c-options-menu__toggle--hover--BorderBottomColor); }\n\n.pf-c-options-menu__toggle:not(.pf-m-plain):active::before, .pf-c-options-menu__toggle:not(.pf-m-plain).pf-m-active::before,\n.pf-c-options-menu.pf-m-text:not(.pf-m-plain) .pf-c-options-menu__toggle-button:active::before,\n.pf-c-options-menu.pf-m-text:not(.pf-m-plain) .pf-c-options-menu__toggle-button.pf-m-active::before {\n --pf-c-options-menu__toggle--BorderBottomColor: var(--pf-c-options-menu__toggle--active--BorderBottomColor);\n border-bottom-width: var(--pf-c-options-menu__toggle--active--BorderBottomWidth); }\n\n.pf-c-options-menu__toggle:not(.pf-m-plain):focus::before,\n.pf-c-options-menu.pf-m-text:not(.pf-m-plain) .pf-c-options-menu__toggle-button:focus::before {\n --pf-c-options-menu__toggle--BorderBottomColor: var(--pf-c-options-menu__toggle--focus--BorderBottomColor);\n border-bottom-width: var(--pf-c-options-menu__toggle--focus--BorderBottomWidth); }\n\n.pf-c-options-menu__toggle {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: space-between;\n min-width: var(--pf-c-options-menu__toggle--MinWidth);\n max-width: 100%;\n padding-left: var(--pf-c-options-menu__toggle--PaddingLeft);\n line-height: var(--pf-c-options-menu__toggle--LineHeight);\n color: var(--pf-c-options-menu__toggle--Color);\n background-color: var(--pf-c-options-menu__toggle--BackgroundColor);\n border: none; }\n .pf-c-options-menu__toggle:not(.pf-m-text) {\n padding-top: var(--pf-c-options-menu__toggle--PaddingTop);\n padding-right: var(--pf-c-options-menu__toggle--PaddingRight);\n padding-bottom: var(--pf-c-options-menu__toggle--PaddingBottom); }\n .pf-c-options-menu.pf-m-expanded > .pf-c-options-menu__toggle::before {\n --pf-c-options-menu__toggle--BorderBottomColor: var(--pf-c-options-menu__toggle--expanded--BorderBottomColor);\n border-bottom-width: var(--pf-c-options-menu__toggle--expanded--BorderBottomWidth); }\n .pf-c-options-menu__toggle.pf-m-plain:not(.pf-m-text) {\n justify-content: center;\n color: var(--pf-c-options-menu__toggle--m-plain--Color); }\n .pf-c-options-menu__toggle.pf-m-plain .pf-c-options-menu__toggle-button-icon {\n line-height: var(--pf-c-options-menu__toggle--LineHeight); }\n .pf-c-options-menu__toggle.pf-m-plain:hover, .pf-c-options-menu__toggle.pf-m-plain:active, .pf-c-options-menu__toggle.pf-m-plain.pf-m-active, .pf-c-options-menu__toggle.pf-m-plain:focus,\n .pf-c-options-menu.pf-m-expanded > .pf-c-options-menu__toggle.pf-m-plain {\n --pf-c-options-menu__toggle--m-plain--Color: var(--pf-c-options-menu__toggle--m-plain--hover--Color); }\n .pf-c-options-menu__toggle.pf-m-plain.pf-m-disabled, .pf-c-options-menu__toggle.pf-m-plain:disabled {\n --pf-c-options-menu__toggle--m-plain--Color: var(--pf-c-options-menu__toggle--m-plain--disabled--Color); }\n .pf-c-options-menu__toggle.pf-m-disabled, .pf-c-options-menu__toggle:disabled {\n pointer-events: none; }\n .pf-c-options-menu__toggle.pf-m-disabled:not(.pf-m-plain), .pf-c-options-menu__toggle.pf-m-disabled.pf-m-text, .pf-c-options-menu__toggle:disabled:not(.pf-m-plain), .pf-c-options-menu__toggle:disabled.pf-m-text {\n --pf-c-options-menu__toggle--BackgroundColor: var(--pf-c-options-menu__toggle--disabled--BackgroundColor); }\n .pf-c-options-menu__toggle.pf-m-disabled::before, .pf-c-options-menu__toggle:disabled::before {\n border: 0; }\n\n.pf-c-options-menu__toggle-button-icon {\n position: relative; }\n\n.pf-c-options-menu__toggle-button {\n padding: var(--pf-c-options-menu__toggle-button--PaddingTop) var(--pf-c-options-menu__toggle-button--PaddingRight) var(--pf-c-options-menu__toggle-button--PaddingBottom) var(--pf-c-options-menu__toggle-button--PaddingLeft);\n background-color: var(--pf-c-options-menu__toggle-button--BackgroundColor);\n border: 0; }\n\n.pf-c-options-menu__toggle-text {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap; }\n\n.pf-c-options-menu__toggle-icon {\n margin-right: var(--pf-c-options-menu__toggle-icon--MarginRight);\n margin-left: var(--pf-c-options-menu__toggle-icon--MarginLeft); }\n .pf-c-options-menu.pf-m-top.pf-m-expanded .pf-c-options-menu__toggle-icon {\n transform: rotate(var(--pf-c-options-menu--m-top--m-expanded__toggle-icon--Rotate)); }\n\n.pf-c-options-menu__menu {\n position: absolute;\n top: var(--pf-c-options-menu__menu--Top);\n z-index: var(--pf-c-options-menu__menu--ZIndex);\n min-width: 100%;\n padding-top: var(--pf-c-options-menu__menu--PaddingTop);\n padding-bottom: var(--pf-c-options-menu__menu--PaddingBottom);\n background-color: var(--pf-c-options-menu__menu--BackgroundColor);\n background-clip: padding-box;\n box-shadow: var(--pf-c-options-menu__menu--BoxShadow); }\n .pf-c-options-menu__menu.pf-m-align-right {\n right: 0; }\n .pf-c-options-menu.pf-m-top .pf-c-options-menu__menu {\n --pf-c-options-menu__menu--Top: var(--pf-c-options-menu--m-top__menu--Top);\n transform: translateY(var(--pf-c-options-menu--m-top__menu--TranslateY)); }\n\n.pf-c-options-menu__menu-item {\n display: flex;\n align-items: baseline;\n width: 100%;\n padding: var(--pf-c-options-menu__menu-item--PaddingTop) var(--pf-c-options-menu__menu-item--PaddingRight) var(--pf-c-options-menu__menu-item--PaddingBottom) var(--pf-c-options-menu__menu-item--PaddingLeft);\n font-size: var(--pf-c-options-menu__menu-item--FontSize);\n color: var(--pf-c-options-menu__menu-item--Color);\n white-space: nowrap;\n background-color: var(--pf-c-options-menu__menu-item--BackgroundColor);\n border: none; }\n .pf-c-options-menu__menu-item:hover, .pf-c-options-menu__menu-item:focus {\n text-decoration: none;\n background-color: var(--pf-c-options-menu__menu-item--hover--BackgroundColor); }\n .pf-c-options-menu__menu-item:disabled, .pf-c-options-menu__menu-item.pf-m-disabled {\n color: var(--pf-c-options-menu__menu-item--disabled--Color);\n pointer-events: none;\n background-color: var(--pf-c-options-menu__menu-item--disabled--BackgroundColor); }\n\n.pf-c-options-menu__menu-item-icon {\n align-self: center;\n width: auto;\n padding-left: var(--pf-c-options-menu__menu-item-icon--PaddingLeft);\n margin-left: auto;\n font-size: var(--pf-c-options-menu__menu-item-icon--FontSize);\n color: var(--pf-c-options-menu__menu-item-icon--Color); }\n\n.pf-c-options-menu__group + .pf-c-options-menu__group {\n padding-top: var(--pf-c-options-menu__group--group--PaddingTop); }\n\n.pf-c-options-menu__group-title {\n padding-top: var(--pf-c-options-menu__group-title--PaddingTop);\n padding-right: var(--pf-c-options-menu__group-title--PaddingRight);\n padding-bottom: var(--pf-c-options-menu__group-title--PaddingBottom);\n padding-left: var(--pf-c-options-menu__group-title--PaddingLeft);\n font-size: var(--pf-c-options-menu__group-title--FontSize);\n font-weight: var(--pf-c-options-menu__group-title--FontWeight);\n color: var(--pf-c-options-menu__group-title--Color); }\n\n.pf-c-overflow-menu {\n --pf-c-overflow-menu--spacer--base: var(--pf-global--spacer--md);\n --pf-c-overflow-menu--spacer: var(--pf-global--spacer--sm);\n --pf-c-overflow-menu__group--spacer: var(--pf-c-overflow-menu--spacer--base);\n --pf-c-overflow-menu__item--spacer: var(--pf-c-overflow-menu--spacer--base);\n --pf-c-overflow-menu--c-divider--m-vertical--spacer: var(--pf-c-overflow-menu--spacer--base);\n --pf-c-overflow-menu__group--m-button-group--spacer: var(--pf-c-overflow-menu--spacer--base);\n --pf-c-overflow-menu__group--m-button-group--space-items: var(--pf-global--spacer--sm);\n --pf-c-overflow-menu__group--m-icon-button-group--spacer: var(--pf-c-overflow-menu--spacer--base);\n --pf-c-overflow-menu__group--m-icon-button-group--space-items: 0;\n display: inline-flex;\n align-items: center; }\n\n.pf-c-overflow-menu__content {\n display: flex;\n align-items: center; }\n\n.pf-c-overflow-menu__group {\n --pf-c-overflow-menu--spacer: var(--pf-c-overflow-menu__group--spacer);\n display: flex;\n align-items: center; }\n .pf-c-overflow-menu__group.pf-m-button-group {\n --pf-c-overflow-menu--spacer: var(--pf-c-overflow-menu__group--m-button-group--spacer); }\n .pf-c-overflow-menu__group.pf-m-button-group > * {\n --pf-c-overflow-menu--spacer: var(--pf-c-overflow-menu__group--m-button-group--space-items); }\n .pf-c-overflow-menu__group.pf-m-icon-button-group {\n --pf-c-overflow-menu--spacer: var(--pf-c-overflow-menu__group--m-icon-button-group--spacer); }\n .pf-c-overflow-menu__group.pf-m-icon-button-group > * {\n --pf-c-overflow-menu--spacer: var(--pf-c-overflow-menu__group--m-icon-button-group--space-items); }\n\n.pf-c-overflow-menu__item {\n --pf-c-overflow-menu--spacer: var(--pf-c-overflow-menu__item--spacer); }\n\n.pf-c-overflow-menu__content,\n.pf-c-overflow-menu__control,\n.pf-c-overflow-menu__group,\n.pf-c-overflow-menu__item {\n margin-right: var(--pf-c-overflow-menu--spacer); }\n .pf-c-overflow-menu__content:last-child,\n .pf-c-overflow-menu__control:last-child,\n .pf-c-overflow-menu__group:last-child,\n .pf-c-overflow-menu__item:last-child {\n --pf-c-overflow-menu--spacer: 0; }\n\n.pf-c-overflow-menu > .pf-c-divider,\n.pf-c-overflow-menu__group > .pf-c-divider {\n --pf-c-overflow-menu--spacer: var(--pf-c-overflow-menu--c-divider--m-vertical--spacer); }\n\n.pf-c-overflow-menu > .pf-c-divider.pf-m-vertical,\n.pf-c-overflow-menu__group > .pf-c-divider.pf-m-vertical {\n margin-right: var(--pf-c-overflow-menu--spacer); }\n .pf-c-overflow-menu > .pf-c-divider.pf-m-vertical:last-child,\n .pf-c-overflow-menu__group > .pf-c-divider.pf-m-vertical:last-child {\n --pf-c-overflow-menu--spacer: 0; }\n\n.pf-c-page {\n --pf-c-page--BackgroundColor: var(--pf-global--BackgroundColor--light-300);\n --pf-c-page__header--BackgroundColor: var(--pf-global--BackgroundColor--dark-100);\n --pf-c-page__header--ZIndex: var(--pf-global--ZIndex--md);\n --pf-c-page__header--MinHeight: 4.75rem;\n --pf-c-page__header-brand--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-page__header-brand--xl--PaddingRight: var(--pf-global--spacer--xl);\n --pf-c-page__header-brand--xl--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-page__header-sidebar-toggle__c-button--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-page__header-sidebar-toggle__c-button--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-page__header-sidebar-toggle__c-button--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-page__header-sidebar-toggle__c-button--PaddingLeft: var(--pf-global--spacer--sm);\n --pf-c-page__header-sidebar-toggle__c-button--MarginRight: var(--pf-global--spacer--md);\n --pf-c-page__header-sidebar-toggle__c-button--MarginLeft: calc(var(--pf-c-page__header-sidebar-toggle__c-button--PaddingLeft) * -1);\n --pf-c-page__header-sidebar-toggle__c-button--FontSize: var(--pf-global--FontSize--2xl);\n --pf-c-page__header-brand-link--c-brand--MaxHeight: 3.75rem;\n --pf-c-page__header-nav--BackgroundColor: var(--pf-global--BackgroundColor--dark-300);\n --pf-c-page__header-nav--xl--BackgroundColor: transparent;\n --pf-c-page__header-nav--xl--PaddingRight: var(--pf-global--spacer--xl);\n --pf-c-page__header-nav--xl--PaddingLeft: var(--pf-global--spacer--xl);\n --pf-c-page__header-tools--MarginRight: var(--pf-global--spacer--md);\n --pf-c-page__header-tools--xl--MarginRight: var(--pf-global--spacer--lg);\n --pf-c-page__header-tools--c-avatar--MarginLeft: var(--pf-global--spacer--md);\n --pf-c-page__header-tools-group--MarginLeft: var(--pf-global--spacer--xl);\n --pf-c-page__header-tools-group--Display: flex;\n --pf-c-page__header-tools-item--Display: block;\n --pf-c-page__header-tools-item--c-notification-badge--hover--BackgroundColor: var(--pf-global--BackgroundColor--dark-200);\n --pf-c-page__header-tools--c-button--notification-badge--m-unread--after--BackgroundColor: var(--pf-global--primary-color--200);\n --pf-c-page__header-tools--c-button--notification-badge--m-attention--after--BackgroundColor: var(--pf-global--danger-color--200);\n --pf-c-page__header-tools--c-button--m-selected--notification-badge--m-unread--after--BackgroundColor: var(--pf-global--primary-color--200);\n --pf-c-page__header-tools--c-button--m-selected--notification-badge--m-attention--after--BackgroundColor: var(--pf-global--danger-color--200);\n --pf-c-page__header-tools--c-button--m-selected--before--Width: auto;\n --pf-c-page__header-tools--c-button--m-selected--before--Height: auto;\n --pf-c-page__header-tools--c-button--m-selected--before--BackgroundColor: var(--pf-global--BackgroundColor--dark-200);\n --pf-c-page__header-tools--c-button--m-selected--before--BorderRadius: var(--pf-global--BorderRadius--sm);\n --pf-c-page__header-tools--c-button--m-selected--c-notification-badge--m-unread--after--BorderColor: transparent;\n --pf-c-page__sidebar--ZIndex: var(--pf-global--ZIndex--sm);\n --pf-c-page__sidebar--Width: 80%;\n --pf-c-page__sidebar--Width: 18.125rem;\n --pf-c-page__sidebar--BackgroundColor: var(--pf-global--BackgroundColor--dark-300);\n --pf-c-page__sidebar--m-light--BackgroundColor: var(--pf-global--BackgroundColor--light-100);\n --pf-c-page__sidebar--BoxShadow: var(--pf-global--BoxShadow--lg-right);\n --pf-c-page__sidebar--Transition: var(--pf-global--Transition);\n --pf-c-page__sidebar--TranslateX: -100%;\n --pf-c-page__sidebar--TranslateZ: 0;\n --pf-c-page__sidebar--m-expanded--TranslateX: 0;\n --pf-c-page__sidebar--xl--TranslateX: 0;\n --pf-c-page__sidebar-body--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-page__sidebar-body--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-page__main--ZIndex: var(--pf-global--ZIndex--xs);\n --pf-c-page__main-section--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-page__main-section--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-page__main-section--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-page__main-section--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-page__main-section--xl--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-page__main-section--xl--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-page__main-section--xl--PaddingBottom: var(--pf-global--spacer--lg);\n --pf-c-page__main-section--xl--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-page__main-breadcrumb--main-section--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-page__main-section--BackgroundColor: var(--pf-global--BackgroundColor--light-300);\n --pf-c-page__main-section--m-light--BackgroundColor: var(--pf-global--BackgroundColor--light-100);\n --pf-c-page__main-section--m-dark-100--BackgroundColor: var(--pf-global--BackgroundColor--dark-transparent-100);\n --pf-c-page__main-section--m-dark-200--BackgroundColor: var(--pf-global--BackgroundColor--dark-transparent-200);\n --pf-c-page--section--m-limit-width--MaxWidth: calc(125rem - var(--pf-c-page__sidebar--Width));\n --pf-c-page--section--m-sticky-top--ZIndex: var(--pf-global--ZIndex--xs);\n --pf-c-page--section--m-sticky-top--BoxShadow: var(--pf-global--BoxShadow--sm-bottom);\n --pf-c-page--section--m-sticky-bottom--ZIndex: var(--pf-global--ZIndex--xs);\n --pf-c-page--section--m-sticky-bottom--BoxShadow: var(--pf-global--BoxShadow--sm-top);\n --pf-c-page--section--m-shadow-bottom--BoxShadow: var(--pf-global--BoxShadow--sm-bottom);\n --pf-c-page--section--m-shadow-bottom--ZIndex: var(--pf-global--ZIndex--xs);\n --pf-c-page--section--m-shadow-top--BoxShadow: var(--pf-global--BoxShadow--sm-top);\n --pf-c-page--section--m-shadow-top--ZIndex: var(--pf-global--ZIndex--xs);\n --pf-c-page__main-nav--BackgroundColor: var(--pf-global--BackgroundColor--light-100);\n --pf-c-page__main-nav--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-page__main-nav--PaddingRight: 0;\n --pf-c-page__main-nav--PaddingLeft: 0;\n --pf-c-page__main-nav--m-sticky-top--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-page__main-nav--xl--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-page__main-nav--xl--PaddingLeft: var(--pf-global--spacer--sm);\n --pf-c-page__main-breadcrumb--BackgroundColor: var(--pf-global--BackgroundColor--light-100);\n --pf-c-page__main-breadcrumb--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-page__main-breadcrumb--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-page__main-breadcrumb--PaddingBottom: 0;\n --pf-c-page__main-breadcrumb--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-page__main-breadcrumb--m-sticky-top--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-page__main-breadcrumb--xl--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-page__main-breadcrumb--xl--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-page__main-wizard--BackgroundColor: var(--pf-global--BackgroundColor--light-100);\n --pf-c-page__main-wizard--BorderTopColor: var(--pf-global--BorderColor--100);\n --pf-c-page__main-wizard--BorderTopWidth: var(--pf-global--BorderWidth--sm);\n display: grid;\n height: 100%;\n grid-template-columns: 1fr;\n grid-template-rows: max-content 1fr;\n grid-template-areas: \"header\" \"main\";\n background-color: var(--pf-c-page--BackgroundColor); }\n @media (min-width: 1200px) {\n .pf-c-page {\n --pf-c-page__header-brand--PaddingLeft: var(--pf-c-page__header-brand--xl--PaddingLeft); } }\n @media screen and (min-width: 1200px) {\n .pf-c-page {\n --pf-c-page__header-nav--BackgroundColor: var(--pf-c-page__header-nav--xl--BackgroundColor);\n --pf-c-page__header-nav--PaddingRight: var(--pf-c-page__header-nav--xl--PaddingRight);\n --pf-c-page__header-nav--PaddingLeft: var(--pf-c-page__header-nav--xl--PaddingLeft); } }\n @media screen and (min-width: 1200px) {\n .pf-c-page {\n --pf-c-page__header-tools--MarginRight: var(--pf-c-page__header-tools--xl--MarginRight); } }\n @media screen and (min-width: 1200px) {\n .pf-c-page {\n --pf-c-page__sidebar--TranslateX: var(--pf-c-page__sidebar--xl--TranslateX); } }\n @media screen and (min-width: 1200px) {\n .pf-c-page {\n --pf-c-page__main-section--PaddingTop: var(--pf-c-page__main-section--xl--PaddingTop);\n --pf-c-page__main-section--PaddingRight: var(--pf-c-page__main-section--xl--PaddingRight);\n --pf-c-page__main-section--PaddingBottom: var(--pf-c-page__main-section--xl--PaddingBottom);\n --pf-c-page__main-section--PaddingLeft: var(--pf-c-page__main-section--xl--PaddingLeft); } }\n @media screen and (min-width: 1200px) {\n .pf-c-page {\n --pf-c-page__main-nav--PaddingRight: var(--pf-c-page__main-nav--xl--PaddingRight);\n --pf-c-page__main-nav--PaddingLeft: var(--pf-c-page__main-nav--xl--PaddingLeft); } }\n @media screen and (min-width: 1200px) {\n .pf-c-page {\n --pf-c-page__main-breadcrumb--PaddingRight: var(--pf-c-page__main-breadcrumb--xl--PaddingRight);\n --pf-c-page__main-breadcrumb--PaddingLeft: var(--pf-c-page__main-breadcrumb--xl--PaddingLeft); } }\n @media (min-width: 1200px) {\n .pf-c-page {\n grid-template-columns: max-content 1fr;\n grid-template-areas: \"header header\" \"nav main\"; } }\n\n.pf-c-page__header {\n color: var(--pf-global--Color--100);\n z-index: var(--pf-c-page__header--ZIndex);\n grid-template-columns: auto auto;\n display: grid;\n grid-area: header;\n align-items: center;\n min-width: 0;\n min-height: var(--pf-c-page__header--MinHeight);\n background-color: var(--pf-c-page__header--BackgroundColor); }\n .pf-c-page__header > * {\n display: flex;\n align-items: center; }\n @media screen and (min-width: 992px) {\n .pf-c-page__header {\n grid-template-columns: auto 1fr auto; } }\n\n.pf-c-page__header-brand {\n grid-column: 1 / 2;\n padding-left: var(--pf-c-page__header-brand--PaddingLeft); }\n @media (min-width: 1200px) {\n .pf-c-page__header-brand {\n padding-right: var(--pf-c-page__header-brand--xl--PaddingRight); } }\n\n.pf-c-page__header-brand-link {\n display: flex;\n flex: 1;\n align-items: center; }\n .pf-c-page__header-brand-link .pf-c-brand {\n max-height: var(--pf-c-page__header-brand-link--c-brand--MaxHeight); }\n\n.pf-c-page__header-brand-toggle .pf-c-button {\n padding: var(--pf-c-page__header-sidebar-toggle__c-button--PaddingTop) var(--pf-c-page__header-sidebar-toggle__c-button--PaddingRight) var(--pf-c-page__header-sidebar-toggle__c-button--PaddingBottom) var(--pf-c-page__header-sidebar-toggle__c-button--PaddingLeft);\n margin-right: var(--pf-c-page__header-sidebar-toggle__c-button--MarginRight);\n margin-left: var(--pf-c-page__header-sidebar-toggle__c-button--MarginLeft);\n font-size: var(--pf-c-page__header-sidebar-toggle__c-button--FontSize);\n line-height: 1; }\n\n.pf-c-page__header-nav {\n align-self: stretch;\n min-width: 0;\n padding-right: var(--pf-c-page__header-nav--PaddingRight);\n padding-left: var(--pf-c-page__header-nav--PaddingLeft);\n background-color: var(--pf-c-page__header-nav--BackgroundColor);\n grid-column: 1 / -1;\n grid-row: 2 / 3; }\n @media screen and (min-width: 1200px) {\n .pf-c-page__header-nav {\n grid-column: 2 / 3;\n grid-row: 1 / 2; } }\n .pf-c-page__header-nav .pf-c-nav {\n align-self: stretch; }\n\n.pf-c-page__header-tools {\n grid-column: 2 / 3;\n margin-right: var(--pf-c-page__header-tools--MarginRight);\n margin-left: auto; }\n .pf-c-page__header-tools .pf-c-avatar {\n margin-left: var(--pf-c-page__header-tools--c-avatar--MarginLeft); }\n @media screen and (min-width: 992px) {\n .pf-c-page__header-tools {\n grid-column: 3 / 4; } }\n\n.pf-c-page__header-tools-group {\n --pf-hidden-visible--visible--Display: var(--pf-c-page__header-tools-group--Display);\n align-items: center; }\n .pf-c-page__header-tools-group + .pf-c-page__header-tools-group {\n margin-left: var(--pf-c-page__header-tools-group--MarginLeft); }\n\n.pf-c-page__header-tools-item {\n --pf-hidden-visible--visible--Display: var(--pf-c-page__header-tools-item--Display); }\n .pf-c-page__header-tools-item .pf-c-notification-badge.pf-m-read:hover {\n --pf-c-notification-badge--after--BackgroundColor: var(--pf-c-page__header-tools-item--c-notification-badge--hover--BackgroundColor); }\n .pf-c-page__header-tools-item.pf-m-selected .pf-c-button {\n background-color: var(--pf-c-page__header-tools--c-button--m-selected--before--BackgroundColor);\n border-radius: var(--pf-c-page__header-tools--c-button--m-selected--before--BorderRadius); }\n .pf-c-page__header-tools-item.pf-m-selected .pf-c-button::before {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n width: var(--pf-c-page__header-tools--c-button--m-selected--before--Width);\n height: var(--pf-c-page__header-tools--c-button--m-selected--before--Height);\n content: \"\"; }\n .pf-c-page__header-tools-item.pf-m-selected .pf-c-button .pf-c-notification-badge.pf-m-unread {\n --pf-c-notification-badge--after--BackgroundColor: var(--pf-c-page__header-tools--c-button--m-selected--notification-badge--m-unread--after--BackgroundColor); }\n .pf-c-page__header-tools-item.pf-m-selected .pf-c-button .pf-c-notification-badge.pf-m-unread::after {\n border-color: var(--pf-c-page__header-tools--c-button--m-selected--c-notification-badge--m-unread--after--BorderColor); }\n .pf-c-page__header-tools-item.pf-m-selected .pf-c-button .pf-c-notification-badge.pf-m-attention {\n --pf-c-notification-badge--after--BackgroundColor: var(--pf-global--danger-color--200); }\n .pf-c-page__header-tools-item .pf-c-button:focus .pf-c-notification-badge.pf-m-unread {\n --pf-c-notification-badge--after--BackgroundColor: var(--pf-c-page__header-tools--c-button--notification-badge--m-unread--after--BackgroundColor); }\n .pf-c-page__header-tools-item .pf-c-button:focus .pf-c-notification-badge.pf-m-attention {\n --pf-c-notification-badge--after--BackgroundColor: var(--pf-c-page__header-tools--c-button--notification-badge--m-attention--after--BackgroundColor); }\n\n.pf-c-page__sidebar {\n grid-area: nav;\n grid-row-start: 2;\n grid-column-start: 1;\n z-index: var(--pf-c-page__sidebar--ZIndex);\n width: var(--pf-c-page__sidebar--Width);\n overflow-x: hidden;\n overflow-y: auto;\n -webkit-overflow-scrolling: touch;\n background-color: var(--pf-c-page__sidebar--BackgroundColor);\n transition: var(--pf-c-page__sidebar--Transition);\n transform: translateX(var(--pf-c-page__sidebar--TranslateX)) translateZ(var(--pf-c-page__sidebar--TranslateZ)); }\n @media screen and (min-width: 1200px) {\n .pf-c-page__sidebar {\n box-shadow: var(--pf-c-page__sidebar--BoxShadow); } }\n .pf-c-page__sidebar.pf-m-expanded {\n --pf-c-page__sidebar--TranslateX: var(--pf-c-page__sidebar--m-expanded--TranslateX);\n box-shadow: var(--pf-c-page__sidebar--BoxShadow); }\n .pf-c-page__sidebar.pf-m-collapsed {\n max-width: 0;\n overflow: hidden; }\n .pf-c-page__sidebar.pf-m-light {\n color: var(--pf-global--Color--100);\n --pf-c-page__sidebar--BackgroundColor: var(--pf-c-page__sidebar--m-light--BackgroundColor); }\n\n.pf-c-page__sidebar-body {\n padding-top: var(--pf-c-page__sidebar-body--PaddingTop);\n padding-bottom: var(--pf-c-page__sidebar-body--PaddingBottom); }\n\n.pf-c-page__main-nav.pf-m-limit-width,\n.pf-c-page__main-breadcrumb.pf-m-limit-width,\n.pf-c-page__main-section.pf-m-limit-width,\n.pf-c-page__main-wizard.pf-m-limit-width {\n display: flex;\n flex-direction: column;\n padding: 0; }\n .pf-c-page__main-nav.pf-m-limit-width > .pf-c-page__main-body,\n .pf-c-page__main-breadcrumb.pf-m-limit-width > .pf-c-page__main-body,\n .pf-c-page__main-section.pf-m-limit-width > .pf-c-page__main-body,\n .pf-c-page__main-wizard.pf-m-limit-width > .pf-c-page__main-body {\n flex: 1;\n max-width: var(--pf-c-page--section--m-limit-width--MaxWidth); }\n\n.pf-c-page__main-nav,\n.pf-c-page__main-breadcrumb,\n.pf-c-page__main-section,\n.pf-c-page__main-wizard,\n.pf-c-page__main-group {\n flex-shrink: 0; }\n .pf-c-page__main-nav.pf-m-sticky-top,\n .pf-c-page__main-breadcrumb.pf-m-sticky-top,\n .pf-c-page__main-section.pf-m-sticky-top,\n .pf-c-page__main-wizard.pf-m-sticky-top,\n .pf-c-page__main-group.pf-m-sticky-top {\n position: sticky;\n top: 0;\n z-index: var(--pf-c-page--section--m-sticky-top--ZIndex);\n box-shadow: var(--pf-c-page--section--m-sticky-top--BoxShadow); }\n .pf-c-page__main-nav.pf-m-sticky-bottom,\n .pf-c-page__main-breadcrumb.pf-m-sticky-bottom,\n .pf-c-page__main-section.pf-m-sticky-bottom,\n .pf-c-page__main-wizard.pf-m-sticky-bottom,\n .pf-c-page__main-group.pf-m-sticky-bottom {\n position: sticky;\n bottom: 0;\n z-index: var(--pf-c-page--section--m-sticky-bottom--ZIndex);\n box-shadow: var(--pf-c-page--section--m-sticky-bottom--BoxShadow); }\n .pf-c-page__main-nav.pf-m-overflow-scroll,\n .pf-c-page__main-breadcrumb.pf-m-overflow-scroll,\n .pf-c-page__main-section.pf-m-overflow-scroll,\n .pf-c-page__main-wizard.pf-m-overflow-scroll,\n .pf-c-page__main-group.pf-m-overflow-scroll {\n position: relative;\n flex-shrink: 1;\n overflow: auto; }\n .pf-c-page__main-nav.pf-m-shadow-bottom,\n .pf-c-page__main-breadcrumb.pf-m-shadow-bottom,\n .pf-c-page__main-section.pf-m-shadow-bottom,\n .pf-c-page__main-wizard.pf-m-shadow-bottom,\n .pf-c-page__main-group.pf-m-shadow-bottom {\n z-index: var(--pf-c-page--section--m-shadow-bottom--ZIndex);\n box-shadow: var(--pf-c-page--section--m-shadow-bottom--BoxShadow); }\n .pf-c-page__main-nav.pf-m-shadow-top,\n .pf-c-page__main-breadcrumb.pf-m-shadow-top,\n .pf-c-page__main-section.pf-m-shadow-top,\n .pf-c-page__main-wizard.pf-m-shadow-top,\n .pf-c-page__main-group.pf-m-shadow-top {\n z-index: var(--pf-c-page--section--m-shadow-top--ZIndex);\n box-shadow: var(--pf-c-page--section--m-shadow-top--BoxShadow); }\n\n.pf-c-page__main,\n.pf-c-page__drawer {\n grid-area: main;\n z-index: var(--pf-c-page__main--ZIndex);\n overflow-x: hidden;\n overflow-y: auto;\n -webkit-overflow-scrolling: touch; }\n .pf-c-page__main:focus,\n .pf-c-page__drawer:focus {\n outline: 0; }\n\n.pf-c-page__main,\n.pf-c-page__main-drawer,\n.pf-c-page__main-group {\n display: flex;\n flex-direction: column; }\n\n.pf-c-page__main-nav {\n padding-top: var(--pf-c-page__main-nav--PaddingTop);\n padding-right: var(--pf-c-page__main-nav--PaddingRight);\n padding-left: var(--pf-c-page__main-nav--PaddingLeft);\n background-color: var(--pf-c-page__main-nav--BackgroundColor); }\n .pf-c-page__main-nav.pf-m-sticky-top,\n .pf-c-page__main-group.pf-m-sticky-top .pf-c-page__main-nav:last-child {\n padding-bottom: var(--pf-c-page__main-nav--m-sticky-top--PaddingBottom); }\n\n.pf-c-page__main-breadcrumb {\n padding: var(--pf-c-page__main-breadcrumb--PaddingTop) var(--pf-c-page__main-breadcrumb--PaddingRight) var(--pf-c-page__main-breadcrumb--PaddingBottom) var(--pf-c-page__main-breadcrumb--PaddingLeft);\n background-color: var(--pf-c-page__main-breadcrumb--BackgroundColor); }\n .pf-c-page__main-breadcrumb + .pf-c-page__main-section {\n --pf-c-page__main-section--PaddingTop: var(--pf-c-page__main-breadcrumb--main-section--PaddingTop); }\n .pf-c-page__main-breadcrumb.pf-m-sticky-top,\n .pf-c-page__main-group.pf-m-sticky-top .pf-c-page__main-breadcrumb:last-child {\n --pf-c-page__main-breadcrumb--PaddingBottom: var(--pf-c-page__main-breadcrumb--m-sticky-top--PaddingBottom); }\n\n.pf-c-page__main-section:last-child, .pf-c-page__main-section:only-child, .pf-c-page__main-section.pf-m-fill,\n.pf-c-page__main-group:last-child,\n.pf-c-page__main-group:only-child,\n.pf-c-page__main-group.pf-m-fill,\n.pf-c-page__main-wizard:last-child,\n.pf-c-page__main-wizard:only-child,\n.pf-c-page__main-wizard.pf-m-fill {\n flex-grow: 1; }\n\n.pf-c-page__main-section.pf-m-no-fill,\n.pf-c-page__main-group.pf-m-no-fill,\n.pf-c-page__main-wizard.pf-m-no-fill {\n flex-grow: 0; }\n\n.pf-c-page__main-section {\n padding: var(--pf-c-page__main-section--PaddingTop) var(--pf-c-page__main-section--PaddingRight) var(--pf-c-page__main-section--PaddingBottom) var(--pf-c-page__main-section--PaddingLeft);\n background-color: var(--pf-c-page__main-section--BackgroundColor); }\n .pf-c-page__main-section.pf-m-light {\n --pf-c-page__main-section--BackgroundColor: var(--pf-c-page__main-section--m-light--BackgroundColor); }\n .pf-c-page__main-section[class*=\"pf-m-dark-\"] {\n color: var(--pf-global--Color--100); }\n .pf-c-page__main-section.pf-m-dark-100 {\n --pf-c-page__main-section--BackgroundColor: var(--pf-c-page__main-section--m-dark-100--BackgroundColor); }\n .pf-c-page__main-section.pf-m-dark-200 {\n --pf-c-page__main-section--BackgroundColor: var(--pf-c-page__main-section--m-dark-200--BackgroundColor); }\n .pf-c-page__main-section.pf-m-padding {\n padding: var(--pf-c-page__main-section--PaddingTop) var(--pf-c-page__main-section--PaddingRight) var(--pf-c-page__main-section--PaddingBottom) var(--pf-c-page__main-section--PaddingLeft); }\n .pf-c-page__main-section.pf-m-no-padding {\n --pf-c-page__main-section--PaddingTop: 0;\n --pf-c-page__main-section--PaddingRight: 0;\n --pf-c-page__main-section--PaddingBottom: 0;\n --pf-c-page__main-section--PaddingLeft: 0; }\n @media (min-width: 576px) {\n .pf-c-page__main-section.pf-m-padding-on-sm {\n padding: var(--pf-c-page__main-section--PaddingTop) var(--pf-c-page__main-section--PaddingRight) var(--pf-c-page__main-section--PaddingBottom) var(--pf-c-page__main-section--PaddingLeft); }\n .pf-c-page__main-section.pf-m-no-padding-on-sm {\n --pf-c-page__main-section--PaddingTop: 0;\n --pf-c-page__main-section--PaddingRight: 0;\n --pf-c-page__main-section--PaddingBottom: 0;\n --pf-c-page__main-section--PaddingLeft: 0; } }\n @media (min-width: 768px) {\n .pf-c-page__main-section.pf-m-padding-on-md {\n padding: var(--pf-c-page__main-section--PaddingTop) var(--pf-c-page__main-section--PaddingRight) var(--pf-c-page__main-section--PaddingBottom) var(--pf-c-page__main-section--PaddingLeft); }\n .pf-c-page__main-section.pf-m-no-padding-on-md {\n --pf-c-page__main-section--PaddingTop: 0;\n --pf-c-page__main-section--PaddingRight: 0;\n --pf-c-page__main-section--PaddingBottom: 0;\n --pf-c-page__main-section--PaddingLeft: 0; } }\n @media (min-width: 992px) {\n .pf-c-page__main-section.pf-m-padding-on-lg {\n padding: var(--pf-c-page__main-section--PaddingTop) var(--pf-c-page__main-section--PaddingRight) var(--pf-c-page__main-section--PaddingBottom) var(--pf-c-page__main-section--PaddingLeft); }\n .pf-c-page__main-section.pf-m-no-padding-on-lg {\n --pf-c-page__main-section--PaddingTop: 0;\n --pf-c-page__main-section--PaddingRight: 0;\n --pf-c-page__main-section--PaddingBottom: 0;\n --pf-c-page__main-section--PaddingLeft: 0; } }\n @media (min-width: 1200px) {\n .pf-c-page__main-section.pf-m-padding-on-xl {\n padding: var(--pf-c-page__main-section--PaddingTop) var(--pf-c-page__main-section--PaddingRight) var(--pf-c-page__main-section--PaddingBottom) var(--pf-c-page__main-section--PaddingLeft); }\n .pf-c-page__main-section.pf-m-no-padding-on-xl {\n --pf-c-page__main-section--PaddingTop: 0;\n --pf-c-page__main-section--PaddingRight: 0;\n --pf-c-page__main-section--PaddingBottom: 0;\n --pf-c-page__main-section--PaddingLeft: 0; } }\n @media (min-width: 1450px) {\n .pf-c-page__main-section.pf-m-padding-on-2xl {\n padding: var(--pf-c-page__main-section--PaddingTop) var(--pf-c-page__main-section--PaddingRight) var(--pf-c-page__main-section--PaddingBottom) var(--pf-c-page__main-section--PaddingLeft); }\n .pf-c-page__main-section.pf-m-no-padding-on-2xl {\n --pf-c-page__main-section--PaddingTop: 0;\n --pf-c-page__main-section--PaddingRight: 0;\n --pf-c-page__main-section--PaddingBottom: 0;\n --pf-c-page__main-section--PaddingLeft: 0; } }\n\n.pf-c-page__main-wizard {\n flex-grow: 1;\n background-color: var(--pf-c-page__main-wizard--BackgroundColor);\n border-top: var(--pf-c-page__main-wizard--BorderTopWidth) solid var(--pf-c-page__main-wizard--BorderTopColor); }\n\n.pf-c-page__main-group {\n flex-shrink: 0; }\n\n.pf-c-page__main-nav .pf-c-page__main-body {\n padding-top: var(--pf-c-page__main-nav--PaddingTop);\n padding-right: var(--pf-c-page__main-nav--PaddingRight);\n padding-left: var(--pf-c-page__main-nav--PaddingLeft); }\n\n.pf-c-page__main-breadcrumb .pf-c-page__main-body {\n padding: var(--pf-c-page__main-breadcrumb--PaddingTop) var(--pf-c-page__main-breadcrumb--PaddingRight) var(--pf-c-page__main-breadcrumb--PaddingBottom) var(--pf-c-page__main-breadcrumb--PaddingLeft); }\n\n.pf-c-page__main-section .pf-c-page__main-body {\n padding: var(--pf-c-page__main-section--PaddingTop) var(--pf-c-page__main-section--PaddingRight) var(--pf-c-page__main-section--PaddingBottom) var(--pf-c-page__main-section--PaddingLeft); }\n\n.pf-c-page__drawer {\n grid-area: main; }\n .pf-c-page__drawer > .pf-c-drawer {\n flex: 1 0 auto; }\n\n.pf-c-pagination {\n --pf-c-pagination--child--MarginRight: var(--pf-global--spacer--lg);\n --pf-c-pagination--m-bottom--child--MarginRight: 0;\n --pf-c-pagination--m-bottom--child--md--MarginRight: var(--pf-global--spacer--lg);\n --pf-c-pagination--m-compact--child--MarginRight: var(--pf-global--spacer--sm);\n --pf-c-pagination--c-options-menu__toggle--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-pagination__nav--Display: none;\n --pf-c-pagination__nav--Visibility: hidden;\n --pf-c-pagination--m-display-summary__nav--Display: none;\n --pf-c-pagination--m-display-summary__nav--Visibility: hidden;\n --pf-c-pagination--m-display-full__nav--Display: inline-flex;\n --pf-c-pagination--m-display-full__nav--Visibility: visible;\n --pf-c-pagination__nav-control--c-button--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-pagination__nav-control--c-button--PaddingLeft: var(--pf-global--spacer--sm);\n --pf-c-pagination__nav-control--c-button--FontSize: var(--pf-global--FontSize--md);\n --pf-c-pagination--m-bottom__nav-control--c-button--OutlineOffset: calc(var(--pf-global--spacer--xs) * -1);\n --pf-c-pagination--m-bottom__nav-control--c-button--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-pagination--m-bottom__nav-control--c-button--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-pagination--m-bottom__nav-control--c-button--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-pagination--m-bottom__nav-control--c-button--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-pagination--m-bottom__nav-control--c-button--md--PaddingTop: var(--pf-global--spacer--form-element);\n --pf-c-pagination--m-bottom__nav-control--c-button--md--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-pagination--m-bottom__nav-control--c-button--md--PaddingBottom: var(--pf-global--spacer--form-element);\n --pf-c-pagination--m-bottom__nav-control--c-button--md--PaddingLeft: var(--pf-global--spacer--sm);\n --pf-c-pagination--m-compact__nav-control--nav-control--MarginLeft: var(--pf-global--spacer--md);\n --pf-c-pagination__nav-page-select--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-pagination__nav-page-select--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-pagination__nav-page-select--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-pagination__nav-page-select--child--MarginRight: var(--pf-global--spacer--xs);\n --pf-c-pagination__nav-page-select--c-form-control--width-base: 3.5ch;\n --pf-c-pagination__nav-page-select--c-form-control--width-chars: 2;\n --pf-c-pagination__nav-page-select--c-form-control--Width: calc(var(--pf-c-pagination__nav-page-select--c-form-control--width-base) + (var(--pf-c-pagination__nav-page-select--c-form-control--width-chars) * 1ch));\n --pf-c-pagination__total-items--Display: block;\n --pf-c-pagination__total-items--Visibility: visible;\n --pf-c-pagination--m-display-summary__total-items--Display: block;\n --pf-c-pagination--m-display-summary__total-items--Visibility: visible;\n --pf-c-pagination--m-display-full__total-items--Display: none;\n --pf-c-pagination--m-display-full__total-items--Visibility: hidden;\n --pf-c-pagination--m-sticky--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-pagination--m-sticky--BoxShadow: var(--pf-global--BoxShadow--sm-bottom);\n --pf-c-pagination--m-sticky--md--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-pagination--m-sticky--md--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-pagination--m-sticky--md--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-pagination--m-sticky--md--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-pagination--m-sticky--ZIndex: var(--pf-global--ZIndex--xs);\n --pf-c-pagination--m-sticky--Top: 0;\n --pf-c-pagination--m-bottom--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-pagination--m-bottom--BoxShadow: var(--pf-global--BoxShadow--sm-top);\n --pf-c-pagination--m-bottom--Bottom: 0;\n --pf-c-pagination--m-bottom--md--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-pagination--m-bottom--md--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-pagination--m-bottom--md--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-pagination--m-bottom--md--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-pagination--m-bottom--xl--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-pagination--m-bottom--xl--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-pagination--m-bottom--m-sticky--BoxShadow: var(--pf-global--BoxShadow--sm-top);\n --pf-c-pagination--c-options-menu--Display: none;\n --pf-c-pagination--c-options-menu--Visibility: hidden;\n --pf-c-pagination--m-display-summary--c-options-menu--Display: none;\n --pf-c-pagination--m-display-summary--c-options-menu--Visibility: hidden;\n --pf-c-pagination--m-display-full--c-options-menu--Display: inline-flex;\n --pf-c-pagination--m-display-full--c-options-menu--Visibility: visible;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: flex-end; }\n @media screen and (min-width: 768px) {\n .pf-c-pagination {\n --pf-c-pagination--m-bottom__nav-control--c-button--PaddingTop: var(--pf-c-pagination--m-bottom__nav-control--c-button--md--PaddingTop);\n --pf-c-pagination--m-bottom__nav-control--c-button--PaddingRight: var(--pf-c-pagination--m-bottom__nav-control--c-button--md--PaddingRight);\n --pf-c-pagination--m-bottom__nav-control--c-button--PaddingBottom: var(--pf-c-pagination--m-bottom__nav-control--c-button--md--PaddingBottom);\n --pf-c-pagination--m-bottom__nav-control--c-button--PaddingLeft: var(--pf-c-pagination--m-bottom__nav-control--c-button--md--PaddingLeft);\n --pf-c-pagination--m-bottom--child--MarginRight: var(--pf-c-pagination--m-bottom--child--md--MarginRight);\n --pf-c-pagination--m-bottom__nav-control--c-button--OutlineOffset: 0;\n --pf-c-pagination--m-bottom--BoxShadow: none;\n --pf-c-pagination--c-options-menu--Display: inline-flex;\n --pf-c-pagination--c-options-menu--Visibility: visible;\n --pf-c-pagination__nav--Display: inline-flex;\n --pf-c-pagination__nav--Visibility: visible;\n --pf-c-pagination__total-items--Display: none;\n --pf-c-pagination__total-items--Visibility: hidden; } }\n @media screen and (min-width: 1200px) {\n .pf-c-pagination {\n --pf-c-pagination--m-bottom--md--PaddingRight: var(--pf-c-pagination--m-bottom--xl--PaddingRight);\n --pf-c-pagination--m-bottom--md--PaddingLeft: var(--pf-c-pagination--m-bottom--xl--PaddingLeft); } }\n .pf-c-pagination > *:not(:last-child):not(.pf-c-pagination__total-items) {\n margin-right: var(--pf-c-pagination--child--MarginRight); }\n .pf-c-pagination .pf-c-options-menu {\n display: var(--pf-c-pagination--c-options-menu--Display);\n visibility: var(--pf-c-pagination--c-options-menu--Visibility); }\n .pf-c-pagination.pf-m-bottom {\n --pf-c-pagination--child--MarginRight: var(--pf-c-pagination--m-bottom--child--MarginRight);\n --pf-c-pagination__nav-control--c-button--PaddingRight: var(--pf-c-pagination--m-bottom__nav-control--c-button--PaddingRight);\n --pf-c-pagination__nav-control--c-button--PaddingLeft: var(--pf-c-pagination--m-bottom__nav-control--c-button--PaddingRight);\n --pf-c-pagination--m-sticky--BoxShadow: var(--pf-c-pagination--m-bottom--m-sticky--BoxShadow);\n --pf-c-pagination--m-sticky--Top: auto;\n position: sticky;\n bottom: var(--pf-c-pagination--m-bottom--Bottom);\n justify-content: center;\n background-color: var(--pf-c-pagination--m-bottom--BackgroundColor);\n box-shadow: var(--pf-c-pagination--m-bottom--BoxShadow); }\n .pf-c-pagination.pf-m-bottom .pf-c-pagination__nav-control .pf-c-button {\n --pf-c-button--PaddingTop: var(--pf-c-pagination--m-bottom__nav-control--c-button--PaddingTop);\n --pf-c-button--PaddingBottom: var(--pf-c-pagination--m-bottom__nav-control--c-button--PaddingBottom);\n outline-offset: var(--pf-c-pagination--m-bottom__nav-control--c-button--OutlineOffset); }\n .pf-c-pagination.pf-m-bottom.pf-m-static {\n --pf-c-pagination--m-bottom--MarginTop: 0;\n --pf-c-pagination--m-bottom--BorderTopWidth: 0;\n position: relative;\n box-shadow: none; }\n .pf-c-pagination.pf-m-bottom .pf-c-pagination__nav-control.pf-m-first,\n .pf-c-pagination.pf-m-bottom .pf-c-pagination__nav-control.pf-m-last,\n .pf-c-pagination.pf-m-bottom .pf-c-pagination__nav-page-select {\n display: none;\n visibility: hidden; }\n .pf-c-pagination.pf-m-bottom .pf-c-options-menu {\n position: absolute;\n display: block;\n visibility: visible; }\n .pf-c-pagination.pf-m-bottom .pf-c-pagination__nav {\n display: flex;\n flex-basis: 100%;\n justify-content: space-between;\n visibility: visible; }\n @media screen and (min-width: 768px) {\n .pf-c-pagination.pf-m-bottom {\n --pf-c-pagination--m-bottom--BorderTopWidth: 0;\n --pf-c-pagination--m-bottom--MarginTop: 0;\n --pf-c-pagination--m-bottom--Bottom: auto;\n position: relative;\n justify-content: flex-end;\n padding: var(--pf-c-pagination--m-bottom--md--PaddingTop) var(--pf-c-pagination--m-bottom--md--PaddingRight) var(--pf-c-pagination--m-bottom--md--PaddingBottom) var(--pf-c-pagination--m-bottom--md--PaddingLeft); }\n .pf-c-pagination.pf-m-bottom .pf-c-pagination__nav-control.pf-m-first,\n .pf-c-pagination.pf-m-bottom .pf-c-pagination__nav-control.pf-m-last,\n .pf-c-pagination.pf-m-bottom .pf-c-pagination__nav-page-select {\n display: block;\n visibility: visible; }\n .pf-c-pagination.pf-m-bottom .pf-c-options-menu {\n position: relative; }\n .pf-c-pagination.pf-m-bottom .pf-c-pagination__nav {\n display: inline-flex;\n flex-basis: auto; } }\n .pf-c-pagination.pf-m-sticky {\n --pf-c-pagination--m-bottom--Bottom: 0;\n position: sticky;\n top: var(--pf-c-pagination--m-sticky--Top);\n z-index: var(--pf-c-pagination--m-sticky--ZIndex);\n padding-top: var(--pf-c-pagination--m-sticky--PaddingTop);\n padding-right: var(--pf-c-pagination--m-sticky--PaddingRight);\n padding-bottom: var(--pf-c-pagination--m-sticky--PaddingBottom);\n padding-left: var(--pf-c-pagination--m-sticky--PaddingLeft);\n background-color: var(--pf-c-pagination--m-sticky--BackgroundColor);\n box-shadow: var(--pf-c-pagination--m-sticky--BoxShadow); }\n @media screen and (min-width: 768px) {\n .pf-c-pagination.pf-m-sticky {\n padding: var(--pf-c-pagination--m-sticky--md--PaddingTop) var(--pf-c-pagination--m-sticky--md--PaddingRight) var(--pf-c-pagination--m-sticky--md--PaddingBottom) var(--pf-c-pagination--m-sticky--md--PaddingLeft); } }\n .pf-c-pagination .pf-c-options-menu__toggle {\n font-size: var(--pf-c-pagination--c-options-menu__toggle--FontSize); }\n .pf-c-pagination.pf-m-compact {\n --pf-c-pagination--child--MarginRight: var(--pf-c-pagination--m-compact--child--MarginRight); }\n\n.pf-c-pagination__nav {\n display: var(--pf-c-pagination__nav--Display);\n justify-content: flex-end;\n visibility: var(--pf-c-pagination__nav--Visibility); }\n\n.pf-c-pagination__nav-control .pf-c-button {\n padding-right: var(--pf-c-pagination__nav-control--c-button--PaddingRight);\n padding-left: var(--pf-c-pagination__nav-control--c-button--PaddingLeft);\n font-size: var(--pf-c-pagination__nav-control--c-button--FontSize); }\n\n.pf-c-pagination.pf-m-compact .pf-c-pagination__nav-control + .pf-c-pagination__nav-control {\n margin-left: var(--pf-c-pagination--m-compact__nav-control--nav-control--MarginLeft); }\n\n.pf-c-pagination__nav-page-select {\n display: flex;\n align-items: center;\n padding-right: var(--pf-c-pagination__nav-page-select--PaddingRight);\n padding-left: var(--pf-c-pagination__nav-page-select--PaddingLeft); }\n .pf-c-pagination__nav-page-select > * {\n font-size: var(--pf-c-pagination__nav-page-select--FontSize);\n white-space: nowrap; }\n .pf-c-pagination__nav-page-select > *:not(:last-child) {\n margin-right: var(--pf-c-pagination__nav-page-select--child--MarginRight); }\n .pf-c-pagination__nav-page-select .pf-c-form-control {\n width: var(--pf-c-pagination__nav-page-select--c-form-control--Width); }\n\n.pf-c-pagination__total-items {\n display: var(--pf-c-pagination__total-items--Display);\n visibility: var(--pf-c-pagination__total-items--Visibility); }\n\n.pf-c-pagination.pf-m-display-summary {\n --pf-c-pagination__nav--Display: var(--pf-c-pagination--m-display-summary__nav--Display);\n --pf-c-pagination__nav--Visibility: var(--pf-c-pagination--m-display-summary__nav--Visibility);\n --pf-c-pagination--c-options-menu--Display: var(--pf-c-pagination--m-display-summary--c-options-menu--Display);\n --pf-c-pagination--c-options-menu--Visibility: var(--pf-c-pagination--m-display-summary--c-options-menu--Visibility);\n --pf-c-pagination__total-items--Display: var(--pf-c-pagination--m-display-summary__total-items--Display);\n --pf-c-pagination__total-items--Visibility: var(--pf-c-pagination--m-display-summary__total-items--Visibility); }\n\n.pf-c-pagination.pf-m-display-full {\n --pf-c-pagination__nav--Display: var(--pf-c-pagination--m-display-full__nav--Display);\n --pf-c-pagination__nav--Visibility: var(--pf-c-pagination--m-display-full__nav--Visibility);\n --pf-c-pagination--c-options-menu--Display: var(--pf-c-pagination--m-display-full--c-options-menu--Display);\n --pf-c-pagination--c-options-menu--Visibility: var(--pf-c-pagination--m-display-full--c-options-menu--Visibility);\n --pf-c-pagination__total-items--Display: var(--pf-c-pagination--m-display-full__total-items--Display);\n --pf-c-pagination__total-items--Visibility: var(--pf-c-pagination--m-display-full__total-items--Visibility); }\n\n@media (min-width: 576px) {\n .pf-c-pagination.pf-m-display-summary-on-sm {\n --pf-c-pagination__nav--Display: var(--pf-c-pagination--m-display-summary__nav--Display);\n --pf-c-pagination__nav--Visibility: var(--pf-c-pagination--m-display-summary__nav--Visibility);\n --pf-c-pagination--c-options-menu--Display: var(--pf-c-pagination--m-display-summary--c-options-menu--Display);\n --pf-c-pagination--c-options-menu--Visibility: var(--pf-c-pagination--m-display-summary--c-options-menu--Visibility);\n --pf-c-pagination__total-items--Display: var(--pf-c-pagination--m-display-summary__total-items--Display);\n --pf-c-pagination__total-items--Visibility: var(--pf-c-pagination--m-display-summary__total-items--Visibility); }\n .pf-c-pagination.pf-m-display-full-on-sm {\n --pf-c-pagination__nav--Display: var(--pf-c-pagination--m-display-full__nav--Display);\n --pf-c-pagination__nav--Visibility: var(--pf-c-pagination--m-display-full__nav--Visibility);\n --pf-c-pagination--c-options-menu--Display: var(--pf-c-pagination--m-display-full--c-options-menu--Display);\n --pf-c-pagination--c-options-menu--Visibility: var(--pf-c-pagination--m-display-full--c-options-menu--Visibility);\n --pf-c-pagination__total-items--Display: var(--pf-c-pagination--m-display-full__total-items--Display);\n --pf-c-pagination__total-items--Visibility: var(--pf-c-pagination--m-display-full__total-items--Visibility); } }\n\n@media (min-width: 768px) {\n .pf-c-pagination.pf-m-display-summary-on-md {\n --pf-c-pagination__nav--Display: var(--pf-c-pagination--m-display-summary__nav--Display);\n --pf-c-pagination__nav--Visibility: var(--pf-c-pagination--m-display-summary__nav--Visibility);\n --pf-c-pagination--c-options-menu--Display: var(--pf-c-pagination--m-display-summary--c-options-menu--Display);\n --pf-c-pagination--c-options-menu--Visibility: var(--pf-c-pagination--m-display-summary--c-options-menu--Visibility);\n --pf-c-pagination__total-items--Display: var(--pf-c-pagination--m-display-summary__total-items--Display);\n --pf-c-pagination__total-items--Visibility: var(--pf-c-pagination--m-display-summary__total-items--Visibility); }\n .pf-c-pagination.pf-m-display-full-on-md {\n --pf-c-pagination__nav--Display: var(--pf-c-pagination--m-display-full__nav--Display);\n --pf-c-pagination__nav--Visibility: var(--pf-c-pagination--m-display-full__nav--Visibility);\n --pf-c-pagination--c-options-menu--Display: var(--pf-c-pagination--m-display-full--c-options-menu--Display);\n --pf-c-pagination--c-options-menu--Visibility: var(--pf-c-pagination--m-display-full--c-options-menu--Visibility);\n --pf-c-pagination__total-items--Display: var(--pf-c-pagination--m-display-full__total-items--Display);\n --pf-c-pagination__total-items--Visibility: var(--pf-c-pagination--m-display-full__total-items--Visibility); } }\n\n@media (min-width: 992px) {\n .pf-c-pagination.pf-m-display-summary-on-lg {\n --pf-c-pagination__nav--Display: var(--pf-c-pagination--m-display-summary__nav--Display);\n --pf-c-pagination__nav--Visibility: var(--pf-c-pagination--m-display-summary__nav--Visibility);\n --pf-c-pagination--c-options-menu--Display: var(--pf-c-pagination--m-display-summary--c-options-menu--Display);\n --pf-c-pagination--c-options-menu--Visibility: var(--pf-c-pagination--m-display-summary--c-options-menu--Visibility);\n --pf-c-pagination__total-items--Display: var(--pf-c-pagination--m-display-summary__total-items--Display);\n --pf-c-pagination__total-items--Visibility: var(--pf-c-pagination--m-display-summary__total-items--Visibility); }\n .pf-c-pagination.pf-m-display-full-on-lg {\n --pf-c-pagination__nav--Display: var(--pf-c-pagination--m-display-full__nav--Display);\n --pf-c-pagination__nav--Visibility: var(--pf-c-pagination--m-display-full__nav--Visibility);\n --pf-c-pagination--c-options-menu--Display: var(--pf-c-pagination--m-display-full--c-options-menu--Display);\n --pf-c-pagination--c-options-menu--Visibility: var(--pf-c-pagination--m-display-full--c-options-menu--Visibility);\n --pf-c-pagination__total-items--Display: var(--pf-c-pagination--m-display-full__total-items--Display);\n --pf-c-pagination__total-items--Visibility: var(--pf-c-pagination--m-display-full__total-items--Visibility); } }\n\n@media (min-width: 1200px) {\n .pf-c-pagination.pf-m-display-summary-on-xl {\n --pf-c-pagination__nav--Display: var(--pf-c-pagination--m-display-summary__nav--Display);\n --pf-c-pagination__nav--Visibility: var(--pf-c-pagination--m-display-summary__nav--Visibility);\n --pf-c-pagination--c-options-menu--Display: var(--pf-c-pagination--m-display-summary--c-options-menu--Display);\n --pf-c-pagination--c-options-menu--Visibility: var(--pf-c-pagination--m-display-summary--c-options-menu--Visibility);\n --pf-c-pagination__total-items--Display: var(--pf-c-pagination--m-display-summary__total-items--Display);\n --pf-c-pagination__total-items--Visibility: var(--pf-c-pagination--m-display-summary__total-items--Visibility); }\n .pf-c-pagination.pf-m-display-full-on-xl {\n --pf-c-pagination__nav--Display: var(--pf-c-pagination--m-display-full__nav--Display);\n --pf-c-pagination__nav--Visibility: var(--pf-c-pagination--m-display-full__nav--Visibility);\n --pf-c-pagination--c-options-menu--Display: var(--pf-c-pagination--m-display-full--c-options-menu--Display);\n --pf-c-pagination--c-options-menu--Visibility: var(--pf-c-pagination--m-display-full--c-options-menu--Visibility);\n --pf-c-pagination__total-items--Display: var(--pf-c-pagination--m-display-full__total-items--Display);\n --pf-c-pagination__total-items--Visibility: var(--pf-c-pagination--m-display-full__total-items--Visibility); } }\n\n@media (min-width: 1450px) {\n .pf-c-pagination.pf-m-display-summary-on-2xl {\n --pf-c-pagination__nav--Display: var(--pf-c-pagination--m-display-summary__nav--Display);\n --pf-c-pagination__nav--Visibility: var(--pf-c-pagination--m-display-summary__nav--Visibility);\n --pf-c-pagination--c-options-menu--Display: var(--pf-c-pagination--m-display-summary--c-options-menu--Display);\n --pf-c-pagination--c-options-menu--Visibility: var(--pf-c-pagination--m-display-summary--c-options-menu--Visibility);\n --pf-c-pagination__total-items--Display: var(--pf-c-pagination--m-display-summary__total-items--Display);\n --pf-c-pagination__total-items--Visibility: var(--pf-c-pagination--m-display-summary__total-items--Visibility); }\n .pf-c-pagination.pf-m-display-full-on-2xl {\n --pf-c-pagination__nav--Display: var(--pf-c-pagination--m-display-full__nav--Display);\n --pf-c-pagination__nav--Visibility: var(--pf-c-pagination--m-display-full__nav--Visibility);\n --pf-c-pagination--c-options-menu--Display: var(--pf-c-pagination--m-display-full--c-options-menu--Display);\n --pf-c-pagination--c-options-menu--Visibility: var(--pf-c-pagination--m-display-full--c-options-menu--Visibility);\n --pf-c-pagination__total-items--Display: var(--pf-c-pagination--m-display-full__total-items--Display);\n --pf-c-pagination__total-items--Visibility: var(--pf-c-pagination--m-display-full__total-items--Visibility); } }\n\n.pf-c-popover {\n --pf-c-popover--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-popover--MinWidth: calc(var(--pf-c-popover__content--PaddingLeft) + var(--pf-c-popover__content--PaddingRight) + 18.75rem);\n --pf-c-popover--MaxWidth: calc(var(--pf-c-popover__content--PaddingLeft) + var(--pf-c-popover__content--PaddingRight) + 18.75rem);\n --pf-c-popover--BoxShadow: var(--pf-global--BoxShadow--md);\n --pf-c-popover__content--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-popover__content--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-popover__content--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-popover__content--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-popover__content--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-popover__arrow--Width: var(--pf-global--arrow--width-lg);\n --pf-c-popover__arrow--Height: var(--pf-global--arrow--width-lg);\n --pf-c-popover__arrow--BoxShadow: var(--pf-global--BoxShadow--md);\n --pf-c-popover__arrow--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-popover__arrow--m-top--TranslateX: -50%;\n --pf-c-popover__arrow--m-top--TranslateY: 50%;\n --pf-c-popover__arrow--m-top--Rotate: 45deg;\n --pf-c-popover__arrow--m-right--TranslateX: -50%;\n --pf-c-popover__arrow--m-right--TranslateY: -50%;\n --pf-c-popover__arrow--m-right--Rotate: 45deg;\n --pf-c-popover__arrow--m-bottom--TranslateX: -50%;\n --pf-c-popover__arrow--m-bottom--TranslateY: -50%;\n --pf-c-popover__arrow--m-bottom--Rotate: 45deg;\n --pf-c-popover__arrow--m-left--TranslateX: 50%;\n --pf-c-popover__arrow--m-left--TranslateY: -50%;\n --pf-c-popover__arrow--m-left--Rotate: 45deg;\n --pf-c-popover--c-button--MarginLeft: var(--pf-global--spacer--sm);\n --pf-c-popover--c-button--Top: calc(var(--pf-c-popover__content--PaddingTop) - var(--pf-global--spacer--form-element));\n --pf-c-popover--c-button--Right: var(--pf-global--spacer--md);\n --pf-c-popover--c-button--sibling--PaddingRight: var(--pf-global--spacer--2xl);\n --pf-c-popover--c-title--MarginBottom: var(--pf-global--spacer--sm);\n --pf-c-popover__footer--MarginTop: var(--pf-global--spacer--md);\n position: relative;\n min-width: var(--pf-c-popover--MinWidth);\n max-width: var(--pf-c-popover--MaxWidth);\n font-size: var(--pf-c-popover--FontSize);\n box-shadow: var(--pf-c-popover--BoxShadow); }\n .pf-c-popover.pf-m-no-padding {\n --pf-c-popover__content--PaddingTop: 0px;\n --pf-c-popover__content--PaddingRight: 0px;\n --pf-c-popover__content--PaddingBottom: 0px;\n --pf-c-popover__content--PaddingLeft: 0px; }\n .pf-c-popover.pf-m-width-auto {\n --pf-c-popover--MinWidth: auto;\n --pf-c-popover--MaxWidth: none; }\n .pf-c-popover.pf-m-top .pf-c-popover__arrow {\n bottom: 0;\n left: 50%;\n transform: translateX(var(--pf-c-popover__arrow--m-top--TranslateX)) translateY(var(--pf-c-popover__arrow--m-top--TranslateY)) rotate(var(--pf-c-popover__arrow--m-top--Rotate)); }\n .pf-c-popover.pf-m-bottom .pf-c-popover__arrow {\n top: 0;\n left: 50%;\n transform: translateX(var(--pf-c-popover__arrow--m-bottom--TranslateX)) translateY(var(--pf-c-popover__arrow--m-bottom--TranslateY)) rotate(var(--pf-c-popover__arrow--m-bottom--Rotate)); }\n .pf-c-popover.pf-m-left .pf-c-popover__arrow {\n top: 50%;\n right: 0;\n transform: translateX(var(--pf-c-popover__arrow--m-left--TranslateX)) translateY(var(--pf-c-popover__arrow--m-left--TranslateY)) rotate(var(--pf-c-popover__arrow--m-left--Rotate)); }\n .pf-c-popover.pf-m-right .pf-c-popover__arrow {\n top: 50%;\n left: 0;\n transform: translateX(var(--pf-c-popover__arrow--m-right--TranslateX)) translateY(var(--pf-c-popover__arrow--m-right--TranslateY)) rotate(var(--pf-c-popover__arrow--m-right--Rotate)); }\n\n.pf-c-popover__content {\n position: relative;\n padding: var(--pf-c-popover__content--PaddingTop) var(--pf-c-popover__content--PaddingRight) var(--pf-c-popover__content--PaddingBottom) var(--pf-c-popover__content--PaddingLeft);\n background-color: var(--pf-c-popover__content--BackgroundColor); }\n .pf-c-popover__content > .pf-c-title {\n margin-bottom: var(--pf-c-popover--c-title--MarginBottom); }\n .pf-c-popover__content > .pf-c-button {\n position: absolute;\n top: var(--pf-c-popover--c-button--Top);\n right: var(--pf-c-popover--c-button--Right); }\n .pf-c-popover__content > .pf-c-button + * {\n padding-right: var(--pf-c-popover--c-button--sibling--PaddingRight); }\n\n.pf-c-popover__arrow {\n position: absolute;\n width: var(--pf-c-popover__arrow--Width);\n height: var(--pf-c-popover__arrow--Height);\n pointer-events: none;\n background-color: var(--pf-c-popover__arrow--BackgroundColor);\n box-shadow: var(--pf-c-popover__arrow--BoxShadow); }\n\n.pf-c-popover__body {\n word-wrap: break-word; }\n\n.pf-c-popover__footer {\n margin-top: var(--pf-c-popover__footer--MarginTop); }\n\n.pf-c-progress {\n --pf-c-progress--GridGap: var(--pf-global--spacer--md);\n --pf-c-progress__bar--before--BackgroundColor: var(--pf-global--primary-color--100);\n --pf-c-progress__bar--Height: var(--pf-global--spacer--md);\n --pf-c-progress__bar--BackgroundColor: var(--pf-global--BackgroundColor--light-100);\n --pf-c-progress__measure--m-static-width--MinWidth: 4.5ch;\n --pf-c-progress__status-icon--Color: var(--pf-global--Color--100);\n --pf-c-progress__status-icon--MarginLeft: var(--pf-global--spacer--sm);\n --pf-c-progress__bar--before--Opacity: .2;\n --pf-c-progress__indicator--Height: var(--pf-c-progress__bar--Height);\n --pf-c-progress__indicator--BackgroundColor: var(--pf-c-progress__bar--before--BackgroundColor);\n --pf-c-progress--m-success__bar--BackgroundColor: var(--pf-global--success-color--100);\n --pf-c-progress--m-warning__bar--BackgroundColor: var(--pf-global--warning-color--100);\n --pf-c-progress--m-danger__bar--BackgroundColor: var(--pf-global--danger-color--100);\n --pf-c-progress--m-success__status-icon--Color: var(--pf-global--success-color--100);\n --pf-c-progress--m-warning__status-icon--Color: var(--pf-global--warning-color--100);\n --pf-c-progress--m-danger__status-icon--Color: var(--pf-global--danger-color--100);\n --pf-c-progress--m-inside__indicator--MinWidth: var(--pf-global--spacer--xl);\n --pf-c-progress--m-inside__measure--Color: var(--pf-global--Color--light-100);\n --pf-c-progress--m-success--m-inside__measure--Color: var(--pf-global--Color--light-100);\n --pf-c-progress--m-warning--m-inside__measure--Color: var(--pf-global--Color--dark-100);\n --pf-c-progress--m-inside__measure--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-progress--m-outside__measure--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-progress--m-sm__bar--Height: var(--pf-global--spacer--sm);\n --pf-c-progress--m-sm__description--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-progress--m-sm__measure--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-progress--m-lg__bar--Height: var(--pf-global--spacer--lg);\n display: grid;\n align-items: end;\n grid-gap: var(--pf-c-progress--GridGap);\n grid-template-columns: auto auto;\n grid-template-rows: 1fr auto; }\n .pf-c-progress.pf-m-sm {\n --pf-c-progress__bar--Height: var(--pf-c-progress--m-sm__bar--Height); }\n .pf-c-progress.pf-m-sm .pf-c-progress__description {\n font-size: var(--pf-c-progress--m-sm__description--FontSize); }\n .pf-c-progress.pf-m-sm .pf-c-progress__measure {\n font-size: var(--pf-c-progress--m-sm__measure--FontSize); }\n .pf-c-progress.pf-m-lg {\n --pf-c-progress__bar--Height: var(--pf-c-progress--m-lg__bar--Height); }\n .pf-c-progress.pf-m-inside .pf-c-progress__indicator {\n display: flex;\n align-items: center;\n justify-content: center;\n min-width: var(--pf-c-progress--m-inside__indicator--MinWidth); }\n .pf-c-progress.pf-m-inside .pf-c-progress__measure {\n font-size: var(--pf-c-progress--m-inside__measure--FontSize);\n color: var(--pf-c-progress--m-inside__measure--Color);\n text-align: center; }\n .pf-c-progress.pf-m-outside .pf-c-progress__description {\n grid-column: 1 / 3; }\n .pf-c-progress.pf-m-outside .pf-c-progress__status {\n grid-column: 2 / 3;\n grid-row: 2 / 3;\n align-self: center; }\n .pf-c-progress.pf-m-outside .pf-c-progress__measure {\n display: inline-block;\n font-size: var(--pf-c-progress--m-outside__measure--FontSize); }\n .pf-c-progress.pf-m-outside .pf-c-progress__measure.pf-m-static-width {\n min-width: var(--pf-c-progress__measure--m-static-width--MinWidth);\n text-align: left; }\n .pf-c-progress.pf-m-outside .pf-c-progress__bar,\n .pf-c-progress.pf-m-outside .pf-c-progress__indicator {\n grid-column: 1 / 2; }\n .pf-c-progress.pf-m-singleline {\n grid-template-rows: 1fr; }\n .pf-c-progress.pf-m-singleline .pf-c-progress__description {\n display: none;\n visibility: hidden; }\n .pf-c-progress.pf-m-singleline .pf-c-progress__bar {\n grid-row: 1 / 2;\n grid-column: 1 / 2; }\n .pf-c-progress.pf-m-singleline .pf-c-progress__status {\n grid-row: 1 / 2;\n grid-column: 2 / 3; }\n .pf-c-progress.pf-m-outside, .pf-c-progress.pf-m-singleline {\n grid-template-columns: 1fr fit-content(50%); }\n .pf-c-progress.pf-m-success {\n --pf-c-progress__bar--before--BackgroundColor: var(--pf-c-progress--m-success__bar--BackgroundColor);\n --pf-c-progress__status-icon--Color: var(--pf-c-progress--m-success__status-icon--Color);\n --pf-c-progress--m-inside__measure--Color: var(--pf-c-progress--m-success--m-inside__measure--Color); }\n .pf-c-progress.pf-m-warning {\n --pf-c-progress__bar--before--BackgroundColor: var(--pf-c-progress--m-warning__bar--BackgroundColor);\n --pf-c-progress__status-icon--Color: var(--pf-c-progress--m-warning__status-icon--Color);\n --pf-c-progress--m-inside__measure--Color: var(--pf-c-progress--m-warning--m-inside__measure--Color); }\n .pf-c-progress.pf-m-danger {\n --pf-c-progress__bar--before--BackgroundColor: var(--pf-c-progress--m-danger__bar--BackgroundColor);\n --pf-c-progress__status-icon--Color: var(--pf-c-progress--m-danger__status-icon--Color); }\n\n.pf-c-progress__description {\n word-break: break-word;\n grid-column: 1 / 2; }\n .pf-c-progress__description.pf-m-truncate {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap; }\n\n.pf-c-progress__status {\n grid-column: 2 / 3;\n grid-row: 1 / 2;\n text-align: right;\n word-break: break-word; }\n\n.pf-c-progress__status-icon {\n margin-left: var(--pf-c-progress__status-icon--MarginLeft);\n color: var(--pf-c-progress__status-icon--Color); }\n\n.pf-c-progress__bar {\n position: relative;\n grid-column: 1 / 3;\n grid-row: 2 / 3;\n align-self: center;\n height: var(--pf-c-progress__bar--Height);\n background-color: var(--pf-c-progress__bar--BackgroundColor); }\n .pf-c-progress__bar::before {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n content: \"\";\n background-color: var(--pf-c-progress__bar--before--BackgroundColor);\n opacity: var(--pf-c-progress__bar--before--Opacity); }\n\n.pf-c-progress__indicator {\n position: absolute;\n top: 0;\n left: 0;\n height: var(--pf-c-progress__indicator--Height);\n background-color: var(--pf-c-progress__indicator--BackgroundColor); }\n\n.pf-c-radio {\n --pf-c-radio--GridGap: var(--pf-global--spacer--xs) var(--pf-global--spacer--sm);\n --pf-c-radio__label--disabled--Color: var(--pf-global--disabled-color--100);\n --pf-c-radio__label--Color: var(--pf-global--Color--100);\n --pf-c-radio__label--FontWeight: var(--pf-global--FontWeight--normal);\n --pf-c-radio__label--FontSize: var(--pf-global--FontSize--md);\n --pf-c-radio__label--LineHeight: var(--pf-global--LineHeight--sm);\n --pf-c-radio__input--MarginTop: -0.1875rem;\n --pf-c-radio__input--first-child--MarginLeft: 0.0625rem;\n --pf-c-radio__input--last-child--MarginRight: 0.0625rem;\n --pf-c-radio__description--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-radio__description--Color: var(--pf-global--Color--200);\n display: grid;\n grid-template-columns: auto 1fr;\n grid-gap: var(--pf-c-radio--GridGap);\n align-items: center;\n justify-items: start; }\n\n.pf-c-radio__label {\n font-size: var(--pf-c-radio__label--FontSize);\n font-weight: var(--pf-c-radio__label--FontWeight);\n line-height: var(--pf-c-radio__label--LineHeight);\n color: var(--pf-c-radio__label--Color); }\n\n.pf-c-radio__input {\n margin-top: var(--pf-c-radio__input--MarginTop); }\n .pf-c-radio__input:first-child {\n margin-left: var(--pf-c-radio__input--first-child--MarginLeft); }\n .pf-c-radio__input:last-child {\n margin-right: var(--pf-c-radio__input--last-child--MarginRight); }\n\n.pf-c-radio__description {\n grid-column: 2;\n font-size: var(--pf-c-radio__description--FontSize);\n color: var(--pf-c-radio__description--Color); }\n\nlabel.pf-c-radio, .pf-c-radio__label,\n.pf-c-radio__input {\n cursor: pointer; }\n\n.pf-c-radio__label:disabled, .pf-c-radio__label.pf-m-disabled,\n.pf-c-radio__input:disabled,\n.pf-c-radio__input.pf-m-disabled {\n --pf-c-radio__label--Color: var(--pf-c-radio__label--disabled--Color);\n cursor: not-allowed; }\n\n.pf-c-search-input {\n --pf-c-search-input__text--before--BorderWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-search-input__text--before--BorderColor: var(--pf-global--BorderColor--300);\n --pf-c-search-input__text--after--BorderBottomWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-search-input__text--after--BorderBottomColor: var(--pf-global--BorderColor--200);\n --pf-c-search-input--hover__text--after--BorderBottomColor: var(--pf-global--primary-color--100);\n --pf-c-search-input__text--focus-within--after--BorderBottomWidth: var(--pf-global--BorderWidth--md);\n --pf-c-search-input__text--focus-within--after--BorderBottomColor: var(--pf-global--primary-color--100);\n --pf-c-search-input__text-input--PaddingTop: var(--pf-global--spacer--form-element);\n --pf-c-search-input__text-input--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-search-input__text-input--PaddingBottom: var(--pf-global--spacer--form-element);\n --pf-c-search-input__text-input--PaddingLeft: var(--pf-global--spacer--xl);\n --pf-c-search-input__text-input--MinWidth: 6ch;\n --pf-c-search-input__icon--Left: var(--pf-global--spacer--sm);\n --pf-c-search-input__icon--Color: var(--pf-global--Color--200);\n --pf-c-search-input__text--hover__icon--Color: var(--pf-global--Color--100);\n --pf-c-search-input__icon--TranslateY: -50%;\n --pf-c-search-input__utilities--MarginRight: var(--pf-global--spacer--sm);\n --pf-c-search-input__utilities--MarginLeft: var(--pf-global--spacer--xs);\n --pf-c-search-input__utilities--child--MarginLeft: var(--pf-global--spacer--xs);\n --pf-c-search-input__utilities--c-button--PaddingRight: var(--pf-global--spacer--xs);\n --pf-c-search-input__utilities--c-button--PaddingLeft: var(--pf-global--spacer--xs);\n position: relative;\n display: flex;\n padding: var(--pf-c-search-input--PaddingTop) var(--pf-c-search-input--PaddingRight) var(--pf-c-search-input--PaddingBottom) var(--pf-c-search-input--PaddingLeft); }\n .pf-c-search-input:hover {\n --pf-c-search-input__text--after--BorderBottomColor: var(--pf-c-search-input--hover__text--after--BorderBottomColor); }\n\n.pf-c-search-input__text {\n flex: 1; }\n .pf-c-search-input__text::before, .pf-c-search-input__text::after {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n pointer-events: none;\n content: \"\"; }\n .pf-c-search-input__text::before {\n border: var(--pf-c-search-input__text--before--BorderWidth) solid var(--pf-c-search-input__text--before--BorderColor); }\n .pf-c-search-input__text::after {\n border-bottom: var(--pf-c-search-input__text--after--BorderBottomWidth) solid var(--pf-c-search-input__text--after--BorderBottomColor); }\n .pf-c-search-input__text:hover, .pf-c-search-input__text:focus-within {\n --pf-c-search-input__icon--Color: var(--pf-c-search-input__text--hover__icon--Color); }\n .pf-c-search-input__text:focus-within {\n --pf-c-search-input__text--after--BorderBottomWidth: var(--pf-c-search-input__text--focus-within--after--BorderBottomWidth);\n --pf-c-search-input__text--after--BorderBottomColor: var(--pf-c-search-input__text--focus-within--after--BorderBottomColor); }\n\n.pf-c-search-input__icon {\n position: absolute;\n top: 50%;\n left: var(--pf-c-search-input__icon--Left);\n color: var(--pf-c-search-input__icon--Color);\n transform: translateY(var(--pf-c-search-input__icon--TranslateY)); }\n\n.pf-c-search-input__text-input {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n position: relative;\n width: 100%;\n min-width: var(--pf-c-search-input__text-input--MinWidth);\n padding: var(--pf-c-search-input__text-input--PaddingTop) var(--pf-c-search-input__text-input--PaddingRight) var(--pf-c-search-input__text-input--PaddingBottom) var(--pf-c-search-input__text-input--PaddingLeft);\n border: 0; }\n\n.pf-c-search-input__utilities {\n display: flex;\n margin-right: var(--pf-c-search-input__utilities--MarginRight);\n margin-left: var(--pf-c-search-input__utilities--MarginLeft); }\n .pf-c-search-input__utilities > * + * {\n margin-left: var(--pf-c-search-input__utilities--child--MarginLeft); }\n .pf-c-search-input__utilities .pf-c-button {\n --pf-c-button--PaddingRight: var(--pf-c-search-input__utilities--c-button--PaddingRight);\n --pf-c-button--PaddingLeft: var(--pf-c-search-input__utilities--c-button--PaddingLeft); }\n\n.pf-c-search-input__nav {\n display: flex; }\n\n.pf-c-search-input__count {\n display: flex;\n align-items: center; }\n\n.pf-c-select {\n color: var(--pf-global--Color--100);\n --pf-c-select__toggle--PaddingTop: var(--pf-global--spacer--form-element);\n --pf-c-select__toggle--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-select__toggle--PaddingBottom: var(--pf-global--spacer--form-element);\n --pf-c-select__toggle--PaddingLeft: var(--pf-global--spacer--sm);\n --pf-c-select__toggle--MinWidth: var(--pf-global--target-size--MinWidth);\n --pf-c-select__toggle--FontSize: var(--pf-global--FontSize--md);\n --pf-c-select__toggle--FontWeight: var(--pf-global--FontWeight--normal);\n --pf-c-select__toggle--LineHeight: var(--pf-global--LineHeight--md);\n --pf-c-select__toggle--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-select__toggle--before--BorderWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-select__toggle--before--BorderTopColor: var(--pf-global--BorderColor--300);\n --pf-c-select__toggle--before--BorderRightColor: var(--pf-global--BorderColor--300);\n --pf-c-select__toggle--before--BorderBottomColor: var(--pf-global--BorderColor--200);\n --pf-c-select__toggle--before--BorderLeftColor: var(--pf-global--BorderColor--300);\n --pf-c-select__toggle--Color: var(--pf-global--Color--100);\n --pf-c-select__toggle--hover--before--BorderBottomColor: var(--pf-global--active-color--100);\n --pf-c-select__toggle--focus--before--BorderBottomColor: var(--pf-global--active-color--100);\n --pf-c-select__toggle--active--before--BorderBottomColor: var(--pf-global--active-color--100);\n --pf-c-select__toggle--m-expanded--before--BorderBottomColor: var(--pf-global--active-color--100);\n --pf-c-select__toggle--focus--before--BorderBottomWidth: var(--pf-global--BorderWidth--md);\n --pf-c-select__toggle--active--before--BorderBottomWidth: var(--pf-global--BorderWidth--md);\n --pf-c-select__toggle--m-expanded--before--BorderBottomWidth: var(--pf-global--BorderWidth--md);\n --pf-c-select__toggle--disabled--BackgroundColor: var(--pf-global--disabled-color--300);\n --pf-c-select__toggle--m-plain--before--BorderColor: transparent;\n --pf-c-select__toggle-wrapper--not-last-child--MarginRight: var(--pf-global--spacer--xs);\n --pf-c-select__toggle-wrapper--MaxWidth: calc(100% - var(--pf-global--spacer--lg));\n --pf-c-select__toggle-wrapper--c-chip-group--MarginTop: 0.3125rem;\n --pf-c-select__toggle-wrapper--c-chip-group--MarginBottom: 0.3125rem;\n --pf-c-select__toggle-typeahead--FlexBasis: 10em;\n --pf-c-select__toggle-typeahead--BackgroundColor: transparent;\n --pf-c-select__toggle-typeahead--BorderTop: none;\n --pf-c-select__toggle-typeahead--BorderRight: none;\n --pf-c-select__toggle-typeahead--BorderLeft: none;\n --pf-c-select__toggle-typeahead--MinWidth: 7.5rem;\n --pf-c-select__toggle-typeahead--focus--PaddingBottom: calc(var(--pf-global--spacer--form-element) - var(--pf-global--BorderWidth--sm));\n --pf-c-select__toggle-icon--toggle-text--MarginLeft: var(--pf-global--spacer--xs);\n --pf-c-select__toggle-badge--PaddingLeft: var(--pf-global--spacer--sm);\n --pf-c-select__toggle-arrow--MarginLeft: var(--pf-global--spacer--md);\n --pf-c-select__toggle-arrow--MarginRight: var(--pf-global--spacer--sm);\n --pf-c-select__toggle-arrow--with-clear--MarginLeft: var(--pf-global--spacer--sm);\n --pf-c-select__toggle-arrow--m-top--m-expanded__toggle-arrow--Rotate: 180deg;\n --pf-c-select__toggle-clear--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-select__toggle-clear--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-select__toggle-clear--toggle-button--PaddingLeft: var(--pf-global--spacer--sm);\n --pf-c-select__toggle-button--Color: var(--pf-global--Color--100);\n --pf-c-select__menu--BackgroundColor: var(--pf-global--BackgroundColor--light-100);\n --pf-c-select__menu--BoxShadow: var(--pf-global--BoxShadow--md);\n --pf-c-select__menu--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-select__menu--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-select__menu--Top: calc(100% + var(--pf-global--spacer--xs));\n --pf-c-select__menu--ZIndex: var(--pf-global--ZIndex--sm);\n --pf-c-select__menu--m-top--TranslateY: calc(-100% - var(--pf-global--spacer--xs));\n --pf-c-select__menu-item--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-select__menu-item--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-select__menu-item--m-selected--PaddingRight: var(--pf-global--spacer--2xl);\n --pf-c-select__menu-item--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-select__menu-item--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-select__menu-item--FontSize: var(--pf-global--FontSize--md);\n --pf-c-select__menu-item--FontWeight: var(--pf-global--FontWeight--normal);\n --pf-c-select__menu-item--LineHeight: var(--pf-global--LineHeight--md);\n --pf-c-select__menu-item--Color: var(--pf-global--Color--dark-100);\n --pf-c-select__menu-item--Width: 100%;\n --pf-c-select__menu-item--disabled--Color: var(--pf-global--Color--dark-200);\n --pf-c-select__menu-item--hover--BackgroundColor: var(--pf-global--BackgroundColor--light-300);\n --pf-c-select__menu-item--focus--BackgroundColor: var(--pf-global--BackgroundColor--light-300);\n --pf-c-select__menu-item--disabled--BackgroundColor: transparent;\n --pf-c-select__menu-item--m-link--Width: auto;\n --pf-c-select__menu-item--m-link--hover--BackgroundColor: transparent;\n --pf-c-select__menu-item--m-link--focus--BackgroundColor: transparent;\n --pf-c-select__menu-item--m-action--Color: var(--pf-global--disabled-color--200);\n --pf-c-select__menu-item--m-action--Width: auto;\n --pf-c-select__menu-item--m-action--FontSize: var(--pf-global--icon--FontSize--sm);\n --pf-c-select__menu-item--m-action--hover--BackgroundColor: transparent;\n --pf-c-select__menu-item--m-action--focus--BackgroundColor: transparent;\n --pf-c-select__menu-item--hover__menu-item--m-action--Color: var(--pf-global--Color--200);\n --pf-c-select__menu-item--m-action--hover--Color: var(--pf-global--Color--100);\n --pf-c-select__menu-item--m-action--focus--Color: var(--pf-global--Color--100);\n --pf-c-select__menu-wrapper--m-favorite__menu-item--m-favorite-action--Color: var(--pf-global--palette--gold-400);\n --pf-c-select__menu-item-icon--Color: var(--pf-global--active-color--100);\n --pf-c-select__menu-item-icon--FontSize: var(--pf-global--icon--FontSize--sm);\n --pf-c-select__menu-item-icon--Right: var(--pf-global--spacer--md);\n --pf-c-select__menu-item-icon--Top: 50%;\n --pf-c-select__menu-item-icon--TranslateY: -50%;\n --pf-c-select__menu-item-action-icon--MinHeight: calc(var(--pf-c-select__menu-item--FontSize) * var(--pf-c-select__menu-item--LineHeight));\n --pf-c-select__menu-item--match--FontWeight: var(--pf-global--FontWeight--bold);\n --pf-c-select__menu-search--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-select__menu-search--PaddingRight: var(--pf-c-select__menu-item--PaddingRight);\n --pf-c-select__menu-search--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-select__menu-search--PaddingLeft: var(--pf-c-select__menu-item--PaddingLeft);\n --pf-c-select__menu-group--menu-group--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-select__menu-group-title--PaddingTop: var(--pf-c-select__menu-item--PaddingTop);\n --pf-c-select__menu-group-title--PaddingRight: var(--pf-c-select__menu-item--PaddingRight);\n --pf-c-select__menu-group-title--PaddingBottom: var(--pf-c-select__menu-item--PaddingBottom);\n --pf-c-select__menu-group-title--PaddingLeft: var(--pf-c-select__menu-item--PaddingLeft);\n --pf-c-select__menu-group-title--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-select__menu-group-title--FontWeight: var(--pf-global--FontWeight--semi-bold);\n --pf-c-select__menu-group-title--Color: var(--pf-global--Color--dark-200);\n --pf-c-select__menu-item-description--FontSize: var(--pf-global--FontSize--xs);\n --pf-c-select__menu-item-description--Color: var(--pf-global--Color--200);\n --pf-c-select__menu-item-description--PaddingRight: var(--pf-c-select__menu-item--PaddingRight);\n --pf-c-select__menu-item-main--PaddingRight: var(--pf-c-select__menu-item--PaddingRight);\n --pf-c-select__menu-item--m-selected__menu-item-main--PaddingRight: var(--pf-c-select__menu-item--m-selected--PaddingRight);\n --pf-c-select-menu--c-divider--MarginTop: var(--pf-global--spacer--sm);\n --pf-c-select-menu--c-divider--MarginBottom: var(--pf-global--spacer--sm);\n position: relative;\n display: inline-block;\n width: 100%; }\n .pf-c-select .pf-c-divider {\n margin-top: var(--pf-c-select-menu--c-divider--MarginTop);\n margin-bottom: var(--pf-c-select-menu--c-divider--MarginBottom); }\n .pf-c-select .pf-c-divider:last-child {\n --pf-c-select-menu--c-divider--MarginBottom: 0; }\n\n.pf-c-select__menu-search + .pf-c-divider {\n --pf-c-select-menu--c-divider--MarginTop: 0; }\n\n.pf-c-select__toggle {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n min-width: var(--pf-c-select__toggle--MinWidth);\n padding: var(--pf-c-select__toggle--PaddingTop) var(--pf-c-select__toggle--PaddingRight) var(--pf-c-select__toggle--PaddingBottom) var(--pf-c-select__toggle--PaddingLeft);\n font-size: var(--pf-c-select__toggle--FontSize);\n font-weight: var(--pf-c-select__toggle--FontWeight);\n line-height: var(--pf-c-select__toggle--LineHeight);\n color: var(--pf-c-select__toggle--Color);\n white-space: nowrap;\n cursor: pointer;\n background-color: var(--pf-c-select__toggle--BackgroundColor);\n border: none; }\n .pf-c-select__toggle.pf-m-disabled, .pf-c-select__toggle:disabled {\n --pf-c-select__toggle--BackgroundColor: var(--pf-c-select__toggle--disabled--BackgroundColor);\n pointer-events: none; }\n .pf-c-select__toggle.pf-m-disabled::before, .pf-c-select__toggle:disabled::before {\n border: 0; }\n .pf-c-select__toggle::before {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n content: \"\";\n border: var(--pf-c-select__toggle--before--BorderWidth) solid;\n border-color: var(--pf-c-select__toggle--before--BorderTopColor) var(--pf-c-select__toggle--before--BorderRightColor) var(--pf-c-select__toggle--before--BorderBottomColor) var(--pf-c-select__toggle--before--BorderLeftColor); }\n .pf-c-select__toggle:hover::before {\n --pf-c-select__toggle--before--BorderBottomColor: var(--pf-c-select__toggle--hover--before--BorderBottomColor); }\n .pf-c-select__toggle:focus::before, .pf-c-select__toggle:focus-within::before {\n --pf-c-select__toggle--before--BorderBottomColor: var(--pf-c-select__toggle--focus--before--BorderBottomColor);\n border-bottom-width: var(--pf-c-select__toggle--focus--before--BorderBottomWidth); }\n .pf-c-select__toggle:active::before, .pf-c-select__toggle.pf-m-active::before {\n --pf-c-select__toggle--before--BorderBottomColor: var(--pf-c-select__toggle--active--before--BorderBottomColor);\n border-bottom-width: var(--pf-c-select__toggle--active--before--BorderBottomWidth); }\n .pf-m-expanded > .pf-c-select__toggle::before {\n --pf-c-select__toggle--before--BorderBottomColor: var(--pf-c-select__toggle--m-expanded--before--BorderBottomColor);\n border-bottom-width: var(--pf-c-select__toggle--m-expanded--before--BorderBottomWidth); }\n .pf-c-select__toggle.pf-m-plain::before {\n border-color: var(--pf-c-select__toggle--m-plain--before--BorderColor); }\n .pf-c-select__toggle.pf-m-typeahead {\n --pf-c-select__toggle--PaddingTop: 0;\n --pf-c-select__toggle--PaddingRight: 0;\n --pf-c-select__toggle--PaddingBottom: 0; }\n .pf-c-select__toggle.pf-m-typeahead .pf-c-form-control {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n position: relative;\n height: auto; }\n .pf-c-select__toggle .pf-c-select__toggle-clear {\n padding-right: var(--pf-c-select__toggle-clear--PaddingRight);\n padding-left: var(--pf-c-select__toggle-clear--PaddingLeft);\n margin-left: auto; }\n .pf-c-select__toggle .pf-c-select__toggle-button {\n color: var(--pf-c-select__toggle-button--Color); }\n .pf-c-select__toggle .pf-c-select__toggle-clear + .pf-c-select__toggle-button {\n padding-left: var(--pf-c-select__toggle-clear--toggle-button--PaddingLeft); }\n\n* + .pf-c-select__toggle-arrow {\n margin-right: var(--pf-c-select__toggle-arrow--MarginRight);\n margin-left: var(--pf-c-select__toggle-arrow--MarginLeft); }\n\n.pf-c-select.pf-m-top.pf-m-expanded .pf-c-select__toggle-arrow {\n transform: rotate(var(--pf-c-select__toggle-arrow--m-top--m-expanded__toggle-arrow--Rotate)); }\n\n.pf-c-select__toggle-text {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap; }\n\n.pf-c-select__toggle-wrapper {\n display: flex;\n flex: 1;\n flex-wrap: wrap;\n align-items: center;\n justify-content: flex-start;\n min-width: 0;\n max-width: var(--pf-c-select__toggle-wrapper--MaxWidth);\n white-space: normal; }\n .pf-c-select__toggle-wrapper > :not(:last-child) {\n margin-right: var(--pf-c-select__toggle-wrapper--not-last-child--MarginRight); }\n .pf-c-select__toggle-wrapper > .pf-c-form-control {\n margin-top: calc(-1 * var(--pf-c-select__toggle-wrapper--m-typeahead--PaddingTop)); }\n .pf-c-select__toggle-wrapper .pf-c-chip-group {\n margin-top: var(--pf-c-select__toggle-wrapper--c-chip-group--MarginTop);\n margin-bottom: var(--pf-c-select__toggle-wrapper--c-chip-group--MarginBottom); }\n .pf-c-select__toggle-wrapper > .pf-c-select__toggle-typeahead:first-child {\n margin-left: calc(-1 * var(--pf-c-select__toggle--PaddingLeft)); }\n\n.pf-c-select__toggle-icon + .pf-c-select__toggle-text {\n margin-left: var(--pf-c-select__toggle-icon--toggle-text--MarginLeft); }\n\n.pf-c-select__toggle-badge {\n display: flex;\n padding-left: var(--pf-c-select__toggle-badge--PaddingLeft); }\n\n.pf-c-select__toggle-typeahead {\n flex-basis: var(--pf-c-select__toggle-typeahead--FlexBasis);\n flex-grow: 1;\n min-width: var(--pf-c-select__toggle-typeahead--MinWidth);\n background-color: var(--pf-c-select__toggle-typeahead--BackgroundColor);\n border-top: var(--pf-c-select__toggle-typeahead--BorderTop);\n border-right: var(--pf-c-select__toggle-typeahead--BorderRight);\n border-bottom-color: inherit;\n border-bottom-style: inherit;\n border-bottom-width: inherit;\n border-left: var(--pf-c-select__toggle-typeahead--BorderLeft);\n flex-shrink: 0; }\n .pf-c-select__toggle-typeahead:focus {\n padding-bottom: var(--pf-c-select__toggle-typeahead--focus--PaddingBottom); }\n\n.pf-c-select__menu {\n position: absolute;\n top: var(--pf-c-select__menu--Top);\n z-index: var(--pf-c-select__menu--ZIndex);\n min-width: 100%;\n padding-top: var(--pf-c-select__menu--PaddingTop);\n padding-bottom: var(--pf-c-select__menu--PaddingBottom);\n background-color: var(--pf-c-select__menu--BackgroundColor);\n background-clip: padding-box;\n box-shadow: var(--pf-c-select__menu--BoxShadow); }\n .pf-c-select__menu.pf-m-align-right {\n right: 0; }\n .pf-c-select.pf-m-top .pf-c-select__menu {\n top: 0;\n transform: translateY(var(--pf-c-select__menu--m-top--TranslateY)); }\n\n.pf-c-select__menu-fieldset {\n border: 0; }\n\n.pf-c-select__menu-wrapper {\n display: flex; }\n .pf-c-select__menu-wrapper.pf-m-favorite .pf-c-select__menu-item.pf-m-favorite-action {\n --pf-c-select__menu-item--Color: var(--pf-c-select__menu-wrapper--m-favorite__menu-item--m-favorite-action--Color); }\n\n.pf-c-select__menu-item {\n position: relative;\n width: var(--pf-c-select__menu-item--Width);\n padding: var(--pf-c-select__menu-item--PaddingTop) var(--pf-c-select__menu-item--PaddingRight) var(--pf-c-select__menu-item--PaddingBottom) var(--pf-c-select__menu-item--PaddingLeft);\n font-size: var(--pf-c-select__menu-item--FontSize);\n font-weight: var(--pf-c-select__menu-item--FontWeight);\n line-height: var(--pf-c-select__menu-item--LineHeight);\n color: var(--pf-c-select__menu-item--Color);\n text-align: left;\n white-space: nowrap;\n background-color: transparent;\n border: none; }\n .pf-c-select__menu-item:hover, .pf-c-select__menu-item:focus, .pf-c-select__menu-item.pf-m-focus {\n --pf-c-select__menu-item--m-action--Color: var(--pf-c-select__menu-item--hover__menu-item--m-action--Color);\n text-decoration: none; }\n .pf-c-select__menu-wrapper:hover, .pf-c-select__menu-item:hover {\n background-color: var(--pf-c-select__menu-item--hover--BackgroundColor); }\n .pf-c-select__menu-wrapper:focus-within,\n .pf-c-select__menu-wrapper.pf-m-focus, .pf-c-select__menu-item:focus, .pf-c-select__menu-item.pf-m-focus {\n position: relative;\n background-color: var(--pf-c-select__menu-item--focus--BackgroundColor); }\n .pf-c-select__menu-item.pf-m-link {\n --pf-c-select__menu-item--PaddingRight: 0;\n --pf-c-select__menu-item-main--PaddingRight: 0;\n --pf-c-select__menu-item-description--PaddingRight: 0;\n --pf-c-select__menu-item--Width: var(--pf-c-select__menu-item--m-link--Width);\n --pf-c-select__menu-item--hover--BackgroundColor: var(--pf-c-select__menu-item--m-link--hover--BackgroundColor);\n --pf-c-select__menu-item--focus--BackgroundColor: var(--pf-c-select__menu-item--m-link--focus--BackgroundColor);\n flex-grow: 1; }\n .pf-c-select__menu-item.pf-m-action {\n --pf-c-select__menu-item--Color: var(--pf-c-select__menu-item--m-action--Color);\n --pf-c-select__menu-item--Width: var(--pf-c-select__menu-item--m-action--Width);\n --pf-c-select__menu-item--hover--BackgroundColor: var(--pf-c-select__menu-item--m-action--hover--BackgroundColor);\n --pf-c-select__menu-item--focus--BackgroundColor: var(--pf-c-select__menu-item--m-action--focus--BackgroundColor);\n display: flex;\n align-items: flex-start;\n font-size: var(--pf-c-select__menu-item--m-action--FontSize); }\n .pf-c-select__menu-item.pf-m-action:hover {\n --pf-c-select__menu-item--m-action--Color: var(--pf-c-select__menu-item--m-action--hover--Color); }\n .pf-c-select__menu-item.pf-m-action:focus {\n --pf-c-select__menu-item--m-action--Color: var(--pf-c-select__menu-item--m-action--focus--Color); }\n .pf-c-select__menu-item.pf-m-selected {\n --pf-c-select__menu-item--PaddingRight: var(--pf-c-select__menu-item--m-selected--PaddingRight);\n --pf-c-select__menu-item-main--PaddingRight: var(--pf-c-select__menu-item--m-selected__menu-item-main--PaddingRight); }\n .pf-c-select__menu-item.pf-m-description {\n white-space: normal; }\n .pf-c-select__menu-item.pf-m-description:not(.pf-c-check) {\n --pf-c-select__menu-item--PaddingRight: 0; }\n .pf-c-select__menu-item.pf-m-description .pf-c-check__label {\n white-space: nowrap; }\n .pf-c-select__menu-wrapper.pf-m-disabled, .pf-c-select__menu-item:disabled, .pf-c-select__menu-item.pf-m-disabled {\n color: var(--pf-c-select__menu-item--disabled--Color);\n pointer-events: none;\n background-color: var(--pf-c-select__menu-item--disabled--BackgroundColor); }\n\n.pf-c-select__menu-item-main {\n position: relative;\n display: block;\n padding-right: var(--pf-c-select__menu-item-main--PaddingRight);\n white-space: nowrap; }\n\n.pf-c-select__menu-item-description {\n display: block;\n padding-right: var(--pf-c-select__menu-item-description--PaddingRight);\n font-size: var(--pf-c-select__menu-item-description--FontSize);\n color: var(--pf-c-select__menu-item-description--Color); }\n\n.pf-c-select__menu-item-icon {\n position: absolute;\n top: var(--pf-c-select__menu-item-icon--Top);\n right: var(--pf-c-select__menu-item-icon--Right);\n font-size: var(--pf-c-select__menu-item-icon--FontSize);\n color: var(--pf-c-select__menu-item-icon--Color);\n transform: translateY(var(--pf-c-select__menu-item-icon--TranslateY)); }\n\n.pf-c-select__menu-item-action-icon {\n display: flex;\n align-items: center;\n min-height: var(--pf-c-select__menu-item-action-icon--MinHeight); }\n\n.pf-c-select__menu-item--match {\n font-weight: var(--pf-c-select__menu-item--match--FontWeight);\n background-color: inherit; }\n\n.pf-c-select__menu-group + .pf-c-select__menu-group {\n padding-top: var(--pf-c-select__menu-group--menu-group--PaddingTop); }\n\n.pf-c-select__menu-search {\n padding: var(--pf-c-select__menu-search--PaddingTop) var(--pf-c-select__menu-search--PaddingRight) var(--pf-c-select__menu-search--PaddingBottom) var(--pf-c-select__menu-search--PaddingLeft); }\n\n.pf-c-select__menu-group-title {\n padding-top: var(--pf-c-select__menu-group-title--PaddingTop);\n padding-right: var(--pf-c-select__menu-group-title--PaddingRight);\n padding-bottom: var(--pf-c-select__menu-group-title--PaddingBottom);\n padding-left: var(--pf-c-select__menu-group-title--PaddingLeft);\n font-size: var(--pf-c-select__menu-group-title--FontSize);\n font-weight: var(--pf-c-select__menu-group-title--FontWeight);\n color: var(--pf-c-select__menu-group-title--Color); }\n\n.pf-c-simple-list {\n --pf-c-simple-list__item-link--PaddingTop: var(--pf-global--spacer--xs);\n --pf-c-simple-list__item-link--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-simple-list__item-link--PaddingBottom: var(--pf-global--spacer--xs);\n --pf-c-simple-list__item-link--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-simple-list__item-link--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-simple-list__item-link--Color: var(--pf-global--Color--100);\n --pf-c-simple-list__item-link--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-simple-list__item-link--FontWeight: var(--pf-global--FontWeight--normal);\n --pf-c-simple-list__item-link--m-current--Color: var(--pf-global--link--Color);\n --pf-c-simple-list__item-link--m-current--BackgroundColor: var(--pf-global--BackgroundColor--200);\n --pf-c-simple-list__item-link--m-current--FontWeight: var(--pf-global--FontWeight--semi-bold);\n --pf-c-simple-list__item-link--hover--Color: var(--pf-global--link--Color);\n --pf-c-simple-list__item-link--hover--BackgroundColor: var(--pf-global--BackgroundColor--200);\n --pf-c-simple-list__item-link--focus--Color: var(--pf-global--link--Color);\n --pf-c-simple-list__item-link--focus--BackgroundColor: var(--pf-global--BackgroundColor--200);\n --pf-c-simple-list__item-link--focus--FontWeight: var(--pf-global--FontWeight--semi-bold);\n --pf-c-simple-list__item-link--active--Color: var(--pf-global--link--Color);\n --pf-c-simple-list__item-link--active--BackgroundColor: var(--pf-global--BackgroundColor--200);\n --pf-c-simple-list__item-link--active--FontWeight: var(--pf-global--FontWeight--semi-bold);\n --pf-c-simple-list__title--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-simple-list__title--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-simple-list__title--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-simple-list__title--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-simple-list__title--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-simple-list__title--Color: var(--pf-global--Color--dark-200);\n --pf-c-simple-list__title--FontWeight: var(--pf-global--FontWeight--semi-bold);\n --pf-c-simple-list__section--section--MarginTop: var(--pf-global--spacer--sm); }\n\n.pf-c-simple-list__item-link {\n display: block;\n width: 100%;\n padding: var(--pf-c-simple-list__item-link--PaddingTop) var(--pf-c-simple-list__item-link--PaddingRight) var(--pf-c-simple-list__item-link--PaddingBottom) var(--pf-c-simple-list__item-link--PaddingLeft);\n font-size: var(--pf-c-simple-list__item-link--FontSize);\n font-weight: var(--pf-c-simple-list__item-link--FontWeight);\n color: var(--pf-c-simple-list__item-link--Color);\n text-align: left;\n background-color: var(--pf-c-simple-list__item-link--BackgroundColor);\n border: none; }\n .pf-c-simple-list__item-link.pf-m-current {\n --pf-c-simple-list__item-link--FontWeight: var(--pf-c-simple-list__item-link--m-current--FontWeight);\n --pf-c-simple-list__item-link--BackgroundColor: var(--pf-c-simple-list__item-link--m-current--BackgroundColor);\n --pf-c-simple-list__item-link--Color: var(--pf-c-simple-list__item-link--m-current--Color); }\n .pf-c-simple-list__item-link:hover {\n text-decoration: none;\n --pf-c-simple-list__item-link--BackgroundColor: var(--pf-c-simple-list__item-link--hover--BackgroundColor);\n --pf-c-simple-list__item-link--Color: var(--pf-c-simple-list__item-link--hover--Color); }\n .pf-c-simple-list__item-link:focus {\n --pf-c-simple-list__item-link--FontWeight: var(--pf-c-simple-list__item-link--focus--FontWeight);\n --pf-c-simple-list__item-link--BackgroundColor: var(--pf-c-simple-list__item-link--focus--BackgroundColor);\n --pf-c-simple-list__item-link--Color: var(--pf-c-simple-list__item-link--focus--Color); }\n .pf-c-simple-list__item-link:active {\n --pf-c-simple-list__item-link--FontWeight: var(--pf-c-simple-list__item-link--active--FontWeight);\n --pf-c-simple-list__item-link--BackgroundColor: var(--pf-c-simple-list__item-link--active--BackgroundColor);\n --pf-c-simple-list__item-link--Color: var(--pf-c-simple-list__item-link--active--Color); }\n\n.pf-c-simple-list__title {\n padding: var(--pf-c-simple-list__title--PaddingTop) var(--pf-c-simple-list__title--PaddingRight) var(--pf-c-simple-list__title--PaddingBottom) var(--pf-c-simple-list__title--PaddingLeft);\n font-size: var(--pf-c-simple-list__title--FontSize);\n font-weight: var(--pf-c-simple-list__title--FontWeight);\n color: var(--pf-c-simple-list__title--Color); }\n\n.pf-c-simple-list__section + .pf-c-simple-list__section {\n margin-top: var(--pf-c-simple-list__section--section--MarginTop); }\n\n.pf-c-skeleton {\n --pf-c-skeleton--BackgroundColor: var(--pf-global--palette--black-150);\n --pf-c-skeleton--Width: auto;\n --pf-c-skeleton--Height: auto;\n --pf-c-skeleton--BorderRadius: var(--pf-global--BorderRadius--sm);\n --pf-c-skeleton--before--PaddingBottom: 0;\n --pf-c-skeleton--before--Height: auto;\n --pf-c-skeleton--before--Content: \"\\00a0\";\n --pf-c-skeleton--after--LinearGradientAngle: 90deg;\n --pf-c-skeleton--after--LinearGradientColorStop1: rgba(237, 237, 237, 0);\n --pf-c-skeleton--after--LinearGradientColorStop2: #ededed;\n --pf-c-skeleton--after--LinearGradientColorStop3: rgba(237, 237, 237, 0);\n --pf-c-skeleton--after--TranslateX: -100%;\n --pf-c-skeleton--after--AnimationName: pf-c-skeleton-loading;\n --pf-c-skeleton--after--AnimationDuration: 2s;\n --pf-c-skeleton--after--AnimationIterationCount: infinite;\n --pf-c-skeleton--after--AnimationTimingFunction: linear;\n --pf-c-skeleton--after--AnimationDelay: .5s;\n --pf-c-skeleton--m-circle--BorderRadius: var(--pf-global--BorderRadius--lg);\n --pf-c-skeleton--m-circle--before--PaddingBottom: 100%;\n --pf-c-skeleton--m-text-4xl--Height: calc(var(--pf-global--FontSize--4xl) * var(--pf-global--LineHeight--sm));\n --pf-c-skeleton--m-text-3xl--Height: calc(var(--pf-global--FontSize--3xl) * var(--pf-global--LineHeight--sm));\n --pf-c-skeleton--m-text-2xl--Height: calc(var(--pf-global--FontSize--2xl) * var(--pf-global--LineHeight--sm));\n --pf-c-skeleton--m-text-xl--Height: calc(var(--pf-global--FontSize--xl) * var(--pf-global--LineHeight--sm));\n --pf-c-skeleton--m-text-lg--Height: calc(var(--pf-global--FontSize--lg) * var(--pf-global--LineHeight--md));\n --pf-c-skeleton--m-text-md--Height: calc(var(--pf-global--FontSize--md) * var(--pf-global--LineHeight--md));\n --pf-c-skeleton--m-text-sm--Height: calc(var(--pf-global--FontSize--sm) * var(--pf-global--LineHeight--md));\n --pf-c-skeleton--m-width-sm--Width: 6.25rem;\n --pf-c-skeleton--m-width-md--Width: 12.5rem;\n --pf-c-skeleton--m-width-lg--Width: 18.75rem;\n --pf-c-skeleton--m-width-25--Width: 25%;\n --pf-c-skeleton--m-width-33--Width: calc(100% / 3);\n --pf-c-skeleton--m-width-50--Width: 50%;\n --pf-c-skeleton--m-width-66--Width: calc(100% / 3 * 2);\n --pf-c-skeleton--m-width-75--Width: 75%;\n --pf-c-skeleton--m-height-sm--Height: 6.25rem;\n --pf-c-skeleton--m-height-md--Height: 12.5rem;\n --pf-c-skeleton--m-height-lg--Height: 18.75rem;\n --pf-c-skeleton--m-height-25--Height: 25%;\n --pf-c-skeleton--m-height-33--Height: calc(100% / 3);\n --pf-c-skeleton--m-height-50--Height: 50%;\n --pf-c-skeleton--m-height-66--Height: calc(100% / 3 * 2);\n --pf-c-skeleton--m-height-75--Height: 75%;\n --pf-c-skeleton--m-height-100--Height: 100%;\n position: relative;\n width: var(--pf-c-skeleton--Width);\n height: var(--pf-c-skeleton--Height);\n overflow: hidden;\n background-color: var(--pf-c-skeleton--BackgroundColor);\n border-radius: var(--pf-c-skeleton--BorderRadius);\n transform: translate(0); }\n .pf-c-skeleton::before {\n display: block;\n height: var(--pf-c-skeleton--before--Height);\n padding-bottom: var(--pf-c-skeleton--before--PaddingBottom);\n content: var(--pf-c-skeleton--before--Content); }\n .pf-c-skeleton::after {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n display: block;\n content: \"\";\n background: linear-gradient(var(--pf-c-skeleton--after--LinearGradientAngle), var(--pf-c-skeleton--after--LinearGradientColorStop1), var(--pf-c-skeleton--after--LinearGradientColorStop2), var(--pf-c-skeleton--after--LinearGradientColorStop3));\n transform: translateX(var(--pf-c-skeleton--after--TranslateX));\n animation: var(--pf-c-skeleton--after--AnimationName) var(--pf-c-skeleton--after--AnimationDuration) var(--pf-c-skeleton--after--AnimationTimingFunction) var(--pf-c-skeleton--after--AnimationDelay) var(--pf-c-skeleton--after--AnimationIterationCount); }\n .pf-c-skeleton.pf-m-circle {\n --pf-c-skeleton--BorderRadius: var(--pf-c-skeleton--m-circle--BorderRadius); }\n .pf-c-skeleton.pf-m-square, .pf-c-skeleton.pf-m-circle {\n --pf-c-skeleton--before--Height: 0;\n --pf-c-skeleton--before--PaddingBottom: var(--pf-c-skeleton--m-circle--before--PaddingBottom); }\n .pf-c-skeleton.pf-m-width-sm {\n --pf-c-skeleton--Width: var(--pf-c-skeleton--m-width-sm--Width); }\n .pf-c-skeleton.pf-m-width-md {\n --pf-c-skeleton--Width: var(--pf-c-skeleton--m-width-md--Width); }\n .pf-c-skeleton.pf-m-width-lg {\n --pf-c-skeleton--Width: var(--pf-c-skeleton--m-width-lg--Width); }\n .pf-c-skeleton.pf-m-width-25 {\n --pf-c-skeleton--Width: var(--pf-c-skeleton--m-width-25--Width); }\n .pf-c-skeleton.pf-m-width-33 {\n --pf-c-skeleton--Width: var(--pf-c-skeleton--m-width-33--Width); }\n .pf-c-skeleton.pf-m-width-50 {\n --pf-c-skeleton--Width: var(--pf-c-skeleton--m-width-50--Width); }\n .pf-c-skeleton.pf-m-width-66 {\n --pf-c-skeleton--Width: var(--pf-c-skeleton--m-width-66--Width); }\n .pf-c-skeleton.pf-m-width-75 {\n --pf-c-skeleton--Width: var(--pf-c-skeleton--m-width-75--Width); }\n .pf-c-skeleton.pf-m-height-sm {\n --pf-c-skeleton--Height: var(--pf-c-skeleton--m-height-sm--Height); }\n .pf-c-skeleton.pf-m-height-md {\n --pf-c-skeleton--Height: var(--pf-c-skeleton--m-height-md--Height); }\n .pf-c-skeleton.pf-m-height-lg {\n --pf-c-skeleton--Height: var(--pf-c-skeleton--m-height-lg--Height); }\n .pf-c-skeleton.pf-m-height-25 {\n --pf-c-skeleton--Height: var(--pf-c-skeleton--m-height-25--Height); }\n .pf-c-skeleton.pf-m-height-33 {\n --pf-c-skeleton--Height: var(--pf-c-skeleton--m-height-33--Height); }\n .pf-c-skeleton.pf-m-height-50 {\n --pf-c-skeleton--Height: var(--pf-c-skeleton--m-height-50--Height); }\n .pf-c-skeleton.pf-m-height-66 {\n --pf-c-skeleton--Height: var(--pf-c-skeleton--m-height-66--Height); }\n .pf-c-skeleton.pf-m-height-75 {\n --pf-c-skeleton--Height: var(--pf-c-skeleton--m-height-75--Height); }\n .pf-c-skeleton.pf-m-height-100 {\n --pf-c-skeleton--Height: var(--pf-c-skeleton--m-height-100--Height); }\n .pf-c-skeleton.pf-m-text-4xl {\n --pf-c-skeleton--Height: var(--pf-c-skeleton--m-text-4xl--Height); }\n .pf-c-skeleton.pf-m-text-3xl {\n --pf-c-skeleton--Height: var(--pf-c-skeleton--m-text-3xl--Height); }\n .pf-c-skeleton.pf-m-text-2xl {\n --pf-c-skeleton--Height: var(--pf-c-skeleton--m-text-2xl--Height); }\n .pf-c-skeleton.pf-m-text-xl {\n --pf-c-skeleton--Height: var(--pf-c-skeleton--m-text-xl--Height); }\n .pf-c-skeleton.pf-m-text-lg {\n --pf-c-skeleton--Height: var(--pf-c-skeleton--m-text-lg--Height); }\n .pf-c-skeleton.pf-m-text-md {\n --pf-c-skeleton--Height: var(--pf-c-skeleton--m-text-md--Height); }\n .pf-c-skeleton.pf-m-text-sm {\n --pf-c-skeleton--Height: var(--pf-c-skeleton--m-text-sm--Height); }\n\n@keyframes pf-c-skeleton-loading {\n 0% {\n transform: translateX(-100%); }\n 60% {\n transform: translateX(100%); }\n 100% {\n transform: translateX(100%); } }\n\n.pf-c-skip-to-content {\n --pf-c-skip-to-content--Top: var(--pf-global--spacer--md);\n --pf-c-skip-to-content--ZIndex: var(--pf-global--ZIndex--2xl);\n --pf-c-skip-to-content--focus--Left: var(--pf-global--spacer--md);\n position: absolute;\n top: var(--pf-c-skip-to-content--Top);\n left: -300%;\n z-index: var(--pf-c-skip-to-content--ZIndex); }\n .pf-c-skip-to-content:focus {\n left: var(--pf-c-skip-to-content--focus--Left); }\n\n.pf-c-slider {\n --pf-c-slider__rail--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-slider__rail--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-slider__rail-track--Height: 0.25rem;\n --pf-c-slider__rail-track--before--base--BackgroundColor: var(--pf-global--BorderColor--100);\n --pf-c-slider__rail-track--before--fill--BackgroundColor: var(--pf-global--active-color--300);\n --pf-c-slider__rail-track--before--BorderRadius: var(--pf-global--BorderRadius--lg);\n --pf-c-slider__rail-track--before--fill--BackgroundColor--gradient-stop: var(--pf-c-slider--value);\n --pf-c-slider__steps--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-slider__steps--Height: var(--pf-c-slider__steps--FontSize);\n --pf-c-slider__step-tick--Top: var(--pf-global--spacer--md);\n --pf-c-slider__step-tick--Width: 0.25rem;\n --pf-c-slider__step-tick--Height: 0.25rem;\n --pf-c-slider__step-tick--BackgroundColor: var(--pf-global--BorderColor--200);\n --pf-c-slider__step-tick--TranslateX: -50%;\n --pf-c-slider__step-tick--BorderRadius: var(--pf-global--BorderRadius--lg);\n --pf-c-slider__step--m-active__slider-tick--BackgroundColor: var(--pf-global--primary-color--100);\n --pf-c-slider__step--first-child__step-tick--TranslateX: 0;\n --pf-c-slider__step--last-child__step-tick--TranslateX: -100%;\n --pf-c-slider__step-label--TranslateX: -50%;\n --pf-c-slider__step-label--Top: calc(var(--pf-global--spacer--xl) + var(--pf-c-slider__rail-track--Height));\n --pf-c-slider__step--first-child__step-label--TranslateX: 0;\n --pf-c-slider__step--last-child__step-label--TranslateX: -100%;\n --pf-c-slider__thumb--Top: calc(var(--pf-c-slider__rail-track--Height) / 2 + var(--pf-global--spacer--md));\n --pf-c-slider__thumb--Width: 1rem;\n --pf-c-slider__thumb--Height: 1rem;\n --pf-c-slider__thumb--Left: var(--pf-c-slider--value);\n --pf-c-slider__thumb--BackgroundColor: var(--pf-global--primary-color--100);\n --pf-c-slider__thumb--TranslateX: -50%;\n --pf-c-slider__thumb--TranslateY: -50%;\n --pf-c-slider__thumb--BorderRadius: var(--pf-global--BorderRadius--lg);\n --pf-c-slider__thumb--BoxShadow--base:\n 0 0 0 2px var(--pf-global--BackgroundColor--100),\n 0 0 0 3px var(--pf-global--primary-color--100);\n --pf-c-slider__thumb--hover--BoxShadow: var(--pf-c-slider__thumb--BoxShadow--base);\n --pf-c-slider__thumb--focus--BoxShadow: var(--pf-c-slider__thumb--BoxShadow--base);\n --pf-c-slider__thumb--active--BoxShadow:\n var(--pf-c-slider__thumb--BoxShadow--base),\n 0 0 2px 5px var(--pf-global--active-color--200);\n --pf-c-slider__value--MarginLeft: var(--pf-global--spacer--md);\n --pf-c-slider__value--c-form-control--width-base: 3.5ch;\n --pf-c-slider__value--c-form-control--width-chars: 3;\n --pf-c-slider__value--c-form-control--Width: calc(var(--pf-c-slider__value--c-form-control--width-base) + (var(--pf-c-slider__value--c-form-control--width-chars) * 1ch));\n --pf-c-slider__value--m-floating--TranslateX: -50%;\n --pf-c-slider__value--m-floating--TranslateY: -100%;\n --pf-c-slider__value--m-floating--Left: var(--pf-c-slider--value);\n --pf-c-slider__value--m-floating--ZIndex: var(--pf-global--ZIndex--sm);\n --pf-c-slider__actions--MarginRight: var(--pf-global--spacer--sm);\n --pf-c-slider__main--actions--MarginLeft: var(--pf-global--spacer--sm);\n display: flex; }\n\n.pf-c-slider__main {\n position: relative;\n flex-grow: 1; }\n\n.pf-c-slider__rail {\n padding-top: var(--pf-c-slider__rail--PaddingTop);\n padding-bottom: var(--pf-c-slider__rail--PaddingBottom); }\n\n.pf-c-slider__rail-track {\n position: relative;\n height: var(--pf-c-slider__rail-track--Height); }\n .pf-c-slider__rail-track::before {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n content: \"\";\n background: linear-gradient(to right, var(--pf-c-slider__rail-track--before--fill--BackgroundColor), var(--pf-c-slider__rail-track--before--fill--BackgroundColor) var(--pf-c-slider__rail-track--before--fill--BackgroundColor--gradient-stop), var(--pf-c-slider__rail-track--before--base--BackgroundColor) var(--pf-c-slider__rail-track--before--fill--BackgroundColor--gradient-stop));\n border-radius: var(--pf-c-slider__rail-track--before--BorderRadius); }\n\n.pf-c-slider__steps {\n height: var(--pf-c-slider__steps--Height);\n font-size: var(--pf-c-slider__steps--FontSize);\n line-height: 1; }\n\n.pf-c-slider__step {\n position: absolute;\n top: 0;\n left: var(--pf-c-slider__step--Left);\n content: \"\"; }\n .pf-c-slider__step.pf-m-active {\n --pf-c-slider__step-tick--BackgroundColor: var(--pf-c-slider__step--m-active__slider-tick--BackgroundColor); }\n .pf-c-slider__step:first-child {\n --pf-c-slider__step-tick--TranslateX: var(--pf-c-slider__step--first-child__step-tick--TranslateX);\n --pf-c-slider__step-label--TranslateX: var(--pf-c-slider__step--first-child__step-label--TranslateX); }\n .pf-c-slider__step:last-child {\n --pf-c-slider__step-tick--TranslateX: var(--pf-c-slider__step--last-child__step-tick--TranslateX);\n --pf-c-slider__step-label--TranslateX: var(--pf-c-slider__step--last-child__step-label--TranslateX); }\n\n.pf-c-slider__step-tick {\n position: absolute;\n top: var(--pf-c-slider__step-tick--Top);\n left: 0;\n width: var(--pf-c-slider__step-tick--Width);\n height: var(--pf-c-slider__step-tick--Height);\n background-color: var(--pf-c-slider__step-tick--BackgroundColor);\n border-radius: var(--pf-c-slider__step-tick--BorderRadius);\n transform: translateX(var(--pf-c-slider__step-tick--TranslateX)); }\n\n.pf-c-slider__step-label {\n position: absolute;\n top: var(--pf-c-slider__step-label--Top);\n transform: translateX(var(--pf-c-slider__step-label--TranslateX)); }\n\n.pf-c-slider__thumb {\n position: absolute;\n top: var(--pf-c-slider__thumb--Top);\n left: var(--pf-c-slider__thumb--Left);\n width: var(--pf-c-slider__thumb--Width);\n height: var(--pf-c-slider__thumb--Height);\n cursor: pointer;\n background-color: var(--pf-c-slider__thumb--BackgroundColor);\n border-radius: var(--pf-c-slider__thumb--BorderRadius);\n box-shadow: var(--pf-c-slider__thumb--BoxShadow);\n transform: translate(var(--pf-c-slider__thumb--TranslateX), var(--pf-c-slider__thumb--TranslateY)); }\n .pf-c-slider__thumb:hover {\n --pf-c-slider__thumb--BoxShadow: var(--pf-c-slider__thumb--hover--BoxShadow); }\n .pf-c-slider__thumb:focus {\n --pf-c-slider__thumb--BoxShadow: var(--pf-c-slider__thumb--focus--BoxShadow);\n outline: 0; }\n .pf-c-slider__thumb:active {\n --pf-c-slider__thumb--BoxShadow: var(--pf-c-slider__thumb--active--BoxShadow); }\n\n.pf-c-slider__value {\n margin-left: var(--pf-c-slider__value--MarginLeft); }\n .pf-c-slider__value.pf-m-floating {\n --pf-c-slider__value--MarginLeft: 0;\n position: absolute;\n top: 0;\n left: var(--pf-c-slider__value--m-floating--Left);\n z-index: var(--pf-c-slider__value--m-floating--ZIndex);\n transform: translate(var(--pf-c-slider__value--m-floating--TranslateX), var(--pf-c-slider__value--m-floating--TranslateY)); }\n .pf-c-slider__value.pf-m-floating .pf-c-input-group {\n align-items: center; }\n .pf-c-slider__value.pf-m-floating .pf-c-input-group__text {\n position: absolute;\n left: 100%; }\n .pf-c-slider__value .pf-c-form-control {\n width: var(--pf-c-slider__value--c-form-control--Width); }\n\n.pf-c-slider__actions {\n display: flex;\n margin-right: var(--pf-c-slider__actions--MarginRight); }\n .pf-c-slider__main ~ .pf-c-slider__actions {\n --pf-c-slider__actions--MarginRight: 0;\n margin-left: var(--pf-c-slider__main--actions--MarginLeft); }\n\n.pf-c-spinner {\n --pf-c-spinner--AnimationDuration: 1.5s;\n --pf-c-spinner--AnimationTimingFunction: cubic-bezier(.77, .005, .315, 1);\n --pf-c-spinner--diameter: var(--pf-global--icon--FontSize--xl);\n --pf-c-spinner--stroke-width-multiplier: .1;\n --pf-c-spinner--stroke-width: calc(var(--pf-c-spinner--diameter) * var(--pf-c-spinner--stroke-width-multiplier));\n --pf-c-spinner--Width: var(--pf-c-spinner--diameter);\n --pf-c-spinner--Height: var(--pf-c-spinner--diameter);\n --pf-c-spinner--Color: var(--pf-global--primary-color--100);\n --pf-c-spinner--m-sm--diameter: var(--pf-global--icon--FontSize--sm);\n --pf-c-spinner--m-md--diameter: var(--pf-global--icon--FontSize--md);\n --pf-c-spinner--m-lg--diameter: var(--pf-global--icon--FontSize--lg);\n --pf-c-spinner--m-xl--diameter: var(--pf-global--icon--FontSize--xl);\n --pf-c-spinner__clipper--Width: var(--pf-c-spinner--diameter);\n --pf-c-spinner__clipper--Height: var(--pf-c-spinner--diameter);\n --pf-c-spinner__clipper--after--BoxShadowColor: var(--pf-c-spinner--Color);\n --pf-c-spinner__clipper--after--Width: var(--pf-c-spinner--diameter);\n --pf-c-spinner__clipper--after--Height: var(--pf-c-spinner--diameter);\n --pf-c-spinner__clipper--after--BoxShadowSpreadRadius: var(--pf-c-spinner--stroke-width);\n --pf-c-spinner__lead-ball--after--BackgroundColor: var(--pf-c-spinner--Color);\n --pf-c-spinner__ball--after--Width: var(--pf-c-spinner--stroke-width);\n --pf-c-spinner__ball--after--Height: var(--pf-c-spinner--stroke-width);\n --pf-c-spinner__tail-ball--after--BackgroundColor: var(--pf-c-spinner--Color);\n position: relative;\n display: inline-block;\n width: var(--pf-c-spinner--Width);\n height: var(--pf-c-spinner--Height);\n text-align: left;\n animation: pf-animation-spinner-parent calc(var(--pf-c-spinner--AnimationDuration) * 2) var(--pf-c-spinner--AnimationTimingFunction) infinite; }\n .pf-c-spinner.pf-m-sm {\n --pf-c-spinner--diameter: var(--pf-c-spinner--m-sm--diameter); }\n .pf-c-spinner.pf-m-md {\n --pf-c-spinner--diameter: var(--pf-c-spinner--m-md--diameter); }\n .pf-c-spinner.pf-m-lg {\n --pf-c-spinner--diameter: var(--pf-c-spinner--m-lg--diameter); }\n .pf-c-spinner.pf-m-xl {\n --pf-c-spinner--diameter: var(--pf-c-spinner--m-xl--diameter); }\n\n@keyframes pf-animation-spinner-parent {\n 0% {\n transform: rotate(0deg); }\n 50% {\n transform: rotate(-540deg); }\n 100% {\n transform: rotate(-1080deg); } }\n\n.pf-c-spinner__clipper {\n position: absolute;\n width: var(--pf-c-spinner__clipper--Width);\n height: var(--pf-c-spinner__clipper--Height);\n clip-path: inset(0 0 50% 50%);\n animation: pf-animation-spinner__clipper var(--pf-c-spinner--AnimationDuration) linear infinite; }\n\n@keyframes pf-animation-spinner__clipper {\n 0% {\n transform: rotate(0deg); }\n 100% {\n transform: rotate(-270deg); } }\n\n.pf-c-spinner__clipper::after {\n position: absolute;\n width: var(--pf-c-spinner__clipper--after--Width);\n height: var(--pf-c-spinner__clipper--after--Height);\n clip-path: inset(0 0 0 50%);\n content: \"\";\n border-radius: 50%;\n box-shadow: inset 0 0 0 var(--pf-c-spinner__clipper--after--BoxShadowSpreadRadius) var(--pf-c-spinner__clipper--after--BoxShadowColor);\n animation: pf-animation-spinner__clipper-after var(--pf-c-spinner--AnimationDuration) linear infinite; }\n\n@keyframes pf-animation-spinner__clipper-after {\n 0% {\n transform: rotate(90deg); }\n 100% {\n transform: rotate(-180deg); } }\n\n.pf-c-spinner__lead-ball {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n animation: pf-animation-spinner__lead-ball var(--pf-c-spinner--AnimationDuration) linear infinite; }\n .pf-c-spinner__lead-ball::after {\n position: absolute;\n top: calc(50% - (var(--pf-c-spinner__ball--after--Height) / 2));\n right: 0;\n width: var(--pf-c-spinner__ball--after--Width);\n height: var(--pf-c-spinner__ball--after--Height);\n content: \"\";\n background-color: var(--pf-c-spinner__lead-ball--after--BackgroundColor);\n border-radius: 50%;\n transform-origin: top right; }\n\n@keyframes pf-animation-spinner__lead-ball {\n 0% {\n transform: rotate(0deg); }\n 34% {\n transform: rotate(-180deg); }\n 100% {\n transform: rotate(-360deg); } }\n\n.pf-c-spinner__tail-ball {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n animation: pf-animation-spinner__tail-ball var(--pf-c-spinner--AnimationDuration) linear infinite; }\n .pf-c-spinner__tail-ball::after {\n position: absolute;\n top: calc(50% - (var(--pf-c-spinner__ball--after--Height) / 2));\n right: 0;\n width: var(--pf-c-spinner__ball--after--Width);\n height: var(--pf-c-spinner__ball--after--Height);\n content: \"\";\n background-color: var(--pf-c-spinner__tail-ball--after--BackgroundColor);\n border-radius: 50%;\n transform-origin: top right; }\n\n@keyframes pf-animation-spinner__tail-ball {\n 0% {\n transform: rotate(0deg); }\n 67.5% {\n transform: rotate(-180deg); }\n 100% {\n transform: rotate(-360deg); } }\n\n.pf-c-switch {\n --pf-c-switch--FontSize: var(--pf-global--FontSize--md);\n --pf-c-switch__toggle-icon--FontSize: calc(var(--pf-c-switch--FontSize) * .625);\n --pf-c-switch__toggle-icon--Color: var(--pf-global--Color--light-100);\n --pf-c-switch__toggle-icon--Left: calc(var(--pf-c-switch--FontSize) * .4);\n --pf-c-switch__toggle-icon--Offset: 0.125rem;\n --pf-c-switch--LineHeight: var(--pf-global--LineHeight--md);\n --pf-c-switch--Height: calc(var(--pf-c-switch--FontSize) * var(--pf-c-switch--LineHeight));\n --pf-c-switch__input--checked__toggle--BackgroundColor: var(--pf-global--primary-color--100);\n --pf-c-switch__input--checked__toggle--before--TranslateX: calc(100% + var(--pf-c-switch__toggle-icon--Offset));\n --pf-c-switch__input--checked__label--Color: var(--pf-global--Color--dark-100);\n --pf-c-switch__input--not-checked__label--Color: var(--pf-global--disabled-color--100);\n --pf-c-switch__input--disabled__label--Color: var(--pf-global--disabled-color--100);\n --pf-c-switch__input--disabled__toggle--BackgroundColor: var(--pf-global--Color--dark-200);\n --pf-c-switch__input--disabled__toggle--before--BackgroundColor: var(--pf-global--disabled-color--200);\n --pf-c-switch__input--focus__toggle--OutlineWidth: var(--pf-global--BorderWidth--md);\n --pf-c-switch__input--focus__toggle--OutlineOffset: var(--pf-global--spacer--sm);\n --pf-c-switch__input--focus__toggle--OutlineColor: var(--pf-global--primary-color--100);\n --pf-c-switch__toggle--Height: calc(var(--pf-c-switch--FontSize) * var(--pf-c-switch--LineHeight));\n --pf-c-switch__toggle--BackgroundColor: var(--pf-global--disabled-color--200);\n --pf-c-switch__toggle--BorderRadius: var(--pf-c-switch--Height);\n --pf-c-switch__toggle--before--Width: calc(var(--pf-c-switch--FontSize) - var(--pf-c-switch__toggle-icon--Offset));\n --pf-c-switch__toggle--before--Height: var(--pf-c-switch__toggle--before--Width);\n --pf-c-switch__toggle--before--Top: calc((var(--pf-c-switch--Height) - var(--pf-c-switch__toggle--before--Height)) / 2);\n --pf-c-switch__toggle--before--Left: var(--pf-c-switch__toggle--before--Top);\n --pf-c-switch__toggle--before--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-switch__toggle--before--BorderRadius: var(--pf-global--BorderRadius--lg);\n --pf-c-switch__toggle--before--BoxShadow: var(--pf-global--BoxShadow--md);\n --pf-c-switch__toggle--before--Transition: transform .25s ease 0s;\n --pf-c-switch__toggle--Width: calc(var(--pf-c-switch--Height) + var(--pf-c-switch__toggle-icon--Offset) + var(--pf-c-switch__toggle--before--Width));\n --pf-c-switch__label--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-switch__label--Color: var(--pf-global--Color--dark-100);\n position: relative;\n display: inline-block;\n height: var(--pf-c-switch--Height);\n font-size: var(--pf-c-switch--FontSize);\n line-height: var(--pf-c-switch--LineHeight);\n vertical-align: middle;\n cursor: pointer; }\n\n.pf-c-switch__input {\n position: absolute;\n cursor: pointer;\n opacity: 0; }\n .pf-c-switch__input:focus ~ .pf-c-switch__toggle {\n outline: var(--pf-c-switch__input--focus__toggle--OutlineWidth) solid var(--pf-c-switch__input--focus__toggle--OutlineColor);\n outline-offset: var(--pf-c-switch__input--focus__toggle--OutlineOffset); }\n .pf-c-switch__input:checked ~ .pf-c-switch__label {\n color: var(--pf-c-switch__input--checked__label--Color); }\n .pf-c-switch__input:checked ~ .pf-c-switch__toggle {\n background-color: var(--pf-c-switch__input--checked__toggle--BackgroundColor); }\n .pf-c-switch__input:checked ~ .pf-c-switch__toggle::before {\n transform: translateX(var(--pf-c-switch__input--checked__toggle--before--TranslateX)); }\n .pf-c-switch__input:checked ~ .pf-m-off {\n display: none; }\n .pf-c-switch__input:not(:checked) ~ .pf-c-switch__label {\n color: var(--pf-c-switch__input--not-checked__label--Color); }\n .pf-c-switch__input:not(:checked) ~ .pf-c-switch__toggle .pf-c-switch__toggle-icon {\n display: none;\n visibility: hidden; }\n .pf-c-switch__input:not(:checked) ~ .pf-m-on {\n display: none; }\n .pf-c-switch__input:disabled {\n cursor: not-allowed; }\n .pf-c-switch__input:disabled ~ .pf-c-switch__label {\n color: var(--pf-c-switch__input--disabled__label--Color);\n cursor: not-allowed; }\n .pf-c-switch__input:disabled ~ .pf-c-switch__toggle {\n cursor: not-allowed;\n background-color: var(--pf-c-switch__input--disabled__toggle--BackgroundColor); }\n .pf-c-switch__input:disabled ~ .pf-c-switch__toggle::before {\n background-color: var(--pf-c-switch__input--disabled__toggle--before--BackgroundColor); }\n\n.pf-c-switch__toggle {\n position: relative;\n display: inline-block;\n width: var(--pf-c-switch__toggle--Width);\n height: var(--pf-c-switch__toggle--Height);\n background-color: var(--pf-c-switch__toggle--BackgroundColor);\n border-radius: var(--pf-c-switch__toggle--BorderRadius); }\n .pf-c-switch__toggle::before {\n position: absolute;\n top: var(--pf-c-switch__toggle--before--Top);\n left: var(--pf-c-switch__toggle--before--Left);\n display: block;\n width: var(--pf-c-switch__toggle--before--Width);\n height: var(--pf-c-switch__toggle--before--Height);\n content: \"\";\n background-color: var(--pf-c-switch__toggle--before--BackgroundColor);\n border-radius: var(--pf-c-switch__toggle--before--BorderRadius);\n box-shadow: var(--pf-c-switch__toggle--before--BoxShadow);\n transition: var(--pf-c-switch__toggle--before--Transition); }\n\n.pf-c-switch__toggle-icon {\n position: absolute;\n top: 0;\n bottom: 0;\n left: var(--pf-c-switch__toggle-icon--Left);\n display: flex;\n align-items: center;\n font-size: var(--pf-c-switch__toggle-icon--FontSize);\n color: var(--pf-c-switch__toggle-icon--Color); }\n\n.pf-c-switch__label {\n display: inline-block;\n padding-left: var(--pf-c-switch__label--PaddingLeft);\n color: var(--pf-c-switch__label--Color);\n vertical-align: top; }\n\n.pf-c-tab-content {\n --pf-c-tab-content--m-light-300: var(--pf-global--BackgroundColor--light-300); }\n .pf-c-tab-content.pf-m-light-300 {\n background-color: var(--pf-c-tab-content--m-light-300); }\n\n.pf-c-table[class*=\"pf-m-grid\"] {\n --pf-c-table--responsive--BorderColor: var(--pf-global--BorderColor--300);\n --pf-c-table--tbody--responsive--border-width--base: var(--pf-global--spacer--sm);\n --pf-c-table--tbody--after--border-width--base: var(--pf-global--BorderWidth--lg);\n --pf-c-table--tbody--after--BorderLeftWidth: 0;\n --pf-c-table--tbody--after--BorderColor: var(--pf-global--active-color--100);\n --pf-c-table-tr--responsive--border-width--base: var(--pf-global--spacer--sm);\n --pf-c-table-tr--responsive--last-child--BorderBottomWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-table-tr--responsive--GridColumnGap: var(--pf-global--spacer--md);\n --pf-c-table-tr--responsive--MarginTop: var(--pf-global--spacer--sm);\n --pf-c-table-tr--responsive--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-table-tr--responsive--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-table-tr--responsive--xl--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-table-tr--responsive--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-table-tr--responsive--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-table-tr--responsive--xl--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-table-tr--responsive--nested-table--PaddingTop: var(--pf-global--spacer--xl);\n --pf-c-table-tr--responsive--nested-table--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-table-tr--responsive--nested-table--PaddingBottom: var(--pf-global--spacer--xl);\n --pf-c-table-tr--responsive--nested-table--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-table--m-grid--cell--hidden-visible--Display: grid;\n --pf-c-table--m-grid--cell--PaddingTop: 0;\n --pf-c-table--m-grid--cell--PaddingRight: 0;\n --pf-c-table--m-grid--cell--PaddingBottom: 0;\n --pf-c-table--m-grid--cell--PaddingLeft: 0;\n --pf-c-table-td--responsive--GridColumnGap: var(--pf-global--spacer--md);\n --pf-c-table--cell--responsive--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-table--cell--responsive--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-table--cell--first-child--responsive--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-table--cell--responsive--PaddingRight: 0;\n --pf-c-table--cell--responsive--PaddingLeft: 0;\n --pf-c-table--m-compact-tr--responsive--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-table--m-compact-tr--responsive--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-table--m-compact-tr-td--responsive--PaddingTop: var(--pf-global--spacer--xs);\n --pf-c-table--m-compact-tr-td--responsive--PaddingBottom: var(--pf-global--spacer--xs);\n --pf-c-table--m-compact__action--responsive--MarginTop: calc(var(--pf-global--spacer--xs) * -1);\n --pf-c-table--m-compact__action--responsive--MarginBottom: calc(var(--pf-global--spacer--xs) * -1);\n --pf-c-table--m-compact__toggle--c-button--responsive--MarginBottom: calc(0.375rem * -1);\n --pf-c-table__expandable-row-content--responsive--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-table__expandable-row-content--responsive--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-table__expandable-row-content--responsive--xl--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-table__expandable-row-content--responsive--xl--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-table__expandable-row-content--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-table__check--responsive--MarginLeft: var(--pf-global--spacer--sm);\n --pf-c-table__check--responsive--MarginTop: 0.875rem;\n --pf-c-table--m-grid__favorite--MarginTop: 0.5rem;\n --pf-c-table--m-grid__check--favorite--MarginLeft: var(--pf-global--spacer--xl);\n --pf-c-table--m-grid__action--MarginTop: 0.375rem;\n --pf-c-table__action--responsive--MarginLeft: var(--pf-global--spacer--xl);\n --pf-c-table--m-grid__favorite--action--MarginLeft: var(--pf-global--spacer--2xl);\n --pf-c-table--m-grid__check--favorite--action--MarginLeft: calc(var(--pf-c-table--m-grid__check--favorite--MarginLeft) + var(--pf-c-table--m-grid__favorite--action--MarginLeft));\n --pf-c-table__toggle__icon--Transition: .2s ease-in 0s;\n --pf-c-table__toggle--m-expanded__icon--Rotate: 180deg; }\n @media screen and (max-width: 1200px) {\n .pf-c-table[class*=\"pf-m-grid\"] {\n --pf-c-table-tr--responsive--PaddingRight: var(--pf-c-table-tr--responsive--xl--PaddingRight);\n --pf-c-table-tr--responsive--PaddingLeft: var(--pf-c-table-tr--responsive--xl--PaddingLeft); } }\n @media screen and (max-width: 1200px) {\n .pf-c-table[class*=\"pf-m-grid\"] {\n --pf-c-table__expandable-row-content--responsive--PaddingRight: var(--pf-c-table__expandable-row-content--responsive--xl--PaddingRight);\n --pf-c-table__expandable-row-content--responsive--PaddingLeft: var(--pf-c-table__expandable-row-content--responsive--xl--PaddingLeft); } }\n\n.pf-m-grid.pf-c-table {\n --pf-c-table--cell--PaddingTop: var(--pf-c-table--m-grid--cell--PaddingTop);\n --pf-c-table--cell--PaddingRight: var(--pf-c-table--m-grid--cell--PaddingRight);\n --pf-c-table--cell--PaddingBottom: var(--pf-c-table--m-grid--cell--PaddingBottom);\n --pf-c-table--cell--PaddingLeft: var(--pf-c-table--m-grid--cell--PaddingLeft);\n --pf-c-table__favorite--c-button--MarginTop: auto;\n --pf-c-table__favorite--c-button--MarginRight: auto;\n --pf-c-table__favorite--c-button--MarginBottom: auto;\n --pf-c-table__favorite--c-button--MarginLeft: auto;\n display: grid;\n border: none; }\n .pf-m-grid.pf-c-table tr > * {\n width: auto;\n min-width: 0;\n max-width: none;\n overflow: visible;\n text-overflow: clip;\n white-space: normal; }\n .pf-m-grid.pf-c-table .pf-c-table__text {\n position: relative;\n width: auto;\n min-width: 0;\n max-width: none;\n overflow: var(--pf-c-table--cell--Overflow);\n text-overflow: var(--pf-c-table--cell--TextOverflow);\n white-space: var(--pf-c-table--cell--WhiteSpace); }\n .pf-m-grid.pf-c-table thead {\n display: none;\n visibility: hidden; }\n .pf-m-grid.pf-c-table tbody {\n display: block; }\n .pf-m-grid.pf-c-table tbody:first-of-type {\n border-top: var(--pf-c-table--tbody--responsive--border-width--base) solid var(--pf-c-table--responsive--BorderColor); }\n .pf-m-grid.pf-c-table table.pf-m-compact > tbody {\n border-top: 0; }\n .pf-m-grid.pf-c-table tr:not(.pf-c-table__expandable-row) {\n border-bottom: var(--pf-c-table-tr--responsive--border-width--base) solid var(--pf-c-table--responsive--BorderColor); }\n .pf-m-grid.pf-c-table tr:last-child,\n .pf-m-grid.pf-c-table tbody:last-of-type:not(:only-of-type) > tr {\n border-bottom-width: var(--pf-c-table-tr--responsive--last-child--BorderBottomWidth); }\n .pf-m-grid.pf-c-table tbody.pf-m-expanded {\n border-bottom: var(--pf-c-table--border-width--base) solid var(--pf-c-table--BorderColor); }\n .pf-m-grid.pf-c-table tbody.pf-m-expanded tr:not(.pf-c-table__expandable-row) {\n border-bottom: 0; }\n .pf-m-grid.pf-c-table tbody.pf-m-expanded:not(:last-of-type) {\n border-bottom: var(--pf-c-table--tbody--responsive--border-width--base) solid var(--pf-c-table--responsive--BorderColor); }\n .pf-m-grid.pf-c-table tr:not(.pf-c-table__expandable-row) {\n display: grid;\n grid-template-columns: 1fr;\n height: auto;\n grid-auto-columns: max-content;\n grid-column-gap: var(--pf-c-table-tr--responsive--GridColumnGap);\n padding: var(--pf-c-table-tr--responsive--PaddingTop) var(--pf-c-table-tr--responsive--PaddingRight) var(--pf-c-table-tr--responsive--PaddingBottom) var(--pf-c-table-tr--responsive--PaddingLeft); }\n .pf-m-grid.pf-c-table tr:not(.pf-c-table__expandable-row) > * {\n padding: var(--pf-c-table--cell--responsive--PaddingTop) var(--pf-c-table--cell--responsive--PaddingRight) var(--pf-c-table--cell--responsive--PaddingBottom) var(--pf-c-table--cell--responsive--PaddingLeft); }\n .pf-m-grid.pf-c-table tr:not(.pf-c-table__expandable-row) > *:first-child {\n --pf-c-table--cell--responsive--PaddingTop: var(--pf-c-table--cell--first-child--responsive--PaddingTop); }\n .pf-m-grid.pf-c-table.pf-m-compact {\n --pf-c-table-tr--responsive--PaddingTop: var(--pf-c-table--m-compact-tr--responsive--PaddingTop);\n --pf-c-table-tr--responsive--PaddingBottom: var(--pf-c-table--m-compact-tr--responsive--PaddingBottom);\n --pf-c-table--cell--responsive--PaddingTop: var(--pf-c-table--m-compact-tr-td--responsive--PaddingTop);\n --pf-c-table--cell--responsive--PaddingBottom: var(--pf-c-table--m-compact-tr-td--responsive--PaddingBottom);\n --pf-c-table__check--input--MarginTop: 0; }\n .pf-m-grid.pf-c-table.pf-m-compact .pf-c-table__action {\n margin-top: var(--pf-c-table--m-compact__action--responsive--MarginTop);\n margin-bottom: var(--pf-c-table--m-compact__action--responsive--MarginTop); }\n .pf-m-grid.pf-c-table.pf-m-compact .pf-c-table__toggle .pf-c-button {\n margin-bottom: var(--pf-c-table--m-compact__toggle--c-button--responsive--MarginBottom); }\n .pf-m-grid.pf-c-table .pf-c-table__icon > * {\n text-align: left; }\n .pf-m-grid.pf-c-table [data-label] {\n --pf-c-table--cell--hidden-visible--Display: var(--pf-c-table--m-grid--cell--hidden-visible--Display);\n grid-column: 1;\n grid-column-gap: var(--pf-c-table-td--responsive--GridColumnGap);\n grid-template-columns: 1fr minmax(0, 1.5fr);\n align-items: start; }\n .pf-m-grid.pf-c-table [data-label] > * {\n grid-column: 2; }\n .pf-m-grid.pf-c-table [data-label]::before {\n font-weight: bold;\n text-align: left;\n content: attr(data-label); }\n .pf-m-grid.pf-c-table tr > *:first-child {\n --pf-c-table--cell--PaddingLeft: 0; }\n .pf-m-grid.pf-c-table tr > *:last-child {\n --pf-c-table--cell--PaddingRight: 0; }\n .pf-m-grid.pf-c-table .pf-c-table {\n --pf-c-table-tr--responsive--PaddingTop: var(--pf-c-table-tr--responsive--nested-table--PaddingTop);\n --pf-c-table-tr--responsive--PaddingRight: var(--pf-c-table-tr--responsive--nested-table--PaddingRight);\n --pf-c-table-tr--responsive--PaddingBottom: var(--pf-c-table-tr--responsive--nested-table--PaddingBottom);\n --pf-c-table-tr--responsive--PaddingLeft: var(--pf-c-table-tr--responsive--nested-table--PaddingLeft);\n border: 0; }\n .pf-m-grid.pf-c-table .pf-c-table tr:not(.pf-c-table__expandable-row) + tr:not(.pf-c-table__expandable-row) {\n --pf-c-table-tr--responsive--PaddingTop: 0; }\n .pf-m-grid.pf-c-table .pf-c-table__compound-expansion-toggle {\n --pf-c-table__compound-expansion-toggle__button--before--BorderRightWidth: 0;\n --pf-c-table__compound-expansion-toggle__button--before--BorderLeftWidth: 0;\n --pf-c-table__compound-expansion-toggle__button--after--Top: 100%; }\n .pf-m-grid.pf-c-table tbody {\n position: relative; }\n .pf-m-grid.pf-c-table tbody::after {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n content: \"\";\n border: 0;\n border-left: var(--pf-c-table--tbody--after--BorderLeftWidth) solid var(--pf-c-table--tbody--after--BorderColor); }\n .pf-m-grid.pf-c-table tbody.pf-m-expanded {\n --pf-c-table--tbody--after--BorderLeftWidth: var(--pf-c-table--tbody--after--border-width--base); }\n .pf-m-grid.pf-c-table tbody.pf-m-expanded tbody {\n --pf-c-table--tbody--after--BorderLeftWidth: 0; }\n .pf-m-grid.pf-c-table tbody > tr > :first-child:not(.pf-c-table__check)::after {\n --pf-c-table__expandable-row--after--BorderLeftWidth: 0;\n position: static;\n width: auto;\n background-color: transparent; }\n .pf-m-grid.pf-c-table .pf-c-table__expandable-row {\n --pf-c-table--cell--responsive--PaddingTop: 0;\n --pf-c-table--cell--responsive--PaddingRight: 0;\n --pf-c-table--cell--responsive--PaddingBottom: 0;\n --pf-c-table--cell--responsive--PaddingLeft: 0;\n --pf-c-table--cell--PaddingRight: 0;\n --pf-c-table--cell--PaddingLeft: 0;\n display: block;\n max-height: var(--pf-c-table__expandable-row--MaxHeight);\n overflow-y: auto;\n border-bottom: none;\n box-shadow: none; }\n .pf-m-grid.pf-c-table .pf-c-table__expandable-row > * {\n position: static;\n display: block; }\n .pf-m-grid.pf-c-table .pf-c-table__expandable-row.pf-m-expanded {\n border-top-color: var(--pf-c-table--BorderColor); }\n .pf-m-grid.pf-c-table .pf-c-table__expandable-row > :first-child:not(.pf-c-table__check)::after {\n content: none; }\n .pf-m-grid.pf-c-table .pf-c-table__expandable-row td.pf-m-no-padding .pf-c-table__expandable-row-content, .pf-m-grid.pf-c-table .pf-c-table__expandable-row th.pf-m-no-padding .pf-c-table__expandable-row-content {\n padding: 0; }\n .pf-m-grid.pf-c-table .pf-c-table__expandable-row:not(.pf-m-expanded) {\n display: none;\n visibility: hidden; }\n .pf-m-grid.pf-c-table .pf-c-table__expandable-row .pf-c-table__expandable-row-content {\n padding-right: var(--pf-c-table__expandable-row-content--responsive--PaddingRight);\n padding-left: var(--pf-c-table__expandable-row-content--responsive--PaddingLeft); }\n .pf-m-grid.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__toggle,\n .pf-m-grid.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__check,\n .pf-m-grid.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__favorite,\n .pf-m-grid.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__action {\n width: auto;\n padding: 0; }\n .pf-m-grid.pf-c-table .pf-c-table__toggle {\n grid-row-start: 20;\n grid-column: -1;\n justify-self: end;\n padding-right: 0; }\n .pf-m-grid.pf-c-table .pf-c-table__toggle::after {\n content: none; }\n .pf-m-grid.pf-c-table .pf-c-table__button {\n --pf-c-table--cell--PaddingTop: var(--pf-c-table--m-grid--cell--PaddingTop);\n --pf-c-table--cell--PaddingRight: var(--pf-c-table--m-grid--cell--PaddingRight);\n --pf-c-table--cell--PaddingBottom: var(--pf-c-table--m-grid--cell--PaddingBottom);\n --pf-c-table--cell--PaddingLeft: var(--pf-c-table--m-grid--cell--PaddingLeft); }\n .pf-m-grid.pf-c-table .pf-c-table__check,\n .pf-m-grid.pf-c-table .pf-c-table__favorite,\n .pf-m-grid.pf-c-table .pf-c-table__action {\n grid-row-start: 1;\n grid-column-start: 2; }\n .pf-m-grid.pf-c-table .pf-c-table__check {\n margin-top: var(--pf-c-table__check--responsive--MarginTop);\n margin-left: var(--pf-c-table__check--responsive--MarginLeft); }\n .pf-m-grid.pf-c-table .pf-c-table__check ~ .pf-c-table__favorite {\n margin-left: var(--pf-c-table--m-grid__check--favorite--MarginLeft); }\n .pf-m-grid.pf-c-table .pf-c-table__check ~ .pf-c-table__favorite ~ .pf-c-table__action {\n margin-left: var(--pf-c-table--m-grid__check--favorite--action--MarginLeft); }\n .pf-m-grid.pf-c-table .pf-c-table__check ~ .pf-c-table__action {\n margin-left: var(--pf-c-table__action--responsive--MarginLeft); }\n .pf-m-grid.pf-c-table .pf-c-table__favorite {\n margin-top: var(--pf-c-table--m-grid__favorite--MarginTop); }\n .pf-m-grid.pf-c-table .pf-c-table__favorite ~ .pf-c-table__action {\n margin-left: var(--pf-c-table--m-grid__favorite--action--MarginLeft); }\n .pf-m-grid.pf-c-table .pf-c-table__action {\n margin-top: var(--pf-c-table--m-grid__action--MarginTop);\n text-align: right; }\n @media screen and (max-width: 576px) {\n .pf-m-grid.pf-c-table .pf-c-table__action {\n grid-row-start: 1;\n grid-column-start: 2;\n margin-left: 0; } }\n .pf-m-grid.pf-c-table .pf-c-table__inline-edit-action {\n grid-column: 2;\n grid-row: 2; }\n .pf-m-grid.pf-c-table .pf-c-table__toggle-icon {\n transition: var(--pf-c-table__toggle__icon--Transition); }\n .pf-c-button.pf-m-expanded > .pf-m-grid.pf-c-table .pf-c-table__toggle-icon {\n transform: rotate(var(--pf-c-table__toggle--m-expanded__icon--Rotate)); }\n .pf-m-grid.pf-c-table .pf-m-nowrap {\n --pf-c-table--cell--Overflow: auto; }\n .pf-m-grid.pf-c-table .pf-m-fit-content {\n width: auto;\n white-space: normal; }\n .pf-m-grid.pf-c-table .pf-m-truncate {\n --pf-c-table--cell--MaxWidth: 100%; }\n .pf-m-grid.pf-c-table [class*=\"pf-m-width\"] {\n --pf-c-table--cell--Width: auto; }\n\n@media screen and (max-width: 768px) {\n .pf-m-grid-md.pf-c-table {\n --pf-c-table--cell--PaddingTop: var(--pf-c-table--m-grid--cell--PaddingTop);\n --pf-c-table--cell--PaddingRight: var(--pf-c-table--m-grid--cell--PaddingRight);\n --pf-c-table--cell--PaddingBottom: var(--pf-c-table--m-grid--cell--PaddingBottom);\n --pf-c-table--cell--PaddingLeft: var(--pf-c-table--m-grid--cell--PaddingLeft);\n --pf-c-table__favorite--c-button--MarginTop: auto;\n --pf-c-table__favorite--c-button--MarginRight: auto;\n --pf-c-table__favorite--c-button--MarginBottom: auto;\n --pf-c-table__favorite--c-button--MarginLeft: auto;\n display: grid;\n border: none; }\n .pf-m-grid-md.pf-c-table tr > * {\n width: auto;\n min-width: 0;\n max-width: none;\n overflow: visible;\n text-overflow: clip;\n white-space: normal; }\n .pf-m-grid-md.pf-c-table .pf-c-table__text {\n position: relative;\n width: auto;\n min-width: 0;\n max-width: none;\n overflow: var(--pf-c-table--cell--Overflow);\n text-overflow: var(--pf-c-table--cell--TextOverflow);\n white-space: var(--pf-c-table--cell--WhiteSpace); }\n .pf-m-grid-md.pf-c-table thead {\n display: none;\n visibility: hidden; }\n .pf-m-grid-md.pf-c-table tbody {\n display: block; }\n .pf-m-grid-md.pf-c-table tbody:first-of-type {\n border-top: var(--pf-c-table--tbody--responsive--border-width--base) solid var(--pf-c-table--responsive--BorderColor); }\n .pf-m-grid-md.pf-c-table table.pf-m-compact > tbody {\n border-top: 0; }\n .pf-m-grid-md.pf-c-table tr:not(.pf-c-table__expandable-row) {\n border-bottom: var(--pf-c-table-tr--responsive--border-width--base) solid var(--pf-c-table--responsive--BorderColor); }\n .pf-m-grid-md.pf-c-table tr:last-child,\n .pf-m-grid-md.pf-c-table tbody:last-of-type:not(:only-of-type) > tr {\n border-bottom-width: var(--pf-c-table-tr--responsive--last-child--BorderBottomWidth); }\n .pf-m-grid-md.pf-c-table tbody.pf-m-expanded {\n border-bottom: var(--pf-c-table--border-width--base) solid var(--pf-c-table--BorderColor); }\n .pf-m-grid-md.pf-c-table tbody.pf-m-expanded tr:not(.pf-c-table__expandable-row) {\n border-bottom: 0; }\n .pf-m-grid-md.pf-c-table tbody.pf-m-expanded:not(:last-of-type) {\n border-bottom: var(--pf-c-table--tbody--responsive--border-width--base) solid var(--pf-c-table--responsive--BorderColor); }\n .pf-m-grid-md.pf-c-table tr:not(.pf-c-table__expandable-row) {\n display: grid;\n grid-template-columns: 1fr;\n height: auto;\n grid-auto-columns: max-content;\n grid-column-gap: var(--pf-c-table-tr--responsive--GridColumnGap);\n padding: var(--pf-c-table-tr--responsive--PaddingTop) var(--pf-c-table-tr--responsive--PaddingRight) var(--pf-c-table-tr--responsive--PaddingBottom) var(--pf-c-table-tr--responsive--PaddingLeft); }\n .pf-m-grid-md.pf-c-table tr:not(.pf-c-table__expandable-row) > * {\n padding: var(--pf-c-table--cell--responsive--PaddingTop) var(--pf-c-table--cell--responsive--PaddingRight) var(--pf-c-table--cell--responsive--PaddingBottom) var(--pf-c-table--cell--responsive--PaddingLeft); }\n .pf-m-grid-md.pf-c-table tr:not(.pf-c-table__expandable-row) > *:first-child {\n --pf-c-table--cell--responsive--PaddingTop: var(--pf-c-table--cell--first-child--responsive--PaddingTop); }\n .pf-m-grid-md.pf-c-table.pf-m-compact {\n --pf-c-table-tr--responsive--PaddingTop: var(--pf-c-table--m-compact-tr--responsive--PaddingTop);\n --pf-c-table-tr--responsive--PaddingBottom: var(--pf-c-table--m-compact-tr--responsive--PaddingBottom);\n --pf-c-table--cell--responsive--PaddingTop: var(--pf-c-table--m-compact-tr-td--responsive--PaddingTop);\n --pf-c-table--cell--responsive--PaddingBottom: var(--pf-c-table--m-compact-tr-td--responsive--PaddingBottom);\n --pf-c-table__check--input--MarginTop: 0; }\n .pf-m-grid-md.pf-c-table.pf-m-compact .pf-c-table__action {\n margin-top: var(--pf-c-table--m-compact__action--responsive--MarginTop);\n margin-bottom: var(--pf-c-table--m-compact__action--responsive--MarginTop); }\n .pf-m-grid-md.pf-c-table.pf-m-compact .pf-c-table__toggle .pf-c-button {\n margin-bottom: var(--pf-c-table--m-compact__toggle--c-button--responsive--MarginBottom); }\n .pf-m-grid-md.pf-c-table .pf-c-table__icon > * {\n text-align: left; }\n .pf-m-grid-md.pf-c-table [data-label] {\n --pf-c-table--cell--hidden-visible--Display: var(--pf-c-table--m-grid--cell--hidden-visible--Display);\n grid-column: 1;\n grid-column-gap: var(--pf-c-table-td--responsive--GridColumnGap);\n grid-template-columns: 1fr minmax(0, 1.5fr);\n align-items: start; }\n .pf-m-grid-md.pf-c-table [data-label] > * {\n grid-column: 2; }\n .pf-m-grid-md.pf-c-table [data-label]::before {\n font-weight: bold;\n text-align: left;\n content: attr(data-label); }\n .pf-m-grid-md.pf-c-table tr > *:first-child {\n --pf-c-table--cell--PaddingLeft: 0; }\n .pf-m-grid-md.pf-c-table tr > *:last-child {\n --pf-c-table--cell--PaddingRight: 0; }\n .pf-m-grid-md.pf-c-table .pf-c-table {\n --pf-c-table-tr--responsive--PaddingTop: var(--pf-c-table-tr--responsive--nested-table--PaddingTop);\n --pf-c-table-tr--responsive--PaddingRight: var(--pf-c-table-tr--responsive--nested-table--PaddingRight);\n --pf-c-table-tr--responsive--PaddingBottom: var(--pf-c-table-tr--responsive--nested-table--PaddingBottom);\n --pf-c-table-tr--responsive--PaddingLeft: var(--pf-c-table-tr--responsive--nested-table--PaddingLeft);\n border: 0; }\n .pf-m-grid-md.pf-c-table .pf-c-table tr:not(.pf-c-table__expandable-row) + tr:not(.pf-c-table__expandable-row) {\n --pf-c-table-tr--responsive--PaddingTop: 0; }\n .pf-m-grid-md.pf-c-table .pf-c-table__compound-expansion-toggle {\n --pf-c-table__compound-expansion-toggle__button--before--BorderRightWidth: 0;\n --pf-c-table__compound-expansion-toggle__button--before--BorderLeftWidth: 0;\n --pf-c-table__compound-expansion-toggle__button--after--Top: 100%; }\n .pf-m-grid-md.pf-c-table tbody {\n position: relative; }\n .pf-m-grid-md.pf-c-table tbody::after {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n content: \"\";\n border: 0;\n border-left: var(--pf-c-table--tbody--after--BorderLeftWidth) solid var(--pf-c-table--tbody--after--BorderColor); }\n .pf-m-grid-md.pf-c-table tbody.pf-m-expanded {\n --pf-c-table--tbody--after--BorderLeftWidth: var(--pf-c-table--tbody--after--border-width--base); }\n .pf-m-grid-md.pf-c-table tbody.pf-m-expanded tbody {\n --pf-c-table--tbody--after--BorderLeftWidth: 0; }\n .pf-m-grid-md.pf-c-table tbody > tr > :first-child:not(.pf-c-table__check)::after {\n --pf-c-table__expandable-row--after--BorderLeftWidth: 0;\n position: static;\n width: auto;\n background-color: transparent; }\n .pf-m-grid-md.pf-c-table .pf-c-table__expandable-row {\n --pf-c-table--cell--responsive--PaddingTop: 0;\n --pf-c-table--cell--responsive--PaddingRight: 0;\n --pf-c-table--cell--responsive--PaddingBottom: 0;\n --pf-c-table--cell--responsive--PaddingLeft: 0;\n --pf-c-table--cell--PaddingRight: 0;\n --pf-c-table--cell--PaddingLeft: 0;\n display: block;\n max-height: var(--pf-c-table__expandable-row--MaxHeight);\n overflow-y: auto;\n border-bottom: none;\n box-shadow: none; }\n .pf-m-grid-md.pf-c-table .pf-c-table__expandable-row > * {\n position: static;\n display: block; }\n .pf-m-grid-md.pf-c-table .pf-c-table__expandable-row.pf-m-expanded {\n border-top-color: var(--pf-c-table--BorderColor); }\n .pf-m-grid-md.pf-c-table .pf-c-table__expandable-row > :first-child:not(.pf-c-table__check)::after {\n content: none; }\n .pf-m-grid-md.pf-c-table .pf-c-table__expandable-row td.pf-m-no-padding .pf-c-table__expandable-row-content, .pf-m-grid-md.pf-c-table .pf-c-table__expandable-row th.pf-m-no-padding .pf-c-table__expandable-row-content {\n padding: 0; }\n .pf-m-grid-md.pf-c-table .pf-c-table__expandable-row:not(.pf-m-expanded) {\n display: none;\n visibility: hidden; }\n .pf-m-grid-md.pf-c-table .pf-c-table__expandable-row .pf-c-table__expandable-row-content {\n padding-right: var(--pf-c-table__expandable-row-content--responsive--PaddingRight);\n padding-left: var(--pf-c-table__expandable-row-content--responsive--PaddingLeft); }\n .pf-m-grid-md.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__toggle,\n .pf-m-grid-md.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__check,\n .pf-m-grid-md.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__favorite,\n .pf-m-grid-md.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__action {\n width: auto;\n padding: 0; }\n .pf-m-grid-md.pf-c-table .pf-c-table__toggle {\n grid-row-start: 20;\n grid-column: -1;\n justify-self: end;\n padding-right: 0; }\n .pf-m-grid-md.pf-c-table .pf-c-table__toggle::after {\n content: none; }\n .pf-m-grid-md.pf-c-table .pf-c-table__button {\n --pf-c-table--cell--PaddingTop: var(--pf-c-table--m-grid--cell--PaddingTop);\n --pf-c-table--cell--PaddingRight: var(--pf-c-table--m-grid--cell--PaddingRight);\n --pf-c-table--cell--PaddingBottom: var(--pf-c-table--m-grid--cell--PaddingBottom);\n --pf-c-table--cell--PaddingLeft: var(--pf-c-table--m-grid--cell--PaddingLeft); }\n .pf-m-grid-md.pf-c-table .pf-c-table__check,\n .pf-m-grid-md.pf-c-table .pf-c-table__favorite,\n .pf-m-grid-md.pf-c-table .pf-c-table__action {\n grid-row-start: 1;\n grid-column-start: 2; }\n .pf-m-grid-md.pf-c-table .pf-c-table__check {\n margin-top: var(--pf-c-table__check--responsive--MarginTop);\n margin-left: var(--pf-c-table__check--responsive--MarginLeft); }\n .pf-m-grid-md.pf-c-table .pf-c-table__check ~ .pf-c-table__favorite {\n margin-left: var(--pf-c-table--m-grid__check--favorite--MarginLeft); }\n .pf-m-grid-md.pf-c-table .pf-c-table__check ~ .pf-c-table__favorite ~ .pf-c-table__action {\n margin-left: var(--pf-c-table--m-grid__check--favorite--action--MarginLeft); }\n .pf-m-grid-md.pf-c-table .pf-c-table__check ~ .pf-c-table__action {\n margin-left: var(--pf-c-table__action--responsive--MarginLeft); }\n .pf-m-grid-md.pf-c-table .pf-c-table__favorite {\n margin-top: var(--pf-c-table--m-grid__favorite--MarginTop); }\n .pf-m-grid-md.pf-c-table .pf-c-table__favorite ~ .pf-c-table__action {\n margin-left: var(--pf-c-table--m-grid__favorite--action--MarginLeft); }\n .pf-m-grid-md.pf-c-table .pf-c-table__action {\n margin-top: var(--pf-c-table--m-grid__action--MarginTop);\n text-align: right; } }\n @media screen and (max-width: 768px) and (max-width: 576px) {\n .pf-m-grid-md.pf-c-table .pf-c-table__action {\n grid-row-start: 1;\n grid-column-start: 2;\n margin-left: 0; } }\n\n@media screen and (max-width: 768px) {\n .pf-m-grid-md.pf-c-table .pf-c-table__inline-edit-action {\n grid-column: 2;\n grid-row: 2; }\n .pf-m-grid-md.pf-c-table .pf-c-table__toggle-icon {\n transition: var(--pf-c-table__toggle__icon--Transition); }\n .pf-c-button.pf-m-expanded > .pf-m-grid-md.pf-c-table .pf-c-table__toggle-icon {\n transform: rotate(var(--pf-c-table__toggle--m-expanded__icon--Rotate)); }\n .pf-m-grid-md.pf-c-table .pf-m-nowrap {\n --pf-c-table--cell--Overflow: auto; }\n .pf-m-grid-md.pf-c-table .pf-m-fit-content {\n width: auto;\n white-space: normal; }\n .pf-m-grid-md.pf-c-table .pf-m-truncate {\n --pf-c-table--cell--MaxWidth: 100%; }\n .pf-m-grid-md.pf-c-table [class*=\"pf-m-width\"] {\n --pf-c-table--cell--Width: auto; } }\n\n@media screen and (max-width: 992px) {\n .pf-m-grid-lg.pf-c-table {\n --pf-c-table--cell--PaddingTop: var(--pf-c-table--m-grid--cell--PaddingTop);\n --pf-c-table--cell--PaddingRight: var(--pf-c-table--m-grid--cell--PaddingRight);\n --pf-c-table--cell--PaddingBottom: var(--pf-c-table--m-grid--cell--PaddingBottom);\n --pf-c-table--cell--PaddingLeft: var(--pf-c-table--m-grid--cell--PaddingLeft);\n --pf-c-table__favorite--c-button--MarginTop: auto;\n --pf-c-table__favorite--c-button--MarginRight: auto;\n --pf-c-table__favorite--c-button--MarginBottom: auto;\n --pf-c-table__favorite--c-button--MarginLeft: auto;\n display: grid;\n border: none; }\n .pf-m-grid-lg.pf-c-table tr > * {\n width: auto;\n min-width: 0;\n max-width: none;\n overflow: visible;\n text-overflow: clip;\n white-space: normal; }\n .pf-m-grid-lg.pf-c-table .pf-c-table__text {\n position: relative;\n width: auto;\n min-width: 0;\n max-width: none;\n overflow: var(--pf-c-table--cell--Overflow);\n text-overflow: var(--pf-c-table--cell--TextOverflow);\n white-space: var(--pf-c-table--cell--WhiteSpace); }\n .pf-m-grid-lg.pf-c-table thead {\n display: none;\n visibility: hidden; }\n .pf-m-grid-lg.pf-c-table tbody {\n display: block; }\n .pf-m-grid-lg.pf-c-table tbody:first-of-type {\n border-top: var(--pf-c-table--tbody--responsive--border-width--base) solid var(--pf-c-table--responsive--BorderColor); }\n .pf-m-grid-lg.pf-c-table table.pf-m-compact > tbody {\n border-top: 0; }\n .pf-m-grid-lg.pf-c-table tr:not(.pf-c-table__expandable-row) {\n border-bottom: var(--pf-c-table-tr--responsive--border-width--base) solid var(--pf-c-table--responsive--BorderColor); }\n .pf-m-grid-lg.pf-c-table tr:last-child,\n .pf-m-grid-lg.pf-c-table tbody:last-of-type:not(:only-of-type) > tr {\n border-bottom-width: var(--pf-c-table-tr--responsive--last-child--BorderBottomWidth); }\n .pf-m-grid-lg.pf-c-table tbody.pf-m-expanded {\n border-bottom: var(--pf-c-table--border-width--base) solid var(--pf-c-table--BorderColor); }\n .pf-m-grid-lg.pf-c-table tbody.pf-m-expanded tr:not(.pf-c-table__expandable-row) {\n border-bottom: 0; }\n .pf-m-grid-lg.pf-c-table tbody.pf-m-expanded:not(:last-of-type) {\n border-bottom: var(--pf-c-table--tbody--responsive--border-width--base) solid var(--pf-c-table--responsive--BorderColor); }\n .pf-m-grid-lg.pf-c-table tr:not(.pf-c-table__expandable-row) {\n display: grid;\n grid-template-columns: 1fr;\n height: auto;\n grid-auto-columns: max-content;\n grid-column-gap: var(--pf-c-table-tr--responsive--GridColumnGap);\n padding: var(--pf-c-table-tr--responsive--PaddingTop) var(--pf-c-table-tr--responsive--PaddingRight) var(--pf-c-table-tr--responsive--PaddingBottom) var(--pf-c-table-tr--responsive--PaddingLeft); }\n .pf-m-grid-lg.pf-c-table tr:not(.pf-c-table__expandable-row) > * {\n padding: var(--pf-c-table--cell--responsive--PaddingTop) var(--pf-c-table--cell--responsive--PaddingRight) var(--pf-c-table--cell--responsive--PaddingBottom) var(--pf-c-table--cell--responsive--PaddingLeft); }\n .pf-m-grid-lg.pf-c-table tr:not(.pf-c-table__expandable-row) > *:first-child {\n --pf-c-table--cell--responsive--PaddingTop: var(--pf-c-table--cell--first-child--responsive--PaddingTop); }\n .pf-m-grid-lg.pf-c-table.pf-m-compact {\n --pf-c-table-tr--responsive--PaddingTop: var(--pf-c-table--m-compact-tr--responsive--PaddingTop);\n --pf-c-table-tr--responsive--PaddingBottom: var(--pf-c-table--m-compact-tr--responsive--PaddingBottom);\n --pf-c-table--cell--responsive--PaddingTop: var(--pf-c-table--m-compact-tr-td--responsive--PaddingTop);\n --pf-c-table--cell--responsive--PaddingBottom: var(--pf-c-table--m-compact-tr-td--responsive--PaddingBottom);\n --pf-c-table__check--input--MarginTop: 0; }\n .pf-m-grid-lg.pf-c-table.pf-m-compact .pf-c-table__action {\n margin-top: var(--pf-c-table--m-compact__action--responsive--MarginTop);\n margin-bottom: var(--pf-c-table--m-compact__action--responsive--MarginTop); }\n .pf-m-grid-lg.pf-c-table.pf-m-compact .pf-c-table__toggle .pf-c-button {\n margin-bottom: var(--pf-c-table--m-compact__toggle--c-button--responsive--MarginBottom); }\n .pf-m-grid-lg.pf-c-table .pf-c-table__icon > * {\n text-align: left; }\n .pf-m-grid-lg.pf-c-table [data-label] {\n --pf-c-table--cell--hidden-visible--Display: var(--pf-c-table--m-grid--cell--hidden-visible--Display);\n grid-column: 1;\n grid-column-gap: var(--pf-c-table-td--responsive--GridColumnGap);\n grid-template-columns: 1fr minmax(0, 1.5fr);\n align-items: start; }\n .pf-m-grid-lg.pf-c-table [data-label] > * {\n grid-column: 2; }\n .pf-m-grid-lg.pf-c-table [data-label]::before {\n font-weight: bold;\n text-align: left;\n content: attr(data-label); }\n .pf-m-grid-lg.pf-c-table tr > *:first-child {\n --pf-c-table--cell--PaddingLeft: 0; }\n .pf-m-grid-lg.pf-c-table tr > *:last-child {\n --pf-c-table--cell--PaddingRight: 0; }\n .pf-m-grid-lg.pf-c-table .pf-c-table {\n --pf-c-table-tr--responsive--PaddingTop: var(--pf-c-table-tr--responsive--nested-table--PaddingTop);\n --pf-c-table-tr--responsive--PaddingRight: var(--pf-c-table-tr--responsive--nested-table--PaddingRight);\n --pf-c-table-tr--responsive--PaddingBottom: var(--pf-c-table-tr--responsive--nested-table--PaddingBottom);\n --pf-c-table-tr--responsive--PaddingLeft: var(--pf-c-table-tr--responsive--nested-table--PaddingLeft);\n border: 0; }\n .pf-m-grid-lg.pf-c-table .pf-c-table tr:not(.pf-c-table__expandable-row) + tr:not(.pf-c-table__expandable-row) {\n --pf-c-table-tr--responsive--PaddingTop: 0; }\n .pf-m-grid-lg.pf-c-table .pf-c-table__compound-expansion-toggle {\n --pf-c-table__compound-expansion-toggle__button--before--BorderRightWidth: 0;\n --pf-c-table__compound-expansion-toggle__button--before--BorderLeftWidth: 0;\n --pf-c-table__compound-expansion-toggle__button--after--Top: 100%; }\n .pf-m-grid-lg.pf-c-table tbody {\n position: relative; }\n .pf-m-grid-lg.pf-c-table tbody::after {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n content: \"\";\n border: 0;\n border-left: var(--pf-c-table--tbody--after--BorderLeftWidth) solid var(--pf-c-table--tbody--after--BorderColor); }\n .pf-m-grid-lg.pf-c-table tbody.pf-m-expanded {\n --pf-c-table--tbody--after--BorderLeftWidth: var(--pf-c-table--tbody--after--border-width--base); }\n .pf-m-grid-lg.pf-c-table tbody.pf-m-expanded tbody {\n --pf-c-table--tbody--after--BorderLeftWidth: 0; }\n .pf-m-grid-lg.pf-c-table tbody > tr > :first-child:not(.pf-c-table__check)::after {\n --pf-c-table__expandable-row--after--BorderLeftWidth: 0;\n position: static;\n width: auto;\n background-color: transparent; }\n .pf-m-grid-lg.pf-c-table .pf-c-table__expandable-row {\n --pf-c-table--cell--responsive--PaddingTop: 0;\n --pf-c-table--cell--responsive--PaddingRight: 0;\n --pf-c-table--cell--responsive--PaddingBottom: 0;\n --pf-c-table--cell--responsive--PaddingLeft: 0;\n --pf-c-table--cell--PaddingRight: 0;\n --pf-c-table--cell--PaddingLeft: 0;\n display: block;\n max-height: var(--pf-c-table__expandable-row--MaxHeight);\n overflow-y: auto;\n border-bottom: none;\n box-shadow: none; }\n .pf-m-grid-lg.pf-c-table .pf-c-table__expandable-row > * {\n position: static;\n display: block; }\n .pf-m-grid-lg.pf-c-table .pf-c-table__expandable-row.pf-m-expanded {\n border-top-color: var(--pf-c-table--BorderColor); }\n .pf-m-grid-lg.pf-c-table .pf-c-table__expandable-row > :first-child:not(.pf-c-table__check)::after {\n content: none; }\n .pf-m-grid-lg.pf-c-table .pf-c-table__expandable-row td.pf-m-no-padding .pf-c-table__expandable-row-content, .pf-m-grid-lg.pf-c-table .pf-c-table__expandable-row th.pf-m-no-padding .pf-c-table__expandable-row-content {\n padding: 0; }\n .pf-m-grid-lg.pf-c-table .pf-c-table__expandable-row:not(.pf-m-expanded) {\n display: none;\n visibility: hidden; }\n .pf-m-grid-lg.pf-c-table .pf-c-table__expandable-row .pf-c-table__expandable-row-content {\n padding-right: var(--pf-c-table__expandable-row-content--responsive--PaddingRight);\n padding-left: var(--pf-c-table__expandable-row-content--responsive--PaddingLeft); }\n .pf-m-grid-lg.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__toggle,\n .pf-m-grid-lg.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__check,\n .pf-m-grid-lg.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__favorite,\n .pf-m-grid-lg.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__action {\n width: auto;\n padding: 0; }\n .pf-m-grid-lg.pf-c-table .pf-c-table__toggle {\n grid-row-start: 20;\n grid-column: -1;\n justify-self: end;\n padding-right: 0; }\n .pf-m-grid-lg.pf-c-table .pf-c-table__toggle::after {\n content: none; }\n .pf-m-grid-lg.pf-c-table .pf-c-table__button {\n --pf-c-table--cell--PaddingTop: var(--pf-c-table--m-grid--cell--PaddingTop);\n --pf-c-table--cell--PaddingRight: var(--pf-c-table--m-grid--cell--PaddingRight);\n --pf-c-table--cell--PaddingBottom: var(--pf-c-table--m-grid--cell--PaddingBottom);\n --pf-c-table--cell--PaddingLeft: var(--pf-c-table--m-grid--cell--PaddingLeft); }\n .pf-m-grid-lg.pf-c-table .pf-c-table__check,\n .pf-m-grid-lg.pf-c-table .pf-c-table__favorite,\n .pf-m-grid-lg.pf-c-table .pf-c-table__action {\n grid-row-start: 1;\n grid-column-start: 2; }\n .pf-m-grid-lg.pf-c-table .pf-c-table__check {\n margin-top: var(--pf-c-table__check--responsive--MarginTop);\n margin-left: var(--pf-c-table__check--responsive--MarginLeft); }\n .pf-m-grid-lg.pf-c-table .pf-c-table__check ~ .pf-c-table__favorite {\n margin-left: var(--pf-c-table--m-grid__check--favorite--MarginLeft); }\n .pf-m-grid-lg.pf-c-table .pf-c-table__check ~ .pf-c-table__favorite ~ .pf-c-table__action {\n margin-left: var(--pf-c-table--m-grid__check--favorite--action--MarginLeft); }\n .pf-m-grid-lg.pf-c-table .pf-c-table__check ~ .pf-c-table__action {\n margin-left: var(--pf-c-table__action--responsive--MarginLeft); }\n .pf-m-grid-lg.pf-c-table .pf-c-table__favorite {\n margin-top: var(--pf-c-table--m-grid__favorite--MarginTop); }\n .pf-m-grid-lg.pf-c-table .pf-c-table__favorite ~ .pf-c-table__action {\n margin-left: var(--pf-c-table--m-grid__favorite--action--MarginLeft); }\n .pf-m-grid-lg.pf-c-table .pf-c-table__action {\n margin-top: var(--pf-c-table--m-grid__action--MarginTop);\n text-align: right; } }\n @media screen and (max-width: 992px) and (max-width: 576px) {\n .pf-m-grid-lg.pf-c-table .pf-c-table__action {\n grid-row-start: 1;\n grid-column-start: 2;\n margin-left: 0; } }\n\n@media screen and (max-width: 992px) {\n .pf-m-grid-lg.pf-c-table .pf-c-table__inline-edit-action {\n grid-column: 2;\n grid-row: 2; }\n .pf-m-grid-lg.pf-c-table .pf-c-table__toggle-icon {\n transition: var(--pf-c-table__toggle__icon--Transition); }\n .pf-c-button.pf-m-expanded > .pf-m-grid-lg.pf-c-table .pf-c-table__toggle-icon {\n transform: rotate(var(--pf-c-table__toggle--m-expanded__icon--Rotate)); }\n .pf-m-grid-lg.pf-c-table .pf-m-nowrap {\n --pf-c-table--cell--Overflow: auto; }\n .pf-m-grid-lg.pf-c-table .pf-m-fit-content {\n width: auto;\n white-space: normal; }\n .pf-m-grid-lg.pf-c-table .pf-m-truncate {\n --pf-c-table--cell--MaxWidth: 100%; }\n .pf-m-grid-lg.pf-c-table [class*=\"pf-m-width\"] {\n --pf-c-table--cell--Width: auto; } }\n\n@media screen and (max-width: 1200px) {\n .pf-m-grid-xl.pf-c-table {\n --pf-c-table--cell--PaddingTop: var(--pf-c-table--m-grid--cell--PaddingTop);\n --pf-c-table--cell--PaddingRight: var(--pf-c-table--m-grid--cell--PaddingRight);\n --pf-c-table--cell--PaddingBottom: var(--pf-c-table--m-grid--cell--PaddingBottom);\n --pf-c-table--cell--PaddingLeft: var(--pf-c-table--m-grid--cell--PaddingLeft);\n --pf-c-table__favorite--c-button--MarginTop: auto;\n --pf-c-table__favorite--c-button--MarginRight: auto;\n --pf-c-table__favorite--c-button--MarginBottom: auto;\n --pf-c-table__favorite--c-button--MarginLeft: auto;\n display: grid;\n border: none; }\n .pf-m-grid-xl.pf-c-table tr > * {\n width: auto;\n min-width: 0;\n max-width: none;\n overflow: visible;\n text-overflow: clip;\n white-space: normal; }\n .pf-m-grid-xl.pf-c-table .pf-c-table__text {\n position: relative;\n width: auto;\n min-width: 0;\n max-width: none;\n overflow: var(--pf-c-table--cell--Overflow);\n text-overflow: var(--pf-c-table--cell--TextOverflow);\n white-space: var(--pf-c-table--cell--WhiteSpace); }\n .pf-m-grid-xl.pf-c-table thead {\n display: none;\n visibility: hidden; }\n .pf-m-grid-xl.pf-c-table tbody {\n display: block; }\n .pf-m-grid-xl.pf-c-table tbody:first-of-type {\n border-top: var(--pf-c-table--tbody--responsive--border-width--base) solid var(--pf-c-table--responsive--BorderColor); }\n .pf-m-grid-xl.pf-c-table table.pf-m-compact > tbody {\n border-top: 0; }\n .pf-m-grid-xl.pf-c-table tr:not(.pf-c-table__expandable-row) {\n border-bottom: var(--pf-c-table-tr--responsive--border-width--base) solid var(--pf-c-table--responsive--BorderColor); }\n .pf-m-grid-xl.pf-c-table tr:last-child,\n .pf-m-grid-xl.pf-c-table tbody:last-of-type:not(:only-of-type) > tr {\n border-bottom-width: var(--pf-c-table-tr--responsive--last-child--BorderBottomWidth); }\n .pf-m-grid-xl.pf-c-table tbody.pf-m-expanded {\n border-bottom: var(--pf-c-table--border-width--base) solid var(--pf-c-table--BorderColor); }\n .pf-m-grid-xl.pf-c-table tbody.pf-m-expanded tr:not(.pf-c-table__expandable-row) {\n border-bottom: 0; }\n .pf-m-grid-xl.pf-c-table tbody.pf-m-expanded:not(:last-of-type) {\n border-bottom: var(--pf-c-table--tbody--responsive--border-width--base) solid var(--pf-c-table--responsive--BorderColor); }\n .pf-m-grid-xl.pf-c-table tr:not(.pf-c-table__expandable-row) {\n display: grid;\n grid-template-columns: 1fr;\n height: auto;\n grid-auto-columns: max-content;\n grid-column-gap: var(--pf-c-table-tr--responsive--GridColumnGap);\n padding: var(--pf-c-table-tr--responsive--PaddingTop) var(--pf-c-table-tr--responsive--PaddingRight) var(--pf-c-table-tr--responsive--PaddingBottom) var(--pf-c-table-tr--responsive--PaddingLeft); }\n .pf-m-grid-xl.pf-c-table tr:not(.pf-c-table__expandable-row) > * {\n padding: var(--pf-c-table--cell--responsive--PaddingTop) var(--pf-c-table--cell--responsive--PaddingRight) var(--pf-c-table--cell--responsive--PaddingBottom) var(--pf-c-table--cell--responsive--PaddingLeft); }\n .pf-m-grid-xl.pf-c-table tr:not(.pf-c-table__expandable-row) > *:first-child {\n --pf-c-table--cell--responsive--PaddingTop: var(--pf-c-table--cell--first-child--responsive--PaddingTop); }\n .pf-m-grid-xl.pf-c-table.pf-m-compact {\n --pf-c-table-tr--responsive--PaddingTop: var(--pf-c-table--m-compact-tr--responsive--PaddingTop);\n --pf-c-table-tr--responsive--PaddingBottom: var(--pf-c-table--m-compact-tr--responsive--PaddingBottom);\n --pf-c-table--cell--responsive--PaddingTop: var(--pf-c-table--m-compact-tr-td--responsive--PaddingTop);\n --pf-c-table--cell--responsive--PaddingBottom: var(--pf-c-table--m-compact-tr-td--responsive--PaddingBottom);\n --pf-c-table__check--input--MarginTop: 0; }\n .pf-m-grid-xl.pf-c-table.pf-m-compact .pf-c-table__action {\n margin-top: var(--pf-c-table--m-compact__action--responsive--MarginTop);\n margin-bottom: var(--pf-c-table--m-compact__action--responsive--MarginTop); }\n .pf-m-grid-xl.pf-c-table.pf-m-compact .pf-c-table__toggle .pf-c-button {\n margin-bottom: var(--pf-c-table--m-compact__toggle--c-button--responsive--MarginBottom); }\n .pf-m-grid-xl.pf-c-table .pf-c-table__icon > * {\n text-align: left; }\n .pf-m-grid-xl.pf-c-table [data-label] {\n --pf-c-table--cell--hidden-visible--Display: var(--pf-c-table--m-grid--cell--hidden-visible--Display);\n grid-column: 1;\n grid-column-gap: var(--pf-c-table-td--responsive--GridColumnGap);\n grid-template-columns: 1fr minmax(0, 1.5fr);\n align-items: start; }\n .pf-m-grid-xl.pf-c-table [data-label] > * {\n grid-column: 2; }\n .pf-m-grid-xl.pf-c-table [data-label]::before {\n font-weight: bold;\n text-align: left;\n content: attr(data-label); }\n .pf-m-grid-xl.pf-c-table tr > *:first-child {\n --pf-c-table--cell--PaddingLeft: 0; }\n .pf-m-grid-xl.pf-c-table tr > *:last-child {\n --pf-c-table--cell--PaddingRight: 0; }\n .pf-m-grid-xl.pf-c-table .pf-c-table {\n --pf-c-table-tr--responsive--PaddingTop: var(--pf-c-table-tr--responsive--nested-table--PaddingTop);\n --pf-c-table-tr--responsive--PaddingRight: var(--pf-c-table-tr--responsive--nested-table--PaddingRight);\n --pf-c-table-tr--responsive--PaddingBottom: var(--pf-c-table-tr--responsive--nested-table--PaddingBottom);\n --pf-c-table-tr--responsive--PaddingLeft: var(--pf-c-table-tr--responsive--nested-table--PaddingLeft);\n border: 0; }\n .pf-m-grid-xl.pf-c-table .pf-c-table tr:not(.pf-c-table__expandable-row) + tr:not(.pf-c-table__expandable-row) {\n --pf-c-table-tr--responsive--PaddingTop: 0; }\n .pf-m-grid-xl.pf-c-table .pf-c-table__compound-expansion-toggle {\n --pf-c-table__compound-expansion-toggle__button--before--BorderRightWidth: 0;\n --pf-c-table__compound-expansion-toggle__button--before--BorderLeftWidth: 0;\n --pf-c-table__compound-expansion-toggle__button--after--Top: 100%; }\n .pf-m-grid-xl.pf-c-table tbody {\n position: relative; }\n .pf-m-grid-xl.pf-c-table tbody::after {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n content: \"\";\n border: 0;\n border-left: var(--pf-c-table--tbody--after--BorderLeftWidth) solid var(--pf-c-table--tbody--after--BorderColor); }\n .pf-m-grid-xl.pf-c-table tbody.pf-m-expanded {\n --pf-c-table--tbody--after--BorderLeftWidth: var(--pf-c-table--tbody--after--border-width--base); }\n .pf-m-grid-xl.pf-c-table tbody.pf-m-expanded tbody {\n --pf-c-table--tbody--after--BorderLeftWidth: 0; }\n .pf-m-grid-xl.pf-c-table tbody > tr > :first-child:not(.pf-c-table__check)::after {\n --pf-c-table__expandable-row--after--BorderLeftWidth: 0;\n position: static;\n width: auto;\n background-color: transparent; }\n .pf-m-grid-xl.pf-c-table .pf-c-table__expandable-row {\n --pf-c-table--cell--responsive--PaddingTop: 0;\n --pf-c-table--cell--responsive--PaddingRight: 0;\n --pf-c-table--cell--responsive--PaddingBottom: 0;\n --pf-c-table--cell--responsive--PaddingLeft: 0;\n --pf-c-table--cell--PaddingRight: 0;\n --pf-c-table--cell--PaddingLeft: 0;\n display: block;\n max-height: var(--pf-c-table__expandable-row--MaxHeight);\n overflow-y: auto;\n border-bottom: none;\n box-shadow: none; }\n .pf-m-grid-xl.pf-c-table .pf-c-table__expandable-row > * {\n position: static;\n display: block; }\n .pf-m-grid-xl.pf-c-table .pf-c-table__expandable-row.pf-m-expanded {\n border-top-color: var(--pf-c-table--BorderColor); }\n .pf-m-grid-xl.pf-c-table .pf-c-table__expandable-row > :first-child:not(.pf-c-table__check)::after {\n content: none; }\n .pf-m-grid-xl.pf-c-table .pf-c-table__expandable-row td.pf-m-no-padding .pf-c-table__expandable-row-content, .pf-m-grid-xl.pf-c-table .pf-c-table__expandable-row th.pf-m-no-padding .pf-c-table__expandable-row-content {\n padding: 0; }\n .pf-m-grid-xl.pf-c-table .pf-c-table__expandable-row:not(.pf-m-expanded) {\n display: none;\n visibility: hidden; }\n .pf-m-grid-xl.pf-c-table .pf-c-table__expandable-row .pf-c-table__expandable-row-content {\n padding-right: var(--pf-c-table__expandable-row-content--responsive--PaddingRight);\n padding-left: var(--pf-c-table__expandable-row-content--responsive--PaddingLeft); }\n .pf-m-grid-xl.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__toggle,\n .pf-m-grid-xl.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__check,\n .pf-m-grid-xl.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__favorite,\n .pf-m-grid-xl.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__action {\n width: auto;\n padding: 0; }\n .pf-m-grid-xl.pf-c-table .pf-c-table__toggle {\n grid-row-start: 20;\n grid-column: -1;\n justify-self: end;\n padding-right: 0; }\n .pf-m-grid-xl.pf-c-table .pf-c-table__toggle::after {\n content: none; }\n .pf-m-grid-xl.pf-c-table .pf-c-table__button {\n --pf-c-table--cell--PaddingTop: var(--pf-c-table--m-grid--cell--PaddingTop);\n --pf-c-table--cell--PaddingRight: var(--pf-c-table--m-grid--cell--PaddingRight);\n --pf-c-table--cell--PaddingBottom: var(--pf-c-table--m-grid--cell--PaddingBottom);\n --pf-c-table--cell--PaddingLeft: var(--pf-c-table--m-grid--cell--PaddingLeft); }\n .pf-m-grid-xl.pf-c-table .pf-c-table__check,\n .pf-m-grid-xl.pf-c-table .pf-c-table__favorite,\n .pf-m-grid-xl.pf-c-table .pf-c-table__action {\n grid-row-start: 1;\n grid-column-start: 2; }\n .pf-m-grid-xl.pf-c-table .pf-c-table__check {\n margin-top: var(--pf-c-table__check--responsive--MarginTop);\n margin-left: var(--pf-c-table__check--responsive--MarginLeft); }\n .pf-m-grid-xl.pf-c-table .pf-c-table__check ~ .pf-c-table__favorite {\n margin-left: var(--pf-c-table--m-grid__check--favorite--MarginLeft); }\n .pf-m-grid-xl.pf-c-table .pf-c-table__check ~ .pf-c-table__favorite ~ .pf-c-table__action {\n margin-left: var(--pf-c-table--m-grid__check--favorite--action--MarginLeft); }\n .pf-m-grid-xl.pf-c-table .pf-c-table__check ~ .pf-c-table__action {\n margin-left: var(--pf-c-table__action--responsive--MarginLeft); }\n .pf-m-grid-xl.pf-c-table .pf-c-table__favorite {\n margin-top: var(--pf-c-table--m-grid__favorite--MarginTop); }\n .pf-m-grid-xl.pf-c-table .pf-c-table__favorite ~ .pf-c-table__action {\n margin-left: var(--pf-c-table--m-grid__favorite--action--MarginLeft); }\n .pf-m-grid-xl.pf-c-table .pf-c-table__action {\n margin-top: var(--pf-c-table--m-grid__action--MarginTop);\n text-align: right; } }\n @media screen and (max-width: 1200px) and (max-width: 576px) {\n .pf-m-grid-xl.pf-c-table .pf-c-table__action {\n grid-row-start: 1;\n grid-column-start: 2;\n margin-left: 0; } }\n\n@media screen and (max-width: 1200px) {\n .pf-m-grid-xl.pf-c-table .pf-c-table__inline-edit-action {\n grid-column: 2;\n grid-row: 2; }\n .pf-m-grid-xl.pf-c-table .pf-c-table__toggle-icon {\n transition: var(--pf-c-table__toggle__icon--Transition); }\n .pf-c-button.pf-m-expanded > .pf-m-grid-xl.pf-c-table .pf-c-table__toggle-icon {\n transform: rotate(var(--pf-c-table__toggle--m-expanded__icon--Rotate)); }\n .pf-m-grid-xl.pf-c-table .pf-m-nowrap {\n --pf-c-table--cell--Overflow: auto; }\n .pf-m-grid-xl.pf-c-table .pf-m-fit-content {\n width: auto;\n white-space: normal; }\n .pf-m-grid-xl.pf-c-table .pf-m-truncate {\n --pf-c-table--cell--MaxWidth: 100%; }\n .pf-m-grid-xl.pf-c-table [class*=\"pf-m-width\"] {\n --pf-c-table--cell--Width: auto; } }\n\n@media screen and (max-width: 1450px) {\n .pf-m-grid-2xl.pf-c-table {\n --pf-c-table--cell--PaddingTop: var(--pf-c-table--m-grid--cell--PaddingTop);\n --pf-c-table--cell--PaddingRight: var(--pf-c-table--m-grid--cell--PaddingRight);\n --pf-c-table--cell--PaddingBottom: var(--pf-c-table--m-grid--cell--PaddingBottom);\n --pf-c-table--cell--PaddingLeft: var(--pf-c-table--m-grid--cell--PaddingLeft);\n --pf-c-table__favorite--c-button--MarginTop: auto;\n --pf-c-table__favorite--c-button--MarginRight: auto;\n --pf-c-table__favorite--c-button--MarginBottom: auto;\n --pf-c-table__favorite--c-button--MarginLeft: auto;\n display: grid;\n border: none; }\n .pf-m-grid-2xl.pf-c-table tr > * {\n width: auto;\n min-width: 0;\n max-width: none;\n overflow: visible;\n text-overflow: clip;\n white-space: normal; }\n .pf-m-grid-2xl.pf-c-table .pf-c-table__text {\n position: relative;\n width: auto;\n min-width: 0;\n max-width: none;\n overflow: var(--pf-c-table--cell--Overflow);\n text-overflow: var(--pf-c-table--cell--TextOverflow);\n white-space: var(--pf-c-table--cell--WhiteSpace); }\n .pf-m-grid-2xl.pf-c-table thead {\n display: none;\n visibility: hidden; }\n .pf-m-grid-2xl.pf-c-table tbody {\n display: block; }\n .pf-m-grid-2xl.pf-c-table tbody:first-of-type {\n border-top: var(--pf-c-table--tbody--responsive--border-width--base) solid var(--pf-c-table--responsive--BorderColor); }\n .pf-m-grid-2xl.pf-c-table table.pf-m-compact > tbody {\n border-top: 0; }\n .pf-m-grid-2xl.pf-c-table tr:not(.pf-c-table__expandable-row) {\n border-bottom: var(--pf-c-table-tr--responsive--border-width--base) solid var(--pf-c-table--responsive--BorderColor); }\n .pf-m-grid-2xl.pf-c-table tr:last-child,\n .pf-m-grid-2xl.pf-c-table tbody:last-of-type:not(:only-of-type) > tr {\n border-bottom-width: var(--pf-c-table-tr--responsive--last-child--BorderBottomWidth); }\n .pf-m-grid-2xl.pf-c-table tbody.pf-m-expanded {\n border-bottom: var(--pf-c-table--border-width--base) solid var(--pf-c-table--BorderColor); }\n .pf-m-grid-2xl.pf-c-table tbody.pf-m-expanded tr:not(.pf-c-table__expandable-row) {\n border-bottom: 0; }\n .pf-m-grid-2xl.pf-c-table tbody.pf-m-expanded:not(:last-of-type) {\n border-bottom: var(--pf-c-table--tbody--responsive--border-width--base) solid var(--pf-c-table--responsive--BorderColor); }\n .pf-m-grid-2xl.pf-c-table tr:not(.pf-c-table__expandable-row) {\n display: grid;\n grid-template-columns: 1fr;\n height: auto;\n grid-auto-columns: max-content;\n grid-column-gap: var(--pf-c-table-tr--responsive--GridColumnGap);\n padding: var(--pf-c-table-tr--responsive--PaddingTop) var(--pf-c-table-tr--responsive--PaddingRight) var(--pf-c-table-tr--responsive--PaddingBottom) var(--pf-c-table-tr--responsive--PaddingLeft); }\n .pf-m-grid-2xl.pf-c-table tr:not(.pf-c-table__expandable-row) > * {\n padding: var(--pf-c-table--cell--responsive--PaddingTop) var(--pf-c-table--cell--responsive--PaddingRight) var(--pf-c-table--cell--responsive--PaddingBottom) var(--pf-c-table--cell--responsive--PaddingLeft); }\n .pf-m-grid-2xl.pf-c-table tr:not(.pf-c-table__expandable-row) > *:first-child {\n --pf-c-table--cell--responsive--PaddingTop: var(--pf-c-table--cell--first-child--responsive--PaddingTop); }\n .pf-m-grid-2xl.pf-c-table.pf-m-compact {\n --pf-c-table-tr--responsive--PaddingTop: var(--pf-c-table--m-compact-tr--responsive--PaddingTop);\n --pf-c-table-tr--responsive--PaddingBottom: var(--pf-c-table--m-compact-tr--responsive--PaddingBottom);\n --pf-c-table--cell--responsive--PaddingTop: var(--pf-c-table--m-compact-tr-td--responsive--PaddingTop);\n --pf-c-table--cell--responsive--PaddingBottom: var(--pf-c-table--m-compact-tr-td--responsive--PaddingBottom);\n --pf-c-table__check--input--MarginTop: 0; }\n .pf-m-grid-2xl.pf-c-table.pf-m-compact .pf-c-table__action {\n margin-top: var(--pf-c-table--m-compact__action--responsive--MarginTop);\n margin-bottom: var(--pf-c-table--m-compact__action--responsive--MarginTop); }\n .pf-m-grid-2xl.pf-c-table.pf-m-compact .pf-c-table__toggle .pf-c-button {\n margin-bottom: var(--pf-c-table--m-compact__toggle--c-button--responsive--MarginBottom); }\n .pf-m-grid-2xl.pf-c-table .pf-c-table__icon > * {\n text-align: left; }\n .pf-m-grid-2xl.pf-c-table [data-label] {\n --pf-c-table--cell--hidden-visible--Display: var(--pf-c-table--m-grid--cell--hidden-visible--Display);\n grid-column: 1;\n grid-column-gap: var(--pf-c-table-td--responsive--GridColumnGap);\n grid-template-columns: 1fr minmax(0, 1.5fr);\n align-items: start; }\n .pf-m-grid-2xl.pf-c-table [data-label] > * {\n grid-column: 2; }\n .pf-m-grid-2xl.pf-c-table [data-label]::before {\n font-weight: bold;\n text-align: left;\n content: attr(data-label); }\n .pf-m-grid-2xl.pf-c-table tr > *:first-child {\n --pf-c-table--cell--PaddingLeft: 0; }\n .pf-m-grid-2xl.pf-c-table tr > *:last-child {\n --pf-c-table--cell--PaddingRight: 0; }\n .pf-m-grid-2xl.pf-c-table .pf-c-table {\n --pf-c-table-tr--responsive--PaddingTop: var(--pf-c-table-tr--responsive--nested-table--PaddingTop);\n --pf-c-table-tr--responsive--PaddingRight: var(--pf-c-table-tr--responsive--nested-table--PaddingRight);\n --pf-c-table-tr--responsive--PaddingBottom: var(--pf-c-table-tr--responsive--nested-table--PaddingBottom);\n --pf-c-table-tr--responsive--PaddingLeft: var(--pf-c-table-tr--responsive--nested-table--PaddingLeft);\n border: 0; }\n .pf-m-grid-2xl.pf-c-table .pf-c-table tr:not(.pf-c-table__expandable-row) + tr:not(.pf-c-table__expandable-row) {\n --pf-c-table-tr--responsive--PaddingTop: 0; }\n .pf-m-grid-2xl.pf-c-table .pf-c-table__compound-expansion-toggle {\n --pf-c-table__compound-expansion-toggle__button--before--BorderRightWidth: 0;\n --pf-c-table__compound-expansion-toggle__button--before--BorderLeftWidth: 0;\n --pf-c-table__compound-expansion-toggle__button--after--Top: 100%; }\n .pf-m-grid-2xl.pf-c-table tbody {\n position: relative; }\n .pf-m-grid-2xl.pf-c-table tbody::after {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n content: \"\";\n border: 0;\n border-left: var(--pf-c-table--tbody--after--BorderLeftWidth) solid var(--pf-c-table--tbody--after--BorderColor); }\n .pf-m-grid-2xl.pf-c-table tbody.pf-m-expanded {\n --pf-c-table--tbody--after--BorderLeftWidth: var(--pf-c-table--tbody--after--border-width--base); }\n .pf-m-grid-2xl.pf-c-table tbody.pf-m-expanded tbody {\n --pf-c-table--tbody--after--BorderLeftWidth: 0; }\n .pf-m-grid-2xl.pf-c-table tbody > tr > :first-child:not(.pf-c-table__check)::after {\n --pf-c-table__expandable-row--after--BorderLeftWidth: 0;\n position: static;\n width: auto;\n background-color: transparent; }\n .pf-m-grid-2xl.pf-c-table .pf-c-table__expandable-row {\n --pf-c-table--cell--responsive--PaddingTop: 0;\n --pf-c-table--cell--responsive--PaddingRight: 0;\n --pf-c-table--cell--responsive--PaddingBottom: 0;\n --pf-c-table--cell--responsive--PaddingLeft: 0;\n --pf-c-table--cell--PaddingRight: 0;\n --pf-c-table--cell--PaddingLeft: 0;\n display: block;\n max-height: var(--pf-c-table__expandable-row--MaxHeight);\n overflow-y: auto;\n border-bottom: none;\n box-shadow: none; }\n .pf-m-grid-2xl.pf-c-table .pf-c-table__expandable-row > * {\n position: static;\n display: block; }\n .pf-m-grid-2xl.pf-c-table .pf-c-table__expandable-row.pf-m-expanded {\n border-top-color: var(--pf-c-table--BorderColor); }\n .pf-m-grid-2xl.pf-c-table .pf-c-table__expandable-row > :first-child:not(.pf-c-table__check)::after {\n content: none; }\n .pf-m-grid-2xl.pf-c-table .pf-c-table__expandable-row td.pf-m-no-padding .pf-c-table__expandable-row-content, .pf-m-grid-2xl.pf-c-table .pf-c-table__expandable-row th.pf-m-no-padding .pf-c-table__expandable-row-content {\n padding: 0; }\n .pf-m-grid-2xl.pf-c-table .pf-c-table__expandable-row:not(.pf-m-expanded) {\n display: none;\n visibility: hidden; }\n .pf-m-grid-2xl.pf-c-table .pf-c-table__expandable-row .pf-c-table__expandable-row-content {\n padding-right: var(--pf-c-table__expandable-row-content--responsive--PaddingRight);\n padding-left: var(--pf-c-table__expandable-row-content--responsive--PaddingLeft); }\n .pf-m-grid-2xl.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__toggle,\n .pf-m-grid-2xl.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__check,\n .pf-m-grid-2xl.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__favorite,\n .pf-m-grid-2xl.pf-c-table tr:not(.pf-c-table__expandable-row) .pf-c-table__action {\n width: auto;\n padding: 0; }\n .pf-m-grid-2xl.pf-c-table .pf-c-table__toggle {\n grid-row-start: 20;\n grid-column: -1;\n justify-self: end;\n padding-right: 0; }\n .pf-m-grid-2xl.pf-c-table .pf-c-table__toggle::after {\n content: none; }\n .pf-m-grid-2xl.pf-c-table .pf-c-table__button {\n --pf-c-table--cell--PaddingTop: var(--pf-c-table--m-grid--cell--PaddingTop);\n --pf-c-table--cell--PaddingRight: var(--pf-c-table--m-grid--cell--PaddingRight);\n --pf-c-table--cell--PaddingBottom: var(--pf-c-table--m-grid--cell--PaddingBottom);\n --pf-c-table--cell--PaddingLeft: var(--pf-c-table--m-grid--cell--PaddingLeft); }\n .pf-m-grid-2xl.pf-c-table .pf-c-table__check,\n .pf-m-grid-2xl.pf-c-table .pf-c-table__favorite,\n .pf-m-grid-2xl.pf-c-table .pf-c-table__action {\n grid-row-start: 1;\n grid-column-start: 2; }\n .pf-m-grid-2xl.pf-c-table .pf-c-table__check {\n margin-top: var(--pf-c-table__check--responsive--MarginTop);\n margin-left: var(--pf-c-table__check--responsive--MarginLeft); }\n .pf-m-grid-2xl.pf-c-table .pf-c-table__check ~ .pf-c-table__favorite {\n margin-left: var(--pf-c-table--m-grid__check--favorite--MarginLeft); }\n .pf-m-grid-2xl.pf-c-table .pf-c-table__check ~ .pf-c-table__favorite ~ .pf-c-table__action {\n margin-left: var(--pf-c-table--m-grid__check--favorite--action--MarginLeft); }\n .pf-m-grid-2xl.pf-c-table .pf-c-table__check ~ .pf-c-table__action {\n margin-left: var(--pf-c-table__action--responsive--MarginLeft); }\n .pf-m-grid-2xl.pf-c-table .pf-c-table__favorite {\n margin-top: var(--pf-c-table--m-grid__favorite--MarginTop); }\n .pf-m-grid-2xl.pf-c-table .pf-c-table__favorite ~ .pf-c-table__action {\n margin-left: var(--pf-c-table--m-grid__favorite--action--MarginLeft); }\n .pf-m-grid-2xl.pf-c-table .pf-c-table__action {\n margin-top: var(--pf-c-table--m-grid__action--MarginTop);\n text-align: right; } }\n @media screen and (max-width: 1450px) and (max-width: 576px) {\n .pf-m-grid-2xl.pf-c-table .pf-c-table__action {\n grid-row-start: 1;\n grid-column-start: 2;\n margin-left: 0; } }\n\n@media screen and (max-width: 1450px) {\n .pf-m-grid-2xl.pf-c-table .pf-c-table__inline-edit-action {\n grid-column: 2;\n grid-row: 2; }\n .pf-m-grid-2xl.pf-c-table .pf-c-table__toggle-icon {\n transition: var(--pf-c-table__toggle__icon--Transition); }\n .pf-c-button.pf-m-expanded > .pf-m-grid-2xl.pf-c-table .pf-c-table__toggle-icon {\n transform: rotate(var(--pf-c-table__toggle--m-expanded__icon--Rotate)); }\n .pf-m-grid-2xl.pf-c-table .pf-m-nowrap {\n --pf-c-table--cell--Overflow: auto; }\n .pf-m-grid-2xl.pf-c-table .pf-m-fit-content {\n width: auto;\n white-space: normal; }\n .pf-m-grid-2xl.pf-c-table .pf-m-truncate {\n --pf-c-table--cell--MaxWidth: 100%; }\n .pf-m-grid-2xl.pf-c-table [class*=\"pf-m-width\"] {\n --pf-c-table--cell--Width: auto; } }\n\n.pf-c-table {\n --pf-c-table--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-table--BorderColor: var(--pf-global--BorderColor--100);\n --pf-c-table--border-width--base: var(--pf-global--BorderWidth--sm);\n --pf-c-table-caption--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-table-caption--Color: var(--pf-global--Color--200);\n --pf-c-table-caption--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-table-caption--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-table-caption--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-table-caption--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-table-caption--xl--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-table-caption--xl--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-table--thead--cell--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-table--thead--cell--FontWeight: var(--pf-global--FontWeight--bold);\n --pf-c-table--tbody--cell--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-table--tbody--cell--PaddingBottom: var(--pf-global--spacer--lg);\n --pf-c-table--cell--FontSize: var(--pf-global--FontSize--md);\n --pf-c-table--cell--FontWeight: var(--pf-global--FontWeight--normal);\n --pf-c-table--cell--Color: var(--pf-global--Color--100);\n --pf-c-table--cell--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-table--cell--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-table--cell--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-table--cell--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-table--cell--first-last-child--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-table--cell--first-last-child--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-table--cell--first-last-child--xl--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-table--cell--first-last-child--xl--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-table--cell--MinWidth: 0;\n --pf-c-table--cell--MaxWidth: none;\n --pf-c-table--cell--Width: auto;\n --pf-c-table--cell--Overflow: visible;\n --pf-c-table--cell--TextOverflow: clip;\n --pf-c-table--cell--WhiteSpace: normal;\n --pf-c-table--cell--WordBreak: normal;\n --pf-c-table--cell--m-help--MinWidth: 11ch;\n --pf-c-table--m-truncate--cell--MaxWidth: 1px;\n --pf-c-table--m-truncate--cell--MinWidth: calc(5ch + var(--pf-c-table--cell--PaddingRight) + var(--pf-c-table--cell--PaddingLeft));\n --pf-c-table--cell--hidden-visible--Display: table-cell;\n --pf-c-table__toggle--c-button--MarginTop: calc(0.375rem * -1);\n --pf-c-table__toggle--c-button__toggle-icon--Rotate: 270deg;\n --pf-c-table__toggle--c-button__toggle-icon--Transition: .2s ease-in 0s;\n --pf-c-table__toggle--c-button--m-expanded__toggle-icon--Rotate: 360deg;\n --pf-c-table__button--BackgroundColor: transparent;\n --pf-c-table__button--Color: var(--pf-global--Color--100);\n --pf-c-table__button--hover--Color: var(--pf-global--Color--100);\n --pf-c-table__button--focus--Color: var(--pf-global--Color--100);\n --pf-c-table__button--active--Color: var(--pf-global--Color--100);\n --pf-c-table__button--OutlineOffset: calc(var(--pf-global--BorderWidth--lg) * -1);\n --pf-c-table--m-compact__toggle--PaddingTop: 0;\n --pf-c-table--m-compact__toggle--PaddingBottom: 0;\n --pf-c-table__check--input--MarginTop: 0.25rem;\n --pf-c-table__check--input--FontSize: var(--pf-global--FontSize--md);\n --pf-c-table--cell--m-favorite--Color: var(--pf-global--Color--light-300);\n --pf-c-table__favorite--c-button--Color: var(--pf-global--Color--light-300);\n --pf-c-table__favorite--c-button--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-table__favorite--c-button--MarginTop: calc(var(--pf-global--spacer--form-element) * -1);\n --pf-c-table__favorite--c-button--MarginRight: calc(var(--pf-global--spacer--md) * -1);\n --pf-c-table__favorite--c-button--MarginBottom: calc(var(--pf-global--spacer--form-element) * -1);\n --pf-c-table__favorite--c-button--MarginLeft: calc(var(--pf-global--spacer--md) * -1);\n --pf-c-table__favorite--m-favorited--c-button--Color: var(--pf-global--palette--gold-400);\n --pf-c-table__sort--m-favorite__button__text--Color: var(--pf-global--Color--200);\n --pf-c-table__sort--m-favorite__button--hover__text--Color: var(--pf-global--Color--100);\n --pf-c-table__sort--m-favorite__button--focus__text--Color: var(--pf-global--Color--100);\n --pf-c-table__sort--m-favorite__button--active__text--Color: var(--pf-global--Color--100);\n --pf-c-table__action--PaddingTop: 0;\n --pf-c-table__action--PaddingRight: 0;\n --pf-c-table__action--PaddingBottom: 0;\n --pf-c-table__action--PaddingLeft: 0;\n --pf-c-table__inline-edit-action--PaddingTop: 0;\n --pf-c-table__inline-edit-action--PaddingRight: 0;\n --pf-c-table__inline-edit-action--PaddingBottom: 0;\n --pf-c-table__inline-edit-action--PaddingLeft: 0;\n --pf-c-table__expandable-row--Transition: var(--pf-global--Transition);\n --pf-c-table__expandable-row--MaxHeight: 28.125rem;\n --pf-c-table__expandable-row-content--Transition: var(--pf-global--Transition);\n --pf-c-table__expandable-row-content--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-table__expandable-row-content--PaddingBottom: var(--pf-global--spacer--lg);\n --pf-c-table__expandable-row--after--Top: calc(var(--pf-c-table--border-width--base) * -1);\n --pf-c-table__expandable-row--after--Bottom: calc(var(--pf-c-table--border-width--base) * -1);\n --pf-c-table__expandable-row--after--border-width--base: var(--pf-global--BorderWidth--lg);\n --pf-c-table__expandable-row--after--BorderLeftWidth: 0;\n --pf-c-table__expandable-row--after--BorderColor: var(--pf-global--active-color--100);\n --pf-c-table__icon-inline--MarginRight: var(--pf-global--spacer--sm);\n --pf-c-table__sort--MinWidth: calc(6ch + var(--pf-c-table--cell--PaddingRight) + var(--pf-c-table--cell--PaddingLeft) + var(--pf-c-table__sort-indicator--MarginLeft));\n --pf-c-table__sort__button--PaddingTop: var(--pf-global--spacer--form-element);\n --pf-c-table__sort__button--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-table__sort__button--PaddingBottom: var(--pf-global--spacer--form-element);\n --pf-c-table__sort__button--PaddingLeft: var(--pf-global--spacer--sm);\n --pf-c-table__sort__button--MarginTop: calc(var(--pf-c-table__sort__button--PaddingTop) * -1);\n --pf-c-table__sort__button--MarginBottom: calc(var(--pf-c-table__sort__button--PaddingBottom) * -1);\n --pf-c-table__sort__button--MarginLeft: calc(var(--pf-c-table__sort__button--PaddingLeft) * -1);\n --pf-c-table__sort__button--Color: var(--pf-global--Color--100);\n --pf-c-table__sort--m-selected__button--Color: var(--pf-global--active-color--100);\n --pf-c-table__sort--m-help--MinWidth: 15ch;\n --pf-c-table__sort__button__text--Color: currentColor;\n --pf-c-table__sort__button--hover__text--Color: currentColor;\n --pf-c-table__sort__button--focus__text--Color: currentColor;\n --pf-c-table__sort__button--active__text--Color: currentColor;\n --pf-c-table__sort-indicator--Color: var(--pf-global--disabled-color--200);\n --pf-c-table__sort-indicator--MarginLeft: var(--pf-global--spacer--md);\n --pf-c-table__sort--m-selected__sort-indicator--Color: var(--pf-global--active-color--100);\n --pf-c-table__sort__button--hover__sort-indicator--Color: var(--pf-global--Color--100);\n --pf-c-table__sort__button--active__sort-indicator--Color: var(--pf-global--Color--100);\n --pf-c-table__sort__button--focus__sort-indicator--Color: var(--pf-global--Color--100);\n --pf-c-table--th--m-help--MinWidth: 11ch;\n --pf-c-table__column-help--MarginLeft: var(--pf-global--spacer--xs);\n --pf-c-table__column-help--TranslateY: 0.125rem;\n --pf-c-table__column-help--c-button--MarginTop: calc(var(--pf-global--spacer--form-element) * -1);\n --pf-c-table__column-help--c-button--MarginBottom: calc(var(--pf-global--spacer--form-element) * -1);\n --pf-c-table__column-help--c-button--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-table__column-help--c-button--PaddingLeft: var(--pf-global--spacer--sm);\n --pf-c-table__compound-expansion-toggle__button--Color: var(--pf-global--active-color--100);\n --pf-c-table__compound-expansion-toggle__button--hover--Color: var(--pf-global--link--Color--hover);\n --pf-c-table__compound-expansion-toggle__button--focus--Color: var(--pf-global--link--Color--hover);\n --pf-c-table__compound-expansion-toggle__button--active--Color: var(--pf-global--link--Color--hover);\n --pf-c-table__compound-expansion-toggle__button--before--border-width--base: var(--pf-global--BorderWidth--sm);\n --pf-c-table__compound-expansion-toggle__button--before--BorderColor: var(--pf-global--BorderColor--100);\n --pf-c-table__compound-expansion-toggle__button--before--BorderRightWidth: 0;\n --pf-c-table__compound-expansion-toggle__button--before--BorderLeftWidth: 0;\n --pf-c-table__compound-expansion-toggle__button--before--Bottom: calc(var(--pf-c-table__compound-expansion-toggle__button--before--border-width--base) * -1);\n --pf-c-table__compound-expansion-toggle__button--before--Left: calc(var(--pf-c-table__compound-expansion-toggle__button--before--border-width--base) * -1);\n --pf-c-table__compound-expansion-toggle__button--after--border-width--base: var(--pf-global--BorderWidth--lg);\n --pf-c-table__compound-expansion-toggle__button--after--BorderColor: var(--pf-global--primary-color--100);\n --pf-c-table__compound-expansion-toggle__button--after--BorderTopWidth: 0;\n --pf-c-table__compound-expansion-toggle__button--after--Top: calc(var(--pf-c-table__compound-expansion-toggle__button--before--border-width--base) * -1);\n --pf-c-table__compound-expansion-toggle__button--after--Left: calc(var(--pf-c-table__compound-expansion-toggle__button--before--border-width--base) * -1);\n --pf-c-table--m-compact-th--PaddingTop: calc(var(--pf-global--spacer--sm) + var(--pf-global--spacer--xs));\n --pf-c-table--m-compact-th--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-table--m-compact--cell--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-table--m-compact--cell--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-table--m-compact--cell--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-table--m-compact--cell--PaddingLeft: var(--pf-global--spacer--sm);\n --pf-c-table--m-compact--cell--first-last-child--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-table--m-compact--cell--first-last-child--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-table--m-compact--cell--first-last-child--xl--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-table--m-compact--cell--first-last-child--xl--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-table--m-compact--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-table--m-compact__expandable-row-content--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-table--m-compact__expandable-row-content--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-table--m-compact__expandable-row-content--PaddingBottom: var(--pf-global--spacer--lg);\n --pf-c-table--m-compact__expandable-row-content--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-table--nested--first-last-child--PaddingRight: var(--pf-global--spacer--3xl);\n --pf-c-table--nested--first-last-child--PaddingLeft: var(--pf-global--spacer--3xl);\n --pf-c-table__expandable-row--m-expanded--BorderBottomColor: var(--pf-global--BorderColor--100);\n color: var(--pf-global--Color--100);\n width: 100%;\n background-color: var(--pf-c-table--BackgroundColor); }\n @media screen and (max-width: 1200px) {\n .pf-c-table {\n --pf-c-table-caption--PaddingRight: var(--pf-c-table-caption--xl--PaddingRight);\n --pf-c-table-caption--PaddingLeft: var(--pf-c-table-caption--xl--PaddingLeft); } }\n @media screen and (min-width: 1200px) {\n .pf-c-table {\n --pf-c-table--cell--first-last-child--PaddingRight: var(--pf-c-table--cell--first-last-child--xl--PaddingRight);\n --pf-c-table--cell--first-last-child--PaddingLeft: var(--pf-c-table--cell--first-last-child--xl--PaddingLeft);\n --pf-c-table--m-compact--cell--first-last-child--PaddingLeft: var(--pf-c-table--m-compact--cell--first-last-child--xl--PaddingLeft);\n --pf-c-table--m-compact--cell--first-last-child--PaddingRight: var(--pf-c-table--m-compact--cell--first-last-child--xl--PaddingRight); } }\n .pf-c-table.pf-m-fixed {\n table-layout: fixed; }\n .pf-c-table.pf-m-sticky-header {\n position: relative; }\n .pf-c-table.pf-m-sticky-header > thead > tr {\n border-bottom: 0; }\n .pf-c-table.pf-m-sticky-header > thead > tr > * {\n position: sticky;\n top: 0;\n z-index: var(--pf-global--ZIndex--xs);\n background: var(--pf-c-table--BackgroundColor); }\n .pf-c-table.pf-m-sticky-header > thead > tr > *::after {\n position: absolute;\n right: 0;\n bottom: 0;\n left: 0;\n content: \"\";\n border-bottom: var(--pf-c-table--border-width--base) solid var(--pf-c-table--BorderColor); }\n .pf-c-table tr:not(.pf-c-table__expandable-row) {\n border-bottom: var(--pf-c-table--border-width--base) solid var(--pf-c-table--BorderColor); }\n .pf-c-table tr > * {\n --pf-hidden-visible--visible--Display: var(--pf-c-table--cell--hidden-visible--Display);\n position: relative;\n width: var(--pf-c-table--cell--Width);\n min-width: var(--pf-c-table--cell--MinWidth);\n max-width: var(--pf-c-table--cell--MaxWidth);\n padding: var(--pf-c-table--cell--PaddingTop) var(--pf-c-table--cell--PaddingRight) var(--pf-c-table--cell--PaddingBottom) var(--pf-c-table--cell--PaddingLeft);\n overflow: var(--pf-c-table--cell--Overflow);\n font-size: var(--pf-c-table--cell--FontSize);\n font-weight: var(--pf-c-table--cell--FontWeight);\n color: var(--pf-c-table--cell--Color);\n text-overflow: var(--pf-c-table--cell--TextOverflow);\n word-break: var(--pf-c-table--cell--WordBreak);\n white-space: var(--pf-c-table--cell--WhiteSpace); }\n .pf-c-table tr > *:first-child {\n --pf-c-table--cell--PaddingLeft: var(--pf-c-table--cell--first-last-child--PaddingLeft); }\n .pf-c-table tr > *:last-child {\n --pf-c-table--cell--PaddingRight: var(--pf-c-table--cell--first-last-child--PaddingRight); }\n .pf-c-table tr > *.pf-m-center {\n text-align: center; }\n .pf-c-table tr > *:empty {\n width: auto;\n min-width: 0;\n padding: 0; }\n .pf-c-table tr > *.pf-m-help {\n --pf-c-table--cell--MinWidth: var(--pf-c-table--cell--m-help--MinWidth); }\n .pf-c-table tr > *.pf-m-favorite {\n --pf-c-table__button--Color: var(--pf-c-table--cell--m-favorite--Color);\n --pf-c-table__sort--MinWidth: fit-content;\n --pf-c-table--cell--MaxWidth: fit-content;\n --pf-c-table--cell--Overflow: visible; }\n .pf-c-table caption {\n padding-top: var(--pf-c-table-caption--PaddingTop);\n padding-bottom: var(--pf-c-table-caption--PaddingBottom);\n padding-left: var(--pf-c-table-caption--PaddingLeft);\n font-size: var(--pf-c-table-caption--FontSize);\n color: var(--pf-c-table-caption--Color);\n text-align: left;\n background-color: var(--pf-c-table--BackgroundColor); }\n .pf-c-table thead {\n --pf-c-table--cell--FontSize: var(--pf-c-table--thead--cell--FontSize);\n --pf-c-table--cell--FontWeight: var(--pf-c-table--thead--cell--FontWeight);\n vertical-align: bottom; }\n .pf-c-table tbody {\n --pf-c-table--cell--PaddingTop: var(--pf-c-table--tbody--cell--PaddingTop);\n --pf-c-table--cell--PaddingBottom: var(--pf-c-table--tbody--cell--PaddingBottom); }\n .pf-c-table tbody > tr > * {\n overflow-wrap: break-word;\n vertical-align: baseline; }\n .pf-c-table tbody > tr > :first-child::after {\n position: absolute;\n top: var(--pf-c-table__expandable-row--after--Top);\n bottom: var(--pf-c-table__expandable-row--after--Bottom);\n left: 0;\n content: \"\";\n background-color: transparent;\n border-left: var(--pf-c-table__expandable-row--after--BorderLeftWidth) solid var(--pf-c-table__expandable-row--after--BorderColor); }\n .pf-c-table tbody .pf-c-table__check > input {\n margin-top: var(--pf-c-table__check--input--MarginTop);\n vertical-align: top; }\n .pf-c-table .pf-c-table__compound-expansion-toggle, .pf-c-table .pf-c-table__compound-expansion-toggle:first-child, .pf-c-table .pf-c-table__compound-expansion-toggle:last-child {\n padding: 0; }\n .pf-c-table .pf-c-table__sort {\n min-width: var(--pf-c-table__sort--MinWidth); }\n .pf-c-table .pf-m-help {\n min-width: var(--pf-c-table--th--m-help--MinWidth); }\n .pf-c-table thead,\n .pf-c-table .pf-m-truncate {\n --pf-c-table--cell--MinWidth: var(--pf-c-table--m-truncate--cell--MinWidth);\n --pf-c-table--cell--MaxWidth: var(--pf-c-table--m-truncate--cell--MaxWidth);\n --pf-c-table--cell--Overflow: hidden;\n --pf-c-table--cell--TextOverflow: ellipsis;\n --pf-c-table--cell--WhiteSpace: nowrap; }\n .pf-c-table .pf-m-wrap {\n --pf-c-table--cell--MinWidth: 0;\n --pf-c-table--cell--MaxWidth: none;\n --pf-c-table--cell--Overflow: visible;\n --pf-c-table--cell--TextOverflow: clip;\n --pf-c-table--cell--WhiteSpace: normal; }\n .pf-c-table .pf-m-nowrap {\n --pf-c-table--cell--MinWidth: 0;\n --pf-c-table--cell--MaxWidth: none;\n --pf-c-table--cell--Overflow: visible;\n --pf-c-table--cell--TextOverflow: clip;\n --pf-c-table--cell--WhiteSpace: nowrap; }\n .pf-c-table .pf-c-table__icon,\n .pf-c-table .pf-m-fit-content {\n --pf-c-table--cell--MinWidth: fit-content;\n --pf-c-table--cell--MaxWidth: fit-content;\n --pf-c-table--cell--Width: 1%;\n --pf-c-table--cell--Overflow: visible;\n --pf-c-table--cell--TextOverflow: clip;\n --pf-c-table--cell--WhiteSpace: nowrap; }\n .pf-c-table .pf-m-break-word {\n --pf-c-table--cell--WordBreak: break-word;\n --pf-c-table--cell--WhiteSpace: normal; }\n .pf-c-table.pf-m-no-border-rows > tbody > tr {\n border-bottom: 0; }\n .pf-c-table.pf-m-no-border-rows > tbody > tr > :first-child::after {\n border-left: 0; }\n .pf-c-table.pf-m-no-border-rows > tbody:not(.pf-m-expanded) .pf-c-table__compound-expansion-toggle .pf-c-table__button::before {\n display: none; }\n .pf-c-table.pf-m-no-border-rows > tbody.pf-m-expanded > .pf-c-table__control-row {\n border-bottom: var(--pf-c-table--border-width--base) solid var(--pf-c-table--BorderColor); }\n .pf-c-table.pf-m-no-border-rows > tbody .pf-c-table__control-row > .pf-c-table__compound-expansion-toggle:first-child > ::before {\n border-left-width: 0; }\n\n.pf-c-table__text {\n --pf-c-table--cell--MaxWidth: 100%;\n position: relative;\n display: block;\n width: var(--pf-c-table--cell--Width);\n min-width: var(--pf-c-table--cell--MinWidth);\n max-width: var(--pf-c-table--cell--MaxWidth);\n overflow: var(--pf-c-table--cell--Overflow);\n text-overflow: var(--pf-c-table--cell--TextOverflow);\n word-break: var(--pf-c-table--cell--WordBreak);\n white-space: var(--pf-c-table--cell--WhiteSpace); }\n .pf-c-table__text.pf-m-truncate {\n --pf-c-table--cell--MinWidth: 100%; }\n .pf-c-table__text.pf-m-truncate > * {\n overflow: var(--pf-c-table--cell--Overflow);\n text-overflow: var(--pf-c-table--cell--TextOverflow);\n white-space: var(--pf-c-table--cell--WhiteSpace); }\n\n.pf-c-table__button {\n position: static;\n width: 100%;\n padding: var(--pf-c-table--cell--PaddingTop) var(--pf-c-table--cell--PaddingRight) var(--pf-c-table--cell--PaddingBottom) var(--pf-c-table--cell--PaddingLeft);\n font-size: inherit;\n font-weight: inherit;\n color: var(--pf-c-table__button--Color);\n text-align: left;\n white-space: inherit;\n user-select: text;\n background-color: var(--pf-c-table__button--BackgroundColor);\n border: 0; }\n .pf-c-table__button::before {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n cursor: pointer;\n content: \"\"; }\n .pf-c-table__button:hover {\n color: var(--pf-c-table__button--hover--Color); }\n .pf-c-table__button:focus {\n color: var(--pf-c-table__button--focus--Color); }\n .pf-c-table__button:active {\n color: var(--pf-c-table__button--active--Color); }\n\n.pf-c-table__sort .pf-c-table__text,\n.pf-c-table__compound-expansion-toggle .pf-c-table__text {\n display: block;\n width: auto;\n overflow: var(--pf-c-table--cell--Overflow);\n text-overflow: var(--pf-c-table--cell--TextOverflow);\n white-space: var(--pf-c-table--cell--WhiteSpace); }\n\n.pf-c-table__sort .pf-c-table__text {\n --pf-c-table--cell--MinWidth: 0; }\n\n.pf-c-table__button-content,\n.pf-c-table__column-help {\n display: inline-grid;\n align-items: end;\n justify-content: start;\n grid-template-columns: auto max-content; }\n .pf-c-table__button-content .pf-c-table__text,\n .pf-c-table__column-help .pf-c-table__text {\n min-width: auto; }\n .pf-c-table thead.pf-m-nowrap .pf-c-table__button-content,\n .pf-c-table tr.pf-m-nowrap .pf-c-table__button-content,\n .pf-c-table th.pf-m-nowrap .pf-c-table__button-content, .pf-c-table thead.pf-m-nowrap\n .pf-c-table__column-help,\n .pf-c-table tr.pf-m-nowrap\n .pf-c-table__column-help,\n .pf-c-table th.pf-m-nowrap\n .pf-c-table__column-help {\n grid-template-columns: min-content max-content; }\n .pf-c-table thead.pf-m-fit-content .pf-c-table__button-content,\n .pf-c-table tr.pf-m-fit-content .pf-c-table__button-content,\n .pf-c-table th.pf-m-fit-content .pf-c-table__button-content, .pf-c-table thead.pf-m-fit-content\n .pf-c-table__column-help,\n .pf-c-table tr.pf-m-fit-content\n .pf-c-table__column-help,\n .pf-c-table th.pf-m-fit-content\n .pf-c-table__column-help {\n grid-template-columns: fit-content max-content; }\n .pf-c-table thead.pf-m-wrap .pf-c-table__button-content,\n .pf-c-table tr.pf-m-wrap .pf-c-table__button-content,\n .pf-c-table th.pf-m-wrap .pf-c-table__button-content,\n .pf-c-table thead.pf-m-truncate .pf-c-table__button-content,\n .pf-c-table tr.pf-m-truncate .pf-c-table__button-content,\n .pf-c-table th.pf-m-truncate .pf-c-table__button-content, .pf-c-table thead.pf-m-wrap\n .pf-c-table__column-help,\n .pf-c-table tr.pf-m-wrap\n .pf-c-table__column-help,\n .pf-c-table th.pf-m-wrap\n .pf-c-table__column-help,\n .pf-c-table thead.pf-m-truncate\n .pf-c-table__column-help,\n .pf-c-table tr.pf-m-truncate\n .pf-c-table__column-help,\n .pf-c-table th.pf-m-truncate\n .pf-c-table__column-help {\n grid-template-columns: auto max-content; }\n\n.pf-c-table .pf-c-table__toggle,\n.pf-c-table .pf-c-table__action,\n.pf-c-table .pf-c-table__inline-edit-action {\n --pf-c-table--cell--PaddingBottom: 0; }\n\n.pf-c-table .pf-c-table__check,\n.pf-c-table .pf-c-table__toggle,\n.pf-c-table .pf-c-table__action,\n.pf-c-table .pf-c-table__favorite,\n.pf-c-table th.pf-m-favorite,\n.pf-c-table .pf-c-table__inline-edit-action {\n --pf-c-table--cell--MinWidth: 0;\n --pf-c-table--cell--Width: 1%; }\n\n.pf-c-table__toggle {\n --pf-c-table--cell--PaddingRight: 0;\n --pf-c-table--cell--PaddingLeft: 0;\n vertical-align: top; }\n .pf-c-table__toggle .pf-c-button {\n margin-top: var(--pf-c-table__toggle--c-button--MarginTop); }\n .pf-c-table__toggle .pf-c-button.pf-m-expanded .pf-c-table__toggle-icon {\n transform: rotate(var(--pf-c-table__toggle--c-button--m-expanded__toggle-icon--Rotate)); }\n .pf-c-table__toggle .pf-c-table__toggle-icon {\n transition: var(--pf-c-table__toggle--c-button__toggle-icon--Transition);\n transform: rotate(var(--pf-c-table__toggle--c-button__toggle-icon--Rotate)); }\n .pf-c-table__toggle svg {\n pointer-events: none; }\n\n.pf-c-table__check {\n --pf-c-table--cell--FontSize: var(--pf-c-table__check--input--FontSize); }\n\n.pf-c-table__favorite .pf-c-button {\n --pf-c-button--m-plain--Color: var(--pf-c-table__favorite--c-button--Color);\n --pf-c-button--FontSize: var(--pf-c-table__favorite--c-button--FontSize);\n margin: var(--pf-c-table__favorite--c-button--MarginTop) var(--pf-c-table__favorite--c-button--MarginRight) var(--pf-c-table__favorite--c-button--MarginBottom) var(--pf-c-table__favorite--c-button--MarginLeft); }\n .pf-m-favorited.pf-c-table__favorite .pf-c-button {\n --pf-c-button--m-plain--Color: var(--pf-c-table__favorite--m-favorited--c-button--Color); }\n\n.pf-c-table__action,\n.pf-c-table__inline-edit-action {\n --pf-c-table--cell--PaddingTop: 0;\n --pf-c-table--cell--PaddingRight: var(--pf-c-table__action--PaddingRight);\n --pf-c-table--cell--PaddingBottom: 0;\n --pf-c-table--cell--PaddingLeft: var(--pf-c-table__action--PaddingLeft);\n padding-top: 0;\n padding-bottom: 0;\n vertical-align: middle; }\n\n.pf-c-table__inline-edit-action {\n --pf-c-table--cell--PaddingLeft: 0;\n --pf-c-table--cell--PaddingRight: 0;\n text-align: right; }\n\n.pf-c-table__compound-expansion-toggle {\n --pf-c-table__button--Color: var(--pf-c-table__compound-expansion-toggle__button--Color);\n --pf-c-table__button--hover--Color: var(--pf-c-table__compound-expansion-toggle__button--hover--Color);\n --pf-c-table__button--focus--Color: var(--pf-c-table__compound-expansion-toggle__button--focus--Color);\n --pf-c-table__button--active--Color: var(--pf-c-table__compound-expansion-toggle__button--active--Color);\n position: relative; }\n .pf-c-table__compound-expansion-toggle.pf-m-truncate {\n overflow: visible; }\n .pf-c-table__compound-expansion-toggle .pf-c-table__button {\n min-width: 100%;\n overflow: hidden; }\n .pf-c-table__compound-expansion-toggle .pf-c-table__button:hover, .pf-c-table__compound-expansion-toggle .pf-c-table__button:focus, .pf-c-table__compound-expansion-toggle .pf-c-table__button:active {\n outline: 0; }\n .pf-c-table__compound-expansion-toggle .pf-c-table__button::before,\n .pf-c-table__compound-expansion-toggle .pf-c-table__button::after {\n position: absolute;\n right: 0;\n content: \"\";\n border-style: solid;\n border-width: 0; }\n .pf-c-table__compound-expansion-toggle .pf-c-table__button::before {\n top: 0;\n bottom: var(--pf-c-table__compound-expansion-toggle__button--before--Bottom);\n left: var(--pf-c-table__compound-expansion-toggle__button--before--Left);\n border-color: var(--pf-c-table__compound-expansion-toggle__button--before--BorderColor);\n border-right-width: var(--pf-c-table__compound-expansion-toggle__button--before--BorderRightWidth);\n border-left-width: var(--pf-c-table__compound-expansion-toggle__button--before--BorderLeftWidth); }\n .pf-c-table__compound-expansion-toggle .pf-c-table__button::after {\n top: var(--pf-c-table__compound-expansion-toggle__button--after--Top);\n left: var(--pf-c-table__compound-expansion-toggle__button--after--Left);\n pointer-events: none;\n border-color: var(--pf-c-table__compound-expansion-toggle__button--after--BorderColor);\n border-top-width: var(--pf-c-table__compound-expansion-toggle__button--after--BorderTopWidth); }\n .pf-c-table__compound-expansion-toggle:hover, .pf-c-table__compound-expansion-toggle:focus-within, .pf-c-table__compound-expansion-toggle.pf-m-expanded {\n --pf-c-table__compound-expansion-toggle__button--before--BorderRightWidth: var(--pf-c-table__compound-expansion-toggle__button--before--border-width--base);\n --pf-c-table__compound-expansion-toggle__button--before--BorderLeftWidth: var(--pf-c-table__compound-expansion-toggle__button--before--border-width--base);\n --pf-c-table__compound-expansion-toggle__button--after--BorderTopWidth: var(--pf-c-table__compound-expansion-toggle__button--after--border-width--base); }\n .pf-c-table__compound-expansion-toggle:first-child {\n --pf-c-table__compound-expansion-toggle__button--before--Left: 0;\n --pf-c-table__compound-expansion-toggle__button--after--Left: 0; }\n .pf-c-table__compound-expansion-toggle.pf-m-expanded .pf-c-table__button::before {\n border-bottom: var(--pf-c-table--BackgroundColor) solid var(--pf-c-table__compound-expansion-toggle__button--before--border-width--base); }\n .pf-c-table__compound-expansion-toggle.pf-m-expanded:first-child {\n --pf-c-table__compound-expansion-toggle__button--before--BorderLeftWidth: 0; }\n .pf-c-table__compound-expansion-toggle:focus-within {\n outline-offset: var(--pf-c-table__button--OutlineOffset); }\n @media (-webkit-min-device-pixel-ratio: 0) {\n .pf-c-table__compound-expansion-toggle:focus-within {\n outline-style: auto;\n outline-color: -webkit-focus-ring-color; } }\n\n.pf-c-table__column-help-action {\n margin-left: var(--pf-c-table__column-help--MarginLeft);\n transform: translateY(var(--pf-c-table__column-help--TranslateY)); }\n .pf-c-table__column-help-action .pf-c-button {\n --pf-c-button--PaddingRight: var(--pf-c-table__column-help--c-button--PaddingRight);\n --pf-c-button--PaddingLeft: var(--pf-c-table__column-help--c-button--PaddingLeft);\n margin-top: var(--pf-c-table__column-help--c-button--MarginTop);\n margin-bottom: var(--pf-c-table__column-help--c-button--MarginBottom);\n font-size: inherit;\n line-height: 1; }\n\n.pf-c-table__sort .pf-c-table__button {\n --pf-c-table--cell--PaddingTop: var(--pf-c-table__sort__button--PaddingTop);\n --pf-c-table--cell--PaddingRight: var(--pf-c-table__sort__button--PaddingRight);\n --pf-c-table--cell--PaddingBottom: var(--pf-c-table__sort__button--PaddingBottom);\n --pf-c-table--cell--PaddingLeft: var(--pf-c-table__sort__button--PaddingLeft);\n display: flex;\n width: auto;\n margin-top: var(--pf-c-table__sort__button--MarginTop);\n margin-bottom: var(--pf-c-table__sort__button--MarginBottom);\n margin-left: var(--pf-c-table__sort__button--MarginLeft); }\n .pf-c-table__sort .pf-c-table__button:hover {\n --pf-c-table__sort-indicator--Color: var(--pf-c-table__sort__button--hover__sort-indicator--Color);\n --pf-c-table__sort__button__text--Color: var(--pf-c-table__sort__button--hover__text--Color); }\n .pf-c-table__sort .pf-c-table__button:focus {\n --pf-c-table__sort-indicator--Color: var(--pf-c-table__sort__button--focus__sort-indicator--Color);\n --pf-c-table__sort__button__text--Color: var(--pf-c-table__sort__button--focus__text--Color); }\n .pf-c-table__sort .pf-c-table__button:active {\n --pf-c-table__sort-indicator--Color: var(--pf-c-table__sort__button--active__sort-indicator--Color);\n --pf-c-table__sort__button__text--Color: var(--pf-c-table__sort__button--active__text--Color); }\n .pf-c-table__sort .pf-c-table__button .pf-c-table__text {\n color: var(--pf-c-table__sort__button__text--Color); }\n\n.pf-c-table__sort.pf-m-selected .pf-c-table__button {\n --pf-c-table__sort-indicator--Color: var(--pf-c-table__sort--m-selected__sort-indicator--Color);\n --pf-c-table__sort__button__text--Color: var(--pf-c-table__sort--m-selected__button__text--Color);\n color: var(--pf-c-table__sort--m-selected__button--Color); }\n\n.pf-c-table__sort.pf-m-help {\n --pf-c-table--th--m-help--MinWidth: var(--pf-c-table__sort--m-help--MinWidth); }\n\n.pf-c-table__sort.pf-m-favorite {\n --pf-c-table__sort__button__text--Color: var(--pf-c-table__sort--m-favorite__button__text--Color);\n --pf-c-table__sort__button--hover__text--Color: var(--pf-c-table__sort--m-favorite__button--hover__text--Color);\n --pf-c-table__sort__button--focus__text--Color: var(--pf-c-table__sort--m-favorite__button--focus__text--Color);\n --pf-c-table__sort__button--active__text--Color: var(--pf-c-table__sort--m-favorite__button--active__text--Color);\n --pf-c-table__sort--m-selected__button__text--Color: currentColor; }\n\n.pf-c-table__sort-indicator {\n grid-column: 2;\n margin-left: var(--pf-c-table__sort-indicator--MarginLeft);\n color: var(--pf-c-table__sort-indicator--Color);\n pointer-events: none; }\n\n.pf-c-table__expandable-row {\n --pf-c-table--cell--PaddingTop: 0;\n --pf-c-table--cell--PaddingBottom: 0;\n position: relative;\n border-bottom: 0 solid transparent;\n box-shadow: 0 0 0 0 transparent; }\n .pf-c-table__expandable-row,\n .pf-c-table__expandable-row td:first-child::after {\n transition: var(--pf-c-table__expandable-row--Transition); }\n .pf-c-table__expandable-row td.pf-m-no-padding,\n .pf-c-table__expandable-row th.pf-m-no-padding {\n padding: 0 0 0 var(--pf-c-table__expandable-row--after--border-width--base); }\n .pf-c-table__expandable-row td.pf-m-no-padding .pf-c-table__expandable-row-content,\n .pf-c-table__expandable-row th.pf-m-no-padding .pf-c-table__expandable-row-content {\n padding: 0; }\n .pf-c-table__expandable-row .pf-c-table__expandable-row-content {\n padding-top: var(--pf-c-table__expandable-row-content--PaddingTop);\n padding-bottom: var(--pf-c-table__expandable-row-content--PaddingBottom); }\n .pf-c-table__expandable-row.pf-m-expanded {\n border-bottom-color: var(--pf-c-table__expandable-row--m-expanded--BorderBottomColor);\n border-bottom-width: var(--pf-c-table--border-width--base);\n box-shadow: var(--pf-c-table__expandable-row--m-expanded--BoxShadow); }\n .pf-c-table__expandable-row:not(.pf-m-expanded) {\n display: none;\n visibility: hidden; }\n\n.pf-c-table__compound-expansion-toggle.pf-m-expanded:first-child,\n.pf-c-table__expandable-row.pf-m-expanded > :first-child,\n.pf-c-table tbody.pf-m-expanded > tr > :not(.pf-c-table__compound-expansion-toggle) {\n --pf-c-table__expandable-row--after--BorderLeftWidth: var(--pf-c-table__expandable-row--after--border-width--base); }\n\n.pf-c-table .pf-c-table tr > *:first-child {\n --pf-c-table--cell--PaddingLeft: var(--pf-c-table--nested--first-last-child--PaddingLeft); }\n\n.pf-c-table .pf-c-table tr > *:last-child {\n --pf-c-table--cell--PaddingRight: var(--pf-c-table--nested--first-last-child--PaddingRight); }\n\n.pf-c-table.pf-m-compact {\n --pf-c-table--cell--FontSize: var(--pf-c-table--m-compact--FontSize);\n --pf-c-table--cell--PaddingTop: var(--pf-c-table--m-compact--cell--PaddingTop);\n --pf-c-table--cell--PaddingRight: var(--pf-c-table--m-compact--cell--PaddingRight);\n --pf-c-table--cell--PaddingBottom: var(--pf-c-table--m-compact--cell--PaddingBottom);\n --pf-c-table--cell--PaddingRight: var(--pf-c-table--m-compact--cell--PaddingLeft); }\n .pf-c-table.pf-m-compact tr {\n --pf-c-table--cell--PaddingLeft: var(--pf-c-table--m-compact--cell--PaddingLeft);\n --pf-c-table--cell--PaddingRight: var(--pf-c-table--m-compact--cell--PaddingRight); }\n .pf-c-table.pf-m-compact tr:not(.pf-c-table__expandable-row) {\n --pf-c-table--cell--FontSize: var(--pf-c-table--m-compact--FontSize);\n --pf-c-table--cell--PaddingTop: var(--pf-c-table--m-compact--cell--PaddingTop);\n --pf-c-table--cell--PaddingBottom: var(--pf-c-table--m-compact--cell--PaddingBottom); }\n .pf-c-table.pf-m-compact tr:not(.pf-c-table__expandable-row) > *:first-child {\n --pf-c-table--cell--PaddingLeft: var(--pf-c-table--m-compact--cell--first-last-child--PaddingLeft); }\n .pf-c-table.pf-m-compact tr:not(.pf-c-table__expandable-row) > *:last-child {\n --pf-c-table--cell--PaddingRight: var(--pf-c-table--m-compact--cell--first-last-child--PaddingRight); }\n .pf-c-table.pf-m-compact thead th {\n --pf-c-table--cell--PaddingTop: var(--pf-c-table--m-compact-th--PaddingTop);\n --pf-c-table--cell--PaddingBottom: var(--pf-c-table--m-compact-th--PaddingBottom); }\n .pf-c-table.pf-m-compact .pf-c-table__action {\n --pf-c-table--cell--PaddingTop: var(--pf-c-table__action--PaddingTop);\n --pf-c-table--cell--PaddingBottom: var(--pf-c-table__action--PaddingBottom);\n --pf-c-table--cell--PaddingLeft: var(--pf-c-table__action--PaddingLeft); }\n .pf-c-table.pf-m-compact .pf-c-table__toggle {\n --pf-c-table--cell--PaddingTop: var(--pf-c-table--m-compact__toggle--PaddingTop);\n --pf-c-table--cell--PaddingBottom: var(--pf-c-table--m-compact__toggle--PaddingBottom); }\n .pf-c-table.pf-m-compact .pf-c-table__icon {\n width: auto;\n min-width: 0;\n text-align: center; }\n .pf-c-table .pf-c-table.pf-m-compact tr > *:first-child {\n --pf-c-table--cell--PaddingLeft: var(--pf-c-table--nested--first-last-child--PaddingLeft); }\n .pf-c-table .pf-c-table.pf-m-compact tr > *:last-child {\n --pf-c-table--cell--PaddingRight: var(--pf-c-table--nested--first-last-child--PaddingRight); }\n .pf-c-table.pf-m-compact .pf-c-table__expandable-row-content {\n --pf-c-table__expandable-row-content--PaddingTop: var(--pf-c-table--m-compact__expandable-row-content--PaddingTop);\n --pf-c-table__expandable-row-content--PaddingBottom: var(--pf-c-table--m-compact__expandable-row-content--PaddingBottom); }\n\n.pf-c-table__icon-inline {\n display: flex;\n align-items: center; }\n .pf-c-table__icon-inline > :not(:last-child) {\n margin-right: var(--pf-c-table__icon-inline--MarginRight); }\n\n.pf-c-table .pf-m-width-10 {\n --pf-c-table--cell--Width: 10%; }\n\n.pf-c-table .pf-m-width-15 {\n --pf-c-table--cell--Width: 15%; }\n\n.pf-c-table .pf-m-width-20 {\n --pf-c-table--cell--Width: 20%; }\n\n.pf-c-table .pf-m-width-25 {\n --pf-c-table--cell--Width: 25%; }\n\n.pf-c-table .pf-m-width-30 {\n --pf-c-table--cell--Width: 30%; }\n\n.pf-c-table .pf-m-width-35 {\n --pf-c-table--cell--Width: 35%; }\n\n.pf-c-table .pf-m-width-40 {\n --pf-c-table--cell--Width: 40%; }\n\n.pf-c-table .pf-m-width-45 {\n --pf-c-table--cell--Width: 45%; }\n\n.pf-c-table .pf-m-width-50 {\n --pf-c-table--cell--Width: 50%; }\n\n.pf-c-table .pf-m-width-60 {\n --pf-c-table--cell--Width: 60%; }\n\n.pf-c-table .pf-m-width-70 {\n --pf-c-table--cell--Width: 70%; }\n\n.pf-c-table .pf-m-width-80 {\n --pf-c-table--cell--Width: 80%; }\n\n.pf-c-table .pf-m-width-90 {\n --pf-c-table--cell--Width: 90%; }\n\n.pf-c-table .pf-m-width-100 {\n --pf-c-table--cell--Width: 100%; }\n\n.pf-c-tabs {\n --pf-c-tabs--inset: 0;\n --pf-c-tabs--before--BorderColor: var(--pf-global--BorderColor--100);\n --pf-c-tabs--before--border-width--base: var(--pf-global--BorderWidth--sm);\n --pf-c-tabs--before--BorderTopWidth: 0;\n --pf-c-tabs--before--BorderRightWidth: 0;\n --pf-c-tabs--before--BorderBottomWidth: var(--pf-c-tabs--before--border-width--base);\n --pf-c-tabs--before--BorderLeftWidth: 0;\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--lg);\n --pf-c-tabs--m-vertical--MaxWidth: 15.625rem;\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--xl);\n --pf-c-tabs--m-box__item--m-current--first-child__link--before--BorderLeftWidth: var(--pf-c-tabs__link--before--border-width--base);\n --pf-c-tabs--m-box__item--m-current--last-child__link--before--BorderRightWidth: var(--pf-c-tabs--before--border-width--base);\n --pf-c-tabs--m-color-scheme--light-300__link--BackgroundColor: transparent;\n --pf-c-tabs--m-color-scheme--light-300__item--m-current__link--BackgroundColor: var(--pf-global--BackgroundColor--light-300);\n --pf-c-tabs__link--Color: var(--pf-global--Color--200);\n --pf-c-tabs__link--FontSize: var(--pf-global--FontSize--md);\n --pf-c-tabs__link--BackgroundColor: transparent;\n --pf-c-tabs__link--OutlineOffset: calc(-1 * 0.375rem);\n --pf-c-tabs__link--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-tabs__link--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-tabs__link--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-tabs__link--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-tabs__item--m-current__link--Color: var(--pf-global--Color--100);\n --pf-c-tabs__item--m-current__link--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-tabs--m-vertical__link--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-tabs--m-vertical__link--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-tabs--m-box__link--BackgroundColor: var(--pf-global--BackgroundColor--200);\n --pf-c-tabs--m-secondary__link--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-tabs__link--before--border-color--base: var(--pf-global--BorderColor--100);\n --pf-c-tabs__link--before--BorderRightColor: var(--pf-c-tabs__link--before--border-color--base);\n --pf-c-tabs__link--before--BorderBottomColor: var(--pf-c-tabs__link--before--border-color--base);\n --pf-c-tabs__link--before--border-width--base: var(--pf-global--BorderWidth--sm);\n --pf-c-tabs__link--before--BorderTopWidth: 0;\n --pf-c-tabs__link--before--BorderRightWidth: 0;\n --pf-c-tabs__link--before--BorderBottomWidth: 0;\n --pf-c-tabs__link--before--BorderLeftWidth: 0;\n --pf-c-tabs__link--before--Left: calc(var(--pf-c-tabs__link--before--border-width--base) * -1);\n --pf-c-tabs__link--after--Top: auto;\n --pf-c-tabs__link--after--Right: 0;\n --pf-c-tabs__link--after--Bottom: 0;\n --pf-c-tabs__link--after--BorderColor: var(--pf-global--BorderColor--light-100);\n --pf-c-tabs__link--after--BorderWidth: 0;\n --pf-c-tabs__link--after--BorderTopWidth: 0;\n --pf-c-tabs__link--after--BorderRightWidth: 0;\n --pf-c-tabs__link--after--BorderLeftWidth: 0;\n --pf-c-tabs__link--hover--after--BorderWidth: var(--pf-global--BorderWidth--lg);\n --pf-c-tabs__link--focus--after--BorderWidth: var(--pf-global--BorderWidth--lg);\n --pf-c-tabs__link--active--after--BorderWidth: var(--pf-global--BorderWidth--lg);\n --pf-c-tabs__item--m-current__link--after--BorderColor: var(--pf-global--active-color--100);\n --pf-c-tabs__item--m-current__link--after--BorderWidth: var(--pf-global--BorderWidth--lg);\n --pf-c-tabs__link--child--MarginRight: var(--pf-global--spacer--md);\n --pf-c-tabs__scroll-button--Color: var(--pf-global--Color--100);\n --pf-c-tabs__scroll-button--hover--Color: var(--pf-global--active-color--100);\n --pf-c-tabs__scroll-button--disabled--Color: var(--pf-global--disabled-color--200);\n --pf-c-tabs__scroll-button--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-tabs__scroll-button--Width: var(--pf-global--spacer--2xl);\n --pf-c-tabs__scroll-button--xl--Width: var(--pf-global--spacer--3xl);\n --pf-c-tabs__scroll-button--OutlineOffset: calc(-1 * var(--pf-global--spacer--xs));\n --pf-c-tabs__scroll-button--TransitionDuration--margin: .125s;\n --pf-c-tabs__scroll-button--TransitionDuration--transform: .125s;\n --pf-c-tabs__scroll-button--TransitionDuration--opacity: .125s;\n --pf-c-tabs__scroll-button--before--BorderColor: var(--pf-c-tabs--before--BorderColor);\n --pf-c-tabs__scroll-button--before--border-width--base: var(--pf-global--BorderWidth--sm);\n --pf-c-tabs__scroll-button--before--BorderRightWidth: 0;\n --pf-c-tabs__scroll-button--before--BorderBottomWidth: var(--pf-c-tabs__scroll-button--before--border-width--base);\n --pf-c-tabs__scroll-button--before--BorderLeftWidth: 0;\n position: relative;\n display: flex;\n padding-right: var(--pf-c-tabs--inset);\n padding-left: var(--pf-c-tabs--inset);\n overflow: hidden; }\n @media screen and (min-width: 1200px) {\n .pf-c-tabs {\n --pf-c-tabs__scroll-button--Width: var(--pf-c-tabs__scroll-button--xl--Width); } }\n .pf-c-tabs::before {\n position: absolute;\n right: 0;\n bottom: 0;\n left: 0;\n border: solid var(--pf-c-tabs--before--BorderColor);\n border-width: var(--pf-c-tabs--before--BorderTopWidth) var(--pf-c-tabs--before--BorderRightWidth) var(--pf-c-tabs--before--BorderBottomWidth) var(--pf-c-tabs--before--BorderLeftWidth); }\n .pf-c-tabs.pf-m-fill .pf-c-tabs__list {\n flex-basis: 100%; }\n .pf-c-tabs.pf-m-fill .pf-c-tabs__item {\n flex-grow: 1; }\n .pf-c-tabs.pf-m-fill .pf-c-tabs__item:first-child {\n --pf-c-tabs--m-box__item--m-current--first-child__link--before--BorderLeftWidth: 0; }\n .pf-c-tabs.pf-m-fill .pf-c-tabs__item:last-child {\n --pf-c-tabs--m-box__item--m-current--last-child__link--before--BorderRightWidth: 0; }\n .pf-c-tabs.pf-m-fill .pf-c-tabs__link {\n flex-basis: 100%;\n justify-content: center; }\n .pf-c-tabs.pf-m-scrollable .pf-c-tabs__scroll-button {\n opacity: 1; }\n .pf-c-tabs.pf-m-scrollable .pf-c-tabs__scroll-button:nth-of-type(1) {\n margin-right: 0;\n transform: translateX(0); }\n .pf-c-tabs.pf-m-scrollable .pf-c-tabs__scroll-button:nth-of-type(2) {\n margin-left: 0;\n transform: translateX(0); }\n .pf-c-tabs.pf-m-secondary, .pf-c-tabs.pf-m-no-border-bottom {\n --pf-c-tabs--before--BorderBottomWidth: 0; }\n .pf-c-tabs.pf-m-box .pf-c-tabs__link, .pf-c-tabs.pf-m-vertical .pf-c-tabs__link {\n --pf-c-tabs__link--after--BorderBottomWidth: 0; }\n .pf-c-tabs.pf-m-box {\n --pf-c-tabs__link--BackgroundColor: var(--pf-c-tabs--m-box__link--BackgroundColor);\n --pf-c-tabs__link--before--BorderBottomWidth: var(--pf-c-tabs__link--before--border-width--base);\n --pf-c-tabs__link--before--BorderRightWidth: var(--pf-c-tabs__link--before--border-width--base);\n --pf-c-tabs__link--after--Top: 0;\n --pf-c-tabs__link--after--Bottom: auto; }\n .pf-c-tabs.pf-m-box .pf-c-tabs__link {\n --pf-c-tabs__link--after--BorderTopWidth: var(--pf-c-tabs__link--after--BorderWidth); }\n .pf-c-tabs.pf-m-box .pf-c-tabs__item:last-child {\n --pf-c-tabs__link--before--BorderRightWidth: 0; }\n .pf-c-tabs.pf-m-box .pf-c-tabs__item.pf-m-current {\n --pf-c-tabs__link--BackgroundColor: var(--pf-c-tabs__item--m-current__link--BackgroundColor);\n --pf-c-tabs__link--before--BorderBottomColor: var(--pf-c-tabs__link--BackgroundColor); }\n .pf-c-tabs.pf-m-box .pf-c-tabs__item.pf-m-current:first-child .pf-c-tabs__link::before {\n border-left-width: var(--pf-c-tabs--m-box__item--m-current--first-child__link--before--BorderLeftWidth); }\n .pf-c-tabs.pf-m-box .pf-c-tabs__item.pf-m-current:last-child .pf-c-tabs__link::before {\n border-right-width: var(--pf-c-tabs--m-box__item--m-current--last-child__link--before--BorderRightWidth); }\n .pf-c-tabs.pf-m-box.pf-m-scrollable .pf-c-tabs__item.pf-m-current:first-child .pf-c-tabs__link::before {\n left: calc(var(--pf-c-tabs__link--before--border-width--base) * -1); }\n .pf-c-tabs.pf-m-box.pf-m-scrollable .pf-c-tabs__scroll-button:nth-of-type(2)::before {\n left: calc(var(--pf-c-tabs__link--before--border-width--base) * -1); }\n .pf-c-tabs.pf-m-box .pf-c-tabs__item.pf-m-current + .pf-c-tabs__item {\n --pf-c-tabs__link--before--Left: 0; }\n .pf-c-tabs.pf-m-box.pf-m-color-scheme--light-300 {\n --pf-c-tabs__link--BackgroundColor: var(--pf-c-tabs--m-color-scheme--light-300__link--BackgroundColor);\n --pf-c-tabs__item--m-current__link--BackgroundColor: var(--pf-c-tabs--m-color-scheme--light-300__item--m-current__link--BackgroundColor); }\n .pf-c-tabs.pf-m-vertical {\n --pf-c-tabs--inset: var(--pf-c-tabs--m-vertical--inset);\n --pf-c-tabs--before--BorderBottomWidth: 0;\n --pf-c-tabs--before--BorderLeftWidth: var(--pf-c-tabs--before--border-width--base);\n --pf-c-tabs__link--PaddingTop: var(--pf-c-tabs--m-vertical__link--PaddingTop);\n --pf-c-tabs__link--PaddingBottom: var(--pf-c-tabs--m-vertical__link--PaddingBottom);\n --pf-c-tabs__link--before--Left: 0;\n --pf-c-tabs__link--after--Top: 0;\n --pf-c-tabs__link--after--Bottom: 0;\n --pf-c-tabs__link--after--Right: auto;\n display: inline-flex;\n flex-direction: column;\n height: 100%;\n padding: 0; }\n .pf-c-tabs.pf-m-vertical::before {\n top: 0;\n right: auto; }\n .pf-c-tabs.pf-m-vertical .pf-c-tabs__list {\n flex-direction: column;\n max-width: var(--pf-c-tabs--m-vertical--MaxWidth); }\n .pf-c-tabs.pf-m-vertical .pf-c-tabs__item:first-child {\n margin-top: var(--pf-c-tabs--inset); }\n .pf-c-tabs.pf-m-vertical .pf-c-tabs__item:last-child {\n margin-bottom: var(--pf-c-tabs--inset); }\n .pf-c-tabs.pf-m-vertical .pf-c-tabs__link {\n --pf-c-tabs__link--after--BorderTopWidth: 0;\n --pf-c-tabs__link--after--BorderLeftWidth: var(--pf-c-tabs__link--after--BorderWidth);\n max-width: 100%;\n text-align: left; }\n .pf-c-tabs.pf-m-vertical .pf-c-tabs__item-text {\n max-width: 100%;\n overflow-wrap: break-word; }\n .pf-c-tabs.pf-m-box.pf-m-vertical {\n --pf-c-tabs--inset: var(--pf-c-tabs--m-vertical--m-box--inset);\n --pf-c-tabs--before--BorderLeftWidth: 0;\n --pf-c-tabs--before--BorderRightWidth: var(--pf-c-tabs--before--border-width--base); }\n .pf-c-tabs.pf-m-box.pf-m-vertical::before {\n right: 0;\n left: auto; }\n .pf-c-tabs.pf-m-box.pf-m-vertical .pf-c-tabs__item:last-child {\n --pf-c-tabs__link--before--BorderBottomWidth: 0;\n --pf-c-tabs__link--before--BorderRightWidth: var(--pf-c-tabs__link--before--border-width--base); }\n .pf-c-tabs.pf-m-box.pf-m-vertical .pf-c-tabs__item.pf-m-current {\n --pf-c-tabs__link--before--BorderRightColor: var(--pf-c-tabs__item--m-current__link--BackgroundColor);\n --pf-c-tabs__link--before--BorderBottomColor: var(--pf-c-tabs__link--before--border-color--base);\n --pf-c-tabs__link--before--BorderBottomWidth: var(--pf-c-tabs__link--before--border-width--base); }\n .pf-c-tabs.pf-m-box.pf-m-vertical .pf-c-tabs__item.pf-m-current:first-child {\n --pf-c-tabs__link--before--BorderTopWidth: var(--pf-c-tabs__link--before--border-width--base); }\n .pf-c-tabs.pf-m-box.pf-m-vertical .pf-c-tabs__item:first-child.pf-m-current {\n --pf-c-tabs__link--before--BorderTopWidth: var(--pf-c-tabs__link--before--border-width--base); }\n .pf-c-tabs.pf-m-box.pf-m-vertical .pf-c-tabs__link::after {\n top: calc(var(--pf-c-tabs__link--before--border-width--base) * -1); }\n .pf-c-tabs.pf-m-box.pf-m-vertical .pf-c-tabs__item:first-child .pf-c-tabs__link::after,\n .pf-c-tabs.pf-m-box.pf-m-vertical .pf-c-tabs__item.pf-m-current + .pf-c-tabs__item .pf-c-tabs__link::after {\n top: 0; }\n .pf-c-tabs.pf-m-secondary {\n --pf-c-tabs__link--FontSize: var(--pf-c-tabs--m-secondary__link--FontSize); }\n\n.pf-c-tabs__list {\n scrollbar-width: none;\n -ms-overflow-style: -ms-autohiding-scrollbar;\n position: relative;\n display: flex;\n max-width: 100%;\n overflow-x: auto;\n scroll-behavior: smooth;\n -webkit-overflow-scrolling: touch; }\n .pf-c-tabs__list::-webkit-scrollbar {\n display: none; }\n\n.pf-c-tabs__item {\n display: flex;\n flex: none; }\n .pf-c-tabs__item.pf-m-current {\n --pf-c-tabs__link--Color: var(--pf-c-tabs__item--m-current__link--Color);\n --pf-c-tabs__link--after--BorderColor: var(--pf-c-tabs__item--m-current__link--after--BorderColor);\n --pf-c-tabs__link--after--BorderWidth: var(--pf-c-tabs__item--m-current__link--after--BorderWidth); }\n\n.pf-c-tabs__link,\n.pf-c-tabs__scroll-button {\n border: 0; }\n\n.pf-c-tabs::before,\n.pf-c-tabs__link::before,\n.pf-c-tabs__link::after,\n.pf-c-tabs__scroll-button::before {\n position: absolute;\n right: 0;\n bottom: 0;\n left: 0;\n content: \"\";\n border-style: solid; }\n\n.pf-c-tabs__link::before,\n.pf-c-tabs__link::after,\n.pf-c-tabs__scroll-button::before {\n top: 0; }\n\n.pf-c-tabs__link {\n --pf-c-tabs__link--after--BorderBottomWidth: var(--pf-c-tabs__link--after--BorderWidth);\n position: relative;\n display: flex;\n flex: 1;\n padding: var(--pf-c-tabs__link--PaddingTop) var(--pf-c-tabs__link--PaddingRight) var(--pf-c-tabs__link--PaddingBottom) var(--pf-c-tabs__link--PaddingLeft);\n font-size: var(--pf-c-tabs__link--FontSize);\n color: var(--pf-c-tabs__link--Color);\n text-decoration: none;\n background-color: var(--pf-c-tabs__link--BackgroundColor);\n outline-offset: var(--pf-c-tabs__link--OutlineOffset); }\n .pf-c-tabs__link::before {\n pointer-events: none;\n border-color: var(--pf-c-tabs__link--before--border-color--base);\n border-width: var(--pf-c-tabs__link--before--BorderTopWidth) var(--pf-c-tabs__link--before--BorderRightWidth) var(--pf-c-tabs__link--before--BorderBottomWidth) var(--pf-c-tabs__link--before--BorderLeftWidth);\n border-right-color: var(--pf-c-tabs__link--before--BorderRightColor);\n border-bottom-color: var(--pf-c-tabs__link--before--BorderBottomColor); }\n .pf-c-tabs__link::after {\n top: var(--pf-c-tabs__link--after--Top);\n right: var(--pf-c-tabs__link--after--Right);\n bottom: var(--pf-c-tabs__link--after--Bottom);\n left: var(--pf-c-tabs__link--before--Left);\n border-color: var(--pf-c-tabs__link--after--BorderColor);\n border-width: var(--pf-c-tabs__link--after--BorderTopWidth) var(--pf-c-tabs__link--after--BorderRightWidth) var(--pf-c-tabs__link--after--BorderBottomWidth) var(--pf-c-tabs__link--after--BorderLeftWidth); }\n .pf-c-tabs__link:hover {\n --pf-c-tabs__link--after--BorderWidth: var(--pf-c-tabs__link--hover--after--BorderWidth); }\n .pf-c-tabs__link:focus {\n --pf-c-tabs__link--after--BorderWidth: var(--pf-c-tabs__link--focus--after--BorderWidth); }\n .pf-c-tabs__link:active {\n --pf-c-tabs__link--after--BorderWidth: var(--pf-c-tabs__link--active--after--BorderWidth); }\n .pf-c-tabs__link .pf-c-tabs__item-icon,\n .pf-c-tabs__link .pf-c-tabs__item-text {\n margin-right: var(--pf-c-tabs__link--child--MarginRight); }\n .pf-c-tabs__link .pf-c-tabs__item-icon:last-child,\n .pf-c-tabs__link .pf-c-tabs__item-text:last-child {\n --pf-c-tabs__link--child--MarginRight: 0; }\n\n.pf-c-tabs__scroll-button {\n flex: none;\n width: var(--pf-c-tabs__scroll-button--Width);\n line-height: 1;\n color: var(--pf-c-tabs__scroll-button--Color);\n background-color: var(--pf-c-tabs__scroll-button--BackgroundColor);\n outline-offset: var(--pf-c-tabs__scroll-button--OutlineOffset);\n opacity: 0;\n transition: margin var(--pf-c-tabs__scroll-button--TransitionDuration--margin), transform var(--pf-c-tabs__scroll-button--TransitionDuration--transform), opacity var(--pf-c-tabs__scroll-button--TransitionDuration--opacity); }\n .pf-c-tabs__scroll-button:hover, .pf-c-tabs__scroll-button:active, .pf-c-tabs__scroll-button:focus {\n --pf-c-tabs__scroll-button--Color: var(--pf-c-tabs__scroll-button--hover--Color); }\n .pf-c-tabs__scroll-button::before {\n border-color: var(--pf-c-tabs__scroll-button--before--BorderColor);\n border-width: 0 var(--pf-c-tabs__scroll-button--before--BorderRightWidth) var(--pf-c-tabs__scroll-button--before--BorderBottomWidth) var(--pf-c-tabs__scroll-button--before--BorderLeftWidth); }\n .pf-c-tabs__scroll-button:nth-of-type(1) {\n --pf-c-tabs__scroll-button--before--BorderRightWidth: var(--pf-c-tabs__scroll-button--before--border-width--base);\n margin-right: calc(var(--pf-c-tabs__scroll-button--Width) * -1);\n transform: translateX(-100%); }\n .pf-c-tabs__scroll-button:nth-of-type(2) {\n --pf-c-tabs__scroll-button--before--BorderLeftWidth: var(--pf-c-tabs__scroll-button--before--border-width--base);\n margin-left: calc(var(--pf-c-tabs__scroll-button--Width) * -1);\n transform: translateX(100%); }\n .pf-c-tabs__scroll-button:disabled {\n --pf-c-tabs__scroll-button--Color: var(--pf-c-tabs__scroll-button--disabled--Color);\n pointer-events: none; }\n\n.pf-c-tabs.pf-m-inset-none {\n --pf-c-tabs--inset: 0;\n --pf-c-tabs--m-vertical--inset: 0;\n --pf-c-tabs--m-vertical--m-box--inset: 0; }\n\n.pf-c-tabs.pf-m-inset-sm {\n --pf-c-tabs--inset: var(--pf-global--spacer--sm);\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--sm);\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--sm); }\n\n.pf-c-tabs.pf-m-inset-md {\n --pf-c-tabs--inset: var(--pf-global--spacer--md);\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--md);\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--md); }\n\n.pf-c-tabs.pf-m-inset-lg {\n --pf-c-tabs--inset: var(--pf-global--spacer--lg);\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--lg);\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--lg); }\n\n.pf-c-tabs.pf-m-inset-xl {\n --pf-c-tabs--inset: var(--pf-global--spacer--xl);\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--xl);\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--xl); }\n\n.pf-c-tabs.pf-m-inset-2xl {\n --pf-c-tabs--inset: var(--pf-global--spacer--2xl);\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--2xl);\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--2xl); }\n\n@media (min-width: 576px) {\n .pf-c-tabs.pf-m-inset-none-on-sm {\n --pf-c-tabs--inset: 0;\n --pf-c-tabs--m-vertical--inset: 0;\n --pf-c-tabs--m-vertical--m-box--inset: 0; }\n .pf-c-tabs.pf-m-inset-sm-on-sm {\n --pf-c-tabs--inset: var(--pf-global--spacer--sm);\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--sm);\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--sm); }\n .pf-c-tabs.pf-m-inset-md-on-sm {\n --pf-c-tabs--inset: var(--pf-global--spacer--md);\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--md);\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--md); }\n .pf-c-tabs.pf-m-inset-lg-on-sm {\n --pf-c-tabs--inset: var(--pf-global--spacer--lg);\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--lg);\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--lg); }\n .pf-c-tabs.pf-m-inset-xl-on-sm {\n --pf-c-tabs--inset: var(--pf-global--spacer--xl);\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--xl);\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--xl); }\n .pf-c-tabs.pf-m-inset-2xl-on-sm {\n --pf-c-tabs--inset: var(--pf-global--spacer--2xl);\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--2xl);\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--2xl); } }\n\n@media (min-width: 768px) {\n .pf-c-tabs.pf-m-inset-none-on-md {\n --pf-c-tabs--inset: 0;\n --pf-c-tabs--m-vertical--inset: 0;\n --pf-c-tabs--m-vertical--m-box--inset: 0; }\n .pf-c-tabs.pf-m-inset-sm-on-md {\n --pf-c-tabs--inset: var(--pf-global--spacer--sm);\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--sm);\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--sm); }\n .pf-c-tabs.pf-m-inset-md-on-md {\n --pf-c-tabs--inset: var(--pf-global--spacer--md);\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--md);\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--md); }\n .pf-c-tabs.pf-m-inset-lg-on-md {\n --pf-c-tabs--inset: var(--pf-global--spacer--lg);\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--lg);\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--lg); }\n .pf-c-tabs.pf-m-inset-xl-on-md {\n --pf-c-tabs--inset: var(--pf-global--spacer--xl);\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--xl);\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--xl); }\n .pf-c-tabs.pf-m-inset-2xl-on-md {\n --pf-c-tabs--inset: var(--pf-global--spacer--2xl);\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--2xl);\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--2xl); } }\n\n@media (min-width: 992px) {\n .pf-c-tabs.pf-m-inset-none-on-lg {\n --pf-c-tabs--inset: 0;\n --pf-c-tabs--m-vertical--inset: 0;\n --pf-c-tabs--m-vertical--m-box--inset: 0; }\n .pf-c-tabs.pf-m-inset-sm-on-lg {\n --pf-c-tabs--inset: var(--pf-global--spacer--sm);\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--sm);\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--sm); }\n .pf-c-tabs.pf-m-inset-md-on-lg {\n --pf-c-tabs--inset: var(--pf-global--spacer--md);\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--md);\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--md); }\n .pf-c-tabs.pf-m-inset-lg-on-lg {\n --pf-c-tabs--inset: var(--pf-global--spacer--lg);\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--lg);\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--lg); }\n .pf-c-tabs.pf-m-inset-xl-on-lg {\n --pf-c-tabs--inset: var(--pf-global--spacer--xl);\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--xl);\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--xl); }\n .pf-c-tabs.pf-m-inset-2xl-on-lg {\n --pf-c-tabs--inset: var(--pf-global--spacer--2xl);\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--2xl);\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--2xl); } }\n\n@media (min-width: 1200px) {\n .pf-c-tabs.pf-m-inset-none-on-xl {\n --pf-c-tabs--inset: 0;\n --pf-c-tabs--m-vertical--inset: 0;\n --pf-c-tabs--m-vertical--m-box--inset: 0; }\n .pf-c-tabs.pf-m-inset-sm-on-xl {\n --pf-c-tabs--inset: var(--pf-global--spacer--sm);\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--sm);\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--sm); }\n .pf-c-tabs.pf-m-inset-md-on-xl {\n --pf-c-tabs--inset: var(--pf-global--spacer--md);\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--md);\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--md); }\n .pf-c-tabs.pf-m-inset-lg-on-xl {\n --pf-c-tabs--inset: var(--pf-global--spacer--lg);\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--lg);\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--lg); }\n .pf-c-tabs.pf-m-inset-xl-on-xl {\n --pf-c-tabs--inset: var(--pf-global--spacer--xl);\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--xl);\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--xl); }\n .pf-c-tabs.pf-m-inset-2xl-on-xl {\n --pf-c-tabs--inset: var(--pf-global--spacer--2xl);\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--2xl);\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--2xl); } }\n\n@media (min-width: 1450px) {\n .pf-c-tabs.pf-m-inset-none-on-2xl {\n --pf-c-tabs--inset: 0;\n --pf-c-tabs--m-vertical--inset: 0;\n --pf-c-tabs--m-vertical--m-box--inset: 0; }\n .pf-c-tabs.pf-m-inset-sm-on-2xl {\n --pf-c-tabs--inset: var(--pf-global--spacer--sm);\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--sm);\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--sm); }\n .pf-c-tabs.pf-m-inset-md-on-2xl {\n --pf-c-tabs--inset: var(--pf-global--spacer--md);\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--md);\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--md); }\n .pf-c-tabs.pf-m-inset-lg-on-2xl {\n --pf-c-tabs--inset: var(--pf-global--spacer--lg);\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--lg);\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--lg); }\n .pf-c-tabs.pf-m-inset-xl-on-2xl {\n --pf-c-tabs--inset: var(--pf-global--spacer--xl);\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--xl);\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--xl); }\n .pf-c-tabs.pf-m-inset-2xl-on-2xl {\n --pf-c-tabs--inset: var(--pf-global--spacer--2xl);\n --pf-c-tabs--m-vertical--inset: var(--pf-global--spacer--2xl);\n --pf-c-tabs--m-vertical--m-box--inset: var(--pf-global--spacer--2xl); } }\n\n.pf-c-tile {\n --pf-c-tile--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-tile--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-tile--PaddingBottom: var(--pf-global--spacer--lg);\n --pf-c-tile--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-tile--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-tile--before--BorderColor: var(--pf-global--BorderColor--100);\n --pf-c-tile--before--BorderWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-tile--before--BorderRadius: var(--pf-global--BorderRadius--sm);\n --pf-c-tile--hover--before--BorderColor: var(--pf-global--primary-color--100);\n --pf-c-tile--m-selected--before--BorderWidth: var(--pf-global--BorderWidth--md);\n --pf-c-tile--m-selected--before--BorderColor: var(--pf-global--primary-color--100);\n --pf-c-tile--focus--before--BorderWidth: var(--pf-global--BorderWidth--md);\n --pf-c-tile--focus--before--BorderColor: var(--pf-global--primary-color--100);\n --pf-c-tile--m-disabled--BackgroundColor: var(--pf-global--disabled-color--300);\n --pf-c-tile__title--Color: var(--pf-global--Color--100);\n --pf-c-tile--hover__title--Color: var(--pf-global--primary-color--100);\n --pf-c-tile--m-selected__title--Color: var(--pf-global--primary-color--100);\n --pf-c-tile--focus__title--Color: var(--pf-global--primary-color--100);\n --pf-c-tile--m-disabled__title--Color: var(--pf-global--disabled-color--100);\n --pf-c-tile__icon--MarginRight: var(--pf-global--spacer--sm);\n --pf-c-tile__icon--FontSize: var(--pf-global--icon--FontSize--md);\n --pf-c-tile__icon--Color: var(--pf-global--Color--100);\n --pf-c-tile--hover__icon--Color: var(--pf-global--primary-color--100);\n --pf-c-tile--m-selected__icon--Color: var(--pf-global--primary-color--100);\n --pf-c-tile--m-disabled__icon--Color: var(--pf-global--disabled-color--100);\n --pf-c-tile--focus__icon--Color: var(--pf-global--primary-color--100);\n --pf-c-tile__header--m-stacked__icon--MarginBottom: var(--pf-global--spacer--xs);\n --pf-c-tile__header--m-stacked__icon--FontSize: var(--pf-global--icon--FontSize--lg);\n --pf-c-tile--m-display-lg__header--m-stacked__icon--FontSize: var(--pf-global--icon--FontSize--xl);\n --pf-c-tile__body--Color: var(--pf-global--Color--100);\n --pf-c-tile__body--FontSize: var(--pf-global--FontSize--xs);\n --pf-c-tile--m-disabled__body--Color: var(--pf-global--disabled-color--100);\n position: relative;\n display: inline-grid;\n padding: var(--pf-c-tile--PaddingTop) var(--pf-c-tile--PaddingRight) var(--pf-c-tile--PaddingBottom) var(--pf-c-tile--PaddingLeft);\n text-align: center;\n cursor: pointer;\n background-color: var(--pf-c-tile--BackgroundColor);\n grid-template-rows: min-content; }\n .pf-c-tile::before {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n pointer-events: none;\n content: \"\";\n border: var(--pf-c-tile--before--BorderWidth) solid var(--pf-c-tile--before--BorderColor);\n border-radius: var(--pf-c-tile--before--BorderRadius); }\n .pf-c-tile:hover {\n --pf-c-tile__title--Color: var(--pf-c-tile--hover__title--Color);\n --pf-c-tile__icon--Color: var(--pf-c-tile--hover__icon--Color);\n --pf-c-tile--before--BorderColor: var(--pf-c-tile--hover--before--BorderColor); }\n .pf-c-tile.pf-m-selected {\n --pf-c-tile__title--Color: var(--pf-c-tile--m-selected__title--Color);\n --pf-c-tile__icon--Color: var(--pf-c-tile--m-selected__icon--Color);\n --pf-c-tile--before--BorderWidth: var(--pf-c-tile--m-selected--before--BorderWidth);\n --pf-c-tile--before--BorderColor: var(--pf-c-tile--m-selected--before--BorderColor); }\n .pf-c-tile:focus {\n --pf-c-tile__title--Color: var(--pf-c-tile--focus__title--Color);\n --pf-c-tile__icon--Color: var(--pf-c-tile--focus__icon--Color);\n --pf-c-tile--before--BorderWidth: var(--pf-c-tile--focus--before--BorderWidth);\n --pf-c-tile--before--BorderColor: var(--pf-c-tile--focus--before--BorderColor); }\n .pf-c-tile.pf-m-disabled {\n --pf-c-tile--BackgroundColor: var(--pf-c-tile--m-disabled--BackgroundColor);\n --pf-c-tile__title--Color: var(--pf-c-tile--m-disabled__title--Color);\n --pf-c-tile__body--Color: var(--pf-c-tile--m-disabled__body--Color);\n --pf-c-tile--before--BorderWidth: 0;\n --pf-c-tile__icon--Color: var(--pf-c-tile--m-disabled__icon--Color);\n pointer-events: none; }\n .pf-c-tile.pf-m-display-lg .pf-c-tile__header.pf-m-stacked {\n --pf-c-tile__icon--FontSize: var(--pf-c-tile--m-display-lg__header--m-stacked__icon--FontSize); }\n\n.pf-c-tile__header {\n display: flex;\n align-items: center;\n justify-content: center; }\n .pf-c-tile__header.pf-m-stacked {\n --pf-c-tile__icon--MarginRight: 0;\n --pf-c-tile__icon--FontSize: var(--pf-c-tile__header--m-stacked__icon--FontSize);\n flex-direction: column;\n justify-content: initial; }\n .pf-c-tile__header.pf-m-stacked .pf-c-tile__icon {\n display: flex;\n align-items: center;\n justify-content: center;\n margin-bottom: var(--pf-c-tile__header--m-stacked__icon--MarginBottom); }\n\n.pf-c-tile__title {\n color: var(--pf-c-tile__title--Color); }\n\n.pf-c-tile__body {\n font-size: var(--pf-c-tile__body--FontSize);\n color: var(--pf-c-tile__body--Color); }\n\n.pf-c-tile__icon {\n margin-right: var(--pf-c-tile__icon--MarginRight);\n font-size: var(--pf-c-tile__icon--FontSize);\n color: var(--pf-c-tile__icon--Color); }\n\n.pf-c-title {\n --pf-c-title--FontFamily: var(--pf-global--FontFamily--heading--sans-serif);\n --pf-c-title--m-4xl--LineHeight: var(--pf-global--LineHeight--sm);\n --pf-c-title--m-4xl--FontSize: var(--pf-global--FontSize--4xl);\n --pf-c-title--m-4xl--FontWeight: var(--pf-global--FontWeight--normal);\n --pf-c-title--m-3xl--LineHeight: var(--pf-global--LineHeight--sm);\n --pf-c-title--m-3xl--FontSize: var(--pf-global--FontSize--3xl);\n --pf-c-title--m-3xl--FontWeight: var(--pf-global--FontWeight--normal);\n --pf-c-title--m-2xl--LineHeight: var(--pf-global--LineHeight--sm);\n --pf-c-title--m-2xl--FontSize: var(--pf-global--FontSize--2xl);\n --pf-c-title--m-2xl--FontWeight: var(--pf-global--FontWeight--normal);\n --pf-c-title--m-xl--LineHeight: var(--pf-global--LineHeight--md);\n --pf-c-title--m-xl--FontSize: var(--pf-global--FontSize--xl);\n --pf-c-title--m-xl--FontWeight: var(--pf-global--FontWeight--normal);\n --pf-c-title--m-lg--LineHeight: var(--pf-global--LineHeight--md);\n --pf-c-title--m-lg--FontSize: var(--pf-global--FontSize--lg);\n --pf-c-title--m-lg--FontWeight: var(--pf-global--FontWeight--normal);\n --pf-c-title--m-md--LineHeight: var(--pf-global--LineHeight--md);\n --pf-c-title--m-md--FontSize: var(--pf-global--FontSize--md);\n --pf-c-title--m-md--FontWeight: var(--pf-global--FontWeight--normal);\n font-family: var(--pf-c-title--FontFamily);\n word-break: break-word; }\n .pf-c-title.pf-m-4xl {\n font-size: var(--pf-c-title--m-4xl--FontSize);\n font-weight: var(--pf-c-title--m-4xl--FontWeight);\n line-height: var(--pf-c-title--m-4xl--LineHeight); }\n .pf-c-title.pf-m-3xl {\n font-size: var(--pf-c-title--m-3xl--FontSize);\n font-weight: var(--pf-c-title--m-3xl--FontWeight);\n line-height: var(--pf-c-title--m-3xl--LineHeight); }\n .pf-c-title.pf-m-2xl {\n font-size: var(--pf-c-title--m-2xl--FontSize);\n font-weight: var(--pf-c-title--m-2xl--FontWeight);\n line-height: var(--pf-c-title--m-2xl--LineHeight); }\n .pf-c-title.pf-m-xl {\n font-size: var(--pf-c-title--m-xl--FontSize);\n font-weight: var(--pf-c-title--m-xl--FontWeight);\n line-height: var(--pf-c-title--m-xl--LineHeight); }\n .pf-c-title.pf-m-lg {\n font-size: var(--pf-c-title--m-lg--FontSize);\n font-weight: var(--pf-c-title--m-lg--FontWeight);\n line-height: var(--pf-c-title--m-lg--LineHeight); }\n .pf-c-title.pf-m-md {\n font-size: var(--pf-c-title--m-md--FontSize);\n font-weight: var(--pf-c-title--m-md--FontWeight);\n line-height: var(--pf-c-title--m-md--LineHeight); }\n\n.pf-m-overpass-font .pf-c-title {\n --pf-c-title--m-md--FontWeight: var(--pf-global--FontWeight--semi-bold);\n --pf-c-title--m-lg--FontWeight: var(--pf-global--FontWeight--semi-bold); }\n\n.pf-c-toggle-group {\n --pf-c-toggle-group__button--PaddingTop: var(--pf-global--spacer--form-element);\n --pf-c-toggle-group__button--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-toggle-group__button--PaddingBottom: var(--pf-global--spacer--form-element);\n --pf-c-toggle-group__button--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-toggle-group__button--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-toggle-group__button--LineHeight: calc(var(--pf-global--FontSize--md) * var(--pf-global--LineHeight--md));\n --pf-c-toggle-group__button--Color: var(--pf-global--Color--100);\n --pf-c-toggle-group__button--BackgroundColor: var(--pf-global--BackgroundColor--200);\n --pf-c-toggle-group__button--hover--BackgroundColor: var(--pf-global--disabled-color--200);\n --pf-c-toggle-group__button--focus--BackgroundColor: var(--pf-global--disabled-color--200);\n --pf-c-toggle-group__button--disabled--BackgroundColor: var(--pf-global--disabled-color--200);\n --pf-c-toggle-group__button--disabled--Color: var(--pf-global--disabled-color--100);\n --pf-c-toggle-group__item--first-child__button--BorderTopLeftRadius: var(--pf-global--BorderRadius--sm);\n --pf-c-toggle-group__item--first-child__button--BorderBottomLeftRadius: var(--pf-global--BorderRadius--sm);\n --pf-c-toggle-group__item--last-child__button--BorderTopRightRadius: var(--pf-global--BorderRadius--sm);\n --pf-c-toggle-group__item--last-child__button--BorderBottomRightRadius: var(--pf-global--BorderRadius--sm);\n --pf-c-toggle-group__icon--text--MarginLeft: var(--pf-global--spacer--sm);\n --pf-c-toggle-group__button--m-light--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-toggle-group__button--m-selected--BackgroundColor: var(--pf-global--primary-color--100);\n --pf-c-toggle-group__button--m-selected--Color: var(--pf-global--Color--light-100);\n display: flex; }\n\n.pf-c-toggle-group__item:first-child .pf-c-toggle-group__button {\n border-top-left-radius: var(--pf-c-toggle-group__item--first-child__button--BorderTopLeftRadius);\n border-bottom-left-radius: var(--pf-c-toggle-group__item--first-child__button--BorderBottomLeftRadius); }\n\n.pf-c-toggle-group__item:last-child .pf-c-toggle-group__button {\n border-top-right-radius: var(--pf-c-toggle-group__item--last-child__button--BorderTopRightRadius);\n border-bottom-right-radius: var(--pf-c-toggle-group__item--last-child__button--BorderBottomRightRadius); }\n\n.pf-c-toggle-group__button {\n display: inline-flex;\n padding: var(--pf-c-toggle-group__button--PaddingTop) var(--pf-c-toggle-group__button--PaddingRight) var(--pf-c-toggle-group__button--PaddingBottom) var(--pf-c-toggle-group__button--PaddingLeft);\n font-size: var(--pf-c-toggle-group__button--FontSize);\n line-height: var(--pf-c-toggle-group__button--LineHeight);\n color: var(--pf-c-toggle-group__button--Color);\n background-color: var(--pf-c-toggle-group__button--BackgroundColor);\n border: 0; }\n .pf-c-toggle-group__button.pf-m-light {\n --pf-c-toggle-group__button--BackgroundColor: var(--pf-c-toggle-group__button--m-light--BackgroundColor); }\n .pf-c-toggle-group__button:hover {\n --pf-c-toggle-group__button--BackgroundColor: var(--pf-c-toggle-group__button--hover--BackgroundColor);\n text-decoration: none; }\n .pf-c-toggle-group__button:focus {\n --pf-c-toggle-group__button--BackgroundColor: var(--pf-c-toggle-group__button--focus--BackgroundColor); }\n .pf-c-toggle-group__button.pf-m-selected {\n --pf-c-toggle-group__button--BackgroundColor: var(--pf-c-toggle-group__button--m-selected--BackgroundColor);\n --pf-c-toggle-group__button--Color: var(--pf-c-toggle-group__button--m-selected--Color); }\n .pf-c-toggle-group__button:disabled, .pf-c-toggle-group__button.pf-m-disabled {\n --pf-c-toggle-group__button--BackgroundColor: var(--pf-c-toggle-group__button--disabled--BackgroundColor);\n --pf-c-toggle-group__button--Color: var(--pf-c-toggle-group__button--disabled--Color);\n pointer-events: none; }\n\n.pf-c-toggle-group__icon + .pf-c-toggle-group__text,\n.pf-c-toggle-group__text + .pf-c-toggle-group__icon {\n margin-left: var(--pf-c-toggle-group__icon--text--MarginLeft); }\n\n.pf-c-tooltip {\n --pf-c-tooltip--MaxWidth: 18.75rem;\n --pf-c-tooltip--BoxShadow: var(--pf-global--BoxShadow--md);\n --pf-c-tooltip__content--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-tooltip__content--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-tooltip__content--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-tooltip__content--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-tooltip__content--Color: var(--pf-global--Color--light-100);\n --pf-c-tooltip__content--BackgroundColor: var(--pf-global--BackgroundColor--dark-100);\n --pf-c-tooltip__content--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-tooltip__arrow--Width: var(--pf-global--arrow--width);\n --pf-c-tooltip__arrow--Height: var(--pf-global--arrow--width);\n --pf-c-tooltip__arrow--m-top--TranslateX: -50%;\n --pf-c-tooltip__arrow--m-top--TranslateY: 50%;\n --pf-c-tooltip__arrow--m-top--Rotate: 45deg;\n --pf-c-tooltip__arrow--m-right--TranslateX: -50%;\n --pf-c-tooltip__arrow--m-right--TranslateY: -50%;\n --pf-c-tooltip__arrow--m-right--Rotate: 45deg;\n --pf-c-tooltip__arrow--m-bottom--TranslateX: -50%;\n --pf-c-tooltip__arrow--m-bottom--TranslateY: -50%;\n --pf-c-tooltip__arrow--m-bottom--Rotate: 45deg;\n --pf-c-tooltip__arrow--m-left--TranslateX: 50%;\n --pf-c-tooltip__arrow--m-left--TranslateY: -50%;\n --pf-c-tooltip__arrow--m-left--Rotate: 45deg;\n position: relative;\n max-width: var(--pf-c-tooltip--MaxWidth);\n box-shadow: var(--pf-c-tooltip--BoxShadow); }\n .pf-c-tooltip.pf-m-top .pf-c-tooltip__arrow {\n bottom: 0;\n left: 50%;\n transform: translateX(var(--pf-c-tooltip__arrow--m-top--TranslateX)) translateY(var(--pf-c-tooltip__arrow--m-top--TranslateY)) rotate(var(--pf-c-tooltip__arrow--m-top--Rotate)); }\n .pf-c-tooltip.pf-m-bottom .pf-c-tooltip__arrow {\n top: 0;\n left: 50%;\n transform: translateX(var(--pf-c-tooltip__arrow--m-bottom--TranslateX)) translateY(var(--pf-c-tooltip__arrow--m-bottom--TranslateY)) rotate(var(--pf-c-tooltip__arrow--m-bottom--Rotate)); }\n .pf-c-tooltip.pf-m-left .pf-c-tooltip__arrow {\n top: 50%;\n right: 0;\n transform: translateX(var(--pf-c-tooltip__arrow--m-left--TranslateX)) translateY(var(--pf-c-tooltip__arrow--m-left--TranslateY)) rotate(var(--pf-c-tooltip__arrow--m-left--Rotate)); }\n .pf-c-tooltip.pf-m-right .pf-c-tooltip__arrow {\n top: 50%;\n left: 0;\n transform: translateX(var(--pf-c-tooltip__arrow--m-right--TranslateX)) translateY(var(--pf-c-tooltip__arrow--m-right--TranslateY)) rotate(var(--pf-c-tooltip__arrow--m-right--Rotate)); }\n\n.pf-c-tooltip__content {\n position: relative;\n padding: var(--pf-c-tooltip__content--PaddingTop) var(--pf-c-tooltip__content--PaddingRight) var(--pf-c-tooltip__content--PaddingBottom) var(--pf-c-tooltip__content--PaddingLeft);\n font-size: var(--pf-c-tooltip__content--FontSize);\n color: var(--pf-c-tooltip__content--Color);\n text-align: center;\n word-break: break-word;\n background-color: var(--pf-c-tooltip__content--BackgroundColor); }\n .pf-c-tooltip__content.pf-m-text-align-left {\n text-align: left; }\n\n.pf-c-tooltip__arrow {\n position: absolute;\n width: var(--pf-c-tooltip__arrow--Width);\n height: var(--pf-c-tooltip__arrow--Height);\n pointer-events: none;\n background-color: var(--pf-c-tooltip__content--BackgroundColor); }\n\n.pf-c-touchspin {\n --pf-c-touchspin__unit--c-input-group--MarginLeft: var(--pf-global--spacer--sm);\n --pf-c-touchspin__icon--FontSize: var(--pf-global--FontSize--xs);\n --pf-c-touchspin--c-form-control--width-base: calc(var(--pf-global--spacer--sm) * 2);\n --pf-c-touchspin--c-form-control--width-chars: 4;\n --pf-c-touchspin--c-form-control--Width: calc(var(--pf-c-touchspin--c-form-control--width-base) + var(--pf-c-touchspin--c-form-control--width-chars) * 1ch);\n display: inline-flex;\n align-items: center; }\n .pf-c-touchspin .pf-c-form-control {\n display: inline-flex;\n width: var(--pf-c-touchspin--c-form-control--Width);\n text-align: right; }\n\n.pf-c-input-group + .pf-c-touchspin__unit,\n.pf-c-touchspin__unit + .pf-c-input-group {\n margin-left: var(--pf-c-touchspin__unit--c-input-group--MarginLeft); }\n\n.pf-c-touchspin__icon {\n font-size: var(--pf-c-touchspin__icon--FontSize); }\n\n.pf-c-tree-view {\n --pf-c-tree-view--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-tree-view--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-tree-view__node--indent--base: calc(var(--pf-global--spacer--md) * 2 + var(--pf-c-tree-view__node-toggle-icon--MinWidth));\n --pf-c-tree-view__node--nested-indent--base: calc(var(--pf-c-tree-view__node--indent--base) - var(--pf-global--spacer--md));\n --pf-c-tree-view__node--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-tree-view__node--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-tree-view__node--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-tree-view__node--PaddingLeft: 0;\n --pf-c-tree-view__node--Color: var(--pf-global--Color--100);\n --pf-c-tree-view__node--m-current--Color: var(--pf-global--link--Color);\n --pf-c-tree-view__node--m-current--FontWeight: var(--pf-global--FontWeight--bold);\n --pf-c-tree-view__node--hover--BackgroundColor: var(--pf-global--BackgroundColor--200);\n --pf-c-tree-view__node--focus--BackgroundColor: var(--pf-global--palette--black-200);\n --pf-c-tree-view__list-item__list-item__node-toggle--Top: var(--pf-c-tree-view__node--PaddingTop);\n --pf-c-tree-view__list-item__list-item__node-toggle--Left: var(--pf-c-tree-view__node--PaddingLeft);\n --pf-c-tree-view__list-item__list-item__node-toggle--TranslateX: -100%;\n --pf-c-tree-view__node-toggle-icon--MinWidth: var(--pf-global--FontSize--md);\n --pf-c-tree-view__node-toggle-icon--Transition: var(--pf-global--Transition);\n --pf-c-tree-view__node-toggle-button--PaddingTop: var(--pf-global--spacer--form-element);\n --pf-c-tree-view__node-toggle-button--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-tree-view__node-toggle-button--PaddingBottom: var(--pf-global--spacer--form-element);\n --pf-c-tree-view__node-toggle-button--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-tree-view__node-toggle-button--MarginTop: calc(var(--pf-global--spacer--form-element) * -1);\n --pf-c-tree-view__node-toggle-button--MarginBottom: calc(var(--pf-global--spacer--form-element) * -1);\n --pf-c-tree-view__node-check--MarginRight: var(--pf-global--spacer--sm);\n --pf-c-tree-view__node-count--MarginLeft: var(--pf-global--spacer--sm);\n --pf-c-tree-view__node-count--c-badge--m-read--BackgroundColor: var(--pf-global--disabled-color--200);\n --pf-c-tree-view__search--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-tree-view__search--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-tree-view__search--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-tree-view__search--PaddingLeft: var(--pf-global--spacer--sm);\n --pf-c-tree-view__node-icon--PaddingRight: var(--pf-global--spacer--sm);\n --pf-c-tree-view__node-icon--Color: var(--pf-global--icon--Color--light);\n --pf-c-tree-view__list-item--m-expanded__node-toggle-icon--Rotate: 90deg;\n --pf-c-tree-view__node-text--max-lines: 1;\n --pf-c-tree-view__action--MarginLeft: var(--pf-global--spacer--md);\n --pf-c-tree-view__action--focus--BackgroundColor: var(--pf-global--BackgroundColor--200);\n --pf-c-tree-view__action--Color: var(--pf-global--icon--Color--light);\n --pf-c-tree-view__action--hover--Color: var(--pf-global--icon--Color--dark);\n --pf-c-tree-view__action--focus--Color: var(--pf-global--icon--Color--dark);\n padding-top: var(--pf-c-tree-view--PaddingTop);\n padding-bottom: var(--pf-c-tree-view--PaddingBottom); }\n\n.pf-c-tree-view__list-item.pf-m-expanded > .pf-c-tree-view__content > .pf-c-tree-view__node > .pf-c-tree-view__node-toggle > .pf-c-tree-view__node-toggle-icon {\n transform: rotate(var(--pf-c-tree-view__list-item--m-expanded__node-toggle-icon--Rotate));\n text-align: center; }\n\n.pf-c-tree-view__node {\n position: relative;\n display: flex;\n flex: 1 1;\n align-items: center;\n min-width: 0;\n padding: var(--pf-c-tree-view__node--PaddingTop) var(--pf-c-tree-view__node--PaddingRight) var(--pf-c-tree-view__node--PaddingBottom) var(--pf-c-tree-view__node--PaddingLeft);\n color: var(--pf-c-tree-view__node--Color);\n text-align: left;\n cursor: pointer;\n border: 0; }\n .pf-c-tree-view__node.pf-m-current {\n --pf-c-tree-view__node--Color: var(--pf-c-tree-view__node--m-current--Color);\n font-weight: var(--pf-c-tree-view__node--m-current--FontWeight); }\n .pf-c-tree-view__node:focus {\n background-color: var(--pf-c-tree-view__node--focus--BackgroundColor); }\n .pf-c-tree-view__node .pf-c-tree-view__node-count {\n margin-left: var(--pf-c-tree-view__node-count--MarginLeft); }\n .pf-c-tree-view__node .pf-c-tree-view__node-count .pf-c-badge.pf-m-read {\n --pf-c-badge--m-read--BackgroundColor: var(--pf-c-tree-view__node-count--c-badge--m-read--BackgroundColor); }\n\n.pf-c-tree-view__node-toggle-icon {\n display: inline-block;\n min-width: var(--pf-c-tree-view__node-toggle-icon--MinWidth);\n transition: var(--pf-c-tree-view__node-toggle-icon--Transition); }\n\n.pf-c-tree-view__node-check {\n margin-right: var(--pf-c-tree-view__node-check--MarginRight); }\n\n.pf-c-tree-view__node-toggle {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: var(--pf-c-tree-view__node-toggle-button--PaddingTop) var(--pf-c-tree-view__node-toggle-button--PaddingRight) var(--pf-c-tree-view__node-toggle-button--PaddingBottom) var(--pf-c-tree-view__node-toggle-button--PaddingLeft);\n margin-top: var(--pf-c-tree-view__node-toggle-button--MarginTop);\n margin-bottom: var(--pf-c-tree-view__node-toggle-button--MarginBottom);\n border: 0; }\n\n.pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__node-toggle {\n position: absolute;\n top: var(--pf-c-tree-view__list-item__list-item__node-toggle--Top);\n left: var(--pf-c-tree-view__list-item__list-item__node-toggle--Left);\n transform: translateX(var(--pf-c-tree-view__list-item__list-item__node-toggle--TranslateX)); }\n\n.pf-c-tree-view__node-text {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap; }\n\n.pf-c-tree-view__search {\n padding: var(--pf-c-tree-view__search--PaddingTop) var(--pf-c-tree-view__search--PaddingRight) var(--pf-c-tree-view__search--PaddingBottom) var(--pf-c-tree-view__search--PaddingLeft); }\n\n.pf-c-tree-view__node-icon {\n padding-right: var(--pf-c-tree-view__node-icon--PaddingRight);\n color: var(--pf-c-tree-view__node-icon--Color); }\n\n.pf-c-tree-view__content {\n display: flex;\n align-items: center; }\n\n.pf-c-tree-view__content:hover,\n.pf-c-tree-view__content:focus-within {\n background-color: var(--pf-c-tree-view__node--hover--BackgroundColor); }\n\n.pf-c-tree-view__action {\n margin-left: var(--pf-c-tree-view__action--MarginLeft);\n color: var(--pf-c-tree-view__action--Color);\n border: 0; }\n .pf-c-tree-view__action:hover {\n --pf-c-tree-view__action--Color: var(--pf-c-tree-view__action--hover--Color); }\n .pf-c-tree-view__action:focus {\n --pf-c-tree-view__action--Color: var(--pf-c-tree-view__action--focus--Color);\n background-color: var(--pf-c-tree-view__action--focus--BackgroundColor); }\n\n.pf-c-tree-view__list-item .pf-c-tree-view__list-item {\n --pf-c-tree-view__node--PaddingLeft: calc(var(--pf-c-tree-view__node--nested-indent--base) * 1 + var(--pf-c-tree-view__node--indent--base));\n --pf-c-tree-view__list-item__list-item__node-toggle--Left: var(--pf-c-tree-view__node--PaddingLeft); }\n\n.pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item {\n --pf-c-tree-view__node--PaddingLeft: calc(var(--pf-c-tree-view__node--nested-indent--base) * 2 + var(--pf-c-tree-view__node--indent--base));\n --pf-c-tree-view__list-item__list-item__node-toggle--Left: var(--pf-c-tree-view__node--PaddingLeft); }\n\n.pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item {\n --pf-c-tree-view__node--PaddingLeft: calc(var(--pf-c-tree-view__node--nested-indent--base) * 3 + var(--pf-c-tree-view__node--indent--base));\n --pf-c-tree-view__list-item__list-item__node-toggle--Left: var(--pf-c-tree-view__node--PaddingLeft); }\n\n.pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item {\n --pf-c-tree-view__node--PaddingLeft: calc(var(--pf-c-tree-view__node--nested-indent--base) * 4 + var(--pf-c-tree-view__node--indent--base));\n --pf-c-tree-view__list-item__list-item__node-toggle--Left: var(--pf-c-tree-view__node--PaddingLeft); }\n\n.pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item {\n --pf-c-tree-view__node--PaddingLeft: calc(var(--pf-c-tree-view__node--nested-indent--base) * 5 + var(--pf-c-tree-view__node--indent--base));\n --pf-c-tree-view__list-item__list-item__node-toggle--Left: var(--pf-c-tree-view__node--PaddingLeft); }\n\n.pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item {\n --pf-c-tree-view__node--PaddingLeft: calc(var(--pf-c-tree-view__node--nested-indent--base) * 6 + var(--pf-c-tree-view__node--indent--base));\n --pf-c-tree-view__list-item__list-item__node-toggle--Left: var(--pf-c-tree-view__node--PaddingLeft); }\n\n.pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item {\n --pf-c-tree-view__node--PaddingLeft: calc(var(--pf-c-tree-view__node--nested-indent--base) * 7 + var(--pf-c-tree-view__node--indent--base));\n --pf-c-tree-view__list-item__list-item__node-toggle--Left: var(--pf-c-tree-view__node--PaddingLeft); }\n\n.pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item {\n --pf-c-tree-view__node--PaddingLeft: calc(var(--pf-c-tree-view__node--nested-indent--base) * 8 + var(--pf-c-tree-view__node--indent--base));\n --pf-c-tree-view__list-item__list-item__node-toggle--Left: var(--pf-c-tree-view__node--PaddingLeft); }\n\n.pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item {\n --pf-c-tree-view__node--PaddingLeft: calc(var(--pf-c-tree-view__node--nested-indent--base) * 9 + var(--pf-c-tree-view__node--indent--base));\n --pf-c-tree-view__list-item__list-item__node-toggle--Left: var(--pf-c-tree-view__node--PaddingLeft); }\n\n.pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item .pf-c-tree-view__list-item {\n --pf-c-tree-view__node--PaddingLeft: calc(var(--pf-c-tree-view__node--nested-indent--base) * 10 + var(--pf-c-tree-view__node--indent--base));\n --pf-c-tree-view__list-item__list-item__node-toggle--Left: var(--pf-c-tree-view__node--PaddingLeft); }\n\n.pf-c-wizard {\n --pf-c-wizard--Height: 100%;\n --pf-c-modal-box--c-wizard--FlexBasis: 47.625rem;\n --pf-c-wizard__header--BackgroundColor: var(--pf-global--BackgroundColor--dark-100);\n --pf-c-wizard__header--ZIndex: var(--pf-global--ZIndex--md);\n --pf-c-wizard__header--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-wizard__header--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-wizard__header--PaddingBottom: var(--pf-global--spacer--lg);\n --pf-c-wizard__header--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-wizard__header--lg--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-wizard__header--lg--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-wizard__header--xl--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-wizard__header--xl--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-wizard__close--Top: calc(var(--pf-global--spacer--lg) - var(--pf-global--spacer--form-element));\n --pf-c-wizard__close--Right: 0;\n --pf-c-wizard__close--xl--Right: var(--pf-global--spacer--lg);\n --pf-c-wizard__close--FontSize: var(--pf-global--FontSize--xl);\n --pf-c-wizard__title--PaddingRight: var(--pf-global--spacer--2xl);\n --pf-c-wizard__description--PaddingTop: var(--pf-global--spacer--sm);\n --pf-c-wizard__description--Color: var(--pf-global--Color--light-200);\n --pf-c-wizard__nav-link--Color: var(--pf-global--Color--100);\n --pf-c-wizard__nav-link--TextDecoration: var(--pf-global--link--TextDecoration);\n --pf-c-wizard__nav-link--hover--Color: var(--pf-global--link--Color);\n --pf-c-wizard__nav-link--focus--Color: var(--pf-global--link--Color);\n --pf-c-wizard__nav-link--m-current--Color: var(--pf-global--link--Color);\n --pf-c-wizard__nav-link--m-current--FontWeight: var(--pf-global--FontWeight--bold);\n --pf-c-wizard__nav-link--m-disabled--Color: var(--pf-global--Color--dark-200);\n --pf-c-wizard__nav-list__nav-list__nav-link--m-current--FontWeight: var(--pf-global--FontWeight--bold);\n --pf-c-wizard__nav-link--before--Width: 1.5rem;\n --pf-c-wizard__nav-link--before--Height: 1.5rem;\n --pf-c-wizard__nav-link--before--Top: 0;\n --pf-c-wizard__nav-link--before--BackgroundColor: var(--pf-global--BackgroundColor--200);\n --pf-c-wizard__nav-link--before--BorderRadius: var(--pf-global--BorderRadius--lg);\n --pf-c-wizard__nav-link--before--Color: var(--pf-global--Color--100);\n --pf-c-wizard__nav-link--before--FontSize: var(--pf-global--FontSize--sm);\n --pf-c-wizard__nav-link--before--TranslateX: calc(-100% - var(--pf-global--spacer--sm));\n --pf-c-wizard__nav-link--m-current--before--BackgroundColor: var(--pf-global--active-color--100);\n --pf-c-wizard__nav-link--m-current--before--Color: var(--pf-global--Color--light-100);\n --pf-c-wizard__nav-link--m-disabled--before--BackgroundColor: transparent;\n --pf-c-wizard__nav-link--m-disabled--before--Color: var(--pf-global--Color--dark-200);\n --pf-c-wizard__toggle--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-wizard__toggle--ZIndex: var(--pf-global--ZIndex--md);\n --pf-c-wizard__toggle--BoxShadow: var(--pf-global--BoxShadow--md-bottom);\n --pf-c-wizard__toggle--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-wizard__toggle--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-wizard__toggle--PaddingBottom: var(--pf-global--spacer--lg);\n --pf-c-wizard__toggle--PaddingLeft: calc(var(--pf-global--spacer--md) + var(--pf-c-wizard__nav-link--before--Width) + var(--pf-global--spacer--sm));\n --pf-c-wizard__toggle--m-expanded--BorderBottomWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-wizard__toggle--m-expanded--BorderBottomColor: var(--pf-global--BorderColor--100);\n --pf-c-wizard--m-in-page__toggle--xl--PaddingLeft: calc(var(--pf-global--spacer--xl) + var(--pf-c-wizard__nav-link--before--Width) + var(--pf-global--spacer--sm));\n --pf-c-wizard__toggle-num--before--Top: 0;\n --pf-c-wizard__toggle-list-item--not-last-child--MarginRight: var(--pf-global--spacer--sm);\n --pf-c-wizard__toggle-list-item--MarginBottom: var(--pf-global--spacer--xs);\n --pf-c-wizard__toggle-list--MarginRight: var(--pf-global--spacer--sm);\n --pf-c-wizard__toggle-list--MarginBottom: calc(var(--pf-c-wizard__toggle-list-item--MarginBottom) * -1);\n --pf-c-wizard__toggle-separator--MarginLeft: var(--pf-global--spacer--sm);\n --pf-c-wizard__toggle-separator--Color: var(--pf-global--BorderColor--200);\n --pf-c-wizard__toggle-icon--LineHeight: var(--pf-global--LineHeight--md);\n --pf-c-wizard__toggle--m-expanded__toggle-icon--Rotate: 180deg;\n --pf-c-wizard__nav--ZIndex: var(--pf-global--ZIndex--sm);\n --pf-c-wizard__nav--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-wizard__nav--BoxShadow: var(--pf-global--BoxShadow--md-bottom);\n --pf-c-wizard__nav--Width: 100%;\n --pf-c-wizard__nav--lg--Width: 15.625rem;\n --pf-c-wizard__nav--lg--BorderRightWidth: var(--pf-global--BorderWidth--sm);\n --pf-c-wizard__nav--lg--BorderRightColor: var(--pf-global--BorderColor--100);\n --pf-c-wizard__nav-list--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-wizard__nav-list--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-wizard__nav-list--PaddingBottom: var(--pf-global--spacer--lg);\n --pf-c-wizard__nav-list--PaddingLeft: calc(var(--pf-global--spacer--md) + var(--pf-c-wizard__nav-link--before--Width) + var(--pf-global--spacer--sm));\n --pf-c-wizard__nav-list--lg--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-wizard__nav-list--lg--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-wizard__nav-list--lg--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-wizard__nav-list--xl--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-wizard__nav-list--xl--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-wizard__nav-list--xl--PaddingBottom: var(--pf-global--spacer--lg);\n --pf-c-wizard__nav-list--xl--PaddingLeft: calc(var(--pf-global--spacer--lg) + var(--pf-c-wizard__nav-link--before--Width) + var(--pf-global--spacer--sm));\n --pf-c-wizard__nav-list--nested--MarginLeft: var(--pf-global--spacer--md);\n --pf-c-wizard__nav-list--nested--MarginTop: var(--pf-global--spacer--md);\n --pf-c-wizard__nav-item--MarginTop: var(--pf-global--spacer--md);\n --pf-c-wizard__outer-wrap--BackgroundColor: var(--pf-global--BackgroundColor--100);\n --pf-c-wizard__outer-wrap--lg--PaddingLeft: var(--pf-c-wizard__nav--Width);\n --pf-c-wizard__main--ZIndex: var(--pf-global--ZIndex--xs);\n --pf-c-wizard__main-body--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-wizard__main-body--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-wizard__main-body--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-wizard__main-body--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-wizard__main-body--xl--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-wizard__main-body--xl--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-wizard__main-body--xl--PaddingBottom: var(--pf-global--spacer--lg);\n --pf-c-wizard__main-body--xl--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-wizard__footer--PaddingTop: var(--pf-global--spacer--md);\n --pf-c-wizard__footer--PaddingRight: var(--pf-global--spacer--md);\n --pf-c-wizard__footer--PaddingBottom: var(--pf-global--spacer--sm);\n --pf-c-wizard__footer--PaddingLeft: var(--pf-global--spacer--md);\n --pf-c-wizard__footer--xl--PaddingTop: var(--pf-global--spacer--lg);\n --pf-c-wizard__footer--xl--PaddingRight: var(--pf-global--spacer--lg);\n --pf-c-wizard__footer--xl--PaddingBottom: var(--pf-global--spacer--md);\n --pf-c-wizard__footer--xl--PaddingLeft: var(--pf-global--spacer--lg);\n --pf-c-wizard__footer--child--MarginRight: var(--pf-global--spacer--md);\n --pf-c-wizard__footer--child--MarginBottom: var(--pf-global--spacer--sm);\n position: relative;\n display: flex;\n flex-direction: column;\n height: var(--pf-c-wizard--Height); }\n @media screen and (min-width: 992px) {\n .pf-c-wizard {\n --pf-c-wizard__header--PaddingRight: var(--pf-c-wizard__header--lg--PaddingRight);\n --pf-c-wizard__header--PaddingLeft: var(--pf-c-wizard__header--lg--PaddingLeft); } }\n @media screen and (min-width: 1200px) {\n .pf-c-wizard {\n --pf-c-wizard__header--PaddingRight: var(--pf-c-wizard__header--xl--PaddingRight);\n --pf-c-wizard__header--PaddingLeft: var(--pf-c-wizard__header--xl--PaddingLeft); } }\n @media screen and (min-width: 1200px) {\n .pf-c-wizard {\n --pf-c-wizard__close--Right: var(--pf-c-wizard__close--xl--Right); } }\n @media screen and (min-width: 992px) {\n .pf-c-wizard {\n --pf-c-wizard__nav--Width: var(--pf-c-wizard__nav--lg--Width);\n --pf-c-wizard__nav--BoxShadow: none; } }\n @media screen and (min-width: 992px) {\n .pf-c-wizard {\n --pf-c-wizard__nav-list--PaddingTop: var(--pf-c-wizard__nav-list--lg--PaddingTop);\n --pf-c-wizard__nav-list--PaddingRight: var(--pf-c-wizard__nav-list--lg--PaddingRight);\n --pf-c-wizard__nav-list--PaddingBottom: var(--pf-c-wizard__nav-list--lg--PaddingBottom); } }\n @media screen and (min-width: 1200px) {\n .pf-c-wizard {\n --pf-c-wizard__nav-list--PaddingTop: var(--pf-c-wizard__nav-list--xl--PaddingTop);\n --pf-c-wizard__nav-list--PaddingRight: var(--pf-c-wizard__nav-list--xl--PaddingRight);\n --pf-c-wizard__nav-list--PaddingBottom: var(--pf-c-wizard__nav-list--xl--PaddingBottom);\n --pf-c-wizard__nav-list--PaddingLeft: var(--pf-c-wizard__nav-list--xl--PaddingLeft); } }\n @media screen and (min-width: 1200px) {\n .pf-c-wizard {\n --pf-c-wizard__main-body--PaddingTop: var(--pf-c-wizard__main-body--xl--PaddingTop);\n --pf-c-wizard__main-body--PaddingRight: var(--pf-c-wizard__main-body--xl--PaddingRight);\n --pf-c-wizard__main-body--PaddingBottom: var(--pf-c-wizard__main-body--xl--PaddingBottom);\n --pf-c-wizard__main-body--PaddingLeft: var(--pf-c-wizard__main-body--xl--PaddingLeft); } }\n @media screen and (min-width: 1200px) {\n .pf-c-wizard {\n --pf-c-wizard__footer--PaddingTop: var(--pf-c-wizard__footer--xl--PaddingTop);\n --pf-c-wizard__footer--PaddingRight: var(--pf-c-wizard__footer--xl--PaddingRight);\n --pf-c-wizard__footer--PaddingBottom: var(--pf-c-wizard__footer--xl--PaddingBottom);\n --pf-c-wizard__footer--PaddingLeft: var(--pf-c-wizard__footer--xl--PaddingLeft); } }\n .pf-c-modal-box .pf-c-wizard {\n flex: 1 1 var(--pf-c-modal-box--c-wizard--FlexBasis);\n min-height: 0; }\n .pf-c-wizard > *:not(.pf-c-wizard__outer-wrap) {\n flex-shrink: 0; }\n .pf-c-wizard.pf-m-finished {\n --pf-c-wizard__outer-wrap--lg--PaddingLeft: 0; }\n .pf-c-wizard.pf-m-finished .pf-c-wizard__nav,\n .pf-c-wizard.pf-m-finished .pf-c-wizard__footer,\n .pf-c-wizard.pf-m-finished .pf-c-wizard__toggle {\n display: none;\n visibility: hidden; }\n\n.pf-c-wizard__header {\n color: var(--pf-global--Color--100);\n position: relative;\n z-index: var(--pf-c-wizard__header--ZIndex);\n padding: var(--pf-c-wizard__header--PaddingTop) var(--pf-c-wizard__header--PaddingRight) var(--pf-c-wizard__header--PaddingBottom) var(--pf-c-wizard__header--PaddingLeft);\n background-color: var(--pf-c-wizard__header--BackgroundColor); }\n .pf-c-wizard__header .pf-c-wizard__close {\n position: absolute;\n top: var(--pf-c-wizard__close--Top);\n right: var(--pf-c-wizard__close--Right);\n font-size: var(--pf-c-wizard__close--FontSize); }\n\n.pf-c-wizard__title {\n padding-right: var(--pf-c-wizard__title--PaddingRight);\n word-wrap: break-word; }\n\n.pf-c-wizard__description {\n display: none;\n padding-top: var(--pf-c-wizard__description--PaddingTop);\n color: var(--pf-c-wizard__description--Color);\n visibility: hidden; }\n @media screen and (min-width: 992px) {\n .pf-c-wizard__description {\n display: block;\n visibility: visible; } }\n\n.pf-c-wizard__toggle {\n position: relative;\n z-index: var(--pf-c-wizard__toggle--ZIndex);\n display: flex;\n justify-content: space-between;\n width: 100%;\n padding: var(--pf-c-wizard__toggle--PaddingTop) var(--pf-c-wizard__toggle--PaddingRight) var(--pf-c-wizard__toggle--PaddingBottom) var(--pf-c-wizard__toggle--PaddingLeft);\n background-color: var(--pf-c-wizard__toggle--BackgroundColor);\n border: 0;\n box-shadow: var(--pf-c-wizard__toggle--BoxShadow); }\n @media screen and (min-width: 992px) {\n .pf-c-wizard__toggle {\n display: none;\n visibility: hidden; } }\n .pf-c-wizard__toggle.pf-m-expanded {\n --pf-c-wizard__toggle--BoxShadow: none;\n border-bottom: var(--pf-c-wizard__toggle--m-expanded--BorderBottomWidth) solid var(--pf-c-wizard__toggle--m-expanded--BorderBottomColor); }\n .pf-c-wizard__toggle.pf-m-expanded .pf-c-wizard__toggle-icon {\n transform: rotate(var(--pf-c-wizard__toggle--m-expanded__toggle-icon--Rotate)); }\n\n.pf-c-wizard__toggle-list {\n position: relative;\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n margin-right: var(--pf-c-wizard__toggle-list--MarginRight);\n margin-bottom: var(--pf-c-wizard__toggle-list--MarginBottom);\n list-style: none; }\n\n.pf-c-wizard__toggle-list-item {\n margin-bottom: var(--pf-c-wizard__toggle-list-item--MarginBottom);\n text-align: left;\n word-break: break-word; }\n .pf-c-wizard__toggle-list-item:not(:last-child) {\n margin-right: var(--pf-c-wizard__toggle-list-item--not-last-child--MarginRight); }\n\n.pf-c-wizard__toggle-num {\n --pf-c-wizard__nav-link--before--Top: var(--pf-c-wizard__toggle-num--before--Top); }\n\n.pf-c-wizard__toggle-separator {\n margin-left: var(--pf-c-wizard__toggle-separator--MarginLeft);\n color: var(--pf-c-wizard__toggle-separator--Color); }\n\n.pf-c-wizard__toggle-icon {\n line-height: var(--pf-c-wizard__toggle-icon--LineHeight); }\n\n.pf-c-wizard__outer-wrap {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-grow: 1;\n min-height: 0;\n background-color: var(--pf-c-wizard__outer-wrap--BackgroundColor); }\n @media screen and (min-width: 992px) {\n .pf-c-wizard__outer-wrap {\n padding-left: var(--pf-c-wizard__outer-wrap--lg--PaddingLeft); } }\n\n.pf-c-wizard__inner-wrap {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-grow: 1;\n min-height: 0; }\n @media screen and (min-width: 992px) {\n .pf-c-wizard__inner-wrap {\n position: static; } }\n\n.pf-c-wizard__nav {\n position: absolute;\n top: 0;\n left: 0;\n z-index: var(--pf-c-wizard__nav--ZIndex);\n display: none;\n width: var(--pf-c-wizard__nav--Width);\n max-height: 100%;\n overflow-y: auto;\n -webkit-overflow-scrolling: touch;\n visibility: hidden;\n background-color: var(--pf-c-wizard__nav--BackgroundColor);\n box-shadow: var(--pf-c-wizard__nav--BoxShadow); }\n .pf-c-wizard__nav.pf-m-expanded {\n display: block;\n visibility: visible; }\n @media screen and (min-width: 992px) {\n .pf-c-wizard__nav {\n display: block;\n height: 100%;\n visibility: visible;\n border-right: var(--pf-c-wizard__nav--lg--BorderRightWidth) solid var(--pf-c-wizard__nav--lg--BorderRightColor); } }\n\n.pf-c-wizard__nav-list {\n padding-top: var(--pf-c-wizard__nav-list--PaddingTop);\n padding-right: var(--pf-c-wizard__nav-list--PaddingRight);\n padding-bottom: var(--pf-c-wizard__nav-list--PaddingBottom);\n padding-left: var(--pf-c-wizard__nav-list--PaddingLeft);\n list-style: none;\n counter-reset: wizard-nav-count; }\n .pf-c-wizard__nav-list .pf-c-wizard__nav-list {\n padding: 0;\n margin-top: var(--pf-c-wizard__nav-list--nested--MarginTop);\n margin-left: var(--pf-c-wizard__nav-list--nested--MarginLeft); }\n .pf-c-wizard__nav-list .pf-c-wizard__nav-list .pf-c-wizard__nav-link::before {\n content: none; }\n .pf-c-wizard__nav-list .pf-c-wizard__nav-list .pf-c-wizard__nav-link.pf-m-current {\n font-weight: var(--pf-c-wizard__nav-list__nav-list__nav-link--m-current--FontWeight); }\n\n.pf-c-wizard__nav-item + .pf-c-wizard__nav-item {\n margin-top: var(--pf-c-wizard__nav-item--MarginTop); }\n\n.pf-c-wizard__nav-link {\n position: relative;\n display: inline-block;\n color: var(--pf-c-wizard__nav-link--Color);\n text-align: left;\n text-decoration: var(--pf-c-wizard__nav-link--TextDecoration);\n word-break: break-word;\n border: 0; }\n .pf-c-wizard__toggle-num, .pf-c-wizard__nav-link::before {\n position: absolute;\n top: var(--pf-c-wizard__nav-link--before--Top);\n left: 0;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--pf-c-wizard__nav-link--before--Width);\n height: var(--pf-c-wizard__nav-link--before--Height);\n font-size: var(--pf-c-wizard__nav-link--before--FontSize);\n line-height: 1;\n color: var(--pf-c-wizard__nav-link--before--Color);\n background-color: var(--pf-c-wizard__nav-link--before--BackgroundColor);\n border-radius: var(--pf-c-wizard__nav-link--before--BorderRadius);\n transform: translateX(var(--pf-c-wizard__nav-link--before--TranslateX)); }\n .pf-c-wizard__nav-link::before {\n top: 0;\n content: counter(wizard-nav-count);\n counter-increment: wizard-nav-count; }\n .pf-c-wizard__nav-link:hover {\n --pf-c-wizard__nav-link--Color: var(--pf-c-wizard__nav-link--hover--Color); }\n .pf-c-wizard__nav-link:focus {\n --pf-c-wizard__nav-link--Color: var(--pf-c-wizard__nav-link--focus--Color); }\n .pf-c-wizard__nav-link.pf-m-current {\n --pf-c-wizard__nav-link--Color: var(--pf-c-wizard__nav-link--m-current--Color);\n font-weight: var(--pf-c-wizard__nav-link--m-current--FontWeight); }\n .pf-c-wizard__toggle-num, .pf-c-wizard__nav-link.pf-m-current::before {\n --pf-c-wizard__nav-link--before--BackgroundColor: var(--pf-c-wizard__nav-link--m-current--before--BackgroundColor);\n --pf-c-wizard__nav-link--before--Color: var(--pf-c-wizard__nav-link--m-current--before--Color); }\n .pf-c-wizard__nav-link:disabled, .pf-c-wizard__nav-link.pf-m-disabled {\n --pf-c-wizard__nav-link--Color: var(--pf-c-wizard__nav-link--m-disabled--Color);\n pointer-events: none; }\n .pf-c-wizard__nav-link:disabled::before, .pf-c-wizard__nav-link.pf-m-disabled::before {\n --pf-c-wizard__nav-link--before--BackgroundColor: var(--pf-c-wizard__nav-link--m-disabled--before--BackgroundColor);\n --pf-c-wizard__nav-link--before--Color: var(--pf-c-wizard__nav-link--m-disabled--before--Color); }\n\n.pf-c-wizard__main {\n z-index: var(--pf-c-wizard__main--ZIndex);\n flex: 1 1 auto;\n overflow-x: hidden;\n overflow-y: auto;\n word-break: break-word; }\n\n.pf-c-wizard__main-body {\n padding: var(--pf-c-wizard__main-body--PaddingTop) var(--pf-c-wizard__main-body--PaddingRight) var(--pf-c-wizard__main-body--PaddingBottom) var(--pf-c-wizard__main-body--PaddingLeft); }\n .pf-c-wizard__main-body.pf-m-no-padding {\n padding: 0; }\n\n.pf-c-wizard__footer {\n display: flex;\n flex-wrap: wrap;\n flex-shrink: 0;\n padding: var(--pf-c-wizard__footer--PaddingTop) var(--pf-c-wizard__footer--PaddingRight) var(--pf-c-wizard__footer--PaddingBottom) var(--pf-c-wizard__footer--PaddingLeft); }\n .pf-c-wizard__footer > * {\n margin-bottom: var(--pf-c-wizard__footer--child--MarginBottom); }\n .pf-c-wizard__footer > *:not(:last-child) {\n margin-right: var(--pf-c-wizard__footer--child--MarginRight); }\n\n.pf-l-bullseye {\n --pf-l-bullseye--Padding: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: var(--pf-l-bullseye--Padding);\n margin: 0; }\n\n.pf-l-flex {\n --pf-l-flex--Display: flex;\n --pf-l-flex--FlexWrap: wrap;\n --pf-l-flex--AlignItems: baseline;\n --pf-l-flex--m-row--AlignItems: baseline;\n --pf-l-flex--m-row-reverse--AlignItems: baseline;\n --pf-l-flex--item--Order: 0;\n --pf-l-flex--spacer-base: var(--pf-global--spacer--md);\n --pf-l-flex--spacer: var(--pf-l-flex--spacer-base);\n --pf-l-flex--spacer--none: 0;\n --pf-l-flex--spacer--xs: var(--pf-global--spacer--xs);\n --pf-l-flex--spacer--sm: var(--pf-global--spacer--sm);\n --pf-l-flex--spacer--md: var(--pf-global--spacer--md);\n --pf-l-flex--spacer--lg: var(--pf-global--spacer--lg);\n --pf-l-flex--spacer--xl: var(--pf-global--spacer--xl);\n --pf-l-flex--spacer--2xl: var(--pf-global--spacer--2xl);\n --pf-l-flex--spacer--3xl: var(--pf-global--spacer--3xl);\n --pf-l-flex--spacer--4xl: var(--pf-global--spacer--4xl);\n display: var(--pf-l-flex--Display);\n flex-wrap: var(--pf-l-flex--FlexWrap);\n align-items: var(--pf-l-flex--AlignItems); }\n .pf-l-flex:last-child {\n --pf-l-flex--spacer: 0; }\n\n.pf-l-flex > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer-base);\n order: var(--pf-l-flex--item--Order);\n max-width: 100%;\n margin-right: var(--pf-l-flex--spacer); }\n @media screen and (min-width: 576px) {\n .pf-l-flex > * {\n order: var(--pf-l-flex--item--Order-on-sm, var(--pf-l-flex--item--Order)); } }\n @media screen and (min-width: 768px) {\n .pf-l-flex > * {\n order: var(--pf-l-flex--item--Order-on-md, var(--pf-l-flex--item--Order-on-sm, var(--pf-l-flex--item--Order))); } }\n @media screen and (min-width: 992px) {\n .pf-l-flex > * {\n order: var(--pf-l-flex--item--Order-on-lg, var(--pf-l-flex--item--Order-on-md, var(--pf-l-flex--item--Order-on-sm, var(--pf-l-flex--item--Order)))); } }\n @media screen and (min-width: 1200px) {\n .pf-l-flex > * {\n order: var(--pf-l-flex--item--Order-on-xl, var(--pf-l-flex--item--Order-on-lg, var(--pf-l-flex--item--Order-on-md, var(--pf-l-flex--item--Order-on-sm, var(--pf-l-flex--item--Order))))); } }\n @media screen and (min-width: 1450px) {\n .pf-l-flex > * {\n order: var(--pf-l-flex--item--Order-on-2xl, var(--pf-l-flex--item--Order-on-xl, var(--pf-l-flex--item--Order-on-lg, var(--pf-l-flex--item--Order-on-md, var(--pf-l-flex--item--Order-on-sm, var(--pf-l-flex--item--Order)))))); } }\n .pf-l-flex > *:last-child {\n --pf-l-flex--spacer: 0; }\n\n.pf-l-flex.pf-m-flex {\n display: var(--pf-l-flex--Display); }\n\n.pf-l-flex.pf-m-inline-flex {\n --pf-l-flex--Display: inline-flex; }\n\n.pf-l-flex.pf-m-column {\n flex-direction: column;\n align-items: normal; }\n .pf-l-flex.pf-m-column > * {\n margin: 0 0 var(--pf-l-flex--spacer) 0; }\n\n.pf-l-flex.pf-m-column-reverse {\n flex-direction: column-reverse;\n align-items: normal; }\n .pf-l-flex.pf-m-column-reverse > * {\n margin: var(--pf-l-flex--spacer) 0 0 0; }\n\n.pf-l-flex.pf-m-row {\n flex-direction: row;\n align-items: var(--pf-l-flex--m-row--AlignItems); }\n .pf-l-flex.pf-m-row > * {\n margin: 0 var(--pf-l-flex--spacer) 0 0; }\n\n.pf-l-flex.pf-m-row-reverse {\n flex-direction: row-reverse;\n align-items: var(--pf-l-flex--m-row-reverse--AlignItems); }\n .pf-l-flex.pf-m-row-reverse > * {\n margin: 0 0 0 var(--pf-l-flex--spacer); }\n\n.pf-l-flex.pf-m-wrap {\n flex-wrap: wrap; }\n\n.pf-l-flex.pf-m-wrap-reverse {\n flex-wrap: wrap-reverse; }\n\n.pf-l-flex.pf-m-nowrap {\n flex-wrap: nowrap; }\n\n.pf-l-flex.pf-m-justify-content-flex-start {\n justify-content: flex-start; }\n\n.pf-l-flex.pf-m-justify-content-flex-end {\n justify-content: flex-end; }\n\n.pf-l-flex.pf-m-justify-content-center {\n justify-content: center; }\n\n.pf-l-flex.pf-m-justify-content-space-between {\n justify-content: space-between; }\n\n.pf-l-flex.pf-m-justify-content-space-around {\n justify-content: space-around; }\n\n.pf-l-flex.pf-m-justify-content-space-evenly {\n justify-content: space-evenly; }\n\n.pf-l-flex.pf-m-align-items-flex-start {\n align-items: flex-start; }\n\n.pf-l-flex.pf-m-align-items-flex-end {\n align-items: flex-end; }\n\n.pf-l-flex.pf-m-align-items-center {\n align-items: center; }\n\n.pf-l-flex.pf-m-align-items-stretch {\n align-items: stretch; }\n\n.pf-l-flex.pf-m-align-items-baseline {\n align-items: baseline; }\n\n.pf-l-flex.pf-m-align-content-flex-start {\n align-content: flex-start; }\n\n.pf-l-flex.pf-m-align-content-flex-end {\n align-content: flex-end; }\n\n.pf-l-flex.pf-m-align-content-center {\n align-content: center; }\n\n.pf-l-flex.pf-m-align-content-stretch {\n align-content: stretch; }\n\n.pf-l-flex.pf-m-align-content-space-between {\n align-content: space-between; }\n\n.pf-l-flex.pf-m-align-content-space-around {\n align-content: space-around; }\n\n.pf-l-flex > .pf-m-align-right {\n margin-left: auto; }\n\n.pf-l-flex > .pf-m-align-left {\n margin-left: 0; }\n\n.pf-l-flex > .pf-m-grow {\n flex-grow: 1; }\n\n.pf-l-flex > .pf-m-shrink {\n flex-shrink: 1; }\n\n.pf-l-flex > .pf-m-full-width {\n width: 100%;\n margin-right: 0; }\n\n.pf-l-flex > .pf-m-flex-1 {\n flex: 1 0 0; }\n\n.pf-l-flex > .pf-m-flex-2 {\n flex: 2 0 0; }\n\n.pf-l-flex > .pf-m-flex-3 {\n flex: 3 0 0; }\n\n.pf-l-flex > .pf-m-flex-4 {\n flex: 4 0 0; }\n\n.pf-l-flex > .pf-m-flex-default {\n flex: 0 1 auto; }\n\n.pf-l-flex > .pf-m-flex-none {\n flex: none; }\n\n.pf-l-flex > .pf-m-align-self-flex-start {\n align-self: flex-start; }\n\n.pf-l-flex > .pf-m-align-self-flex-end {\n align-self: flex-end; }\n\n.pf-l-flex > .pf-m-align-self-center {\n align-self: center; }\n\n.pf-l-flex > .pf-m-align-self-baseline {\n align-self: baseline; }\n\n.pf-l-flex > .pf-m-align-self-stretch {\n align-self: stretch; }\n\n@media (min-width: 576px) {\n .pf-l-flex.pf-m-flex-on-sm {\n display: var(--pf-l-flex--Display); }\n .pf-l-flex.pf-m-inline-flex-on-sm {\n --pf-l-flex--Display: inline-flex; }\n .pf-l-flex.pf-m-column-on-sm {\n flex-direction: column;\n align-items: normal; }\n .pf-l-flex.pf-m-column-on-sm > * {\n margin: 0 0 var(--pf-l-flex--spacer) 0; }\n .pf-l-flex.pf-m-column-reverse-on-sm {\n flex-direction: column-reverse;\n align-items: normal; }\n .pf-l-flex.pf-m-column-reverse-on-sm > * {\n margin: var(--pf-l-flex--spacer) 0 0 0; }\n .pf-l-flex.pf-m-row-on-sm {\n flex-direction: row;\n align-items: var(--pf-l-flex--m-row--AlignItems); }\n .pf-l-flex.pf-m-row-on-sm > * {\n margin: 0 var(--pf-l-flex--spacer) 0 0; }\n .pf-l-flex.pf-m-row-reverse-on-sm {\n flex-direction: row-reverse;\n align-items: var(--pf-l-flex--m-row-reverse--AlignItems); }\n .pf-l-flex.pf-m-row-reverse-on-sm > * {\n margin: 0 0 0 var(--pf-l-flex--spacer); }\n .pf-l-flex.pf-m-wrap-on-sm {\n flex-wrap: wrap; }\n .pf-l-flex.pf-m-wrap-reverse-on-sm {\n flex-wrap: wrap-reverse; }\n .pf-l-flex.pf-m-nowrap-on-sm {\n flex-wrap: nowrap; }\n .pf-l-flex.pf-m-justify-content-flex-start-on-sm {\n justify-content: flex-start; }\n .pf-l-flex.pf-m-justify-content-flex-end-on-sm {\n justify-content: flex-end; }\n .pf-l-flex.pf-m-justify-content-center-on-sm {\n justify-content: center; }\n .pf-l-flex.pf-m-justify-content-space-between-on-sm {\n justify-content: space-between; }\n .pf-l-flex.pf-m-justify-content-space-around-on-sm {\n justify-content: space-around; }\n .pf-l-flex.pf-m-justify-content-space-evenly-on-sm {\n justify-content: space-evenly; }\n .pf-l-flex.pf-m-align-items-flex-start-on-sm {\n align-items: flex-start; }\n .pf-l-flex.pf-m-align-items-flex-end-on-sm {\n align-items: flex-end; }\n .pf-l-flex.pf-m-align-items-center-on-sm {\n align-items: center; }\n .pf-l-flex.pf-m-align-items-stretch-on-sm {\n align-items: stretch; }\n .pf-l-flex.pf-m-align-items-baseline-on-sm {\n align-items: baseline; }\n .pf-l-flex.pf-m-align-content-flex-start-on-sm {\n align-content: flex-start; }\n .pf-l-flex.pf-m-align-content-flex-end-on-sm {\n align-content: flex-end; }\n .pf-l-flex.pf-m-align-content-center-on-sm {\n align-content: center; }\n .pf-l-flex.pf-m-align-content-stretch-on-sm {\n align-content: stretch; }\n .pf-l-flex.pf-m-align-content-space-between-on-sm {\n align-content: space-between; }\n .pf-l-flex.pf-m-align-content-space-around-on-sm {\n align-content: space-around; }\n .pf-l-flex > .pf-m-align-right-on-sm {\n margin-left: auto; }\n .pf-l-flex > .pf-m-align-left-on-sm {\n margin-left: 0; }\n .pf-l-flex > .pf-m-grow-on-sm {\n flex-grow: 1; }\n .pf-l-flex > .pf-m-shrink-on-sm {\n flex-shrink: 1; }\n .pf-l-flex > .pf-m-full-width-on-sm {\n width: 100%;\n margin-right: 0; }\n .pf-l-flex > .pf-m-flex-1-on-sm {\n flex: 1 0 0; }\n .pf-l-flex > .pf-m-flex-2-on-sm {\n flex: 2 0 0; }\n .pf-l-flex > .pf-m-flex-3-on-sm {\n flex: 3 0 0; }\n .pf-l-flex > .pf-m-flex-4-on-sm {\n flex: 4 0 0; }\n .pf-l-flex > .pf-m-flex-default-on-sm {\n flex: 0 1 auto; }\n .pf-l-flex > .pf-m-flex-none-on-sm {\n flex: none; }\n .pf-l-flex > .pf-m-align-self-flex-start-on-sm {\n align-self: flex-start; }\n .pf-l-flex > .pf-m-align-self-flex-end-on-sm {\n align-self: flex-end; }\n .pf-l-flex > .pf-m-align-self-center-on-sm {\n align-self: center; }\n .pf-l-flex > .pf-m-align-self-baseline-on-sm {\n align-self: baseline; }\n .pf-l-flex > .pf-m-align-self-stretch-on-sm {\n align-self: stretch; } }\n\n@media (min-width: 768px) {\n .pf-l-flex.pf-m-flex-on-md {\n display: var(--pf-l-flex--Display); }\n .pf-l-flex.pf-m-inline-flex-on-md {\n --pf-l-flex--Display: inline-flex; }\n .pf-l-flex.pf-m-column-on-md {\n flex-direction: column;\n align-items: normal; }\n .pf-l-flex.pf-m-column-on-md > * {\n margin: 0 0 var(--pf-l-flex--spacer) 0; }\n .pf-l-flex.pf-m-column-reverse-on-md {\n flex-direction: column-reverse;\n align-items: normal; }\n .pf-l-flex.pf-m-column-reverse-on-md > * {\n margin: var(--pf-l-flex--spacer) 0 0 0; }\n .pf-l-flex.pf-m-row-on-md {\n flex-direction: row;\n align-items: var(--pf-l-flex--m-row--AlignItems); }\n .pf-l-flex.pf-m-row-on-md > * {\n margin: 0 var(--pf-l-flex--spacer) 0 0; }\n .pf-l-flex.pf-m-row-reverse-on-md {\n flex-direction: row-reverse;\n align-items: var(--pf-l-flex--m-row-reverse--AlignItems); }\n .pf-l-flex.pf-m-row-reverse-on-md > * {\n margin: 0 0 0 var(--pf-l-flex--spacer); }\n .pf-l-flex.pf-m-wrap-on-md {\n flex-wrap: wrap; }\n .pf-l-flex.pf-m-wrap-reverse-on-md {\n flex-wrap: wrap-reverse; }\n .pf-l-flex.pf-m-nowrap-on-md {\n flex-wrap: nowrap; }\n .pf-l-flex.pf-m-justify-content-flex-start-on-md {\n justify-content: flex-start; }\n .pf-l-flex.pf-m-justify-content-flex-end-on-md {\n justify-content: flex-end; }\n .pf-l-flex.pf-m-justify-content-center-on-md {\n justify-content: center; }\n .pf-l-flex.pf-m-justify-content-space-between-on-md {\n justify-content: space-between; }\n .pf-l-flex.pf-m-justify-content-space-around-on-md {\n justify-content: space-around; }\n .pf-l-flex.pf-m-justify-content-space-evenly-on-md {\n justify-content: space-evenly; }\n .pf-l-flex.pf-m-align-items-flex-start-on-md {\n align-items: flex-start; }\n .pf-l-flex.pf-m-align-items-flex-end-on-md {\n align-items: flex-end; }\n .pf-l-flex.pf-m-align-items-center-on-md {\n align-items: center; }\n .pf-l-flex.pf-m-align-items-stretch-on-md {\n align-items: stretch; }\n .pf-l-flex.pf-m-align-items-baseline-on-md {\n align-items: baseline; }\n .pf-l-flex.pf-m-align-content-flex-start-on-md {\n align-content: flex-start; }\n .pf-l-flex.pf-m-align-content-flex-end-on-md {\n align-content: flex-end; }\n .pf-l-flex.pf-m-align-content-center-on-md {\n align-content: center; }\n .pf-l-flex.pf-m-align-content-stretch-on-md {\n align-content: stretch; }\n .pf-l-flex.pf-m-align-content-space-between-on-md {\n align-content: space-between; }\n .pf-l-flex.pf-m-align-content-space-around-on-md {\n align-content: space-around; }\n .pf-l-flex > .pf-m-align-right-on-md {\n margin-left: auto; }\n .pf-l-flex > .pf-m-align-left-on-md {\n margin-left: 0; }\n .pf-l-flex > .pf-m-grow-on-md {\n flex-grow: 1; }\n .pf-l-flex > .pf-m-shrink-on-md {\n flex-shrink: 1; }\n .pf-l-flex > .pf-m-full-width-on-md {\n width: 100%;\n margin-right: 0; }\n .pf-l-flex > .pf-m-flex-1-on-md {\n flex: 1 0 0; }\n .pf-l-flex > .pf-m-flex-2-on-md {\n flex: 2 0 0; }\n .pf-l-flex > .pf-m-flex-3-on-md {\n flex: 3 0 0; }\n .pf-l-flex > .pf-m-flex-4-on-md {\n flex: 4 0 0; }\n .pf-l-flex > .pf-m-flex-default-on-md {\n flex: 0 1 auto; }\n .pf-l-flex > .pf-m-flex-none-on-md {\n flex: none; }\n .pf-l-flex > .pf-m-align-self-flex-start-on-md {\n align-self: flex-start; }\n .pf-l-flex > .pf-m-align-self-flex-end-on-md {\n align-self: flex-end; }\n .pf-l-flex > .pf-m-align-self-center-on-md {\n align-self: center; }\n .pf-l-flex > .pf-m-align-self-baseline-on-md {\n align-self: baseline; }\n .pf-l-flex > .pf-m-align-self-stretch-on-md {\n align-self: stretch; } }\n\n@media (min-width: 992px) {\n .pf-l-flex.pf-m-flex-on-lg {\n display: var(--pf-l-flex--Display); }\n .pf-l-flex.pf-m-inline-flex-on-lg {\n --pf-l-flex--Display: inline-flex; }\n .pf-l-flex.pf-m-column-on-lg {\n flex-direction: column;\n align-items: normal; }\n .pf-l-flex.pf-m-column-on-lg > * {\n margin: 0 0 var(--pf-l-flex--spacer) 0; }\n .pf-l-flex.pf-m-column-reverse-on-lg {\n flex-direction: column-reverse;\n align-items: normal; }\n .pf-l-flex.pf-m-column-reverse-on-lg > * {\n margin: var(--pf-l-flex--spacer) 0 0 0; }\n .pf-l-flex.pf-m-row-on-lg {\n flex-direction: row;\n align-items: var(--pf-l-flex--m-row--AlignItems); }\n .pf-l-flex.pf-m-row-on-lg > * {\n margin: 0 var(--pf-l-flex--spacer) 0 0; }\n .pf-l-flex.pf-m-row-reverse-on-lg {\n flex-direction: row-reverse;\n align-items: var(--pf-l-flex--m-row-reverse--AlignItems); }\n .pf-l-flex.pf-m-row-reverse-on-lg > * {\n margin: 0 0 0 var(--pf-l-flex--spacer); }\n .pf-l-flex.pf-m-wrap-on-lg {\n flex-wrap: wrap; }\n .pf-l-flex.pf-m-wrap-reverse-on-lg {\n flex-wrap: wrap-reverse; }\n .pf-l-flex.pf-m-nowrap-on-lg {\n flex-wrap: nowrap; }\n .pf-l-flex.pf-m-justify-content-flex-start-on-lg {\n justify-content: flex-start; }\n .pf-l-flex.pf-m-justify-content-flex-end-on-lg {\n justify-content: flex-end; }\n .pf-l-flex.pf-m-justify-content-center-on-lg {\n justify-content: center; }\n .pf-l-flex.pf-m-justify-content-space-between-on-lg {\n justify-content: space-between; }\n .pf-l-flex.pf-m-justify-content-space-around-on-lg {\n justify-content: space-around; }\n .pf-l-flex.pf-m-justify-content-space-evenly-on-lg {\n justify-content: space-evenly; }\n .pf-l-flex.pf-m-align-items-flex-start-on-lg {\n align-items: flex-start; }\n .pf-l-flex.pf-m-align-items-flex-end-on-lg {\n align-items: flex-end; }\n .pf-l-flex.pf-m-align-items-center-on-lg {\n align-items: center; }\n .pf-l-flex.pf-m-align-items-stretch-on-lg {\n align-items: stretch; }\n .pf-l-flex.pf-m-align-items-baseline-on-lg {\n align-items: baseline; }\n .pf-l-flex.pf-m-align-content-flex-start-on-lg {\n align-content: flex-start; }\n .pf-l-flex.pf-m-align-content-flex-end-on-lg {\n align-content: flex-end; }\n .pf-l-flex.pf-m-align-content-center-on-lg {\n align-content: center; }\n .pf-l-flex.pf-m-align-content-stretch-on-lg {\n align-content: stretch; }\n .pf-l-flex.pf-m-align-content-space-between-on-lg {\n align-content: space-between; }\n .pf-l-flex.pf-m-align-content-space-around-on-lg {\n align-content: space-around; }\n .pf-l-flex > .pf-m-align-right-on-lg {\n margin-left: auto; }\n .pf-l-flex > .pf-m-align-left-on-lg {\n margin-left: 0; }\n .pf-l-flex > .pf-m-grow-on-lg {\n flex-grow: 1; }\n .pf-l-flex > .pf-m-shrink-on-lg {\n flex-shrink: 1; }\n .pf-l-flex > .pf-m-full-width-on-lg {\n width: 100%;\n margin-right: 0; }\n .pf-l-flex > .pf-m-flex-1-on-lg {\n flex: 1 0 0; }\n .pf-l-flex > .pf-m-flex-2-on-lg {\n flex: 2 0 0; }\n .pf-l-flex > .pf-m-flex-3-on-lg {\n flex: 3 0 0; }\n .pf-l-flex > .pf-m-flex-4-on-lg {\n flex: 4 0 0; }\n .pf-l-flex > .pf-m-flex-default-on-lg {\n flex: 0 1 auto; }\n .pf-l-flex > .pf-m-flex-none-on-lg {\n flex: none; }\n .pf-l-flex > .pf-m-align-self-flex-start-on-lg {\n align-self: flex-start; }\n .pf-l-flex > .pf-m-align-self-flex-end-on-lg {\n align-self: flex-end; }\n .pf-l-flex > .pf-m-align-self-center-on-lg {\n align-self: center; }\n .pf-l-flex > .pf-m-align-self-baseline-on-lg {\n align-self: baseline; }\n .pf-l-flex > .pf-m-align-self-stretch-on-lg {\n align-self: stretch; } }\n\n@media (min-width: 1200px) {\n .pf-l-flex.pf-m-flex-on-xl {\n display: var(--pf-l-flex--Display); }\n .pf-l-flex.pf-m-inline-flex-on-xl {\n --pf-l-flex--Display: inline-flex; }\n .pf-l-flex.pf-m-column-on-xl {\n flex-direction: column;\n align-items: normal; }\n .pf-l-flex.pf-m-column-on-xl > * {\n margin: 0 0 var(--pf-l-flex--spacer) 0; }\n .pf-l-flex.pf-m-column-reverse-on-xl {\n flex-direction: column-reverse;\n align-items: normal; }\n .pf-l-flex.pf-m-column-reverse-on-xl > * {\n margin: var(--pf-l-flex--spacer) 0 0 0; }\n .pf-l-flex.pf-m-row-on-xl {\n flex-direction: row;\n align-items: var(--pf-l-flex--m-row--AlignItems); }\n .pf-l-flex.pf-m-row-on-xl > * {\n margin: 0 var(--pf-l-flex--spacer) 0 0; }\n .pf-l-flex.pf-m-row-reverse-on-xl {\n flex-direction: row-reverse;\n align-items: var(--pf-l-flex--m-row-reverse--AlignItems); }\n .pf-l-flex.pf-m-row-reverse-on-xl > * {\n margin: 0 0 0 var(--pf-l-flex--spacer); }\n .pf-l-flex.pf-m-wrap-on-xl {\n flex-wrap: wrap; }\n .pf-l-flex.pf-m-wrap-reverse-on-xl {\n flex-wrap: wrap-reverse; }\n .pf-l-flex.pf-m-nowrap-on-xl {\n flex-wrap: nowrap; }\n .pf-l-flex.pf-m-justify-content-flex-start-on-xl {\n justify-content: flex-start; }\n .pf-l-flex.pf-m-justify-content-flex-end-on-xl {\n justify-content: flex-end; }\n .pf-l-flex.pf-m-justify-content-center-on-xl {\n justify-content: center; }\n .pf-l-flex.pf-m-justify-content-space-between-on-xl {\n justify-content: space-between; }\n .pf-l-flex.pf-m-justify-content-space-around-on-xl {\n justify-content: space-around; }\n .pf-l-flex.pf-m-justify-content-space-evenly-on-xl {\n justify-content: space-evenly; }\n .pf-l-flex.pf-m-align-items-flex-start-on-xl {\n align-items: flex-start; }\n .pf-l-flex.pf-m-align-items-flex-end-on-xl {\n align-items: flex-end; }\n .pf-l-flex.pf-m-align-items-center-on-xl {\n align-items: center; }\n .pf-l-flex.pf-m-align-items-stretch-on-xl {\n align-items: stretch; }\n .pf-l-flex.pf-m-align-items-baseline-on-xl {\n align-items: baseline; }\n .pf-l-flex.pf-m-align-content-flex-start-on-xl {\n align-content: flex-start; }\n .pf-l-flex.pf-m-align-content-flex-end-on-xl {\n align-content: flex-end; }\n .pf-l-flex.pf-m-align-content-center-on-xl {\n align-content: center; }\n .pf-l-flex.pf-m-align-content-stretch-on-xl {\n align-content: stretch; }\n .pf-l-flex.pf-m-align-content-space-between-on-xl {\n align-content: space-between; }\n .pf-l-flex.pf-m-align-content-space-around-on-xl {\n align-content: space-around; }\n .pf-l-flex > .pf-m-align-right-on-xl {\n margin-left: auto; }\n .pf-l-flex > .pf-m-align-left-on-xl {\n margin-left: 0; }\n .pf-l-flex > .pf-m-grow-on-xl {\n flex-grow: 1; }\n .pf-l-flex > .pf-m-shrink-on-xl {\n flex-shrink: 1; }\n .pf-l-flex > .pf-m-full-width-on-xl {\n width: 100%;\n margin-right: 0; }\n .pf-l-flex > .pf-m-flex-1-on-xl {\n flex: 1 0 0; }\n .pf-l-flex > .pf-m-flex-2-on-xl {\n flex: 2 0 0; }\n .pf-l-flex > .pf-m-flex-3-on-xl {\n flex: 3 0 0; }\n .pf-l-flex > .pf-m-flex-4-on-xl {\n flex: 4 0 0; }\n .pf-l-flex > .pf-m-flex-default-on-xl {\n flex: 0 1 auto; }\n .pf-l-flex > .pf-m-flex-none-on-xl {\n flex: none; }\n .pf-l-flex > .pf-m-align-self-flex-start-on-xl {\n align-self: flex-start; }\n .pf-l-flex > .pf-m-align-self-flex-end-on-xl {\n align-self: flex-end; }\n .pf-l-flex > .pf-m-align-self-center-on-xl {\n align-self: center; }\n .pf-l-flex > .pf-m-align-self-baseline-on-xl {\n align-self: baseline; }\n .pf-l-flex > .pf-m-align-self-stretch-on-xl {\n align-self: stretch; } }\n\n@media (min-width: 1450px) {\n .pf-l-flex.pf-m-flex-on-2xl {\n display: var(--pf-l-flex--Display); }\n .pf-l-flex.pf-m-inline-flex-on-2xl {\n --pf-l-flex--Display: inline-flex; }\n .pf-l-flex.pf-m-column-on-2xl {\n flex-direction: column;\n align-items: normal; }\n .pf-l-flex.pf-m-column-on-2xl > * {\n margin: 0 0 var(--pf-l-flex--spacer) 0; }\n .pf-l-flex.pf-m-column-reverse-on-2xl {\n flex-direction: column-reverse;\n align-items: normal; }\n .pf-l-flex.pf-m-column-reverse-on-2xl > * {\n margin: var(--pf-l-flex--spacer) 0 0 0; }\n .pf-l-flex.pf-m-row-on-2xl {\n flex-direction: row;\n align-items: var(--pf-l-flex--m-row--AlignItems); }\n .pf-l-flex.pf-m-row-on-2xl > * {\n margin: 0 var(--pf-l-flex--spacer) 0 0; }\n .pf-l-flex.pf-m-row-reverse-on-2xl {\n flex-direction: row-reverse;\n align-items: var(--pf-l-flex--m-row-reverse--AlignItems); }\n .pf-l-flex.pf-m-row-reverse-on-2xl > * {\n margin: 0 0 0 var(--pf-l-flex--spacer); }\n .pf-l-flex.pf-m-wrap-on-2xl {\n flex-wrap: wrap; }\n .pf-l-flex.pf-m-wrap-reverse-on-2xl {\n flex-wrap: wrap-reverse; }\n .pf-l-flex.pf-m-nowrap-on-2xl {\n flex-wrap: nowrap; }\n .pf-l-flex.pf-m-justify-content-flex-start-on-2xl {\n justify-content: flex-start; }\n .pf-l-flex.pf-m-justify-content-flex-end-on-2xl {\n justify-content: flex-end; }\n .pf-l-flex.pf-m-justify-content-center-on-2xl {\n justify-content: center; }\n .pf-l-flex.pf-m-justify-content-space-between-on-2xl {\n justify-content: space-between; }\n .pf-l-flex.pf-m-justify-content-space-around-on-2xl {\n justify-content: space-around; }\n .pf-l-flex.pf-m-justify-content-space-evenly-on-2xl {\n justify-content: space-evenly; }\n .pf-l-flex.pf-m-align-items-flex-start-on-2xl {\n align-items: flex-start; }\n .pf-l-flex.pf-m-align-items-flex-end-on-2xl {\n align-items: flex-end; }\n .pf-l-flex.pf-m-align-items-center-on-2xl {\n align-items: center; }\n .pf-l-flex.pf-m-align-items-stretch-on-2xl {\n align-items: stretch; }\n .pf-l-flex.pf-m-align-items-baseline-on-2xl {\n align-items: baseline; }\n .pf-l-flex.pf-m-align-content-flex-start-on-2xl {\n align-content: flex-start; }\n .pf-l-flex.pf-m-align-content-flex-end-on-2xl {\n align-content: flex-end; }\n .pf-l-flex.pf-m-align-content-center-on-2xl {\n align-content: center; }\n .pf-l-flex.pf-m-align-content-stretch-on-2xl {\n align-content: stretch; }\n .pf-l-flex.pf-m-align-content-space-between-on-2xl {\n align-content: space-between; }\n .pf-l-flex.pf-m-align-content-space-around-on-2xl {\n align-content: space-around; }\n .pf-l-flex > .pf-m-align-right-on-2xl {\n margin-left: auto; }\n .pf-l-flex > .pf-m-align-left-on-2xl {\n margin-left: 0; }\n .pf-l-flex > .pf-m-grow-on-2xl {\n flex-grow: 1; }\n .pf-l-flex > .pf-m-shrink-on-2xl {\n flex-shrink: 1; }\n .pf-l-flex > .pf-m-full-width-on-2xl {\n width: 100%;\n margin-right: 0; }\n .pf-l-flex > .pf-m-flex-1-on-2xl {\n flex: 1 0 0; }\n .pf-l-flex > .pf-m-flex-2-on-2xl {\n flex: 2 0 0; }\n .pf-l-flex > .pf-m-flex-3-on-2xl {\n flex: 3 0 0; }\n .pf-l-flex > .pf-m-flex-4-on-2xl {\n flex: 4 0 0; }\n .pf-l-flex > .pf-m-flex-default-on-2xl {\n flex: 0 1 auto; }\n .pf-l-flex > .pf-m-flex-none-on-2xl {\n flex: none; }\n .pf-l-flex > .pf-m-align-self-flex-start-on-2xl {\n align-self: flex-start; }\n .pf-l-flex > .pf-m-align-self-flex-end-on-2xl {\n align-self: flex-end; }\n .pf-l-flex > .pf-m-align-self-center-on-2xl {\n align-self: center; }\n .pf-l-flex > .pf-m-align-self-baseline-on-2xl {\n align-self: baseline; }\n .pf-l-flex > .pf-m-align-self-stretch-on-2xl {\n align-self: stretch; } }\n\n.pf-l-flex.pf-m-space-items-none > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--none); }\n\n.pf-l-flex.pf-m-space-items-none > :last-child {\n --pf-l-flex--spacer: 0; }\n\n.pf-l-flex.pf-m-space-items-xs > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xs); }\n\n.pf-l-flex.pf-m-space-items-xs > :last-child {\n --pf-l-flex--spacer: 0; }\n\n.pf-l-flex.pf-m-space-items-sm > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--sm); }\n\n.pf-l-flex.pf-m-space-items-sm > :last-child {\n --pf-l-flex--spacer: 0; }\n\n.pf-l-flex.pf-m-space-items-md > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--md); }\n\n.pf-l-flex.pf-m-space-items-md > :last-child {\n --pf-l-flex--spacer: 0; }\n\n.pf-l-flex.pf-m-space-items-lg > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--lg); }\n\n.pf-l-flex.pf-m-space-items-lg > :last-child {\n --pf-l-flex--spacer: 0; }\n\n.pf-l-flex.pf-m-space-items-xl > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xl); }\n\n.pf-l-flex.pf-m-space-items-xl > :last-child {\n --pf-l-flex--spacer: 0; }\n\n.pf-l-flex.pf-m-space-items-2xl > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--2xl); }\n\n.pf-l-flex.pf-m-space-items-2xl > :last-child {\n --pf-l-flex--spacer: 0; }\n\n.pf-l-flex.pf-m-space-items-3xl > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--3xl); }\n\n.pf-l-flex.pf-m-space-items-3xl > :last-child {\n --pf-l-flex--spacer: 0; }\n\n.pf-l-flex.pf-m-space-items-4xl > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--4xl); }\n\n.pf-l-flex.pf-m-space-items-4xl > :last-child {\n --pf-l-flex--spacer: 0; }\n\n@media (min-width: 576px) {\n .pf-l-flex.pf-m-space-items-none-on-sm > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--none); }\n .pf-l-flex.pf-m-space-items-none-on-sm > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-xs-on-sm > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xs); }\n .pf-l-flex.pf-m-space-items-xs-on-sm > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-sm-on-sm > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--sm); }\n .pf-l-flex.pf-m-space-items-sm-on-sm > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-md-on-sm > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--md); }\n .pf-l-flex.pf-m-space-items-md-on-sm > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-lg-on-sm > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--lg); }\n .pf-l-flex.pf-m-space-items-lg-on-sm > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-xl-on-sm > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xl); }\n .pf-l-flex.pf-m-space-items-xl-on-sm > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-2xl-on-sm > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--2xl); }\n .pf-l-flex.pf-m-space-items-2xl-on-sm > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-3xl-on-sm > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--3xl); }\n .pf-l-flex.pf-m-space-items-3xl-on-sm > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-4xl-on-sm > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--4xl); }\n .pf-l-flex.pf-m-space-items-4xl-on-sm > :last-child {\n --pf-l-flex--spacer: 0; } }\n\n@media (min-width: 768px) {\n .pf-l-flex.pf-m-space-items-none-on-md > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--none); }\n .pf-l-flex.pf-m-space-items-none-on-md > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-xs-on-md > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xs); }\n .pf-l-flex.pf-m-space-items-xs-on-md > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-sm-on-md > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--sm); }\n .pf-l-flex.pf-m-space-items-sm-on-md > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-md-on-md > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--md); }\n .pf-l-flex.pf-m-space-items-md-on-md > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-lg-on-md > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--lg); }\n .pf-l-flex.pf-m-space-items-lg-on-md > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-xl-on-md > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xl); }\n .pf-l-flex.pf-m-space-items-xl-on-md > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-2xl-on-md > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--2xl); }\n .pf-l-flex.pf-m-space-items-2xl-on-md > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-3xl-on-md > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--3xl); }\n .pf-l-flex.pf-m-space-items-3xl-on-md > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-4xl-on-md > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--4xl); }\n .pf-l-flex.pf-m-space-items-4xl-on-md > :last-child {\n --pf-l-flex--spacer: 0; } }\n\n@media (min-width: 992px) {\n .pf-l-flex.pf-m-space-items-none-on-lg > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--none); }\n .pf-l-flex.pf-m-space-items-none-on-lg > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-xs-on-lg > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xs); }\n .pf-l-flex.pf-m-space-items-xs-on-lg > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-sm-on-lg > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--sm); }\n .pf-l-flex.pf-m-space-items-sm-on-lg > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-md-on-lg > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--md); }\n .pf-l-flex.pf-m-space-items-md-on-lg > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-lg-on-lg > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--lg); }\n .pf-l-flex.pf-m-space-items-lg-on-lg > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-xl-on-lg > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xl); }\n .pf-l-flex.pf-m-space-items-xl-on-lg > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-2xl-on-lg > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--2xl); }\n .pf-l-flex.pf-m-space-items-2xl-on-lg > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-3xl-on-lg > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--3xl); }\n .pf-l-flex.pf-m-space-items-3xl-on-lg > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-4xl-on-lg > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--4xl); }\n .pf-l-flex.pf-m-space-items-4xl-on-lg > :last-child {\n --pf-l-flex--spacer: 0; } }\n\n@media (min-width: 1200px) {\n .pf-l-flex.pf-m-space-items-none-on-xl > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--none); }\n .pf-l-flex.pf-m-space-items-none-on-xl > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-xs-on-xl > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xs); }\n .pf-l-flex.pf-m-space-items-xs-on-xl > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-sm-on-xl > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--sm); }\n .pf-l-flex.pf-m-space-items-sm-on-xl > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-md-on-xl > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--md); }\n .pf-l-flex.pf-m-space-items-md-on-xl > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-lg-on-xl > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--lg); }\n .pf-l-flex.pf-m-space-items-lg-on-xl > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-xl-on-xl > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xl); }\n .pf-l-flex.pf-m-space-items-xl-on-xl > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-2xl-on-xl > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--2xl); }\n .pf-l-flex.pf-m-space-items-2xl-on-xl > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-3xl-on-xl > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--3xl); }\n .pf-l-flex.pf-m-space-items-3xl-on-xl > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-4xl-on-xl > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--4xl); }\n .pf-l-flex.pf-m-space-items-4xl-on-xl > :last-child {\n --pf-l-flex--spacer: 0; } }\n\n@media (min-width: 1450px) {\n .pf-l-flex.pf-m-space-items-none-on-2xl > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--none); }\n .pf-l-flex.pf-m-space-items-none-on-2xl > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-xs-on-2xl > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xs); }\n .pf-l-flex.pf-m-space-items-xs-on-2xl > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-sm-on-2xl > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--sm); }\n .pf-l-flex.pf-m-space-items-sm-on-2xl > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-md-on-2xl > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--md); }\n .pf-l-flex.pf-m-space-items-md-on-2xl > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-lg-on-2xl > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--lg); }\n .pf-l-flex.pf-m-space-items-lg-on-2xl > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-xl-on-2xl > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xl); }\n .pf-l-flex.pf-m-space-items-xl-on-2xl > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-2xl-on-2xl > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--2xl); }\n .pf-l-flex.pf-m-space-items-2xl-on-2xl > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-3xl-on-2xl > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--3xl); }\n .pf-l-flex.pf-m-space-items-3xl-on-2xl > :last-child {\n --pf-l-flex--spacer: 0; }\n .pf-l-flex.pf-m-space-items-4xl-on-2xl > * {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--4xl); }\n .pf-l-flex.pf-m-space-items-4xl-on-2xl > :last-child {\n --pf-l-flex--spacer: 0; } }\n\n.pf-l-flex .pf-m-spacer-none {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--none); }\n .pf-l-flex .pf-m-spacer-none:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--none); }\n\n.pf-l-flex .pf-m-spacer-xs {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xs); }\n .pf-l-flex .pf-m-spacer-xs:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xs); }\n\n.pf-l-flex .pf-m-spacer-sm {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--sm); }\n .pf-l-flex .pf-m-spacer-sm:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--sm); }\n\n.pf-l-flex .pf-m-spacer-md {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--md); }\n .pf-l-flex .pf-m-spacer-md:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--md); }\n\n.pf-l-flex .pf-m-spacer-lg {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--lg); }\n .pf-l-flex .pf-m-spacer-lg:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--lg); }\n\n.pf-l-flex .pf-m-spacer-xl {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xl); }\n .pf-l-flex .pf-m-spacer-xl:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xl); }\n\n.pf-l-flex .pf-m-spacer-2xl {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--2xl); }\n .pf-l-flex .pf-m-spacer-2xl:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--2xl); }\n\n.pf-l-flex .pf-m-spacer-3xl {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--3xl); }\n .pf-l-flex .pf-m-spacer-3xl:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--3xl); }\n\n.pf-l-flex .pf-m-spacer-4xl {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--4xl); }\n .pf-l-flex .pf-m-spacer-4xl:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--4xl); }\n\n@media (min-width: 576px) {\n .pf-l-flex .pf-m-spacer-none-on-sm {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--none); }\n .pf-l-flex .pf-m-spacer-none-on-sm:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--none); }\n .pf-l-flex .pf-m-spacer-xs-on-sm {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xs); }\n .pf-l-flex .pf-m-spacer-xs-on-sm:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xs); }\n .pf-l-flex .pf-m-spacer-sm-on-sm {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--sm); }\n .pf-l-flex .pf-m-spacer-sm-on-sm:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--sm); }\n .pf-l-flex .pf-m-spacer-md-on-sm {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--md); }\n .pf-l-flex .pf-m-spacer-md-on-sm:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--md); }\n .pf-l-flex .pf-m-spacer-lg-on-sm {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--lg); }\n .pf-l-flex .pf-m-spacer-lg-on-sm:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--lg); }\n .pf-l-flex .pf-m-spacer-xl-on-sm {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xl); }\n .pf-l-flex .pf-m-spacer-xl-on-sm:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xl); }\n .pf-l-flex .pf-m-spacer-2xl-on-sm {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--2xl); }\n .pf-l-flex .pf-m-spacer-2xl-on-sm:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--2xl); }\n .pf-l-flex .pf-m-spacer-3xl-on-sm {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--3xl); }\n .pf-l-flex .pf-m-spacer-3xl-on-sm:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--3xl); }\n .pf-l-flex .pf-m-spacer-4xl-on-sm {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--4xl); }\n .pf-l-flex .pf-m-spacer-4xl-on-sm:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--4xl); } }\n\n@media (min-width: 768px) {\n .pf-l-flex .pf-m-spacer-none-on-md {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--none); }\n .pf-l-flex .pf-m-spacer-none-on-md:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--none); }\n .pf-l-flex .pf-m-spacer-xs-on-md {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xs); }\n .pf-l-flex .pf-m-spacer-xs-on-md:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xs); }\n .pf-l-flex .pf-m-spacer-sm-on-md {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--sm); }\n .pf-l-flex .pf-m-spacer-sm-on-md:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--sm); }\n .pf-l-flex .pf-m-spacer-md-on-md {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--md); }\n .pf-l-flex .pf-m-spacer-md-on-md:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--md); }\n .pf-l-flex .pf-m-spacer-lg-on-md {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--lg); }\n .pf-l-flex .pf-m-spacer-lg-on-md:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--lg); }\n .pf-l-flex .pf-m-spacer-xl-on-md {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xl); }\n .pf-l-flex .pf-m-spacer-xl-on-md:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xl); }\n .pf-l-flex .pf-m-spacer-2xl-on-md {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--2xl); }\n .pf-l-flex .pf-m-spacer-2xl-on-md:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--2xl); }\n .pf-l-flex .pf-m-spacer-3xl-on-md {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--3xl); }\n .pf-l-flex .pf-m-spacer-3xl-on-md:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--3xl); }\n .pf-l-flex .pf-m-spacer-4xl-on-md {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--4xl); }\n .pf-l-flex .pf-m-spacer-4xl-on-md:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--4xl); } }\n\n@media (min-width: 992px) {\n .pf-l-flex .pf-m-spacer-none-on-lg {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--none); }\n .pf-l-flex .pf-m-spacer-none-on-lg:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--none); }\n .pf-l-flex .pf-m-spacer-xs-on-lg {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xs); }\n .pf-l-flex .pf-m-spacer-xs-on-lg:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xs); }\n .pf-l-flex .pf-m-spacer-sm-on-lg {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--sm); }\n .pf-l-flex .pf-m-spacer-sm-on-lg:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--sm); }\n .pf-l-flex .pf-m-spacer-md-on-lg {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--md); }\n .pf-l-flex .pf-m-spacer-md-on-lg:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--md); }\n .pf-l-flex .pf-m-spacer-lg-on-lg {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--lg); }\n .pf-l-flex .pf-m-spacer-lg-on-lg:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--lg); }\n .pf-l-flex .pf-m-spacer-xl-on-lg {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xl); }\n .pf-l-flex .pf-m-spacer-xl-on-lg:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xl); }\n .pf-l-flex .pf-m-spacer-2xl-on-lg {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--2xl); }\n .pf-l-flex .pf-m-spacer-2xl-on-lg:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--2xl); }\n .pf-l-flex .pf-m-spacer-3xl-on-lg {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--3xl); }\n .pf-l-flex .pf-m-spacer-3xl-on-lg:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--3xl); }\n .pf-l-flex .pf-m-spacer-4xl-on-lg {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--4xl); }\n .pf-l-flex .pf-m-spacer-4xl-on-lg:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--4xl); } }\n\n@media (min-width: 1200px) {\n .pf-l-flex .pf-m-spacer-none-on-xl {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--none); }\n .pf-l-flex .pf-m-spacer-none-on-xl:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--none); }\n .pf-l-flex .pf-m-spacer-xs-on-xl {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xs); }\n .pf-l-flex .pf-m-spacer-xs-on-xl:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xs); }\n .pf-l-flex .pf-m-spacer-sm-on-xl {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--sm); }\n .pf-l-flex .pf-m-spacer-sm-on-xl:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--sm); }\n .pf-l-flex .pf-m-spacer-md-on-xl {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--md); }\n .pf-l-flex .pf-m-spacer-md-on-xl:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--md); }\n .pf-l-flex .pf-m-spacer-lg-on-xl {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--lg); }\n .pf-l-flex .pf-m-spacer-lg-on-xl:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--lg); }\n .pf-l-flex .pf-m-spacer-xl-on-xl {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xl); }\n .pf-l-flex .pf-m-spacer-xl-on-xl:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xl); }\n .pf-l-flex .pf-m-spacer-2xl-on-xl {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--2xl); }\n .pf-l-flex .pf-m-spacer-2xl-on-xl:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--2xl); }\n .pf-l-flex .pf-m-spacer-3xl-on-xl {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--3xl); }\n .pf-l-flex .pf-m-spacer-3xl-on-xl:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--3xl); }\n .pf-l-flex .pf-m-spacer-4xl-on-xl {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--4xl); }\n .pf-l-flex .pf-m-spacer-4xl-on-xl:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--4xl); } }\n\n@media (min-width: 1450px) {\n .pf-l-flex .pf-m-spacer-none-on-2xl {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--none); }\n .pf-l-flex .pf-m-spacer-none-on-2xl:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--none); }\n .pf-l-flex .pf-m-spacer-xs-on-2xl {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xs); }\n .pf-l-flex .pf-m-spacer-xs-on-2xl:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xs); }\n .pf-l-flex .pf-m-spacer-sm-on-2xl {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--sm); }\n .pf-l-flex .pf-m-spacer-sm-on-2xl:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--sm); }\n .pf-l-flex .pf-m-spacer-md-on-2xl {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--md); }\n .pf-l-flex .pf-m-spacer-md-on-2xl:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--md); }\n .pf-l-flex .pf-m-spacer-lg-on-2xl {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--lg); }\n .pf-l-flex .pf-m-spacer-lg-on-2xl:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--lg); }\n .pf-l-flex .pf-m-spacer-xl-on-2xl {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xl); }\n .pf-l-flex .pf-m-spacer-xl-on-2xl:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--xl); }\n .pf-l-flex .pf-m-spacer-2xl-on-2xl {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--2xl); }\n .pf-l-flex .pf-m-spacer-2xl-on-2xl:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--2xl); }\n .pf-l-flex .pf-m-spacer-3xl-on-2xl {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--3xl); }\n .pf-l-flex .pf-m-spacer-3xl-on-2xl:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--3xl); }\n .pf-l-flex .pf-m-spacer-4xl-on-2xl {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--4xl); }\n .pf-l-flex .pf-m-spacer-4xl-on-2xl:last-child {\n --pf-l-flex--spacer: var(--pf-l-flex--spacer--4xl); } }\n\n.pf-l-gallery {\n --pf-l-gallery--m-gutter--GridGap: var(--pf-global--gutter);\n --pf-l-gallery--GridTemplateColumns--min: 250px;\n --pf-l-gallery--GridTemplateColumns--minmax--min: var(--pf-l-gallery--GridTemplateColumns--min);\n --pf-l-gallery--GridTemplateColumns--max: 1fr;\n --pf-l-gallery--GridTemplateColumns--minmax--max: var(--pf-l-gallery--GridTemplateColumns--max);\n --pf-l-gallery--GridTemplateColumns: repeat(auto-fill, minmax(var(--pf-l-gallery--GridTemplateColumns--minmax--min), var(--pf-l-gallery--GridTemplateColumns--minmax--max)));\n --pf-l-gallery--GridTemplateRows: auto;\n display: grid;\n grid-template-columns: var(--pf-l-gallery--GridTemplateColumns);\n grid-template-rows: var(--pf-l-gallery--GridTemplateRows);\n --pf-l-gallery--GridTemplateColumns--minmax--min: var(--pf-l-gallery--GridTemplateColumns--min);\n --pf-l-gallery--GridTemplateColumns--minmax--max: var(--pf-l-gallery--GridTemplateColumns--max); }\n .pf-l-gallery.pf-m-gutter {\n grid-gap: var(--pf-l-gallery--m-gutter--GridGap); }\n @media (min-width: 576px) {\n .pf-l-gallery {\n --pf-l-gallery--GridTemplateColumns--minmax--min: var(--pf-l-gallery--GridTemplateColumns--min-on-sm, var(--pf-l-gallery--GridTemplateColumns--min)); } }\n @media (min-width: 768px) {\n .pf-l-gallery {\n --pf-l-gallery--GridTemplateColumns--minmax--min: var(--pf-l-gallery--GridTemplateColumns--min-on-md, var(--pf-l-gallery--GridTemplateColumns--min-on-sm, var(--pf-l-gallery--GridTemplateColumns--min))); } }\n @media (min-width: 992px) {\n .pf-l-gallery {\n --pf-l-gallery--GridTemplateColumns--minmax--min: var(--pf-l-gallery--GridTemplateColumns--min-on-lg, var(--pf-l-gallery--GridTemplateColumns--min-on-md, var(--pf-l-gallery--GridTemplateColumns--min-on-sm, var(--pf-l-gallery--GridTemplateColumns--min)))); } }\n @media (min-width: 1200px) {\n .pf-l-gallery {\n --pf-l-gallery--GridTemplateColumns--minmax--min: var(--pf-l-gallery--GridTemplateColumns--min-on-xl, var(--pf-l-gallery--GridTemplateColumns--min-on-lg, var(--pf-l-gallery--GridTemplateColumns--min-on-md, var(--pf-l-gallery--GridTemplateColumns--min-on-sm, var(--pf-l-gallery--GridTemplateColumns--min))))); } }\n @media (min-width: 1450px) {\n .pf-l-gallery {\n --pf-l-gallery--GridTemplateColumns--minmax--min: var(--pf-l-gallery--GridTemplateColumns--min-on-2xl, var(--pf-l-gallery--GridTemplateColumns--min-on-xl, var(--pf-l-gallery--GridTemplateColumns--min-on-lg, var(--pf-l-gallery--GridTemplateColumns--min-on-md, var(--pf-l-gallery--GridTemplateColumns--min-on-sm, var(--pf-l-gallery--GridTemplateColumns--min)))))); } }\n @media (min-width: 576px) {\n .pf-l-gallery {\n --pf-l-gallery--GridTemplateColumns--minmax--max: var(--pf-l-gallery--GridTemplateColumns--max-on-sm, var(--pf-l-gallery--GridTemplateColumns--max)); } }\n @media (min-width: 768px) {\n .pf-l-gallery {\n --pf-l-gallery--GridTemplateColumns--minmax--max: var(--pf-l-gallery--GridTemplateColumns--max-on-md, var(--pf-l-gallery--GridTemplateColumns--max-on-sm, var(--pf-l-gallery--GridTemplateColumns--max))); } }\n @media (min-width: 992px) {\n .pf-l-gallery {\n --pf-l-gallery--GridTemplateColumns--minmax--max: var(--pf-l-gallery--GridTemplateColumns--max-on-lg, var(--pf-l-gallery--GridTemplateColumns--max-on-md, var(--pf-l-gallery--GridTemplateColumns--max-on-sm, var(--pf-l-gallery--GridTemplateColumns--max)))); } }\n @media (min-width: 1200px) {\n .pf-l-gallery {\n --pf-l-gallery--GridTemplateColumns--minmax--max: var(--pf-l-gallery--GridTemplateColumns--max-on-xl, var(--pf-l-gallery--GridTemplateColumns--max-on-lg, var(--pf-l-gallery--GridTemplateColumns--max-on-md, var(--pf-l-gallery--GridTemplateColumns--max-on-sm, var(--pf-l-gallery--GridTemplateColumns--max))))); } }\n @media (min-width: 1450px) {\n .pf-l-gallery {\n --pf-l-gallery--GridTemplateColumns--minmax--max: var(--pf-l-gallery--GridTemplateColumns--max-on-2xl, var(--pf-l-gallery--GridTemplateColumns--max-on-xl, var(--pf-l-gallery--GridTemplateColumns--max-on-lg, var(--pf-l-gallery--GridTemplateColumns--max-on-md, var(--pf-l-gallery--GridTemplateColumns--max-on-sm, var(--pf-l-gallery--GridTemplateColumns--max)))))); } }\n\n.pf-l-grid {\n --pf-l-grid--m-gutter--GridGap: var(--pf-global--gutter);\n --pf-l-grid__item--GridColumnStart: auto;\n --pf-l-grid__item--GridColumnEnd: span 12;\n --pf-l-grid--item--Order: 0;\n display: grid;\n grid-template-columns: repeat(12, [col-start] 1fr); }\n .pf-l-grid > *,\n .pf-l-grid .pf-l-grid__item {\n min-width: 0;\n min-height: 0;\n grid-column-start: var(--pf-l-grid__item--GridColumnStart);\n grid-column-end: var(--pf-l-grid__item--GridColumnEnd);\n order: var(--pf-l-grid--item--Order); }\n @media (min-width: 576px) {\n .pf-l-grid > *,\n .pf-l-grid .pf-l-grid__item {\n order: var(--pf-l-grid--item--Order-on-sm, var(--pf-l-grid--item--Order)); } }\n @media (min-width: 768px) {\n .pf-l-grid > *,\n .pf-l-grid .pf-l-grid__item {\n order: var(--pf-l-grid--item--Order-on-md, var(--pf-l-grid--item--Order-on-sm, var(--pf-l-grid--item--Order))); } }\n @media (min-width: 992px) {\n .pf-l-grid > *,\n .pf-l-grid .pf-l-grid__item {\n order: var(--pf-l-grid--item--Order-on-lg, var(--pf-l-grid--item--Order-on-md, var(--pf-l-grid--item--Order-on-sm, var(--pf-l-grid--item--Order)))); } }\n @media (min-width: 1200px) {\n .pf-l-grid > *,\n .pf-l-grid .pf-l-grid__item {\n order: var(--pf-l-grid--item--Order-on-xl, var(--pf-l-grid--item--Order-on-lg, var(--pf-l-grid--item--Order-on-md, var(--pf-l-grid--item--Order-on-sm, var(--pf-l-grid--item--Order))))); } }\n @media (min-width: 1450px) {\n .pf-l-grid > *,\n .pf-l-grid .pf-l-grid__item {\n order: var(--pf-l-grid--item--Order-on-2xl, var(--pf-l-grid--item--Order-on-xl, var(--pf-l-grid--item--Order-on-lg, var(--pf-l-grid--item--Order-on-md, var(--pf-l-grid--item--Order-on-sm, var(--pf-l-grid--item--Order)))))); } }\n .pf-l-grid.pf-m-all-1-col > * {\n --pf-l-grid__item--GridColumnEnd: span 1; }\n .pf-l-grid.pf-m-all-2-col > * {\n --pf-l-grid__item--GridColumnEnd: span 2; }\n .pf-l-grid.pf-m-all-3-col > * {\n --pf-l-grid__item--GridColumnEnd: span 3; }\n .pf-l-grid.pf-m-all-4-col > * {\n --pf-l-grid__item--GridColumnEnd: span 4; }\n .pf-l-grid.pf-m-all-5-col > * {\n --pf-l-grid__item--GridColumnEnd: span 5; }\n .pf-l-grid.pf-m-all-6-col > * {\n --pf-l-grid__item--GridColumnEnd: span 6; }\n .pf-l-grid.pf-m-all-7-col > * {\n --pf-l-grid__item--GridColumnEnd: span 7; }\n .pf-l-grid.pf-m-all-8-col > * {\n --pf-l-grid__item--GridColumnEnd: span 8; }\n .pf-l-grid.pf-m-all-9-col > * {\n --pf-l-grid__item--GridColumnEnd: span 9; }\n .pf-l-grid.pf-m-all-10-col > * {\n --pf-l-grid__item--GridColumnEnd: span 10; }\n .pf-l-grid.pf-m-all-11-col > * {\n --pf-l-grid__item--GridColumnEnd: span 11; }\n .pf-l-grid.pf-m-all-12-col > * {\n --pf-l-grid__item--GridColumnEnd: span 12; }\n @media screen and (min-width: 576px) {\n .pf-l-grid.pf-m-all-1-col-on-sm > * {\n --pf-l-grid__item--GridColumnEnd: span 1; }\n .pf-l-grid.pf-m-all-2-col-on-sm > * {\n --pf-l-grid__item--GridColumnEnd: span 2; }\n .pf-l-grid.pf-m-all-3-col-on-sm > * {\n --pf-l-grid__item--GridColumnEnd: span 3; }\n .pf-l-grid.pf-m-all-4-col-on-sm > * {\n --pf-l-grid__item--GridColumnEnd: span 4; }\n .pf-l-grid.pf-m-all-5-col-on-sm > * {\n --pf-l-grid__item--GridColumnEnd: span 5; }\n .pf-l-grid.pf-m-all-6-col-on-sm > * {\n --pf-l-grid__item--GridColumnEnd: span 6; }\n .pf-l-grid.pf-m-all-7-col-on-sm > * {\n --pf-l-grid__item--GridColumnEnd: span 7; }\n .pf-l-grid.pf-m-all-8-col-on-sm > * {\n --pf-l-grid__item--GridColumnEnd: span 8; }\n .pf-l-grid.pf-m-all-9-col-on-sm > * {\n --pf-l-grid__item--GridColumnEnd: span 9; }\n .pf-l-grid.pf-m-all-10-col-on-sm > * {\n --pf-l-grid__item--GridColumnEnd: span 10; }\n .pf-l-grid.pf-m-all-11-col-on-sm > * {\n --pf-l-grid__item--GridColumnEnd: span 11; }\n .pf-l-grid.pf-m-all-12-col-on-sm > * {\n --pf-l-grid__item--GridColumnEnd: span 12; } }\n @media screen and (min-width: 768px) {\n .pf-l-grid.pf-m-all-1-col-on-md > * {\n --pf-l-grid__item--GridColumnEnd: span 1; }\n .pf-l-grid.pf-m-all-2-col-on-md > * {\n --pf-l-grid__item--GridColumnEnd: span 2; }\n .pf-l-grid.pf-m-all-3-col-on-md > * {\n --pf-l-grid__item--GridColumnEnd: span 3; }\n .pf-l-grid.pf-m-all-4-col-on-md > * {\n --pf-l-grid__item--GridColumnEnd: span 4; }\n .pf-l-grid.pf-m-all-5-col-on-md > * {\n --pf-l-grid__item--GridColumnEnd: span 5; }\n .pf-l-grid.pf-m-all-6-col-on-md > * {\n --pf-l-grid__item--GridColumnEnd: span 6; }\n .pf-l-grid.pf-m-all-7-col-on-md > * {\n --pf-l-grid__item--GridColumnEnd: span 7; }\n .pf-l-grid.pf-m-all-8-col-on-md > * {\n --pf-l-grid__item--GridColumnEnd: span 8; }\n .pf-l-grid.pf-m-all-9-col-on-md > * {\n --pf-l-grid__item--GridColumnEnd: span 9; }\n .pf-l-grid.pf-m-all-10-col-on-md > * {\n --pf-l-grid__item--GridColumnEnd: span 10; }\n .pf-l-grid.pf-m-all-11-col-on-md > * {\n --pf-l-grid__item--GridColumnEnd: span 11; }\n .pf-l-grid.pf-m-all-12-col-on-md > * {\n --pf-l-grid__item--GridColumnEnd: span 12; } }\n @media screen and (min-width: 992px) {\n .pf-l-grid.pf-m-all-1-col-on-lg > * {\n --pf-l-grid__item--GridColumnEnd: span 1; }\n .pf-l-grid.pf-m-all-2-col-on-lg > * {\n --pf-l-grid__item--GridColumnEnd: span 2; }\n .pf-l-grid.pf-m-all-3-col-on-lg > * {\n --pf-l-grid__item--GridColumnEnd: span 3; }\n .pf-l-grid.pf-m-all-4-col-on-lg > * {\n --pf-l-grid__item--GridColumnEnd: span 4; }\n .pf-l-grid.pf-m-all-5-col-on-lg > * {\n --pf-l-grid__item--GridColumnEnd: span 5; }\n .pf-l-grid.pf-m-all-6-col-on-lg > * {\n --pf-l-grid__item--GridColumnEnd: span 6; }\n .pf-l-grid.pf-m-all-7-col-on-lg > * {\n --pf-l-grid__item--GridColumnEnd: span 7; }\n .pf-l-grid.pf-m-all-8-col-on-lg > * {\n --pf-l-grid__item--GridColumnEnd: span 8; }\n .pf-l-grid.pf-m-all-9-col-on-lg > * {\n --pf-l-grid__item--GridColumnEnd: span 9; }\n .pf-l-grid.pf-m-all-10-col-on-lg > * {\n --pf-l-grid__item--GridColumnEnd: span 10; }\n .pf-l-grid.pf-m-all-11-col-on-lg > * {\n --pf-l-grid__item--GridColumnEnd: span 11; }\n .pf-l-grid.pf-m-all-12-col-on-lg > * {\n --pf-l-grid__item--GridColumnEnd: span 12; } }\n @media screen and (min-width: 1200px) {\n .pf-l-grid.pf-m-all-1-col-on-xl > * {\n --pf-l-grid__item--GridColumnEnd: span 1; }\n .pf-l-grid.pf-m-all-2-col-on-xl > * {\n --pf-l-grid__item--GridColumnEnd: span 2; }\n .pf-l-grid.pf-m-all-3-col-on-xl > * {\n --pf-l-grid__item--GridColumnEnd: span 3; }\n .pf-l-grid.pf-m-all-4-col-on-xl > * {\n --pf-l-grid__item--GridColumnEnd: span 4; }\n .pf-l-grid.pf-m-all-5-col-on-xl > * {\n --pf-l-grid__item--GridColumnEnd: span 5; }\n .pf-l-grid.pf-m-all-6-col-on-xl > * {\n --pf-l-grid__item--GridColumnEnd: span 6; }\n .pf-l-grid.pf-m-all-7-col-on-xl > * {\n --pf-l-grid__item--GridColumnEnd: span 7; }\n .pf-l-grid.pf-m-all-8-col-on-xl > * {\n --pf-l-grid__item--GridColumnEnd: span 8; }\n .pf-l-grid.pf-m-all-9-col-on-xl > * {\n --pf-l-grid__item--GridColumnEnd: span 9; }\n .pf-l-grid.pf-m-all-10-col-on-xl > * {\n --pf-l-grid__item--GridColumnEnd: span 10; }\n .pf-l-grid.pf-m-all-11-col-on-xl > * {\n --pf-l-grid__item--GridColumnEnd: span 11; }\n .pf-l-grid.pf-m-all-12-col-on-xl > * {\n --pf-l-grid__item--GridColumnEnd: span 12; } }\n @media screen and (min-width: 1450px) {\n .pf-l-grid.pf-m-all-1-col-on-2xl > * {\n --pf-l-grid__item--GridColumnEnd: span 1; }\n .pf-l-grid.pf-m-all-2-col-on-2xl > * {\n --pf-l-grid__item--GridColumnEnd: span 2; }\n .pf-l-grid.pf-m-all-3-col-on-2xl > * {\n --pf-l-grid__item--GridColumnEnd: span 3; }\n .pf-l-grid.pf-m-all-4-col-on-2xl > * {\n --pf-l-grid__item--GridColumnEnd: span 4; }\n .pf-l-grid.pf-m-all-5-col-on-2xl > * {\n --pf-l-grid__item--GridColumnEnd: span 5; }\n .pf-l-grid.pf-m-all-6-col-on-2xl > * {\n --pf-l-grid__item--GridColumnEnd: span 6; }\n .pf-l-grid.pf-m-all-7-col-on-2xl > * {\n --pf-l-grid__item--GridColumnEnd: span 7; }\n .pf-l-grid.pf-m-all-8-col-on-2xl > * {\n --pf-l-grid__item--GridColumnEnd: span 8; }\n .pf-l-grid.pf-m-all-9-col-on-2xl > * {\n --pf-l-grid__item--GridColumnEnd: span 9; }\n .pf-l-grid.pf-m-all-10-col-on-2xl > * {\n --pf-l-grid__item--GridColumnEnd: span 10; }\n .pf-l-grid.pf-m-all-11-col-on-2xl > * {\n --pf-l-grid__item--GridColumnEnd: span 11; }\n .pf-l-grid.pf-m-all-12-col-on-2xl > * {\n --pf-l-grid__item--GridColumnEnd: span 12; } }\n .pf-l-grid > .pf-m-1-col {\n --pf-l-grid__item--GridColumnEnd: span 1; }\n .pf-l-grid > .pf-m-2-col {\n --pf-l-grid__item--GridColumnEnd: span 2; }\n .pf-l-grid > .pf-m-3-col {\n --pf-l-grid__item--GridColumnEnd: span 3; }\n .pf-l-grid > .pf-m-4-col {\n --pf-l-grid__item--GridColumnEnd: span 4; }\n .pf-l-grid > .pf-m-5-col {\n --pf-l-grid__item--GridColumnEnd: span 5; }\n .pf-l-grid > .pf-m-6-col {\n --pf-l-grid__item--GridColumnEnd: span 6; }\n .pf-l-grid > .pf-m-7-col {\n --pf-l-grid__item--GridColumnEnd: span 7; }\n .pf-l-grid > .pf-m-8-col {\n --pf-l-grid__item--GridColumnEnd: span 8; }\n .pf-l-grid > .pf-m-9-col {\n --pf-l-grid__item--GridColumnEnd: span 9; }\n .pf-l-grid > .pf-m-10-col {\n --pf-l-grid__item--GridColumnEnd: span 10; }\n .pf-l-grid > .pf-m-11-col {\n --pf-l-grid__item--GridColumnEnd: span 11; }\n .pf-l-grid > .pf-m-12-col {\n --pf-l-grid__item--GridColumnEnd: span 12; }\n .pf-l-grid > .pf-m-offset-1-col {\n --pf-l-grid__item--GridColumnStart: col-start calc(1 + 1); }\n .pf-l-grid > .pf-m-offset-2-col {\n --pf-l-grid__item--GridColumnStart: col-start calc(2 + 1); }\n .pf-l-grid > .pf-m-offset-3-col {\n --pf-l-grid__item--GridColumnStart: col-start calc(3 + 1); }\n .pf-l-grid > .pf-m-offset-4-col {\n --pf-l-grid__item--GridColumnStart: col-start calc(4 + 1); }\n .pf-l-grid > .pf-m-offset-5-col {\n --pf-l-grid__item--GridColumnStart: col-start calc(5 + 1); }\n .pf-l-grid > .pf-m-offset-6-col {\n --pf-l-grid__item--GridColumnStart: col-start calc(6 + 1); }\n .pf-l-grid > .pf-m-offset-7-col {\n --pf-l-grid__item--GridColumnStart: col-start calc(7 + 1); }\n .pf-l-grid > .pf-m-offset-8-col {\n --pf-l-grid__item--GridColumnStart: col-start calc(8 + 1); }\n .pf-l-grid > .pf-m-offset-9-col {\n --pf-l-grid__item--GridColumnStart: col-start calc(9 + 1); }\n .pf-l-grid > .pf-m-offset-10-col {\n --pf-l-grid__item--GridColumnStart: col-start calc(10 + 1); }\n .pf-l-grid > .pf-m-offset-11-col {\n --pf-l-grid__item--GridColumnStart: col-start calc(11 + 1); }\n .pf-l-grid > .pf-m-offset-12-col {\n --pf-l-grid__item--GridColumnStart: col-start calc(12 + 1); }\n .pf-l-grid > .pf-m-1-row {\n grid-row: span 1; }\n .pf-l-grid > .pf-m-2-row {\n grid-row: span 2; }\n .pf-l-grid > .pf-m-3-row {\n grid-row: span 3; }\n .pf-l-grid > .pf-m-4-row {\n grid-row: span 4; }\n .pf-l-grid > .pf-m-5-row {\n grid-row: span 5; }\n .pf-l-grid > .pf-m-6-row {\n grid-row: span 6; }\n .pf-l-grid > .pf-m-7-row {\n grid-row: span 7; }\n .pf-l-grid > .pf-m-8-row {\n grid-row: span 8; }\n .pf-l-grid > .pf-m-9-row {\n grid-row: span 9; }\n .pf-l-grid > .pf-m-10-row {\n grid-row: span 10; }\n .pf-l-grid > .pf-m-11-row {\n grid-row: span 11; }\n .pf-l-grid > .pf-m-12-row {\n grid-row: span 12; }\n @media screen and (min-width: 576px) {\n .pf-l-grid > .pf-m-1-col-on-sm {\n --pf-l-grid__item--GridColumnEnd: span 1; }\n .pf-l-grid > .pf-m-2-col-on-sm {\n --pf-l-grid__item--GridColumnEnd: span 2; }\n .pf-l-grid > .pf-m-3-col-on-sm {\n --pf-l-grid__item--GridColumnEnd: span 3; }\n .pf-l-grid > .pf-m-4-col-on-sm {\n --pf-l-grid__item--GridColumnEnd: span 4; }\n .pf-l-grid > .pf-m-5-col-on-sm {\n --pf-l-grid__item--GridColumnEnd: span 5; }\n .pf-l-grid > .pf-m-6-col-on-sm {\n --pf-l-grid__item--GridColumnEnd: span 6; }\n .pf-l-grid > .pf-m-7-col-on-sm {\n --pf-l-grid__item--GridColumnEnd: span 7; }\n .pf-l-grid > .pf-m-8-col-on-sm {\n --pf-l-grid__item--GridColumnEnd: span 8; }\n .pf-l-grid > .pf-m-9-col-on-sm {\n --pf-l-grid__item--GridColumnEnd: span 9; }\n .pf-l-grid > .pf-m-10-col-on-sm {\n --pf-l-grid__item--GridColumnEnd: span 10; }\n .pf-l-grid > .pf-m-11-col-on-sm {\n --pf-l-grid__item--GridColumnEnd: span 11; }\n .pf-l-grid > .pf-m-12-col-on-sm {\n --pf-l-grid__item--GridColumnEnd: span 12; }\n .pf-l-grid > .pf-m-offset-1-col-on-sm {\n --pf-l-grid__item--GridColumnStart: col-start calc(1 + 1); }\n .pf-l-grid > .pf-m-offset-2-col-on-sm {\n --pf-l-grid__item--GridColumnStart: col-start calc(2 + 1); }\n .pf-l-grid > .pf-m-offset-3-col-on-sm {\n --pf-l-grid__item--GridColumnStart: col-start calc(3 + 1); }\n .pf-l-grid > .pf-m-offset-4-col-on-sm {\n --pf-l-grid__item--GridColumnStart: col-start calc(4 + 1); }\n .pf-l-grid > .pf-m-offset-5-col-on-sm {\n --pf-l-grid__item--GridColumnStart: col-start calc(5 + 1); }\n .pf-l-grid > .pf-m-offset-6-col-on-sm {\n --pf-l-grid__item--GridColumnStart: col-start calc(6 + 1); }\n .pf-l-grid > .pf-m-offset-7-col-on-sm {\n --pf-l-grid__item--GridColumnStart: col-start calc(7 + 1); }\n .pf-l-grid > .pf-m-offset-8-col-on-sm {\n --pf-l-grid__item--GridColumnStart: col-start calc(8 + 1); }\n .pf-l-grid > .pf-m-offset-9-col-on-sm {\n --pf-l-grid__item--GridColumnStart: col-start calc(9 + 1); }\n .pf-l-grid > .pf-m-offset-10-col-on-sm {\n --pf-l-grid__item--GridColumnStart: col-start calc(10 + 1); }\n .pf-l-grid > .pf-m-offset-11-col-on-sm {\n --pf-l-grid__item--GridColumnStart: col-start calc(11 + 1); }\n .pf-l-grid > .pf-m-offset-12-col-on-sm {\n --pf-l-grid__item--GridColumnStart: col-start calc(12 + 1); }\n .pf-l-grid > .pf-m-1-row-on-sm {\n grid-row: span 1; }\n .pf-l-grid > .pf-m-2-row-on-sm {\n grid-row: span 2; }\n .pf-l-grid > .pf-m-3-row-on-sm {\n grid-row: span 3; }\n .pf-l-grid > .pf-m-4-row-on-sm {\n grid-row: span 4; }\n .pf-l-grid > .pf-m-5-row-on-sm {\n grid-row: span 5; }\n .pf-l-grid > .pf-m-6-row-on-sm {\n grid-row: span 6; }\n .pf-l-grid > .pf-m-7-row-on-sm {\n grid-row: span 7; }\n .pf-l-grid > .pf-m-8-row-on-sm {\n grid-row: span 8; }\n .pf-l-grid > .pf-m-9-row-on-sm {\n grid-row: span 9; }\n .pf-l-grid > .pf-m-10-row-on-sm {\n grid-row: span 10; }\n .pf-l-grid > .pf-m-11-row-on-sm {\n grid-row: span 11; }\n .pf-l-grid > .pf-m-12-row-on-sm {\n grid-row: span 12; } }\n @media screen and (min-width: 768px) {\n .pf-l-grid > .pf-m-1-col-on-md {\n --pf-l-grid__item--GridColumnEnd: span 1; }\n .pf-l-grid > .pf-m-2-col-on-md {\n --pf-l-grid__item--GridColumnEnd: span 2; }\n .pf-l-grid > .pf-m-3-col-on-md {\n --pf-l-grid__item--GridColumnEnd: span 3; }\n .pf-l-grid > .pf-m-4-col-on-md {\n --pf-l-grid__item--GridColumnEnd: span 4; }\n .pf-l-grid > .pf-m-5-col-on-md {\n --pf-l-grid__item--GridColumnEnd: span 5; }\n .pf-l-grid > .pf-m-6-col-on-md {\n --pf-l-grid__item--GridColumnEnd: span 6; }\n .pf-l-grid > .pf-m-7-col-on-md {\n --pf-l-grid__item--GridColumnEnd: span 7; }\n .pf-l-grid > .pf-m-8-col-on-md {\n --pf-l-grid__item--GridColumnEnd: span 8; }\n .pf-l-grid > .pf-m-9-col-on-md {\n --pf-l-grid__item--GridColumnEnd: span 9; }\n .pf-l-grid > .pf-m-10-col-on-md {\n --pf-l-grid__item--GridColumnEnd: span 10; }\n .pf-l-grid > .pf-m-11-col-on-md {\n --pf-l-grid__item--GridColumnEnd: span 11; }\n .pf-l-grid > .pf-m-12-col-on-md {\n --pf-l-grid__item--GridColumnEnd: span 12; }\n .pf-l-grid > .pf-m-offset-1-col-on-md {\n --pf-l-grid__item--GridColumnStart: col-start calc(1 + 1); }\n .pf-l-grid > .pf-m-offset-2-col-on-md {\n --pf-l-grid__item--GridColumnStart: col-start calc(2 + 1); }\n .pf-l-grid > .pf-m-offset-3-col-on-md {\n --pf-l-grid__item--GridColumnStart: col-start calc(3 + 1); }\n .pf-l-grid > .pf-m-offset-4-col-on-md {\n --pf-l-grid__item--GridColumnStart: col-start calc(4 + 1); }\n .pf-l-grid > .pf-m-offset-5-col-on-md {\n --pf-l-grid__item--GridColumnStart: col-start calc(5 + 1); }\n .pf-l-grid > .pf-m-offset-6-col-on-md {\n --pf-l-grid__item--GridColumnStart: col-start calc(6 + 1); }\n .pf-l-grid > .pf-m-offset-7-col-on-md {\n --pf-l-grid__item--GridColumnStart: col-start calc(7 + 1); }\n .pf-l-grid > .pf-m-offset-8-col-on-md {\n --pf-l-grid__item--GridColumnStart: col-start calc(8 + 1); }\n .pf-l-grid > .pf-m-offset-9-col-on-md {\n --pf-l-grid__item--GridColumnStart: col-start calc(9 + 1); }\n .pf-l-grid > .pf-m-offset-10-col-on-md {\n --pf-l-grid__item--GridColumnStart: col-start calc(10 + 1); }\n .pf-l-grid > .pf-m-offset-11-col-on-md {\n --pf-l-grid__item--GridColumnStart: col-start calc(11 + 1); }\n .pf-l-grid > .pf-m-offset-12-col-on-md {\n --pf-l-grid__item--GridColumnStart: col-start calc(12 + 1); }\n .pf-l-grid > .pf-m-1-row-on-md {\n grid-row: span 1; }\n .pf-l-grid > .pf-m-2-row-on-md {\n grid-row: span 2; }\n .pf-l-grid > .pf-m-3-row-on-md {\n grid-row: span 3; }\n .pf-l-grid > .pf-m-4-row-on-md {\n grid-row: span 4; }\n .pf-l-grid > .pf-m-5-row-on-md {\n grid-row: span 5; }\n .pf-l-grid > .pf-m-6-row-on-md {\n grid-row: span 6; }\n .pf-l-grid > .pf-m-7-row-on-md {\n grid-row: span 7; }\n .pf-l-grid > .pf-m-8-row-on-md {\n grid-row: span 8; }\n .pf-l-grid > .pf-m-9-row-on-md {\n grid-row: span 9; }\n .pf-l-grid > .pf-m-10-row-on-md {\n grid-row: span 10; }\n .pf-l-grid > .pf-m-11-row-on-md {\n grid-row: span 11; }\n .pf-l-grid > .pf-m-12-row-on-md {\n grid-row: span 12; } }\n @media screen and (min-width: 992px) {\n .pf-l-grid > .pf-m-1-col-on-lg {\n --pf-l-grid__item--GridColumnEnd: span 1; }\n .pf-l-grid > .pf-m-2-col-on-lg {\n --pf-l-grid__item--GridColumnEnd: span 2; }\n .pf-l-grid > .pf-m-3-col-on-lg {\n --pf-l-grid__item--GridColumnEnd: span 3; }\n .pf-l-grid > .pf-m-4-col-on-lg {\n --pf-l-grid__item--GridColumnEnd: span 4; }\n .pf-l-grid > .pf-m-5-col-on-lg {\n --pf-l-grid__item--GridColumnEnd: span 5; }\n .pf-l-grid > .pf-m-6-col-on-lg {\n --pf-l-grid__item--GridColumnEnd: span 6; }\n .pf-l-grid > .pf-m-7-col-on-lg {\n --pf-l-grid__item--GridColumnEnd: span 7; }\n .pf-l-grid > .pf-m-8-col-on-lg {\n --pf-l-grid__item--GridColumnEnd: span 8; }\n .pf-l-grid > .pf-m-9-col-on-lg {\n --pf-l-grid__item--GridColumnEnd: span 9; }\n .pf-l-grid > .pf-m-10-col-on-lg {\n --pf-l-grid__item--GridColumnEnd: span 10; }\n .pf-l-grid > .pf-m-11-col-on-lg {\n --pf-l-grid__item--GridColumnEnd: span 11; }\n .pf-l-grid > .pf-m-12-col-on-lg {\n --pf-l-grid__item--GridColumnEnd: span 12; }\n .pf-l-grid > .pf-m-offset-1-col-on-lg {\n --pf-l-grid__item--GridColumnStart: col-start calc(1 + 1); }\n .pf-l-grid > .pf-m-offset-2-col-on-lg {\n --pf-l-grid__item--GridColumnStart: col-start calc(2 + 1); }\n .pf-l-grid > .pf-m-offset-3-col-on-lg {\n --pf-l-grid__item--GridColumnStart: col-start calc(3 + 1); }\n .pf-l-grid > .pf-m-offset-4-col-on-lg {\n --pf-l-grid__item--GridColumnStart: col-start calc(4 + 1); }\n .pf-l-grid > .pf-m-offset-5-col-on-lg {\n --pf-l-grid__item--GridColumnStart: col-start calc(5 + 1); }\n .pf-l-grid > .pf-m-offset-6-col-on-lg {\n --pf-l-grid__item--GridColumnStart: col-start calc(6 + 1); }\n .pf-l-grid > .pf-m-offset-7-col-on-lg {\n --pf-l-grid__item--GridColumnStart: col-start calc(7 + 1); }\n .pf-l-grid > .pf-m-offset-8-col-on-lg {\n --pf-l-grid__item--GridColumnStart: col-start calc(8 + 1); }\n .pf-l-grid > .pf-m-offset-9-col-on-lg {\n --pf-l-grid__item--GridColumnStart: col-start calc(9 + 1); }\n .pf-l-grid > .pf-m-offset-10-col-on-lg {\n --pf-l-grid__item--GridColumnStart: col-start calc(10 + 1); }\n .pf-l-grid > .pf-m-offset-11-col-on-lg {\n --pf-l-grid__item--GridColumnStart: col-start calc(11 + 1); }\n .pf-l-grid > .pf-m-offset-12-col-on-lg {\n --pf-l-grid__item--GridColumnStart: col-start calc(12 + 1); }\n .pf-l-grid > .pf-m-1-row-on-lg {\n grid-row: span 1; }\n .pf-l-grid > .pf-m-2-row-on-lg {\n grid-row: span 2; }\n .pf-l-grid > .pf-m-3-row-on-lg {\n grid-row: span 3; }\n .pf-l-grid > .pf-m-4-row-on-lg {\n grid-row: span 4; }\n .pf-l-grid > .pf-m-5-row-on-lg {\n grid-row: span 5; }\n .pf-l-grid > .pf-m-6-row-on-lg {\n grid-row: span 6; }\n .pf-l-grid > .pf-m-7-row-on-lg {\n grid-row: span 7; }\n .pf-l-grid > .pf-m-8-row-on-lg {\n grid-row: span 8; }\n .pf-l-grid > .pf-m-9-row-on-lg {\n grid-row: span 9; }\n .pf-l-grid > .pf-m-10-row-on-lg {\n grid-row: span 10; }\n .pf-l-grid > .pf-m-11-row-on-lg {\n grid-row: span 11; }\n .pf-l-grid > .pf-m-12-row-on-lg {\n grid-row: span 12; } }\n @media screen and (min-width: 1200px) {\n .pf-l-grid > .pf-m-1-col-on-xl {\n --pf-l-grid__item--GridColumnEnd: span 1; }\n .pf-l-grid > .pf-m-2-col-on-xl {\n --pf-l-grid__item--GridColumnEnd: span 2; }\n .pf-l-grid > .pf-m-3-col-on-xl {\n --pf-l-grid__item--GridColumnEnd: span 3; }\n .pf-l-grid > .pf-m-4-col-on-xl {\n --pf-l-grid__item--GridColumnEnd: span 4; }\n .pf-l-grid > .pf-m-5-col-on-xl {\n --pf-l-grid__item--GridColumnEnd: span 5; }\n .pf-l-grid > .pf-m-6-col-on-xl {\n --pf-l-grid__item--GridColumnEnd: span 6; }\n .pf-l-grid > .pf-m-7-col-on-xl {\n --pf-l-grid__item--GridColumnEnd: span 7; }\n .pf-l-grid > .pf-m-8-col-on-xl {\n --pf-l-grid__item--GridColumnEnd: span 8; }\n .pf-l-grid > .pf-m-9-col-on-xl {\n --pf-l-grid__item--GridColumnEnd: span 9; }\n .pf-l-grid > .pf-m-10-col-on-xl {\n --pf-l-grid__item--GridColumnEnd: span 10; }\n .pf-l-grid > .pf-m-11-col-on-xl {\n --pf-l-grid__item--GridColumnEnd: span 11; }\n .pf-l-grid > .pf-m-12-col-on-xl {\n --pf-l-grid__item--GridColumnEnd: span 12; }\n .pf-l-grid > .pf-m-offset-1-col-on-xl {\n --pf-l-grid__item--GridColumnStart: col-start calc(1 + 1); }\n .pf-l-grid > .pf-m-offset-2-col-on-xl {\n --pf-l-grid__item--GridColumnStart: col-start calc(2 + 1); }\n .pf-l-grid > .pf-m-offset-3-col-on-xl {\n --pf-l-grid__item--GridColumnStart: col-start calc(3 + 1); }\n .pf-l-grid > .pf-m-offset-4-col-on-xl {\n --pf-l-grid__item--GridColumnStart: col-start calc(4 + 1); }\n .pf-l-grid > .pf-m-offset-5-col-on-xl {\n --pf-l-grid__item--GridColumnStart: col-start calc(5 + 1); }\n .pf-l-grid > .pf-m-offset-6-col-on-xl {\n --pf-l-grid__item--GridColumnStart: col-start calc(6 + 1); }\n .pf-l-grid > .pf-m-offset-7-col-on-xl {\n --pf-l-grid__item--GridColumnStart: col-start calc(7 + 1); }\n .pf-l-grid > .pf-m-offset-8-col-on-xl {\n --pf-l-grid__item--GridColumnStart: col-start calc(8 + 1); }\n .pf-l-grid > .pf-m-offset-9-col-on-xl {\n --pf-l-grid__item--GridColumnStart: col-start calc(9 + 1); }\n .pf-l-grid > .pf-m-offset-10-col-on-xl {\n --pf-l-grid__item--GridColumnStart: col-start calc(10 + 1); }\n .pf-l-grid > .pf-m-offset-11-col-on-xl {\n --pf-l-grid__item--GridColumnStart: col-start calc(11 + 1); }\n .pf-l-grid > .pf-m-offset-12-col-on-xl {\n --pf-l-grid__item--GridColumnStart: col-start calc(12 + 1); }\n .pf-l-grid > .pf-m-1-row-on-xl {\n grid-row: span 1; }\n .pf-l-grid > .pf-m-2-row-on-xl {\n grid-row: span 2; }\n .pf-l-grid > .pf-m-3-row-on-xl {\n grid-row: span 3; }\n .pf-l-grid > .pf-m-4-row-on-xl {\n grid-row: span 4; }\n .pf-l-grid > .pf-m-5-row-on-xl {\n grid-row: span 5; }\n .pf-l-grid > .pf-m-6-row-on-xl {\n grid-row: span 6; }\n .pf-l-grid > .pf-m-7-row-on-xl {\n grid-row: span 7; }\n .pf-l-grid > .pf-m-8-row-on-xl {\n grid-row: span 8; }\n .pf-l-grid > .pf-m-9-row-on-xl {\n grid-row: span 9; }\n .pf-l-grid > .pf-m-10-row-on-xl {\n grid-row: span 10; }\n .pf-l-grid > .pf-m-11-row-on-xl {\n grid-row: span 11; }\n .pf-l-grid > .pf-m-12-row-on-xl {\n grid-row: span 12; } }\n @media screen and (min-width: 1450px) {\n .pf-l-grid > .pf-m-1-col-on-2xl {\n --pf-l-grid__item--GridColumnEnd: span 1; }\n .pf-l-grid > .pf-m-2-col-on-2xl {\n --pf-l-grid__item--GridColumnEnd: span 2; }\n .pf-l-grid > .pf-m-3-col-on-2xl {\n --pf-l-grid__item--GridColumnEnd: span 3; }\n .pf-l-grid > .pf-m-4-col-on-2xl {\n --pf-l-grid__item--GridColumnEnd: span 4; }\n .pf-l-grid > .pf-m-5-col-on-2xl {\n --pf-l-grid__item--GridColumnEnd: span 5; }\n .pf-l-grid > .pf-m-6-col-on-2xl {\n --pf-l-grid__item--GridColumnEnd: span 6; }\n .pf-l-grid > .pf-m-7-col-on-2xl {\n --pf-l-grid__item--GridColumnEnd: span 7; }\n .pf-l-grid > .pf-m-8-col-on-2xl {\n --pf-l-grid__item--GridColumnEnd: span 8; }\n .pf-l-grid > .pf-m-9-col-on-2xl {\n --pf-l-grid__item--GridColumnEnd: span 9; }\n .pf-l-grid > .pf-m-10-col-on-2xl {\n --pf-l-grid__item--GridColumnEnd: span 10; }\n .pf-l-grid > .pf-m-11-col-on-2xl {\n --pf-l-grid__item--GridColumnEnd: span 11; }\n .pf-l-grid > .pf-m-12-col-on-2xl {\n --pf-l-grid__item--GridColumnEnd: span 12; }\n .pf-l-grid > .pf-m-offset-1-col-on-2xl {\n --pf-l-grid__item--GridColumnStart: col-start calc(1 + 1); }\n .pf-l-grid > .pf-m-offset-2-col-on-2xl {\n --pf-l-grid__item--GridColumnStart: col-start calc(2 + 1); }\n .pf-l-grid > .pf-m-offset-3-col-on-2xl {\n --pf-l-grid__item--GridColumnStart: col-start calc(3 + 1); }\n .pf-l-grid > .pf-m-offset-4-col-on-2xl {\n --pf-l-grid__item--GridColumnStart: col-start calc(4 + 1); }\n .pf-l-grid > .pf-m-offset-5-col-on-2xl {\n --pf-l-grid__item--GridColumnStart: col-start calc(5 + 1); }\n .pf-l-grid > .pf-m-offset-6-col-on-2xl {\n --pf-l-grid__item--GridColumnStart: col-start calc(6 + 1); }\n .pf-l-grid > .pf-m-offset-7-col-on-2xl {\n --pf-l-grid__item--GridColumnStart: col-start calc(7 + 1); }\n .pf-l-grid > .pf-m-offset-8-col-on-2xl {\n --pf-l-grid__item--GridColumnStart: col-start calc(8 + 1); }\n .pf-l-grid > .pf-m-offset-9-col-on-2xl {\n --pf-l-grid__item--GridColumnStart: col-start calc(9 + 1); }\n .pf-l-grid > .pf-m-offset-10-col-on-2xl {\n --pf-l-grid__item--GridColumnStart: col-start calc(10 + 1); }\n .pf-l-grid > .pf-m-offset-11-col-on-2xl {\n --pf-l-grid__item--GridColumnStart: col-start calc(11 + 1); }\n .pf-l-grid > .pf-m-offset-12-col-on-2xl {\n --pf-l-grid__item--GridColumnStart: col-start calc(12 + 1); }\n .pf-l-grid > .pf-m-1-row-on-2xl {\n grid-row: span 1; }\n .pf-l-grid > .pf-m-2-row-on-2xl {\n grid-row: span 2; }\n .pf-l-grid > .pf-m-3-row-on-2xl {\n grid-row: span 3; }\n .pf-l-grid > .pf-m-4-row-on-2xl {\n grid-row: span 4; }\n .pf-l-grid > .pf-m-5-row-on-2xl {\n grid-row: span 5; }\n .pf-l-grid > .pf-m-6-row-on-2xl {\n grid-row: span 6; }\n .pf-l-grid > .pf-m-7-row-on-2xl {\n grid-row: span 7; }\n .pf-l-grid > .pf-m-8-row-on-2xl {\n grid-row: span 8; }\n .pf-l-grid > .pf-m-9-row-on-2xl {\n grid-row: span 9; }\n .pf-l-grid > .pf-m-10-row-on-2xl {\n grid-row: span 10; }\n .pf-l-grid > .pf-m-11-row-on-2xl {\n grid-row: span 11; }\n .pf-l-grid > .pf-m-12-row-on-2xl {\n grid-row: span 12; } }\n .pf-l-grid.pf-m-gutter {\n grid-gap: var(--pf-l-grid--m-gutter--GridGap); }\n\n.pf-l-level {\n --pf-l-level--m-gutter--MarginRight: var(--pf-global--gutter);\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between; }\n .pf-l-level.pf-m-gutter > *:not(:last-child) {\n margin-right: var(--pf-l-level--m-gutter--MarginRight); }\n\n.pf-l-split {\n --pf-l-split--m-gutter--MarginRight: var(--pf-global--gutter);\n display: flex;\n flex-wrap: nowrap;\n padding: 0;\n margin: 0; }\n\n.pf-l-split__item.pf-m-fill {\n flex-grow: 1; }\n\n.pf-l-split.pf-m-gutter > *:not(:last-child) {\n margin-right: var(--pf-l-split--m-gutter--MarginRight); }\n\n.pf-l-stack {\n --pf-l-stack--m-gutter--MarginBottom: var(--pf-global--gutter);\n display: flex;\n flex-direction: column;\n height: 100%; }\n\n.pf-l-stack__item.pf-m-fill {\n flex-grow: 1; }\n\n.pf-l-stack.pf-m-gutter > *:not(:last-child) {\n margin-bottom: var(--pf-l-stack--m-gutter--MarginBottom); }\n"]} \ No newline at end of file diff --git a/awx/ui/public/static/js/d3-collection.v1.min.js b/awx/ui/public/static/js/d3-collection.v1.min.js deleted file mode 100644 index bffa8f534e0f..000000000000 --- a/awx/ui/public/static/js/d3-collection.v1.min.js +++ /dev/null @@ -1,3 +0,0 @@ -/* eslint-disable */ -// https://d3js.org/d3-collection/ v1.0.7 Copyright 2018 Mike Bostock -!function(n,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(n.d3=n.d3||{})}(this,function(n){"use strict";function t(){}function e(n,e){var r=new t;if(n instanceof t)n.each(function(n,t){r.set(t,n)});else if(Array.isArray(n)){var i,u=-1,o=n.length;if(null==e)for(;++u=f.length)return null!=n&&r.sort(n),null!=t?t(r):r;for(var s,c,h,l=-1,v=r.length,p=f[i++],y=e(),d=u();++lf.length)return e;var i,u=c[r-1];return null!=t&&r>=f.length?i=e.entries():(i=[],e.each(function(t,e){i.push({key:e,values:n(t,r)})})),null!=u?i.sort(function(n,t){return u(n.key,t.key)}):i}(a(n,0,u,o),0)},key:function(n){return f.push(n),s},sortKeys:function(n){return c[f.length-1]=n,s},sortValues:function(t){return n=t,s},rollup:function(n){return t=n,s}}},n.set=c,n.map=e,n.keys=function(n){var t=[];for(var e in n)t.push(e);return t},n.values=function(n){var t=[];for(var e in n)t.push(n[e]);return t},n.entries=function(n){var t=[];for(var e in n)t.push({key:e,value:n[e]});return t},Object.defineProperty(n,"__esModule",{value:!0})}); \ No newline at end of file diff --git a/awx/ui/public/static/js/d3-dispatch.v1.min.js b/awx/ui/public/static/js/d3-dispatch.v1.min.js deleted file mode 100644 index 818ea65001be..000000000000 --- a/awx/ui/public/static/js/d3-dispatch.v1.min.js +++ /dev/null @@ -1,3 +0,0 @@ -/* eslint-disable */ -// https://d3js.org/d3-dispatch/ v1.0.6 Copyright 2019 Mike Bostock -!function(n,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((n=n||self).d3=n.d3||{})}(this,function(n){"use strict";var e={value:function(){}};function t(){for(var n,e=0,t=arguments.length,o={};e=0&&(t=n.slice(r+1),n=n.slice(0,r)),n&&!e.hasOwnProperty(n))throw new Error("unknown type: "+n);return{type:n,name:t}})}function i(n,e){for(var t,r=0,o=n.length;r0)for(var t,r,o=new Array(t),i=0;iv+c||ry+c||ul.index){var h=v-f.x-f.vx,g=y-f.y-f.vy,s=h*h+g*g;sn.r&&(n.r=n[t].r)}function v(){if(e){var t,i,u=e.length;for(r=new Array(u),t=0;t=c)){(n.data!==e||n.next)&&(0===h&&(d+=(h=o())*h),0===v&&(d+=(v=o())*v),d1?(null==e?l.remove(n):l.set(n,p(e)),t):l.get(n)},find:function(t,e,r){var i,u,o,f,a,c=0,l=n.length;for(null==r?r=1/0:r*=r,c=0;c1?(v.on(n,e),t):v.on(n)}}},n.forceX=function(n){var t,e,r,i=u(.1);function o(n){for(var i,u=0,o=t.length;u=(s=(y+v)/2))?y=s:v=s,(l=r>=(h=(d+p)/2))?d=h:p=h,n=c,!(c=c[_=l<<1|u]))return n[_]=x,t;if(o=+t._x.call(null,c.data),a=+t._y.call(null,c.data),i===o&&r===a)return x.next=c,n?n[_]=x:t._root=x,t;do{n=n?n[_]=new Array(4):t._root=new Array(4),(u=i>=(s=(y+v)/2))?y=s:v=s,(l=r>=(h=(d+p)/2))?d=h:p=h}while((_=l<<1|u)==(f=(a>=h)<<1|o>=s));return n[f]=c,n[_]=x,t}function r(t,i,r,e,n){this.node=t,this.x0=i,this.y0=r,this.x1=e,this.y1=n}function e(t){return t[0]}function n(t){return t[1]}function s(t,i,r){var s=new h(null==i?e:i,null==r?n:r,NaN,NaN,NaN,NaN);return null==t?s:s.addAll(t)}function h(t,i,r,e,n,s){this._x=t,this._y=i,this._x0=r,this._y0=e,this._x1=n,this._y1=s,this._root=void 0}function o(t){for(var i={data:t.data},r=i;t=t.next;)r=r.next={data:t.data};return i}var a=s.prototype=h.prototype;a.copy=function(){var t,i,r=new h(this._x,this._y,this._x0,this._y0,this._x1,this._y1),e=this._root;if(!e)return r;if(!e.length)return r._root=o(e),r;for(t=[{source:e,target:r._root=new Array(4)}];e=t.pop();)for(var n=0;n<4;++n)(i=e.source[n])&&(i.length?t.push({source:i,target:e.target[n]=new Array(4)}):e.target[n]=o(i));return r},a.add=function(t){var r=+this._x.call(null,t),e=+this._y.call(null,t);return i(this.cover(r,e),r,e,t)},a.addAll=function(t){var r,e,n,s,h=t.length,o=new Array(h),a=new Array(h),u=1/0,l=1/0,_=-1/0,f=-1/0;for(e=0;e_&&(_=n),sf&&(f=s));if(u>_||l>f)return this;for(this.cover(u,l).cover(_,f),e=0;et||t>=n||e>i||i>=s;)switch(o=(ic||(h=u.y0)>x||(o=u.x1)<_||(a=u.y1)=p)<<1|t>=v)&&(u=y[y.length-1],y[y.length-1]=y[y.length-1-l],y[y.length-1-l]=u)}else{var w=t-+this._x.call(null,d.data),N=i-+this._y.call(null,d.data),g=w*w+N*N;if(g=(o=(x+d)/2))?x=o:d=o,(l=h>=(a=(y+v)/2))?y=a:v=a,i=c,!(c=c[_=l<<1|u]))return this;if(!c.length)break;(i[_+1&3]||i[_+2&3]||i[_+3&3])&&(r=i,f=_)}for(;c.data!==t;)if(e=c,!(c=c.next))return this;return(n=c.next)&&delete c.next,e?(n?e.next=n:delete e.next,this):i?(n?i[_]=n:delete i[_],(c=i[0]||i[1]||i[2]||i[3])&&c===(i[3]||i[2]||i[1]||i[0])&&!c.length&&(r?r[f]=c:this._root=c),this):(this._root=n,this)},a.removeAll=function(t){for(var i=0,r=t.length;i=0&&e._call.call(null,t),e=e._next;--o}function h(){c=(l=a.now())+f,o=i=0;try{d()}finally{o=0,function(){var t,o,i=n,r=1/0;for(;i;)i._call?(r>i._time&&(r=i._time),t=i,i=i._next):(o=i._next,i._next=null,i=t?t._next=o:n=o);e=t,v(r)}(),c=0}}function y(){var t=a.now(),n=t-l;n>u&&(f-=n,l=t)}function v(t){o||(i&&(i=clearTimeout(i)),t-c>24?(t<1/0&&(i=setTimeout(h,t-a.now()-f)),r&&(r=clearInterval(r))):(r||(l=a.now(),r=setInterval(y,u)),o=1,s(h)))}p.prototype=w.prototype={constructor:p,restart:function(t,o,i){if("function"!=typeof t)throw new TypeError("callback is not a function");i=(null==i?_():+i)+(null==o?0:+o),this._next||e===this||(e?e._next=this:n=this,e=this),this._call=t,this._time=i,v()},stop:function(){this._call&&(this._call=null,this._time=1/0,v())}},t.interval=function(t,n,e){var o=new p,i=n;return null==n?(o.restart(t,n,e),o):(n=+n,e=null==e?_():+e,o.restart(function r(u){u+=i,o.restart(r,i+=n,e),t(u)},n,e),o)},t.now=_,t.timeout=function(t,n,e){var o=new p;return n=null==n?0:+n,o.restart(function(e){o.stop(),t(e+n)},n,e),o},t.timer=w,t.timerFlush=d,Object.defineProperty(t,"__esModule",{value:!0})}); \ No newline at end of file diff --git a/awx/ui/public/static/media/192.png b/awx/ui/public/static/media/192.png new file mode 100644 index 000000000000..dd37dd9c035f Binary files /dev/null and b/awx/ui/public/static/media/192.png differ diff --git a/awx/ui/public/static/media/256.png b/awx/ui/public/static/media/256.png new file mode 100644 index 000000000000..e5df858b89bf Binary files /dev/null and b/awx/ui/public/static/media/256.png differ diff --git a/awx/ui/public/static/media/384.png b/awx/ui/public/static/media/384.png new file mode 100644 index 000000000000..c5c9f66a8eaf Binary files /dev/null and b/awx/ui/public/static/media/384.png differ diff --git a/awx/ui/public/static/media/512.png b/awx/ui/public/static/media/512.png new file mode 100644 index 000000000000..a53944ac70d5 Binary files /dev/null and b/awx/ui/public/static/media/512.png differ diff --git a/awx/ui/public/static/media/brand-logo.png b/awx/ui/public/static/media/brand-logo.png new file mode 100644 index 000000000000..6a52016f04a1 Binary files /dev/null and b/awx/ui/public/static/media/brand-logo.png differ diff --git a/awx/ui/public/static/media/brand-logo.svg b/awx/ui/public/static/media/brand-logo.svg new file mode 100644 index 000000000000..6d80915fb665 --- /dev/null +++ b/awx/ui/public/static/media/brand-logo.svg @@ -0,0 +1,232 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/awx/ui/public/static/media/brand-logo192.png b/awx/ui/public/static/media/brand-logo192.png new file mode 100644 index 000000000000..74489717d03f Binary files /dev/null and b/awx/ui/public/static/media/brand-logo192.png differ diff --git a/awx/ui/public/static/media/favicon.png b/awx/ui/public/static/media/favicon.png new file mode 100644 index 000000000000..170ed20f8924 Binary files /dev/null and b/awx/ui/public/static/media/favicon.png differ diff --git a/awx/ui/public/static/media/favicon.svg b/awx/ui/public/static/media/favicon.svg new file mode 100644 index 000000000000..6d80915fb665 --- /dev/null +++ b/awx/ui/public/static/media/favicon.svg @@ -0,0 +1,232 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/awx/ui/src/App.js b/awx/ui/src/App.js deleted file mode 100644 index 5f35ecfbc2d7..000000000000 --- a/awx/ui/src/App.js +++ /dev/null @@ -1,192 +0,0 @@ -import React, { useEffect } from 'react'; -import { - useRouteMatch, - useLocation, - HashRouter, - Route, - Switch, - Redirect, - useHistory, -} from 'react-router-dom'; -import { ErrorBoundary } from 'react-error-boundary'; -import { I18nProvider } from '@lingui/react'; -import { i18n } from '@lingui/core'; -import { Card, PageSection } from '@patternfly/react-core'; -import { - ConfigProvider, - useAuthorizedPath, - useUserProfile, -} from 'contexts/Config'; -import { SessionProvider, useSession } from 'contexts/Session'; -import AppContainer from 'components/AppContainer'; -import Background from 'components/Background'; -import ContentError from 'components/ContentError'; -import NotFound from 'screens/NotFound'; -import Login from 'screens/Login'; -import { isAuthenticated } from 'util/auth'; -import { getLanguageWithoutRegionCode } from 'util/language'; -import Metrics from 'screens/Metrics'; -import SubscriptionEdit from 'screens/Setting/Subscription/SubscriptionEdit'; -import useTitle from 'hooks/useTitle'; -import { dynamicActivate, locales } from './i18nLoader'; -import getRouteConfig from './routeConfig'; -import { SESSION_REDIRECT_URL } from './constants'; - -function ErrorFallback({ error }) { - return ( - - - - - - ); -} - -const RenderAppContainer = () => { - const userProfile = useUserProfile(); - const navRouteConfig = getRouteConfig(userProfile); - - return ( - - - - ); -}; - -const AuthorizedRoutes = ({ routeConfig }) => { - const isAuthorized = useAuthorizedPath(); - const match = useRouteMatch(); - - if (!isAuthorized) { - return ( - - - - - - - - - - - - - ); - } - - return ( - - {routeConfig - .flatMap(({ routes }) => routes) - .map(({ path, screen: Screen }) => ( - - - - )) - .concat( - - - , - - - - )} - - ); -}; - -export function ProtectedRoute({ children, ...rest }) { - const { - authRedirectTo, - isUserBeingLoggedOut, - loginRedirectOverride, - setAuthRedirectTo, - } = useSession(); - const location = useLocation(); - - useEffect(() => { - setAuthRedirectTo( - authRedirectTo === '/logout' - ? '/' - : `${location.pathname}${location.search}` - ); - }); - - if (isAuthenticated(document.cookie)) { - return ( - - - {children} - - - ); - } - - if ( - loginRedirectOverride && - !window.location.href.includes('/login') && - !isUserBeingLoggedOut - ) { - window.location.replace(loginRedirectOverride); - return null; - } - return ; -} - -function App() { - const history = useHistory(); - const { hash, search, pathname } = useLocation(); - let language = getLanguageWithoutRegionCode(navigator); - if (!Object.keys(locales).includes(language)) { - // If there isn't a string catalog available for the browser's - // preferred language, default to one that has strings. - language = 'en'; - } - - useEffect(() => { - dynamicActivate(language); - }, [language]); - - useTitle(); - - const redirectURL = window.sessionStorage.getItem(SESSION_REDIRECT_URL); - if (redirectURL) { - window.sessionStorage.removeItem(SESSION_REDIRECT_URL); - if (redirectURL !== '/' || redirectURL !== '/home') - history.replace(redirectURL); - } - - return ( - - - - - - - - - - - - - - - - - - - - - - - ); -} - -export default () => ( - - - -); diff --git a/awx/ui/src/App.test.js b/awx/ui/src/App.test.js deleted file mode 100644 index e1f2fb3bc342..000000000000 --- a/awx/ui/src/App.test.js +++ /dev/null @@ -1,71 +0,0 @@ -import React from 'react'; -import { act } from 'react-dom/test-utils'; -import { RootAPI } from 'api'; -import * as SessionContext from 'contexts/Session'; -import { shallow } from 'enzyme'; -import { mountWithContexts } from '../testUtils/enzymeHelpers'; -import App, { ProtectedRoute } from './App'; - -jest.mock('./api'); -jest.mock('util/webWorker', () => jest.fn()); - -describe('', () => { - beforeEach(() => { - RootAPI.readAssetVariables.mockResolvedValue({ - data: { - BRAND_NAME: 'AWX', - }, - }); - }); - - test('renders ok', async () => { - const contextValues = { - setAuthRedirectTo: jest.fn(), - isSessionExpired: false, - isUserBeingLoggedOut: false, - loginRedirectOverride: null, - }; - jest - .spyOn(SessionContext, 'useSession') - .mockImplementation(() => contextValues); - - let wrapper; - await act(async () => { - wrapper = shallow(); - }); - expect(wrapper.length).toBe(1); - jest.clearAllMocks(); - }); - - test('redirect to login override', async () => { - const { location } = window; - delete window.location; - window.location = { - replace: jest.fn(), - href: '/', - }; - - expect(window.location.replace).not.toHaveBeenCalled(); - - const contextValues = { - setAuthRedirectTo: jest.fn(), - isSessionExpired: false, - isUserBeingLoggedOut: false, - loginRedirectOverride: '/sso/test', - }; - jest - .spyOn(SessionContext, 'useSession') - .mockImplementation(() => contextValues); - - await act(async () => { - mountWithContexts( - -
foo
-
- ); - }); - - expect(window.location.replace).toHaveBeenCalled(); - window.location = location; - }); -}); diff --git a/awx/ui/src/api/Base.js b/awx/ui/src/api/Base.js deleted file mode 100644 index d51669d4d30f..000000000000 --- a/awx/ui/src/api/Base.js +++ /dev/null @@ -1,70 +0,0 @@ -/* eslint-disable default-param-last */ -import axios from 'axios'; -import { encodeQueryString } from 'util/qs'; -import debounce from 'util/debounce'; -import { SESSION_TIMEOUT_KEY } from '../constants'; - -const updateStorage = debounce((key, val) => { - window.localStorage.setItem(key, val); - window.dispatchEvent(new Event('storage')); -}, 500); - -const defaultHttp = axios.create({ - xsrfCookieName: 'csrftoken', - xsrfHeaderName: 'X-CSRFToken', - paramsSerializer(params) { - return encodeQueryString(params); - }, -}); - -defaultHttp.interceptors.response.use((response) => { - const timeout = response?.headers['session-timeout']; - if (timeout) { - const timeoutDate = new Date().getTime() + timeout * 1000; - updateStorage(SESSION_TIMEOUT_KEY, String(timeoutDate)); - } - return response; -}); - -class Base { - constructor(http = defaultHttp, baseURL) { - this.http = http; - this.baseUrl = baseURL; - } - - create(data) { - return this.http.post(this.baseUrl, data); - } - - destroy(id) { - return this.http.delete(`${this.baseUrl}${id}/`); - } - - read(params) { - return this.http.get(this.baseUrl, { - params, - }); - } - - readDetail(id) { - return this.http.get(`${this.baseUrl}${id}/`); - } - - readOptions() { - return this.http.options(this.baseUrl); - } - - replace(id, data) { - return this.http.put(`${this.baseUrl}${id}/`, data); - } - - update(id, data) { - return this.http.patch(`${this.baseUrl}${id}/`, data); - } - - copy(id, data) { - return this.http.post(`${this.baseUrl}${id}/copy/`, data); - } -} - -export default Base; diff --git a/awx/ui/src/api/Base.test.js b/awx/ui/src/api/Base.test.js deleted file mode 100644 index 7a8f1621508e..000000000000 --- a/awx/ui/src/api/Base.test.js +++ /dev/null @@ -1,106 +0,0 @@ -import Base from './Base'; - -describe('Base', () => { - const mockBaseURL = '/api/v2/organizations/'; - - let BaseAPI; - let mockHttp; - - beforeEach(() => { - const createPromise = () => Promise.resolve(); - mockHttp = { - delete: jest.fn(createPromise), - get: jest.fn(createPromise), - options: jest.fn(createPromise), - patch: jest.fn(createPromise), - post: jest.fn(createPromise), - put: jest.fn(createPromise), - }; - BaseAPI = new Base(mockHttp, mockBaseURL); - }); - - afterEach(() => { - jest.resetAllMocks(); - }); - - test('create calls http method with expected data', async () => { - const data = { name: 'test ' }; - await BaseAPI.create(data); - - expect(mockHttp.post).toHaveBeenCalledTimes(1); - expect(mockHttp.post.mock.calls[0][1]).toEqual(data); - }); - - test('destroy calls http method with expected data', async () => { - const resourceId = 1; - await BaseAPI.destroy(resourceId); - - expect(mockHttp.delete).toHaveBeenCalledTimes(1); - expect(mockHttp.delete.mock.calls[0][0]).toEqual( - `${mockBaseURL}${resourceId}/` - ); - }); - - test('read calls http method with expected data', async () => { - const testParams = { foo: 'bar' }; - const testParamsDuplicates = { foo: ['bar', 'baz'] }; - - await BaseAPI.read(testParams); - await BaseAPI.read(); - await BaseAPI.read(testParamsDuplicates); - - expect(mockHttp.get).toHaveBeenCalledTimes(3); - expect(mockHttp.get.mock.calls[0][0]).toEqual(`${mockBaseURL}`); - expect(mockHttp.get.mock.calls[0][1]).toEqual({ params: { foo: 'bar' } }); - expect(mockHttp.get.mock.calls[1][0]).toEqual(`${mockBaseURL}`); - expect(mockHttp.get.mock.calls[1][1]).toEqual({ params: undefined }); - expect(mockHttp.get.mock.calls[2][0]).toEqual(`${mockBaseURL}`); - expect(mockHttp.get.mock.calls[2][1]).toEqual({ - params: { foo: ['bar', 'baz'] }, - }); - }); - - test('readDetail calls http method with expected data', async () => { - const resourceId = 1; - - await BaseAPI.readDetail(resourceId); - - expect(mockHttp.get).toHaveBeenCalledTimes(1); - expect(mockHttp.get.mock.calls[0][0]).toEqual( - `${mockBaseURL}${resourceId}/` - ); - }); - - test('readOptions calls http method with expected data', async () => { - await BaseAPI.readOptions(); - - expect(mockHttp.options).toHaveBeenCalledTimes(1); - expect(mockHttp.options.mock.calls[0][0]).toEqual(`${mockBaseURL}`); - }); - - test('replace calls http method with expected data', async () => { - const resourceId = 1; - const data = { name: 'test ' }; - - await BaseAPI.replace(resourceId, data); - - expect(mockHttp.put).toHaveBeenCalledTimes(1); - expect(mockHttp.put.mock.calls[0][0]).toEqual( - `${mockBaseURL}${resourceId}/` - ); - expect(mockHttp.put.mock.calls[0][1]).toEqual(data); - }); - - test('update calls http method with expected data', async () => { - const resourceId = 1; - const data = { name: 'test ' }; - - await BaseAPI.update(resourceId, data); - - expect(mockHttp.patch).toHaveBeenCalledTimes(1); - expect(mockHttp.patch.mock.calls[0][0]).toEqual( - `${mockBaseURL}${resourceId}/` - ); - expect(mockHttp.patch.mock.calls[0][1]).toEqual(data); - }); -}); diff --git a/awx/ui/src/api/index.js b/awx/ui/src/api/index.js deleted file mode 100644 index 5281ad861d10..000000000000 --- a/awx/ui/src/api/index.js +++ /dev/null @@ -1,142 +0,0 @@ -import ActivityStream from './models/ActivityStream'; -import AdHocCommands from './models/AdHocCommands'; -import Applications from './models/Applications'; -import Auth from './models/Auth'; -import Config from './models/Config'; -import CredentialInputSources from './models/CredentialInputSources'; -import CredentialTypes from './models/CredentialTypes'; -import Credentials from './models/Credentials'; -import Dashboard from './models/Dashboard'; -import ExecutionEnvironments from './models/ExecutionEnvironments'; -import Groups from './models/Groups'; -import Hosts from './models/Hosts'; -import InstanceGroups from './models/InstanceGroups'; -import Instances from './models/Instances'; -import Inventories from './models/Inventories'; -import InventoryScripts from './models/InventoryScripts'; -import InventorySources from './models/InventorySources'; -import InventoryUpdates from './models/InventoryUpdates'; -import JobTemplates from './models/JobTemplates'; -import Jobs from './models/Jobs'; -import JobEvents from './models/JobEvents'; -import Labels from './models/Labels'; -import Me from './models/Me'; -import Mesh from './models/Mesh'; -import Metrics from './models/Metrics'; -import NotificationTemplates from './models/NotificationTemplates'; -import Notifications from './models/Notifications'; -import Organizations from './models/Organizations'; -import ProjectUpdates from './models/ProjectUpdates'; -import Projects from './models/Projects'; -import Roles from './models/Roles'; -import Root from './models/Root'; -import Schedules from './models/Schedules'; -import Settings from './models/Settings'; -import SystemJobs from './models/SystemJobs'; -import SystemJobTemplates from './models/SystemJobTemplates'; -import Teams from './models/Teams'; -import Tokens from './models/Tokens'; -import UnifiedJobTemplates from './models/UnifiedJobTemplates'; -import UnifiedJobs from './models/UnifiedJobs'; -import Users from './models/Users'; -import WorkflowApprovals from './models/WorkflowApprovals'; -import WorkflowApprovalTemplates from './models/WorkflowApprovalTemplates'; -import WorkflowJobTemplateNodes from './models/WorkflowJobTemplateNodes'; -import WorkflowJobTemplates from './models/WorkflowJobTemplates'; -import WorkflowJobs from './models/WorkflowJobs'; - -const ActivityStreamAPI = new ActivityStream(); -const AdHocCommandsAPI = new AdHocCommands(); -const ApplicationsAPI = new Applications(); -const AuthAPI = new Auth(); -const ConfigAPI = new Config(); -const CredentialInputSourcesAPI = new CredentialInputSources(); -const CredentialTypesAPI = new CredentialTypes(); -const CredentialsAPI = new Credentials(); -const DashboardAPI = new Dashboard(); -const ExecutionEnvironmentsAPI = new ExecutionEnvironments(); -const GroupsAPI = new Groups(); -const HostsAPI = new Hosts(); -const InstanceGroupsAPI = new InstanceGroups(); -const InstancesAPI = new Instances(); -const InventoriesAPI = new Inventories(); -const InventoryScriptsAPI = new InventoryScripts(); -const InventorySourcesAPI = new InventorySources(); -const InventoryUpdatesAPI = new InventoryUpdates(); -const JobTemplatesAPI = new JobTemplates(); -const JobsAPI = new Jobs(); -const JobEventsAPI = new JobEvents(); -const LabelsAPI = new Labels(); -const MeAPI = new Me(); -const MeshAPI = new Mesh(); -const MetricsAPI = new Metrics(); -const NotificationTemplatesAPI = new NotificationTemplates(); -const NotificationsAPI = new Notifications(); -const OrganizationsAPI = new Organizations(); -const ProjectUpdatesAPI = new ProjectUpdates(); -const ProjectsAPI = new Projects(); -const RolesAPI = new Roles(); -const RootAPI = new Root(); -const SchedulesAPI = new Schedules(); -const SettingsAPI = new Settings(); -const SystemJobsAPI = new SystemJobs(); -const SystemJobTemplatesAPI = new SystemJobTemplates(); -const TeamsAPI = new Teams(); -const TokensAPI = new Tokens(); -const UnifiedJobTemplatesAPI = new UnifiedJobTemplates(); -const UnifiedJobsAPI = new UnifiedJobs(); -const UsersAPI = new Users(); -const WorkflowApprovalsAPI = new WorkflowApprovals(); -const WorkflowApprovalTemplatesAPI = new WorkflowApprovalTemplates(); -const WorkflowJobTemplateNodesAPI = new WorkflowJobTemplateNodes(); -const WorkflowJobTemplatesAPI = new WorkflowJobTemplates(); -const WorkflowJobsAPI = new WorkflowJobs(); - -export { - ActivityStreamAPI, - AdHocCommandsAPI, - ApplicationsAPI, - AuthAPI, - ConfigAPI, - CredentialInputSourcesAPI, - CredentialTypesAPI, - CredentialsAPI, - DashboardAPI, - ExecutionEnvironmentsAPI, - GroupsAPI, - HostsAPI, - InstanceGroupsAPI, - InstancesAPI, - InventoriesAPI, - InventoryScriptsAPI, - InventorySourcesAPI, - InventoryUpdatesAPI, - JobTemplatesAPI, - JobsAPI, - JobEventsAPI, - LabelsAPI, - MeAPI, - MeshAPI, - MetricsAPI, - NotificationTemplatesAPI, - NotificationsAPI, - OrganizationsAPI, - ProjectUpdatesAPI, - ProjectsAPI, - RolesAPI, - RootAPI, - SchedulesAPI, - SettingsAPI, - SystemJobsAPI, - SystemJobTemplatesAPI, - TeamsAPI, - TokensAPI, - UnifiedJobTemplatesAPI, - UnifiedJobsAPI, - UsersAPI, - WorkflowApprovalsAPI, - WorkflowApprovalTemplatesAPI, - WorkflowJobTemplateNodesAPI, - WorkflowJobTemplatesAPI, - WorkflowJobsAPI, -}; diff --git a/awx/ui/src/api/mixins/InstanceGroups.mixin.js b/awx/ui/src/api/mixins/InstanceGroups.mixin.js deleted file mode 100644 index e2e230122c8c..000000000000 --- a/awx/ui/src/api/mixins/InstanceGroups.mixin.js +++ /dev/null @@ -1,44 +0,0 @@ -function isEqual(array1, array2) { - return ( - array1.length === array2.length && - array1.every((element, index) => element.id === array2[index].id) - ); -} - -const InstanceGroupsMixin = (parent) => - class extends parent { - readInstanceGroups(resourceId, params) { - return this.http.get(`${this.baseUrl}${resourceId}/instance_groups/`, { - params, - }); - } - - associateInstanceGroup(resourceId, instanceGroupId) { - return this.http.post(`${this.baseUrl}${resourceId}/instance_groups/`, { - id: instanceGroupId, - }); - } - - disassociateInstanceGroup(resourceId, instanceGroupId) { - return this.http.post(`${this.baseUrl}${resourceId}/instance_groups/`, { - id: instanceGroupId, - disassociate: true, - }); - } - - async orderInstanceGroups(resourceId, current, original) { - /* eslint-disable no-await-in-loop, no-restricted-syntax */ - // Resolve Promises sequentially to maintain order and avoid race condition - if (!isEqual(current, original)) { - for (const group of original) { - await this.disassociateInstanceGroup(resourceId, group.id); - } - for (const group of current) { - await this.associateInstanceGroup(resourceId, group.id); - } - } - } - /* eslint-enable no-await-in-loop, no-restricted-syntax */ - }; - -export default InstanceGroupsMixin; diff --git a/awx/ui/src/api/mixins/Labels.mixin.js b/awx/ui/src/api/mixins/Labels.mixin.js deleted file mode 100644 index 98aae12034cb..000000000000 --- a/awx/ui/src/api/mixins/Labels.mixin.js +++ /dev/null @@ -1,49 +0,0 @@ -const LabelsMixin = (parent) => - class extends parent { - readLabels(id, params) { - return this.http.get(`${this.baseUrl}${id}/labels/`, { - params, - }); - } - - readAllLabels(id) { - const fetchLabels = async (pageNo = 1, labels = []) => { - try { - const { data } = await this.http.get(`${this.baseUrl}${id}/labels/`, { - params: { - page: pageNo, - page_size: 200, - }, - }); - if (data?.next) { - return fetchLabels(pageNo + 1, labels.concat(data.results)); - } - return Promise.resolve({ - data: { - results: labels.concat(data.results), - }, - }); - } catch (error) { - return Promise.reject(error); - } - }; - - return fetchLabels(); - } - - associateLabel(id, label, orgId) { - return this.http.post(`${this.baseUrl}${id}/labels/`, { - name: label.name, - organization: orgId, - }); - } - - disassociateLabel(id, label) { - return this.http.post(`${this.baseUrl}${id}/labels/`, { - id: label.id, - disassociate: true, - }); - } - }; - -export default LabelsMixin; diff --git a/awx/ui/src/api/mixins/LaunchUpdate.mixin.js b/awx/ui/src/api/mixins/LaunchUpdate.mixin.js deleted file mode 100644 index cad3c0e53f08..000000000000 --- a/awx/ui/src/api/mixins/LaunchUpdate.mixin.js +++ /dev/null @@ -1,12 +0,0 @@ -const LaunchUpdateMixin = (parent) => - class extends parent { - launchUpdate(id, data) { - return this.http.post(`${this.baseUrl}${id}/update/`, data); - } - - readLaunchUpdate(id) { - return this.http.get(`${this.baseUrl}${id}/update/`); - } - }; - -export default LaunchUpdateMixin; diff --git a/awx/ui/src/api/mixins/Notifications.mixin.js b/awx/ui/src/api/mixins/Notifications.mixin.js deleted file mode 100644 index c3782e2d8eae..000000000000 --- a/awx/ui/src/api/mixins/Notifications.mixin.js +++ /dev/null @@ -1,170 +0,0 @@ -const NotificationsMixin = (parent) => - class extends parent { - readOptionsNotificationTemplates(id) { - return this.http.options(`${this.baseUrl}${id}/notification_templates/`); - } - - readNotificationTemplates(id, params) { - return this.http.get( - `${this.baseUrl}${id}/notification_templates/`, - params - ); - } - - readNotificationTemplatesStarted(id, params) { - return this.http.get( - `${this.baseUrl}${id}/notification_templates_started/`, - { params } - ); - } - - readNotificationTemplatesSuccess(id, params) { - return this.http.get( - `${this.baseUrl}${id}/notification_templates_success/`, - { params } - ); - } - - readNotificationTemplatesError(id, params) { - return this.http.get( - `${this.baseUrl}${id}/notification_templates_error/`, - { params } - ); - } - - associateNotificationTemplatesStarted(resourceId, notificationId) { - return this.http.post( - `${this.baseUrl}${resourceId}/notification_templates_started/`, - { id: notificationId } - ); - } - - disassociateNotificationTemplatesStarted(resourceId, notificationId) { - return this.http.post( - `${this.baseUrl}${resourceId}/notification_templates_started/`, - { id: notificationId, disassociate: true } - ); - } - - associateNotificationTemplatesSuccess(resourceId, notificationId) { - return this.http.post( - `${this.baseUrl}${resourceId}/notification_templates_success/`, - { id: notificationId } - ); - } - - disassociateNotificationTemplatesSuccess(resourceId, notificationId) { - return this.http.post( - `${this.baseUrl}${resourceId}/notification_templates_success/`, - { id: notificationId, disassociate: true } - ); - } - - associateNotificationTemplatesError(resourceId, notificationId) { - return this.http.post( - `${this.baseUrl}${resourceId}/notification_templates_error/`, - { id: notificationId } - ); - } - - disassociateNotificationTemplatesError(resourceId, notificationId) { - return this.http.post( - `${this.baseUrl}${resourceId}/notification_templates_error/`, - { id: notificationId, disassociate: true } - ); - } - - /** - * This is a helper method meant to simplify setting the "on" status of - * a related notification. - * - * @param[resourceId] - id of the base resource - * @param[notificationId] - id of the notification - * @param[notificationType] - the type of notification, options are "success" and "error" - */ - associateNotificationTemplate( - resourceId, - notificationId, - notificationType - ) { - if (notificationType === 'approvals') { - return this.associateNotificationTemplatesApprovals( - resourceId, - notificationId - ); - } - - if (notificationType === 'started') { - return this.associateNotificationTemplatesStarted( - resourceId, - notificationId - ); - } - - if (notificationType === 'success') { - return this.associateNotificationTemplatesSuccess( - resourceId, - notificationId - ); - } - - if (notificationType === 'error') { - return this.associateNotificationTemplatesError( - resourceId, - notificationId - ); - } - - throw new Error( - `Unsupported notificationType for association: ${notificationType}` - ); - } - - /** - * This is a helper method meant to simplify setting the "off" status of - * a related notification. - * - * @param[resourceId] - id of the base resource - * @param[notificationId] - id of the notification - * @param[notificationType] - the type of notification, options are "success" and "error" - */ - disassociateNotificationTemplate( - resourceId, - notificationId, - notificationType - ) { - if (notificationType === 'approvals') { - return this.disassociateNotificationTemplatesApprovals( - resourceId, - notificationId - ); - } - - if (notificationType === 'started') { - return this.disassociateNotificationTemplatesStarted( - resourceId, - notificationId - ); - } - - if (notificationType === 'success') { - return this.disassociateNotificationTemplatesSuccess( - resourceId, - notificationId - ); - } - - if (notificationType === 'error') { - return this.disassociateNotificationTemplatesError( - resourceId, - notificationId - ); - } - - throw new Error( - `Unsupported notificationType for disassociation: ${notificationType}` - ); - } - }; - -export default NotificationsMixin; diff --git a/awx/ui/src/api/mixins/Runnable.mixin.js b/awx/ui/src/api/mixins/Runnable.mixin.js deleted file mode 100644 index 2c9b27b28818..000000000000 --- a/awx/ui/src/api/mixins/Runnable.mixin.js +++ /dev/null @@ -1,48 +0,0 @@ -const Runnable = (parent) => - class extends parent { - jobEventSlug = '/events/'; - - cancel(id) { - const endpoint = `${this.baseUrl}${id}/cancel/`; - - return this.http.post(endpoint); - } - - launchUpdate(id, data) { - const endpoint = `${this.baseUrl}${id}/update/`; - - return this.http.post(endpoint, data); - } - - readLaunchUpdate(id) { - const endpoint = `${this.baseUrl}${id}/update/`; - - return this.http.get(endpoint); - } - - readEvents(id, params = {}) { - const endpoint = `${this.baseUrl}${id}${this.jobEventSlug}`; - - return this.http.get(endpoint, { params }); - } - - readEventOptions(id) { - const endpoint = `${this.baseUrl}${id}${this.jobEventSlug}`; - - return this.http.options(endpoint); - } - - readRelaunch(id) { - const endpoint = `${this.baseUrl}${id}/relaunch/`; - - return this.http.get(endpoint); - } - - relaunch(id, data) { - const endpoint = `${this.baseUrl}${id}/relaunch/`; - - return this.http.post(endpoint, data); - } - }; - -export default Runnable; diff --git a/awx/ui/src/api/mixins/Schedules.mixin.js b/awx/ui/src/api/mixins/Schedules.mixin.js deleted file mode 100644 index 450e7c727a40..000000000000 --- a/awx/ui/src/api/mixins/Schedules.mixin.js +++ /dev/null @@ -1,16 +0,0 @@ -const SchedulesMixin = (parent) => - class extends parent { - createSchedule(id, data) { - return this.http.post(`${this.baseUrl}${id}/schedules/`, data); - } - - readSchedules(id, params) { - return this.http.get(`${this.baseUrl}${id}/schedules/`, { params }); - } - - readScheduleOptions(id) { - return this.http.options(`${this.baseUrl}${id}/schedules/`); - } - }; - -export default SchedulesMixin; diff --git a/awx/ui/src/api/models/ActivityStream.js b/awx/ui/src/api/models/ActivityStream.js deleted file mode 100644 index 68f748dc18bd..000000000000 --- a/awx/ui/src/api/models/ActivityStream.js +++ /dev/null @@ -1,10 +0,0 @@ -import Base from '../Base'; - -class ActivityStream extends Base { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/activity_stream/'; - } -} - -export default ActivityStream; diff --git a/awx/ui/src/api/models/AdHocCommands.js b/awx/ui/src/api/models/AdHocCommands.js deleted file mode 100644 index 0bec670de9ae..000000000000 --- a/awx/ui/src/api/models/AdHocCommands.js +++ /dev/null @@ -1,15 +0,0 @@ -import Base from '../Base'; -import RunnableMixin from '../mixins/Runnable.mixin'; - -class AdHocCommands extends RunnableMixin(Base) { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/ad_hoc_commands/'; - } - - readCredentials(id) { - return this.http.get(`${this.baseUrl}${id}/credentials/`); - } -} - -export default AdHocCommands; diff --git a/awx/ui/src/api/models/Applications.js b/awx/ui/src/api/models/Applications.js deleted file mode 100644 index d53f911dbc02..000000000000 --- a/awx/ui/src/api/models/Applications.js +++ /dev/null @@ -1,20 +0,0 @@ -import Base from '../Base'; - -class Applications extends Base { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/applications/'; - } - - readTokens(appId, params) { - return this.http.get(`${this.baseUrl}${appId}/tokens/`, { - params, - }); - } - - readTokenOptions(appId) { - return this.http.options(`${this.baseUrl}${appId}/tokens/`); - } -} - -export default Applications; diff --git a/awx/ui/src/api/models/Auth.js b/awx/ui/src/api/models/Auth.js deleted file mode 100644 index cae34f8fc322..000000000000 --- a/awx/ui/src/api/models/Auth.js +++ /dev/null @@ -1,10 +0,0 @@ -import Base from '../Base'; - -class Auth extends Base { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/auth/'; - } -} - -export default Auth; diff --git a/awx/ui/src/api/models/Config.js b/awx/ui/src/api/models/Config.js deleted file mode 100644 index ae73f88d65f1..000000000000 --- a/awx/ui/src/api/models/Config.js +++ /dev/null @@ -1,22 +0,0 @@ -import Base from '../Base'; - -class Config extends Base { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/config/'; - this.read = this.read.bind(this); - } - - readSubscriptions(username, password) { - return this.http.post(`${this.baseUrl}subscriptions/`, { - subscriptions_username: username, - subscriptions_password: password, - }); - } - - attach(data) { - return this.http.post(`${this.baseUrl}attach/`, data); - } -} - -export default Config; diff --git a/awx/ui/src/api/models/CredentialInputSources.js b/awx/ui/src/api/models/CredentialInputSources.js deleted file mode 100644 index c82f27a22ec7..000000000000 --- a/awx/ui/src/api/models/CredentialInputSources.js +++ /dev/null @@ -1,10 +0,0 @@ -import Base from '../Base'; - -class CredentialInputSources extends Base { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/credential_input_sources/'; - } -} - -export default CredentialInputSources; diff --git a/awx/ui/src/api/models/CredentialTypes.js b/awx/ui/src/api/models/CredentialTypes.js deleted file mode 100644 index 72f641c117bf..000000000000 --- a/awx/ui/src/api/models/CredentialTypes.js +++ /dev/null @@ -1,44 +0,0 @@ -import Base from '../Base'; - -class CredentialTypes extends Base { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/credential_types/'; - } - - async loadAllTypes( - acceptableKinds = [ - 'machine', - 'cloud', - 'net', - 'ssh', - 'vault', - 'kubernetes', - 'cryptography', - ] - ) { - const pageSize = 200; - // The number of credential types a user can have is unlimited. In practice, it is unlikely for - // users to have more than a page at the maximum request size. - const { - data: { next, results }, - } = await this.read({ page_size: pageSize }); - let nextResults = []; - if (next) { - const { data } = await this.read({ - page_size: pageSize, - page: 2, - }); - nextResults = data.results; - } - return results - .concat(nextResults) - .filter((type) => acceptableKinds.includes(type.kind)); - } - - test(id, data) { - return this.http.post(`${this.baseUrl}${id}/test/`, data); - } -} - -export default CredentialTypes; diff --git a/awx/ui/src/api/models/CredentialTypes.test.js b/awx/ui/src/api/models/CredentialTypes.test.js deleted file mode 100644 index 885c68a47a9f..000000000000 --- a/awx/ui/src/api/models/CredentialTypes.test.js +++ /dev/null @@ -1,68 +0,0 @@ -import CredentialTypes from './CredentialTypes'; - -const typesData = [ - { id: 1, kind: 'machine' }, - { id: 2, kind: 'cloud' }, -]; - -describe('CredentialTypesAPI', () => { - test('should load all types', async () => { - const getPromise = () => - Promise.resolve({ - data: { - results: typesData, - }, - }); - const mockHttp = { get: jest.fn(getPromise) }; - const CredentialTypesAPI = new CredentialTypes(mockHttp); - - const types = await CredentialTypesAPI.loadAllTypes(); - - expect(mockHttp.get).toHaveBeenCalledTimes(1); - expect(mockHttp.get.mock.calls[0]).toEqual([ - `api/v2/credential_types/`, - { params: { page_size: 200 } }, - ]); - expect(types).toEqual(typesData); - }); - - test('should load all types (2 pages)', async () => { - const getPromise = () => - Promise.resolve({ - data: { - results: typesData, - next: 2, - }, - }); - const mockHttp = { get: jest.fn(getPromise) }; - const CredentialTypesAPI = new CredentialTypes(mockHttp); - - const types = await CredentialTypesAPI.loadAllTypes(); - - expect(mockHttp.get).toHaveBeenCalledTimes(2); - expect(mockHttp.get.mock.calls[0]).toEqual([ - `api/v2/credential_types/`, - { params: { page_size: 200 } }, - ]); - expect(mockHttp.get.mock.calls[1]).toEqual([ - `api/v2/credential_types/`, - { params: { page_size: 200, page: 2 } }, - ]); - expect(types).toHaveLength(4); - }); - - test('should filter by acceptable kinds', async () => { - const getPromise = () => - Promise.resolve({ - data: { - results: typesData, - }, - }); - const mockHttp = { get: jest.fn(getPromise) }; - const CredentialTypesAPI = new CredentialTypes(mockHttp); - - const types = await CredentialTypesAPI.loadAllTypes(['machine']); - - expect(types).toEqual([typesData[0]]); - }); -}); diff --git a/awx/ui/src/api/models/Credentials.js b/awx/ui/src/api/models/Credentials.js deleted file mode 100644 index 44bfbb9d0a4b..000000000000 --- a/awx/ui/src/api/models/Credentials.js +++ /dev/null @@ -1,62 +0,0 @@ -import Base from '../Base'; - -class Credentials extends Base { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/credentials/'; - - this.readAccessList = this.readAccessList.bind(this); - this.readAccessOptions = this.readAccessOptions.bind(this); - this.readInputSources = this.readInputSources.bind(this); - } - - readAccessList(id, params) { - return this.http.get(`${this.baseUrl}${id}/access_list/`, { - params, - }); - } - - readAccessOptions(id) { - return this.http.options(`${this.baseUrl}${id}/access_list/`); - } - - readInputSources(id) { - const maxRequests = 5; - let requestCounter = 0; - const fetchInputSources = async (pageNo = 1, inputSources = []) => { - try { - requestCounter++; - const { data } = await this.http.get( - `${this.baseUrl}${id}/input_sources/`, - { - params: { - page: pageNo, - page_size: 200, - }, - } - ); - if (data?.next && requestCounter <= maxRequests) { - return fetchInputSources( - pageNo + 1, - inputSources.concat(data.results) - ); - } - return Promise.resolve({ - data: { - results: inputSources.concat(data.results), - }, - }); - } catch (error) { - return Promise.reject(error); - } - }; - - return fetchInputSources(); - } - - test(id, data) { - return this.http.post(`${this.baseUrl}${id}/test/`, data); - } -} - -export default Credentials; diff --git a/awx/ui/src/api/models/Dashboard.js b/awx/ui/src/api/models/Dashboard.js deleted file mode 100644 index 06c00f191c32..000000000000 --- a/awx/ui/src/api/models/Dashboard.js +++ /dev/null @@ -1,16 +0,0 @@ -import Base from '../Base'; - -class Dashboard extends Base { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/dashboard/'; - } - - readJobGraph(params) { - return this.http.get(`${this.baseUrl}graphs/jobs/`, { - params, - }); - } -} - -export default Dashboard; diff --git a/awx/ui/src/api/models/ExecutionEnvironments.js b/awx/ui/src/api/models/ExecutionEnvironments.js deleted file mode 100644 index 8c2fff9a0c35..000000000000 --- a/awx/ui/src/api/models/ExecutionEnvironments.js +++ /dev/null @@ -1,20 +0,0 @@ -import Base from '../Base'; - -class ExecutionEnvironments extends Base { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/execution_environments/'; - } - - readUnifiedJobTemplates(id, params) { - return this.http.get(`${this.baseUrl}${id}/unified_job_templates/`, { - params, - }); - } - - readUnifiedJobTemplateOptions(id) { - return this.http.options(`${this.baseUrl}${id}/unified_job_templates/`); - } -} - -export default ExecutionEnvironments; diff --git a/awx/ui/src/api/models/Groups.js b/awx/ui/src/api/models/Groups.js deleted file mode 100644 index 6677a9e27317..000000000000 --- a/awx/ui/src/api/models/Groups.js +++ /dev/null @@ -1,59 +0,0 @@ -import Base from '../Base'; - -class Groups extends Base { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/groups/'; - - this.associateHost = this.associateHost.bind(this); - this.createHost = this.createHost.bind(this); - this.readAllHosts = this.readAllHosts.bind(this); - this.disassociateHost = this.disassociateHost.bind(this); - } - - associateHost(id, hostId) { - return this.http.post(`${this.baseUrl}${id}/hosts/`, { - id: hostId, - }); - } - - createHost(id, data) { - return this.http.post(`${this.baseUrl}${id}/hosts/`, data); - } - - readAllHosts(id, params) { - return this.http.get(`${this.baseUrl}${id}/all_hosts/`, { - params, - }); - } - - disassociateHost(id, host) { - return this.http.post(`${this.baseUrl}${id}/hosts/`, { - id: host.id, - disassociate: true, - }); - } - - readChildren(id, params) { - return this.http.get(`${this.baseUrl}${id}/children/`, { params }); - } - - associateChildGroup(id, childId) { - return this.http.post(`${this.baseUrl}${id}/children/`, { id: childId }); - } - - disassociateChildGroup(id, childId) { - return this.http.post(`${this.baseUrl}${id}/children/`, { - disassociate: id, - id: childId, - }); - } - - readPotentialGroups(id, params) { - return this.http.get(`${this.baseUrl}${id}/potential_children/`, { - params, - }); - } -} - -export default Groups; diff --git a/awx/ui/src/api/models/Hosts.js b/awx/ui/src/api/models/Hosts.js deleted file mode 100644 index 0422407da9e1..000000000000 --- a/awx/ui/src/api/models/Hosts.js +++ /dev/null @@ -1,43 +0,0 @@ -import Base from '../Base'; - -class Hosts extends Base { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/hosts/'; - - this.readFacts = this.readFacts.bind(this); - this.readAllGroups = this.readAllGroups.bind(this); - this.readGroupsOptions = this.readGroupsOptions.bind(this); - this.associateGroup = this.associateGroup.bind(this); - this.disassociateGroup = this.disassociateGroup.bind(this); - } - - readFacts(id) { - return this.http.get(`${this.baseUrl}${id}/ansible_facts/`); - } - - readAllGroups(id, params) { - return this.http.get(`${this.baseUrl}${id}/all_groups/`, { params }); - } - - readGroups(id, params) { - return this.http.get(`${this.baseUrl}${id}/groups/`, { params }); - } - - readGroupsOptions(id) { - return this.http.options(`${this.baseUrl}${id}/groups/`); - } - - associateGroup(id, groupId) { - return this.http.post(`${this.baseUrl}${id}/groups/`, { id: groupId }); - } - - disassociateGroup(id, group) { - return this.http.post(`${this.baseUrl}${id}/groups/`, { - id: group.id, - disassociate: true, - }); - } -} - -export default Hosts; diff --git a/awx/ui/src/api/models/InstanceGroups.js b/awx/ui/src/api/models/InstanceGroups.js deleted file mode 100644 index e28a1694e41a..000000000000 --- a/awx/ui/src/api/models/InstanceGroups.js +++ /dev/null @@ -1,41 +0,0 @@ -import Base from '../Base'; - -class InstanceGroups extends Base { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/instance_groups/'; - - this.associateInstance = this.associateInstance.bind(this); - this.disassociateInstance = this.disassociateInstance.bind(this); - this.readInstanceOptions = this.readInstanceOptions.bind(this); - this.readInstances = this.readInstances.bind(this); - this.readJobs = this.readJobs.bind(this); - } - - associateInstance(instanceGroupId, instanceId) { - return this.http.post(`${this.baseUrl}${instanceGroupId}/instances/`, { - id: instanceId, - }); - } - - disassociateInstance(instanceGroupId, instanceId) { - return this.http.post(`${this.baseUrl}${instanceGroupId}/instances/`, { - id: instanceId, - disassociate: true, - }); - } - - readInstances(id, params) { - return this.http.get(`${this.baseUrl}${id}/instances/`, { params }); - } - - readInstanceOptions(id) { - return this.http.options(`${this.baseUrl}${id}/instances/`); - } - - readJobs(id) { - return this.http.get(`${this.baseUrl}${id}/jobs/`); - } -} - -export default InstanceGroups; diff --git a/awx/ui/src/api/models/Instances.js b/awx/ui/src/api/models/Instances.js deleted file mode 100644 index 388bb2eb4e17..000000000000 --- a/awx/ui/src/api/models/Instances.js +++ /dev/null @@ -1,37 +0,0 @@ -import Base from '../Base'; - -class Instances extends Base { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/instances/'; - - this.readHealthCheckDetail = this.readHealthCheckDetail.bind(this); - this.healthCheck = this.healthCheck.bind(this); - this.readInstanceGroup = this.readInstanceGroup.bind(this); - this.deprovisionInstance = this.deprovisionInstance.bind(this); - } - - healthCheck(instanceId) { - return this.http.post(`${this.baseUrl}${instanceId}/health_check/`); - } - - readHealthCheckDetail(instanceId) { - return this.http.get(`${this.baseUrl}${instanceId}/health_check/`); - } - - readPeers(instanceId, params) { - return this.http.get(`${this.baseUrl}${instanceId}/peers/`, { params }); - } - - readInstanceGroup(instanceId) { - return this.http.get(`${this.baseUrl}${instanceId}/instance_groups/`); - } - - deprovisionInstance(instanceId) { - return this.http.patch(`${this.baseUrl}${instanceId}/`, { - node_state: 'deprovisioning', - }); - } -} - -export default Instances; diff --git a/awx/ui/src/api/models/Inventories.js b/awx/ui/src/api/models/Inventories.js deleted file mode 100644 index fd1653045f1b..000000000000 --- a/awx/ui/src/api/models/Inventories.js +++ /dev/null @@ -1,135 +0,0 @@ -import Base from '../Base'; -import InstanceGroupsMixin from '../mixins/InstanceGroups.mixin'; - -class Inventories extends InstanceGroupsMixin(Base) { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/inventories/'; - - this.readAccessList = this.readAccessList.bind(this); - this.readAccessOptions = this.readAccessOptions.bind(this); - this.readHosts = this.readHosts.bind(this); - this.readHostDetail = this.readHostDetail.bind(this); - this.readGroups = this.readGroups.bind(this); - this.readGroupsOptions = this.readGroupsOptions.bind(this); - this.promoteGroup = this.promoteGroup.bind(this); - } - - readAccessList(id, params) { - return this.http.get(`${this.baseUrl}${id}/access_list/`, { - params, - }); - } - - readAccessOptions(id) { - return this.http.options(`${this.baseUrl}${id}/access_list/`); - } - - createHost(id, data) { - return this.http.post(`${this.baseUrl}${id}/hosts/`, data); - } - - readHosts(id, params) { - return this.http.get(`${this.baseUrl}${id}/hosts/`, { - params, - }); - } - - async readHostDetail(inventoryId, hostId) { - const { - data: { results }, - } = await this.http.get( - `${this.baseUrl}${inventoryId}/hosts/?id=${hostId}` - ); - - if (Array.isArray(results) && results.length) { - return results[0]; - } - - throw new Error( - `How did you get here? Host not found for Inventory ID: ${inventoryId}` - ); - } - - readGroups(id, params) { - return this.http.get(`${this.baseUrl}${id}/groups/`, { - params, - }); - } - - readGroupsOptions(id) { - return this.http.options(`${this.baseUrl}${id}/groups/`); - } - - readHostsOptions(id) { - return this.http.options(`${this.baseUrl}${id}/hosts/`); - } - - promoteGroup(inventoryId, groupId) { - return this.http.post(`${this.baseUrl}${inventoryId}/groups/`, { - id: groupId, - disassociate: true, - }); - } - - readSources(inventoryId, params) { - return this.http.get(`${this.baseUrl}${inventoryId}/inventory_sources/`, { - params, - }); - } - - updateSources(inventoryId) { - return this.http.get( - `${this.baseUrl}${inventoryId}/update_inventory_sources/` - ); - } - - async readSourceDetail(inventoryId, sourceId) { - const { - data: { results }, - } = await this.http.get( - `${this.baseUrl}${inventoryId}/inventory_sources/?id=${sourceId}` - ); - - if (Array.isArray(results) && results.length) { - return results[0]; - } - - throw new Error( - `How did you get here? Source not found for Inventory ID: ${inventoryId}` - ); - } - - syncAllSources(inventoryId) { - return this.http.post( - `${this.baseUrl}${inventoryId}/update_inventory_sources/` - ); - } - - readAdHocOptions(inventoryId) { - return this.http.options(`${this.baseUrl}${inventoryId}/ad_hoc_commands/`); - } - - launchAdHocCommands(inventoryId, values) { - return this.http.post( - `${this.baseUrl}${inventoryId}/ad_hoc_commands/`, - values - ); - } - - associateLabel(id, label, orgId) { - return this.http.post(`${this.baseUrl}${id}/labels/`, { - name: label.name, - organization: orgId, - }); - } - - disassociateLabel(id, label) { - return this.http.post(`${this.baseUrl}${id}/labels/`, { - id: label.id, - disassociate: true, - }); - } -} - -export default Inventories; diff --git a/awx/ui/src/api/models/InventoryScripts.js b/awx/ui/src/api/models/InventoryScripts.js deleted file mode 100644 index 030238e67f9b..000000000000 --- a/awx/ui/src/api/models/InventoryScripts.js +++ /dev/null @@ -1,10 +0,0 @@ -import Base from '../Base'; - -class InventoryScripts extends Base { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/inventory_scripts/'; - } -} - -export default InventoryScripts; diff --git a/awx/ui/src/api/models/InventorySources.js b/awx/ui/src/api/models/InventorySources.js deleted file mode 100644 index 66ad6dbc91cf..000000000000 --- a/awx/ui/src/api/models/InventorySources.js +++ /dev/null @@ -1,41 +0,0 @@ -import Base from '../Base'; -import NotificationsMixin from '../mixins/Notifications.mixin'; -import LaunchUpdateMixin from '../mixins/LaunchUpdate.mixin'; -import SchedulesMixin from '../mixins/Schedules.mixin'; - -class InventorySources extends LaunchUpdateMixin( - NotificationsMixin(SchedulesMixin(Base)) -) { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/inventory_sources/'; - - this.createSchedule = this.createSchedule.bind(this); - this.createSyncStart = this.createSyncStart.bind(this); - this.destroyGroups = this.destroyGroups.bind(this); - this.destroyHosts = this.destroyHosts.bind(this); - } - - createSyncStart(sourceId, extraVars) { - return this.http.post(`${this.baseUrl}${sourceId}/update/`, { - extra_vars: extraVars, - }); - } - - readGroups(id) { - return this.http.get(`${this.baseUrl}${id}/groups/`); - } - - readHosts(id) { - return this.http.get(`${this.baseUrl}${id}/hosts/`); - } - - destroyGroups(id) { - return this.http.delete(`${this.baseUrl}${id}/groups/`); - } - - destroyHosts(id) { - return this.http.delete(`${this.baseUrl}${id}/hosts/`); - } -} -export default InventorySources; diff --git a/awx/ui/src/api/models/InventoryUpdates.js b/awx/ui/src/api/models/InventoryUpdates.js deleted file mode 100644 index 3d2e218720b6..000000000000 --- a/awx/ui/src/api/models/InventoryUpdates.js +++ /dev/null @@ -1,19 +0,0 @@ -import Base from '../Base'; -import RunnableMixin from '../mixins/Runnable.mixin'; - -class InventoryUpdates extends RunnableMixin(Base) { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/inventory_updates/'; - this.createSyncCancel = this.createSyncCancel.bind(this); - } - - createSyncCancel(sourceId) { - return this.http.post(`${this.baseUrl}${sourceId}/cancel/`); - } - - readCredentials(id) { - return this.http.get(`${this.baseUrl}${id}/credentials/`); - } -} -export default InventoryUpdates; diff --git a/awx/ui/src/api/models/JobEvents.js b/awx/ui/src/api/models/JobEvents.js deleted file mode 100644 index dad879af8963..000000000000 --- a/awx/ui/src/api/models/JobEvents.js +++ /dev/null @@ -1,14 +0,0 @@ -import Base from '../Base'; - -class JobEvents extends Base { - constructor(http) { - super(http); - this.baseUrl = '/api/v2/job_events/'; - } - - readChildren(id, params) { - return this.http.get(`${this.baseUrl}${id}/children/`, { params }); - } -} - -export default JobEvents; diff --git a/awx/ui/src/api/models/JobTemplates.js b/awx/ui/src/api/models/JobTemplates.js deleted file mode 100644 index d2c1eb7a5d43..000000000000 --- a/awx/ui/src/api/models/JobTemplates.js +++ /dev/null @@ -1,93 +0,0 @@ -import Base from '../Base'; -import NotificationsMixin from '../mixins/Notifications.mixin'; -import InstanceGroupsMixin from '../mixins/InstanceGroups.mixin'; -import LabelsMixin from '../mixins/Labels.mixin'; -import SchedulesMixin from '../mixins/Schedules.mixin'; - -class JobTemplates extends SchedulesMixin( - InstanceGroupsMixin(NotificationsMixin(LabelsMixin(Base))) -) { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/job_templates/'; - - this.createSchedule = this.createSchedule.bind(this); - this.launch = this.launch.bind(this); - this.readLaunch = this.readLaunch.bind(this); - this.associateLabel = this.associateLabel.bind(this); - this.disassociateLabel = this.disassociateLabel.bind(this); - this.readCredentials = this.readCredentials.bind(this); - this.readAccessList = this.readAccessList.bind(this); - this.readAccessOptions = this.readAccessOptions.bind(this); - this.readWebhookKey = this.readWebhookKey.bind(this); - } - - launch(id, data) { - return this.http.post(`${this.baseUrl}${id}/launch/`, data); - } - - readTemplateOptions(id) { - return this.http.options(`${this.baseUrl}${id}/`); - } - - readLaunch(id) { - return this.http.get(`${this.baseUrl}${id}/launch/`); - } - - readCredentials(id, params) { - return this.http.get(`${this.baseUrl}${id}/credentials/`, { - params, - }); - } - - associateCredentials(id, credentialId) { - return this.http.post(`${this.baseUrl}${id}/credentials/`, { - id: credentialId, - }); - } - - disassociateCredentials(id, credentialId) { - return this.http.post(`${this.baseUrl}${id}/credentials/`, { - id: credentialId, - disassociate: true, - }); - } - - readAccessList(id, params) { - return this.http.get(`${this.baseUrl}${id}/access_list/`, { - params, - }); - } - - readAccessOptions(id) { - return this.http.options(`${this.baseUrl}${id}/access_list/`); - } - - readScheduleList(id, params) { - return this.http.get(`${this.baseUrl}${id}/schedules/`, { - params, - }); - } - - readSurvey(id) { - return this.http.get(`${this.baseUrl}${id}/survey_spec/`); - } - - updateSurvey(id, survey) { - return this.http.post(`${this.baseUrl}${id}/survey_spec/`, survey); - } - - destroySurvey(id) { - return this.http.delete(`${this.baseUrl}${id}/survey_spec/`); - } - - readWebhookKey(id) { - return this.http.get(`${this.baseUrl}${id}/webhook_key/`); - } - - updateWebhookKey(id) { - return this.http.post(`${this.baseUrl}${id}/webhook_key/`); - } -} - -export default JobTemplates; diff --git a/awx/ui/src/api/models/Jobs.js b/awx/ui/src/api/models/Jobs.js deleted file mode 100644 index 2e12c3ceb30b..000000000000 --- a/awx/ui/src/api/models/Jobs.js +++ /dev/null @@ -1,28 +0,0 @@ -import Base from '../Base'; -import RunnableMixin from '../mixins/Runnable.mixin'; - -class Jobs extends RunnableMixin(Base) { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/jobs/'; - this.jobEventSlug = '/job_events/'; - } - - cancel(id) { - return this.http.post(`${this.baseUrl}${id}/cancel/`); - } - - readCredentials(id) { - return this.http.get(`${this.baseUrl}${id}/credentials/`); - } - - readDetail(id) { - return this.http.get(`${this.baseUrl}${id}/`); - } - - readChildrenSummary(id) { - return this.http.get(`${this.baseUrl}${id}/job_events/children_summary/`); - } -} - -export default Jobs; diff --git a/awx/ui/src/api/models/Labels.js b/awx/ui/src/api/models/Labels.js deleted file mode 100644 index ecc9d078faf8..000000000000 --- a/awx/ui/src/api/models/Labels.js +++ /dev/null @@ -1,10 +0,0 @@ -import Base from '../Base'; - -class Labels extends Base { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/labels/'; - } -} - -export default Labels; diff --git a/awx/ui/src/api/models/Me.js b/awx/ui/src/api/models/Me.js deleted file mode 100644 index b9f7c6c03bfc..000000000000 --- a/awx/ui/src/api/models/Me.js +++ /dev/null @@ -1,10 +0,0 @@ -import Base from '../Base'; - -class Me extends Base { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/me/'; - } -} - -export default Me; diff --git a/awx/ui/src/api/models/Mesh.js b/awx/ui/src/api/models/Mesh.js deleted file mode 100644 index d7ad08067c68..000000000000 --- a/awx/ui/src/api/models/Mesh.js +++ /dev/null @@ -1,9 +0,0 @@ -import Base from '../Base'; - -class Mesh extends Base { - constructor(http) { - super(http); - this.baseUrl = '/api/v2/mesh_visualizer/'; - } -} -export default Mesh; diff --git a/awx/ui/src/api/models/Metrics.js b/awx/ui/src/api/models/Metrics.js deleted file mode 100644 index 8fd742664599..000000000000 --- a/awx/ui/src/api/models/Metrics.js +++ /dev/null @@ -1,9 +0,0 @@ -import Base from '../Base'; - -class Metrics extends Base { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/metrics/'; - } -} -export default Metrics; diff --git a/awx/ui/src/api/models/NotificationTemplates.js b/awx/ui/src/api/models/NotificationTemplates.js deleted file mode 100644 index 6b83a46ed10f..000000000000 --- a/awx/ui/src/api/models/NotificationTemplates.js +++ /dev/null @@ -1,14 +0,0 @@ -import Base from '../Base'; - -class NotificationTemplates extends Base { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/notification_templates/'; - } - - test(id) { - return this.http.post(`${this.baseUrl}${id}/test/`); - } -} - -export default NotificationTemplates; diff --git a/awx/ui/src/api/models/Notifications.js b/awx/ui/src/api/models/Notifications.js deleted file mode 100644 index 6aca7210852c..000000000000 --- a/awx/ui/src/api/models/Notifications.js +++ /dev/null @@ -1,10 +0,0 @@ -import Base from '../Base'; - -class Notifications extends Base { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/notifications/'; - } -} - -export default Notifications; diff --git a/awx/ui/src/api/models/Organizations.js b/awx/ui/src/api/models/Organizations.js deleted file mode 100644 index c20f72a1812f..000000000000 --- a/awx/ui/src/api/models/Organizations.js +++ /dev/null @@ -1,86 +0,0 @@ -import Base from '../Base'; -import NotificationsMixin from '../mixins/Notifications.mixin'; -import InstanceGroupsMixin from '../mixins/InstanceGroups.mixin'; - -class Organizations extends InstanceGroupsMixin(NotificationsMixin(Base)) { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/organizations/'; - } - - readAccessList(id, params) { - return this.http.get(`${this.baseUrl}${id}/access_list/`, { params }); - } - - readAccessOptions(id) { - return this.http.options(`${this.baseUrl}${id}/access_list/`); - } - - readTeams(id, params) { - return this.http.get(`${this.baseUrl}${id}/teams/`, { params }); - } - - readTeamsOptions(id) { - return this.http.options(`${this.baseUrl}${id}/teams/`); - } - - readGalaxyCredentials(id, params) { - return this.http.get(`${this.baseUrl}${id}/galaxy_credentials/`, { - params, - }); - } - - readExecutionEnvironments(id, params) { - return this.http.get(`${this.baseUrl}${id}/execution_environments/`, { - params, - }); - } - - readExecutionEnvironmentsOptions(id) { - return this.http.options(`${this.baseUrl}${id}/execution_environments/`); - } - - createUser(id, data) { - return this.http.post(`${this.baseUrl}${id}/users/`, data); - } - - readNotificationTemplatesApprovals(id, params) { - return this.http.get( - `${this.baseUrl}${id}/notification_templates_approvals/`, - { params } - ); - } - - associateNotificationTemplatesApprovals(resourceId, notificationId) { - return this.http.post( - `${this.baseUrl}${resourceId}/notification_templates_approvals/`, - { id: notificationId } - ); - } - - disassociateNotificationTemplatesApprovals(resourceId, notificationId) { - return this.http.post( - `${this.baseUrl}${resourceId}/notification_templates_approvals/`, - { id: notificationId, disassociate: true } - ); - } - - associateGalaxyCredential(resourceId, credentialId) { - return this.http.post(`${this.baseUrl}${resourceId}/galaxy_credentials/`, { - id: credentialId, - }); - } - - disassociateGalaxyCredential(resourceId, credentialId) { - return this.http.post(`${this.baseUrl}${resourceId}/galaxy_credentials/`, { - id: credentialId, - disassociate: true, - }); - } - - readAdmins(id, params) { - return this.http.get(`${this.baseUrl}${id}/admins/`, { params }); - } -} - -export default Organizations; diff --git a/awx/ui/src/api/models/Organizations.test.js b/awx/ui/src/api/models/Organizations.test.js deleted file mode 100644 index 728aa6f36550..000000000000 --- a/awx/ui/src/api/models/Organizations.test.js +++ /dev/null @@ -1,62 +0,0 @@ -import { describeNotificationMixin } from '../../../testUtils/apiReusable'; -import Organizations from './Organizations'; - -describe('OrganizationsAPI', () => { - const orgId = 1; - let mockHttp; - let OrganizationsAPI; - beforeEach(() => { - const createPromise = () => Promise.resolve(); - mockHttp = { get: jest.fn(createPromise) }; - - OrganizationsAPI = new Organizations(mockHttp); - }); - - afterEach(() => { - jest.resetAllMocks(); - }); - - test('read access list calls get with expected params', async () => { - const testParams = { foo: 'bar' }; - const testParamsDuplicates = { foo: ['bar', 'baz'] }; - - const mockBaseURL = `api/v2/organizations/${orgId}/access_list/`; - - await OrganizationsAPI.readAccessList(orgId); - await OrganizationsAPI.readAccessList(orgId, testParams); - await OrganizationsAPI.readAccessList(orgId, testParamsDuplicates); - - expect(mockHttp.get).toHaveBeenCalledTimes(3); - expect(mockHttp.get.mock.calls[0][0]).toEqual(`${mockBaseURL}`); - expect(mockHttp.get.mock.calls[0][1]).toEqual({ params: undefined }); - expect(mockHttp.get.mock.calls[1][0]).toEqual(`${mockBaseURL}`); - expect(mockHttp.get.mock.calls[1][1]).toEqual({ params: { foo: 'bar' } }); - expect(mockHttp.get.mock.calls[2][0]).toEqual(`${mockBaseURL}`); - expect(mockHttp.get.mock.calls[2][1]).toEqual({ - params: { foo: ['bar', 'baz'] }, - }); - }); - - test('read teams calls get with expected params', async () => { - const testParams = { foo: 'bar' }; - const testParamsDuplicates = { foo: ['bar', 'baz'] }; - - const mockBaseURL = `api/v2/organizations/${orgId}/teams/`; - - await OrganizationsAPI.readTeams(orgId); - await OrganizationsAPI.readTeams(orgId, testParams); - await OrganizationsAPI.readTeams(orgId, testParamsDuplicates); - - expect(mockHttp.get).toHaveBeenCalledTimes(3); - expect(mockHttp.get.mock.calls[0][0]).toEqual(`${mockBaseURL}`); - expect(mockHttp.get.mock.calls[0][1]).toEqual({ params: undefined }); - expect(mockHttp.get.mock.calls[1][0]).toEqual(`${mockBaseURL}`); - expect(mockHttp.get.mock.calls[1][1]).toEqual({ params: { foo: 'bar' } }); - expect(mockHttp.get.mock.calls[2][0]).toEqual(`${mockBaseURL}`); - expect(mockHttp.get.mock.calls[2][1]).toEqual({ - params: { foo: ['bar', 'baz'] }, - }); - }); -}); - -describeNotificationMixin(Organizations, 'Organizations[NotificationsMixin]'); diff --git a/awx/ui/src/api/models/ProjectUpdates.js b/awx/ui/src/api/models/ProjectUpdates.js deleted file mode 100644 index aead3b5d0a86..000000000000 --- a/awx/ui/src/api/models/ProjectUpdates.js +++ /dev/null @@ -1,15 +0,0 @@ -import Base from '../Base'; -import RunnableMixin from '../mixins/Runnable.mixin'; - -class ProjectUpdates extends RunnableMixin(Base) { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/project_updates/'; - } - - readCredentials(id) { - return this.http.get(`${this.baseUrl}${id}/credentials/`); - } -} - -export default ProjectUpdates; diff --git a/awx/ui/src/api/models/Projects.js b/awx/ui/src/api/models/Projects.js deleted file mode 100644 index 437da8caca1c..000000000000 --- a/awx/ui/src/api/models/Projects.js +++ /dev/null @@ -1,47 +0,0 @@ -import Base from '../Base'; -import NotificationsMixin from '../mixins/Notifications.mixin'; -import LaunchUpdateMixin from '../mixins/LaunchUpdate.mixin'; -import SchedulesMixin from '../mixins/Schedules.mixin'; - -class Projects extends SchedulesMixin( - LaunchUpdateMixin(NotificationsMixin(Base)) -) { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/projects/'; - - this.readAccessList = this.readAccessList.bind(this); - this.readAccessOptions = this.readAccessOptions.bind(this); - this.readInventories = this.readInventories.bind(this); - this.readPlaybooks = this.readPlaybooks.bind(this); - this.readSync = this.readSync.bind(this); - this.sync = this.sync.bind(this); - this.createSchedule = this.createSchedule.bind(this); - } - - readAccessList(id, params) { - return this.http.get(`${this.baseUrl}${id}/access_list/`, { params }); - } - - readAccessOptions(id) { - return this.http.options(`${this.baseUrl}${id}/access_list/`); - } - - readInventories(id) { - return this.http.get(`${this.baseUrl}${id}/inventories/`); - } - - readPlaybooks(id) { - return this.http.get(`${this.baseUrl}${id}/playbooks/`); - } - - readSync(id) { - return this.http.get(`${this.baseUrl}${id}/update/`); - } - - sync(id) { - return this.http.post(`${this.baseUrl}${id}/update/`); - } -} - -export default Projects; diff --git a/awx/ui/src/api/models/Roles.js b/awx/ui/src/api/models/Roles.js deleted file mode 100644 index 70195891e43d..000000000000 --- a/awx/ui/src/api/models/Roles.js +++ /dev/null @@ -1,23 +0,0 @@ -import Base from '../Base'; - -class Roles extends Base { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/roles/'; - } - - disassociateUserRole(roleId, userId) { - return this.http.post(`${this.baseUrl}${roleId}/users/`, { - disassociate: true, - id: userId, - }); - } - - disassociateTeamRole(roleId, teamId) { - return this.http.post(`${this.baseUrl}${roleId}/teams/`, { - disassociate: true, - id: teamId, - }); - } -} -export default Roles; diff --git a/awx/ui/src/api/models/Root.js b/awx/ui/src/api/models/Root.js deleted file mode 100644 index 4fe6384d8339..000000000000 --- a/awx/ui/src/api/models/Root.js +++ /dev/null @@ -1,38 +0,0 @@ -import Base from '../Base'; - -class Root extends Base { - constructor(http) { - super(http); - this.baseUrl = 'api/'; - this.redirectURL = '/api/v2/config/'; - } - - async login(username, password, redirect = this.redirectURL) { - const loginUrl = `${this.baseUrl}login/`; - const un = encodeURIComponent(username); - const pw = encodeURIComponent(password); - const next = encodeURIComponent(redirect); - - const data = `username=${un}&password=${pw}&next=${next}`; - const headers = { 'Content-Type': 'application/x-www-form-urlencoded' }; - - await this.http.get(loginUrl, { headers }); - const response = await this.http.post(loginUrl, data, { headers }); - - return response; - } - - logout() { - return this.http.get(`${this.baseUrl}logout/`); - } - - readAssetVariables() { - // TODO: There's better ways of doing this. Build tools, scripts, - // automation etc. should relocate this variable file to an importable - // location in src prior to building. That said, a raw http call - // works for now. - return this.http.get('static/media/default.strings.json'); - } -} - -export default Root; diff --git a/awx/ui/src/api/models/Root.test.js b/awx/ui/src/api/models/Root.test.js deleted file mode 100644 index dd2d820c4f38..000000000000 --- a/awx/ui/src/api/models/Root.test.js +++ /dev/null @@ -1,50 +0,0 @@ -import Root from './Root'; - -describe('RootAPI', () => { - let mockHttp; - let RootAPI; - beforeEach(() => { - const createPromise = () => Promise.resolve(); - mockHttp = { - get: jest.fn(createPromise), - post: jest.fn(createPromise), - }; - - RootAPI = new Root(mockHttp); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - test('login calls get and post with expected content headers', async () => { - const headers = { 'Content-Type': 'application/x-www-form-urlencoded' }; - - await RootAPI.login('username', 'password'); - - expect(mockHttp.get).toHaveBeenCalledTimes(1); - expect(mockHttp.get.mock.calls[0]).toContainEqual({ headers }); - - expect(mockHttp.post).toHaveBeenCalledTimes(1); - expect(mockHttp.post.mock.calls[0]).toContainEqual({ headers }); - }); - - test('login sends expected data', async () => { - await RootAPI.login('foo', 'bar'); - await RootAPI.login('foo', 'bar', 'baz'); - - expect(mockHttp.post).toHaveBeenCalledTimes(2); - expect(mockHttp.post.mock.calls[0]).toContainEqual( - 'username=foo&password=bar&next=%2Fapi%2Fv2%2Fconfig%2F' - ); - expect(mockHttp.post.mock.calls[1]).toContainEqual( - 'username=foo&password=bar&next=baz' - ); - }); - - test('logout calls expected http method', async () => { - await RootAPI.logout(); - - expect(mockHttp.get).toHaveBeenCalledTimes(1); - }); -}); diff --git a/awx/ui/src/api/models/Schedules.js b/awx/ui/src/api/models/Schedules.js deleted file mode 100644 index a32c62053804..000000000000 --- a/awx/ui/src/api/models/Schedules.js +++ /dev/null @@ -1,37 +0,0 @@ -import Base from '../Base'; -import InstanceGroupsMixin from '../mixins/InstanceGroups.mixin'; -import LabelsMixin from '../mixins/Labels.mixin'; - -class Schedules extends InstanceGroupsMixin(LabelsMixin(Base)) { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/schedules/'; - } - - createPreview(data) { - return this.http.post(`${this.baseUrl}preview/`, data); - } - - readCredentials(resourceId, params) { - return this.http.get(`${this.baseUrl}${resourceId}/credentials/`, params); - } - - associateCredential(resourceId, credentialId) { - return this.http.post(`${this.baseUrl}${resourceId}/credentials/`, { - id: credentialId, - }); - } - - disassociateCredential(resourceId, credentialId) { - return this.http.post(`${this.baseUrl}${resourceId}/credentials/`, { - id: credentialId, - disassociate: true, - }); - } - - readZoneInfo() { - return this.http.get(`${this.baseUrl}zoneinfo/`); - } -} - -export default Schedules; diff --git a/awx/ui/src/api/models/Settings.js b/awx/ui/src/api/models/Settings.js deleted file mode 100644 index 89aad94c00f4..000000000000 --- a/awx/ui/src/api/models/Settings.js +++ /dev/null @@ -1,42 +0,0 @@ -import Base from '../Base'; - -class Settings extends Base { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/settings/'; - } - - readAllOptions() { - return this.http.options(`${this.baseUrl}all/`); - } - - updateAll(data) { - return this.http.patch(`${this.baseUrl}all/`, data); - } - - readAll() { - return this.http.get(`${this.baseUrl}all/`); - } - - updateCategory(category, data) { - return this.http.patch(`${this.baseUrl}${category}/`, data); - } - - readCategory(category) { - return this.http.get(`${this.baseUrl}${category}/`); - } - - readCategoryOptions(category) { - return this.http.options(`${this.baseUrl}${category}/`); - } - - createTest(category, data) { - return this.http.post(`${this.baseUrl}${category}/test/`, data); - } - - revertCategory(category) { - return this.http.delete(`${this.baseUrl}${category}/`); - } -} - -export default Settings; diff --git a/awx/ui/src/api/models/SystemJobTemplates.js b/awx/ui/src/api/models/SystemJobTemplates.js deleted file mode 100644 index f99fbb71d758..000000000000 --- a/awx/ui/src/api/models/SystemJobTemplates.js +++ /dev/null @@ -1,18 +0,0 @@ -import Base from '../Base'; -import NotificationsMixin from '../mixins/Notifications.mixin'; -import SchedulesMixin from '../mixins/Schedules.mixin'; - -const Mixins = SchedulesMixin(NotificationsMixin(Base)); - -class SystemJobTemplates extends Mixins { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/system_job_templates/'; - } - - launch(id, data) { - return this.http.post(`${this.baseUrl}${id}/launch/`, data); - } -} - -export default SystemJobTemplates; diff --git a/awx/ui/src/api/models/SystemJobs.js b/awx/ui/src/api/models/SystemJobs.js deleted file mode 100644 index aadbfabeb290..000000000000 --- a/awx/ui/src/api/models/SystemJobs.js +++ /dev/null @@ -1,16 +0,0 @@ -import Base from '../Base'; - -import RunnableMixin from '../mixins/Runnable.mixin'; - -class SystemJobs extends RunnableMixin(Base) { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/system_jobs/'; - } - - readCredentials(id) { - return this.http.get(`${this.baseUrl}${id}/credentials/`); - } -} - -export default SystemJobs; diff --git a/awx/ui/src/api/models/Teams.js b/awx/ui/src/api/models/Teams.js deleted file mode 100644 index 031718a0788f..000000000000 --- a/awx/ui/src/api/models/Teams.js +++ /dev/null @@ -1,47 +0,0 @@ -import Base from '../Base'; - -class Teams extends Base { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/teams/'; - } - - associateRole(teamId, roleId) { - return this.http.post(`${this.baseUrl}${teamId}/roles/`, { - id: roleId, - }); - } - - disassociateRole(teamId, roleId) { - return this.http.post(`${this.baseUrl}${teamId}/roles/`, { - id: roleId, - disassociate: true, - }); - } - - readRoles(teamId, params) { - return this.http.get(`${this.baseUrl}${teamId}/roles/`, { - params, - }); - } - - readRoleOptions(teamId) { - return this.http.options(`${this.baseUrl}${teamId}/roles/`); - } - - readAccessList(teamId, params) { - return this.http.get(`${this.baseUrl}${teamId}/access_list/`, { - params, - }); - } - - readAccessOptions(id) { - return this.http.options(`${this.baseUrl}${id}/access_list/`); - } - - readUsersAccessOptions(teamId) { - return this.http.options(`${this.baseUrl}${teamId}/users/`); - } -} - -export default Teams; diff --git a/awx/ui/src/api/models/Teams.test.js b/awx/ui/src/api/models/Teams.test.js deleted file mode 100644 index 0cfbf652f2db..000000000000 --- a/awx/ui/src/api/models/Teams.test.js +++ /dev/null @@ -1,43 +0,0 @@ -import Teams from './Teams'; - -describe('TeamsAPI', () => { - const teamId = 1; - const roleId = 7; - - let TeamsAPI; - let mockHttp; - - beforeEach(() => { - const createPromise = () => Promise.resolve(); - mockHttp = { post: jest.fn(createPromise) }; - - TeamsAPI = new Teams(mockHttp); - }); - - afterEach(() => { - jest.resetAllMocks(); - }); - - test('associate role calls post with expected params', async () => { - await TeamsAPI.associateRole(teamId, roleId); - - expect(mockHttp.post).toHaveBeenCalledTimes(1); - expect(mockHttp.post.mock.calls[0]).toContainEqual( - `api/v2/teams/${teamId}/roles/`, - { id: roleId } - ); - }); - - test('read teams calls post with expected params', async () => { - await TeamsAPI.disassociateRole(teamId, roleId); - - expect(mockHttp.post).toHaveBeenCalledTimes(1); - expect(mockHttp.post.mock.calls[0]).toContainEqual( - `api/v2/teams/${teamId}/roles/`, - { - id: roleId, - disassociate: true, - } - ); - }); -}); diff --git a/awx/ui/src/api/models/Tokens.js b/awx/ui/src/api/models/Tokens.js deleted file mode 100644 index 2b1027d2a2bf..000000000000 --- a/awx/ui/src/api/models/Tokens.js +++ /dev/null @@ -1,10 +0,0 @@ -import Base from '../Base'; - -class Tokens extends Base { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/tokens/'; - } -} - -export default Tokens; diff --git a/awx/ui/src/api/models/UnifiedJobTemplates.js b/awx/ui/src/api/models/UnifiedJobTemplates.js deleted file mode 100644 index 24ea77a0e6d0..000000000000 --- a/awx/ui/src/api/models/UnifiedJobTemplates.js +++ /dev/null @@ -1,10 +0,0 @@ -import Base from '../Base'; - -class UnifiedJobTemplates extends Base { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/unified_job_templates/'; - } -} - -export default UnifiedJobTemplates; diff --git a/awx/ui/src/api/models/UnifiedJobs.js b/awx/ui/src/api/models/UnifiedJobs.js deleted file mode 100644 index 23337f0baf97..000000000000 --- a/awx/ui/src/api/models/UnifiedJobs.js +++ /dev/null @@ -1,10 +0,0 @@ -import Base from '../Base'; - -class UnifiedJobs extends Base { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/unified_jobs/'; - } -} - -export default UnifiedJobs; diff --git a/awx/ui/src/api/models/Users.js b/awx/ui/src/api/models/Users.js deleted file mode 100644 index 8fa84ca7a3b1..000000000000 --- a/awx/ui/src/api/models/Users.js +++ /dev/null @@ -1,75 +0,0 @@ -import Base from '../Base'; - -class Users extends Base { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/users/'; - } - - associateRole(userId, roleId) { - return this.http.post(`${this.baseUrl}${userId}/roles/`, { - id: roleId, - }); - } - - createToken(userId, data) { - return this.http.post(`${this.baseUrl}${userId}/authorized_tokens/`, data); - } - - disassociateRole(userId, roleId) { - return this.http.post(`${this.baseUrl}${userId}/roles/`, { - id: roleId, - disassociate: true, - }); - } - - readOrganizations(userId, params) { - return this.http.get(`${this.baseUrl}${userId}/organizations/`, { - params, - }); - } - - readOrganizationOptions(userId, params) { - return this.http.options(`${this.baseUrl}${userId}/organizations/`, { - params, - }); - } - - readRoles(userId, params) { - return this.http.get(`${this.baseUrl}${userId}/roles/`, { - params, - }); - } - - readRoleOptions(userId) { - return this.http.options(`${this.baseUrl}${userId}/roles/`); - } - - readTeams(userId, params) { - return this.http.get(`${this.baseUrl}${userId}/teams/`, { - params, - }); - } - - readTeamsOptions(userId) { - return this.http.options(`${this.baseUrl}${userId}/teams/`); - } - - readTokens(userId, params) { - return this.http.get(`${this.baseUrl}${userId}/tokens/`, { - params, - }); - } - - readAdminOfOrganizations(userId, params) { - return this.http.get(`${this.baseUrl}${userId}/admin_of_organizations/`, { - params, - }); - } - - readTokenOptions(userId) { - return this.http.options(`${this.baseUrl}${userId}/tokens/`); - } -} - -export default Users; diff --git a/awx/ui/src/api/models/Users.test.js b/awx/ui/src/api/models/Users.test.js deleted file mode 100644 index 42af9424230f..000000000000 --- a/awx/ui/src/api/models/Users.test.js +++ /dev/null @@ -1,40 +0,0 @@ -import Users from './Users'; - -describe('UsersAPI', () => { - const userId = 1; - const roleId = 7; - let UsersAPI; - let mockHttp; - beforeEach(() => { - const createPromise = () => Promise.resolve(); - mockHttp = { post: jest.fn(createPromise) }; - UsersAPI = new Users(mockHttp); - }); - - afterEach(() => { - jest.resetAllMocks(); - }); - - test('associate role calls post with expected params', async () => { - await UsersAPI.associateRole(userId, roleId); - - expect(mockHttp.post).toHaveBeenCalledTimes(1); - expect(mockHttp.post.mock.calls[0]).toContainEqual( - `api/v2/users/${userId}/roles/`, - { id: roleId } - ); - }); - - test('read users calls post with expected params', async () => { - await UsersAPI.disassociateRole(userId, roleId); - - expect(mockHttp.post).toHaveBeenCalledTimes(1); - expect(mockHttp.post.mock.calls[0]).toContainEqual( - `api/v2/users/${userId}/roles/`, - { - id: roleId, - disassociate: true, - } - ); - }); -}); diff --git a/awx/ui/src/api/models/WorkflowApprovalTemplates.js b/awx/ui/src/api/models/WorkflowApprovalTemplates.js deleted file mode 100644 index 53ca7a74c250..000000000000 --- a/awx/ui/src/api/models/WorkflowApprovalTemplates.js +++ /dev/null @@ -1,10 +0,0 @@ -import Base from '../Base'; - -class WorkflowApprovalTemplates extends Base { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/workflow_approval_templates/'; - } -} - -export default WorkflowApprovalTemplates; diff --git a/awx/ui/src/api/models/WorkflowApprovals.js b/awx/ui/src/api/models/WorkflowApprovals.js deleted file mode 100644 index fc0581f8cece..000000000000 --- a/awx/ui/src/api/models/WorkflowApprovals.js +++ /dev/null @@ -1,18 +0,0 @@ -import Base from '../Base'; - -class WorkflowApprovals extends Base { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/workflow_approvals/'; - } - - approve(id) { - return this.http.post(`${this.baseUrl}${id}/approve/`); - } - - deny(id) { - return this.http.post(`${this.baseUrl}${id}/deny/`); - } -} - -export default WorkflowApprovals; diff --git a/awx/ui/src/api/models/WorkflowJobTemplateNodes.js b/awx/ui/src/api/models/WorkflowJobTemplateNodes.js deleted file mode 100644 index fce36ad51666..000000000000 --- a/awx/ui/src/api/models/WorkflowJobTemplateNodes.js +++ /dev/null @@ -1,75 +0,0 @@ -import Base from '../Base'; -import InstanceGroupsMixin from '../mixins/InstanceGroups.mixin'; -import LabelsMixin from '../mixins/Labels.mixin'; - -class WorkflowJobTemplateNodes extends LabelsMixin(InstanceGroupsMixin(Base)) { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/workflow_job_template_nodes/'; - } - - createApprovalTemplate(id, data) { - return this.http.post( - `${this.baseUrl}${id}/create_approval_template/`, - data - ); - } - - associateSuccessNode(id, idToAssociate) { - return this.http.post(`${this.baseUrl}${id}/success_nodes/`, { - id: idToAssociate, - }); - } - - associateFailureNode(id, idToAssociate) { - return this.http.post(`${this.baseUrl}${id}/failure_nodes/`, { - id: idToAssociate, - }); - } - - associateAlwaysNode(id, idToAssociate) { - return this.http.post(`${this.baseUrl}${id}/always_nodes/`, { - id: idToAssociate, - }); - } - - disassociateSuccessNode(id, idToDissociate) { - return this.http.post(`${this.baseUrl}${id}/success_nodes/`, { - id: idToDissociate, - disassociate: true, - }); - } - - disassociateFailuresNode(id, idToDissociate) { - return this.http.post(`${this.baseUrl}${id}/failure_nodes/`, { - id: idToDissociate, - disassociate: true, - }); - } - - disassociateAlwaysNode(id, idToDissociate) { - return this.http.post(`${this.baseUrl}${id}/always_nodes/`, { - id: idToDissociate, - disassociate: true, - }); - } - - readCredentials(id) { - return this.http.get(`${this.baseUrl}${id}/credentials/`); - } - - associateCredentials(id, credentialId) { - return this.http.post(`${this.baseUrl}${id}/credentials/`, { - id: credentialId, - }); - } - - disassociateCredentials(id, credentialId) { - return this.http.post(`${this.baseUrl}${id}/credentials/`, { - id: credentialId, - disassociate: true, - }); - } -} - -export default WorkflowJobTemplateNodes; diff --git a/awx/ui/src/api/models/WorkflowJobTemplates.js b/awx/ui/src/api/models/WorkflowJobTemplates.js deleted file mode 100644 index 430b8caed2da..000000000000 --- a/awx/ui/src/api/models/WorkflowJobTemplates.js +++ /dev/null @@ -1,110 +0,0 @@ -import Base from '../Base'; -import SchedulesMixin from '../mixins/Schedules.mixin'; -import NotificationsMixin from '../mixins/Notifications.mixin'; -import LabelsMixin from '../mixins/Labels.mixin'; - -class WorkflowJobTemplates extends SchedulesMixin( - NotificationsMixin(LabelsMixin(Base)) -) { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/workflow_job_templates/'; - this.createSchedule = this.createSchedule.bind(this); - } - - readWebhookKey(id) { - return this.http.get(`${this.baseUrl}${id}/webhook_key/`); - } - - readWorkflowJobTemplateOptions(id) { - return this.http.options(`${this.baseUrl}${id}/`); - } - - updateWebhookKey(id) { - return this.http.post(`${this.baseUrl}${id}/webhook_key/`); - } - - associateLabel(id, label, orgId) { - return this.http.post(`${this.baseUrl}${id}/labels/`, { - name: label.name, - organization: orgId, - }); - } - - createNode(id, data) { - return this.http.post(`${this.baseUrl}${id}/workflow_nodes/`, data); - } - - disassociateLabel(id, label) { - return this.http.post(`${this.baseUrl}${id}/labels/`, { - id: label.id, - disassociate: true, - }); - } - - launch(id, data) { - return this.http.post(`${this.baseUrl}${id}/launch/`, data); - } - - readLaunch(id) { - return this.http.get(`${this.baseUrl}${id}/launch/`); - } - - readNodes(id, params) { - return this.http.get(`${this.baseUrl}${id}/workflow_nodes/`, { - params, - }); - } - - readAccessList(id, params) { - return this.http.get(`${this.baseUrl}${id}/access_list/`, { - params, - }); - } - - readAccessOptions(id) { - return this.http.options(`${this.baseUrl}${id}/access_list/`); - } - - readSurvey(id) { - return this.http.get(`${this.baseUrl}${id}/survey_spec/`); - } - - updateSurvey(id, survey) { - return this.http.post(`${this.baseUrl}${id}/survey_spec/`, survey); - } - - destroySurvey(id) { - return this.http.delete(`${this.baseUrl}${id}/survey_spec/`); - } - - readNotificationTemplatesApprovals(id, params) { - return this.http.get( - `${this.baseUrl}${id}/notification_templates_approvals/`, - { - params, - } - ); - } - - associateNotificationTemplatesApprovals(resourceId, notificationId) { - return this.http.post( - `${this.baseUrl}${resourceId}/notification_templates_approvals/`, - { - id: notificationId, - } - ); - } - - disassociateNotificationTemplatesApprovals(resourceId, notificationId) { - return this.http.post( - `${this.baseUrl}${resourceId}/notification_templates_approvals/`, - { - id: notificationId, - disassociate: true, - } - ); - } -} - -export default WorkflowJobTemplates; diff --git a/awx/ui/src/api/models/WorkflowJobs.js b/awx/ui/src/api/models/WorkflowJobs.js deleted file mode 100644 index 1214368401ec..000000000000 --- a/awx/ui/src/api/models/WorkflowJobs.js +++ /dev/null @@ -1,19 +0,0 @@ -import Base from '../Base'; -import RunnableMixin from '../mixins/Runnable.mixin'; - -class WorkflowJobs extends RunnableMixin(Base) { - constructor(http) { - super(http); - this.baseUrl = 'api/v2/workflow_jobs/'; - } - - readNodes(id, params) { - return this.http.get(`${this.baseUrl}${id}/workflow_nodes/`, { params }); - } - - readCredentials(id) { - return this.http.get(`${this.baseUrl}${id}/credentials/`); - } -} - -export default WorkflowJobs; diff --git a/awx/ui/src/border.css b/awx/ui/src/border.css deleted file mode 100644 index f69d3c79669b..000000000000 --- a/awx/ui/src/border.css +++ /dev/null @@ -1,11 +0,0 @@ -.pf-c-select .pf-c-select__toggle:before { - border-top: var(--pf-c-select__toggle--before--BorderTopWidth) solid - var(--pf-c-select__toggle--before--BorderTopColor); - border-right: var(--pf-c-select__toggle--before--BorderRightWidth) solid - var(--pf-c-select__toggle--before--BorderRightColor); - border-bottom: var(--pf-c-select__toggle--before--BorderBottomWidth) solid - var(--pf-c-select__toggle--before--BorderBottomColor); - border-left: var(--pf-c-select__toggle--before--BorderLeftWidth) solid - var(--pf-c-select__toggle--before--BorderLeftColor); -} -/* https://github.com/patternfly/patternfly-react/issues/5650 */ diff --git a/awx/ui/src/components/About/About.js b/awx/ui/src/components/About/About.js deleted file mode 100644 index b58c880b51da..000000000000 --- a/awx/ui/src/components/About/About.js +++ /dev/null @@ -1,73 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { t } from '@lingui/macro'; -import { AboutModal } from '@patternfly/react-core'; -import useBrandName from 'hooks/useBrandName'; - -function About({ version, isOpen, onClose }) { - const brandName = useBrandName(); - - const createSpeechBubble = () => { - let text = ''; - if (typeof brandName === 'string' && brandName.length > 0) { - text = - brandName.indexOf('AWX') === -1 - ? `${brandName} Controller ${version}` - : `${brandName} ${version}`; - } - - let top = ''; - let bottom = ''; - - for (let i = 0; i < text.length; i++) { - top += '_'; - bottom += '-'; - } - - top = ` __${top}__ \n`; - text = `< ${text} >\n`; - bottom = ` --${bottom}-- `; - - return top + text + bottom; - }; - - const speechBubble = createSpeechBubble(); - const copyright = t`Copyright`; - const redHatInc = t`Red Hat, Inc.`; - - return ( - -
-        {speechBubble}
-        {`
-          \\
-          \\   ^__^
-              (oo)\\_______
-              (__)      A )\\
-                  ||----w |
-                  ||     ||
-                    `}
-      
-
- ); -} - -About.propTypes = { - isOpen: PropTypes.bool, - onClose: PropTypes.func.isRequired, - version: PropTypes.string, -}; - -About.defaultProps = { - isOpen: false, - version: null, -}; - -export default About; diff --git a/awx/ui/src/components/About/About.test.js b/awx/ui/src/components/About/About.test.js deleted file mode 100644 index 293e87678035..000000000000 --- a/awx/ui/src/components/About/About.test.js +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react'; -import { shallow } from 'enzyme'; -import About from './About'; - -jest.mock('../../hooks/useBrandName', () => ({ - __esModule: true, - default: () => ({ - current: 'AWX', - }), -})); - -describe('', () => { - test('should render AboutModal', () => { - const onClose = jest.fn(); - const wrapper = shallow(); - - const modal = wrapper.find('AboutModal'); - expect(modal).toHaveLength(1); - expect(modal.prop('onClose')).toEqual(onClose); - expect(modal.prop('productName')).toEqual({ current: 'AWX' }); - expect(modal.prop('isOpen')).toEqual(true); - }); -}); diff --git a/awx/ui/src/components/About/index.js b/awx/ui/src/components/About/index.js deleted file mode 100644 index 1ef71b80e713..000000000000 --- a/awx/ui/src/components/About/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './About'; diff --git a/awx/ui/src/components/AdHocCommands/AdHocCommands.js b/awx/ui/src/components/AdHocCommands/AdHocCommands.js deleted file mode 100644 index 6036053e079e..000000000000 --- a/awx/ui/src/components/AdHocCommands/AdHocCommands.js +++ /dev/null @@ -1,172 +0,0 @@ -import React, { useCallback, useEffect, useState, useContext } from 'react'; -import { useHistory, useParams } from 'react-router-dom'; - -import { t } from '@lingui/macro'; -import PropTypes from 'prop-types'; -import { Button, DropdownItem, Tooltip } from '@patternfly/react-core'; - -import useRequest, { useDismissableError } from 'hooks/useRequest'; -import { InventoriesAPI, CredentialTypesAPI } from 'api'; - -import { KebabifiedContext } from 'contexts/Kebabified'; -import AlertModal from '../AlertModal'; -import ErrorDetail from '../ErrorDetail'; -import AdHocCommandsWizard from './AdHocCommandsWizard'; -import ContentError from '../ContentError'; - -function AdHocCommands({ - adHocItems, - hasListItems, - onLaunchLoading, - moduleOptions, -}) { - const history = useHistory(); - const { id } = useParams(); - - const [isWizardOpen, setIsWizardOpen] = useState(false); - const { isKebabified, onKebabModalChange } = useContext(KebabifiedContext); - - useEffect(() => { - if (isKebabified) { - onKebabModalChange(isWizardOpen); - } - }, [isKebabified, isWizardOpen, onKebabModalChange]); - - const { - result: { credentialTypeId, organizationId }, - request: fetchData, - error: fetchError, - } = useRequest( - useCallback(async () => { - const [{ data }, cred] = await Promise.all([ - InventoriesAPI.readDetail(id), - CredentialTypesAPI.read({ namespace: 'ssh' }), - ]); - return { - credentialTypeId: cred.data.results[0].id, - organizationId: data.organization, - }; - }, [id]), - { organizationId: null } - ); - useEffect(() => { - fetchData(); - }, [fetchData]); - - const { - isLoading: isLaunchLoading, - error: launchError, - request: launchAdHocCommands, - } = useRequest( - useCallback( - async (values) => { - const { data } = await InventoriesAPI.launchAdHocCommands(id, values); - history.push(`/jobs/command/${data.id}/output`); - }, - - [id, history] - ) - ); - - const { error, dismissError } = useDismissableError( - launchError || fetchError - ); - - const handleSubmit = async (values) => { - const { - credentials, - credential_passwords: { become_password, ssh_password, ssh_key_unlock }, - execution_environment, - ...remainingValues - } = values; - const newCredential = credentials[0].id; - - const manipulatedValues = { - credential: newCredential, - become_password, - ssh_password, - ssh_key_unlock, - execution_environment: execution_environment[0]?.id, - ...remainingValues, - }; - await launchAdHocCommands(manipulatedValues); - }; - useEffect( - () => onLaunchLoading(isLaunchLoading), - [isLaunchLoading, onLaunchLoading] - ); - - if (error && isWizardOpen) { - return ( - { - dismissError(); - setIsWizardOpen(false); - }} - > - {launchError ? ( - <> - {t`Failed to launch job.`} - - - ) : ( - - )} - - ); - } - return ( - // render buttons for drop down and for toolbar - // if modal is open render the modal - <> - - {isKebabified ? ( - setIsWizardOpen(true)} - ouiaId="run-command-dropdown-item" - > - {t`Run Command`} - - ) : ( - - )} - - - {isWizardOpen && ( - setIsWizardOpen(false)} - onLaunch={handleSubmit} - onDismissError={() => dismissError()} - /> - )} - - ); -} - -AdHocCommands.propTypes = { - adHocItems: PropTypes.arrayOf(PropTypes.object).isRequired, - hasListItems: PropTypes.bool.isRequired, - onLaunchLoading: PropTypes.func.isRequired, - moduleOptions: PropTypes.arrayOf(PropTypes.array).isRequired, -}; - -export default AdHocCommands; diff --git a/awx/ui/src/components/AdHocCommands/AdHocCommands.test.js b/awx/ui/src/components/AdHocCommands/AdHocCommands.test.js deleted file mode 100644 index 6e51fb3522e7..000000000000 --- a/awx/ui/src/components/AdHocCommands/AdHocCommands.test.js +++ /dev/null @@ -1,453 +0,0 @@ -import React from 'react'; -import { act } from 'react-dom/test-utils'; -import { - CredentialTypesAPI, - InventoriesAPI, - CredentialsAPI, - ExecutionEnvironmentsAPI, - RootAPI, -} from 'api'; -import { - mountWithContexts, - waitForElement, -} from '../../../testUtils/enzymeHelpers'; -import AdHocCommands from './AdHocCommands'; - -jest.mock('../../api/models/CredentialTypes'); -jest.mock('../../api/models/Inventories'); -jest.mock('../../api/models/Credentials'); -jest.mock('../../api/models/ExecutionEnvironments'); -jest.mock('../../api/models/Root'); - -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ - id: 1, - }), -})); -const credentials = [ - { id: 1, kind: 'cloud', name: 'Cred 1', url: 'www.google.com' }, - { id: 2, kind: 'ssh', name: 'Cred 2', url: 'www.google.com' }, - { id: 3, kind: 'Ansible', name: 'Cred 3', url: 'www.google.com' }, - { id: 4, kind: 'Machine', name: 'Cred 4', url: 'www.google.com' }, - { id: 5, kind: 'Machine', name: 'Cred 5', url: 'www.google.com' }, -]; - -const adHocItems = [ - { - name: 'Inventory 1 Org 0', - }, - { name: 'Inventory 2 Org 0' }, -]; - -describe('', () => { - beforeEach(() => { - RootAPI.readAssetVariables.mockResolvedValue({ - data: { - BRAND_NAME: 'AWX', - }, - }); - CredentialTypesAPI.read.mockResolvedValue({ - data: { count: 1, results: [{ id: 1, name: 'cred' }] }, - }); - ExecutionEnvironmentsAPI.read.mockResolvedValue({ - data: { - results: [ - { id: 1, name: 'EE1 1', url: 'wwww.google.com' }, - { id: 2, name: 'EE2', url: 'wwww.google.com' }, - ], - count: 2, - }, - }); - }); - let wrapper; - - afterEach(() => { - jest.clearAllMocks(); - }); - - test('mounts successfully', async () => { - await act(async () => { - wrapper = mountWithContexts( - jest.fn()} - moduleOptions={[ - ['command', 'command'], - ['shell', 'shell'], - ]} - /> - ); - }); - expect(wrapper.find('AdHocCommands').length).toBe(1); - }); - - test('should open the wizard', async () => { - InventoriesAPI.readDetail.mockResolvedValue({ data: { organization: 1 } }); - CredentialTypesAPI.read.mockResolvedValue({ - data: { results: [{ id: 1 }] }, - }); - ExecutionEnvironmentsAPI.read.mockResolvedValue({ - data: { - results: [ - { id: 1, name: 'EE1 1', url: 'wwww.google.com' }, - { id: 2, name: 'EE2', url: 'wwww.google.com' }, - ], - count: 2, - }, - }); - await act(async () => { - wrapper = mountWithContexts( - jest.fn()} - /> - ); - }); - await waitForElement( - wrapper, - 'button[aria-label="Run Command"]', - (el) => el.length === 1 - ); - await act(async () => - wrapper.find('button[aria-label="Run Command"]').prop('onClick')() - ); - - wrapper.update(); - - expect(wrapper.find('AdHocCommandsWizard').length).toBe(1); - }); - - test('should submit properly', async () => { - InventoriesAPI.launchAdHocCommands.mockResolvedValue({ data: { id: 1 } }); - InventoriesAPI.readDetail.mockResolvedValue({ - data: { organization: 1 }, - }); - - CredentialsAPI.read.mockResolvedValue({ - data: { - results: credentials, - count: 5, - }, - }); - CredentialsAPI.readOptions.mockResolvedValue({ - data: { actions: { GET: {} } }, - }); - - ExecutionEnvironmentsAPI.read.mockResolvedValue({ - data: { - results: [ - { id: 1, name: 'EE1 1', url: 'wwww.google.com' }, - { id: 2, name: 'EE2', url: 'wwww.google.com' }, - ], - count: 2, - }, - }); - ExecutionEnvironmentsAPI.readOptions.mockResolvedValue({ - data: { actions: { GET: {}, POST: {} } }, - }); - await act(async () => { - wrapper = mountWithContexts( - jest.fn()} - /> - ); - }); - await waitForElement( - wrapper, - 'button[aria-label="Run Command"]', - (el) => el.length === 1 - ); - await act(async () => - wrapper.find('button[aria-label="Run Command"]').prop('onClick')() - ); - wrapper.update(); - - await act(async () => { - wrapper.find('AnsibleSelect[name="module_name"]').prop('onChange')( - {}, - 'command' - ); - wrapper.find('input#module_args').simulate('change', { - target: { value: 'foo', name: 'module_args' }, - }); - wrapper.find('AnsibleSelect[name="verbosity"]').prop('onChange')({}, 1); - }); - - wrapper.update(); - - expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe( - false - ); - await act(async () => - wrapper.find('Button[type="submit"]').prop('onClick')() - ); - await waitForElement(wrapper, 'ContentEmpty', (el) => el.length === 0); - - // second step of wizard - - await act(async () => { - wrapper.find('td#check-action-item-2').find('input').simulate('click'); - }); - - wrapper.update(); - - expect( - wrapper.find('CheckboxListItem[label="EE2"]').prop('isSelected') - ).toBe(true); - - await act(async () => - wrapper.find('Button[type="submit"]').prop('onClick')() - ); - // third step of wizard - await waitForElement(wrapper, 'ContentEmpty', (el) => el.length === 0); - - await act(async () => { - wrapper.find('td#check-action-item-4').find('input').simulate('click'); - }); - - wrapper.update(); - - expect( - wrapper.find('CheckboxListItem[label="Cred 4"]').prop('isSelected') - ).toBe(true); - - await act(async () => - wrapper.find('Button[type="submit"]').prop('onClick')() - ); - wrapper.update(); - - // fourth step - await act(async () => - wrapper.find('Button[type="submit"]').prop('onClick')() - ); - - expect(InventoriesAPI.launchAdHocCommands).toBeCalledWith(1, { - module_args: 'foo', - diff_mode: false, - credential: 4, - become_password: undefined, - job_type: 'run', - become_enabled: '', - extra_vars: '---', - forks: 0, - limit: 'Inventory 1 Org 0, Inventory 2 Org 0', - module_name: 'command', - ssh_key_unlock: undefined, - ssh_password: undefined, - verbosity: 1, - execution_environment: 2, - }); - }); - - test('should throw error on submission properly', async () => { - InventoriesAPI.launchAdHocCommands.mockRejectedValue( - new Error({ - response: { - config: { - method: 'post', - url: '/api/v2/inventories/1/ad_hoc_commands', - }, - data: 'An error occurred', - status: 403, - }, - }) - ); - InventoriesAPI.readDetail.mockResolvedValue({ - data: { organization: 1 }, - }); - CredentialTypesAPI.read.mockResolvedValue({ - data: { - results: [ - { - id: 1, - }, - ], - }, - }); - CredentialsAPI.read.mockResolvedValue({ - data: { - results: credentials, - count: 5, - }, - }); - CredentialsAPI.readOptions.mockResolvedValue({ - data: { actions: { GET: {} } }, - }); - - ExecutionEnvironmentsAPI.read.mockResolvedValue({ - data: { - results: [ - { - id: 1, - name: 'EE1 1', - url: 'wwww.google.com', - }, - { - id: 2, - name: 'EE2', - url: 'wwww.google.com', - }, - ], - count: 2, - }, - }); - ExecutionEnvironmentsAPI.readOptions.mockResolvedValue({ - data: { actions: { GET: {}, POST: {} } }, - }); - await act(async () => { - wrapper = mountWithContexts( - jest.fn()} - /> - ); - }); - await waitForElement( - wrapper, - 'button[aria-label="Run Command"]', - (el) => el.length === 1 - ); - await act(async () => - wrapper.find('button[aria-label="Run Command"]').prop('onClick')() - ); - wrapper.update(); - - await act(async () => { - wrapper.find('AnsibleSelect[name="module_name"]').prop('onChange')( - {}, - 'command' - ); - wrapper.find('input#module_args').simulate('change', { - target: { - value: 'foo', - name: 'module_args', - }, - }); - wrapper.find('AnsibleSelect[name="verbosity"]').prop('onChange')({}, 1); - }); - - wrapper.update(); - - expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe( - false - ); - - await act(async () => - wrapper.find('Button[type="submit"]').prop('onClick')() - ); - - await waitForElement(wrapper, 'ContentEmpty', (el) => el.length === 0); - - // second step of wizard - - await act(async () => { - wrapper.find('td#check-action-item-2').find('input').simulate('click'); - }); - - wrapper.update(); - - expect( - wrapper.find('CheckboxListItem[label="EE2"]').prop('isSelected') - ).toBe(true); - - await act(async () => - wrapper.find('Button[type="submit"]').prop('onClick')() - ); - // third step of wizard - await waitForElement(wrapper, 'ContentEmpty', (el) => el.length === 0); - - await act(async () => { - wrapper.find('td#check-action-item-4').find('input').simulate('click'); - }); - - wrapper.update(); - - expect( - wrapper.find('CheckboxListItem[label="Cred 4"]').prop('isSelected') - ).toBe(true); - - await act(async () => - wrapper.find('Button[type="submit"]').prop('onClick')() - ); - wrapper.update(); - - // fourth step of wizard - - await act(async () => - wrapper.find('Button[type="submit"]').prop('onClick')() - ); - await waitForElement(wrapper, 'ErrorDetail', (el) => el.length > 0); - }); - - test('should disable run command button due to lack of list items', async () => { - InventoriesAPI.readHosts.mockResolvedValue({ - data: { results: [], count: 0 }, - }); - - await act(async () => { - wrapper = mountWithContexts( - jest.fn()} - /> - ); - }); - await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0); - const runCommandsButton = wrapper.find('button[aria-label="Run Command"]'); - expect(runCommandsButton.prop('disabled')).toBe(true); - }); - - test('should open alert modal when error on fetching data', async () => { - InventoriesAPI.readDetail.mockRejectedValue( - new Error({ - response: { - config: { - method: 'options', - url: '/api/v2/inventories/1/', - }, - data: 'An error occurred', - status: 403, - }, - }) - ); - await act(async () => { - wrapper = mountWithContexts( - jest.fn()} - /> - ); - }); - await act(async () => wrapper.find('button').prop('onClick')()); - wrapper.update(); - expect(wrapper.find('ErrorDetail').length).toBe(1); - }); -}); diff --git a/awx/ui/src/components/AdHocCommands/AdHocCommandsWizard.js b/awx/ui/src/components/AdHocCommands/AdHocCommandsWizard.js deleted file mode 100644 index 94e4ff6e799d..000000000000 --- a/awx/ui/src/components/AdHocCommands/AdHocCommandsWizard.js +++ /dev/null @@ -1,82 +0,0 @@ -import React from 'react'; -import { t } from '@lingui/macro'; -import { withFormik, useFormikContext } from 'formik'; -import PropTypes from 'prop-types'; -import Wizard from '../Wizard'; -import useAdHocLaunchSteps from './useAdHocLaunchSteps'; - -function AdHocCommandsWizard({ - onLaunch, - moduleOptions, - onCloseWizard, - credentialTypeId, - organizationId, -}) { - const { setFieldTouched, values } = useFormikContext(); - - const { steps, validateStep, visitStep, visitAllSteps } = useAdHocLaunchSteps( - moduleOptions, - organizationId, - credentialTypeId - ); - - return ( - { - if (nextStep.id === 'preview') { - visitAllSteps(setFieldTouched); - } else { - visitStep(prevStep.prevId, setFieldTouched); - validateStep(nextStep.id); - } - }} - onClose={() => onCloseWizard()} - onSave={() => { - onLaunch(values); - }} - onGoToStep={(nextStep, prevStep) => { - if (nextStep.id === 'preview') { - visitAllSteps(setFieldTouched); - } else { - visitStep(prevStep.prevId, setFieldTouched); - validateStep(nextStep.id); - } - }} - steps={steps} - title={t`Run command`} - backButtonText={t`Back`} - cancelButtonText={t`Cancel`} - nextButtonText={t`Next`} - /> - ); -} - -const FormikApp = withFormik({ - mapPropsToValues({ adHocItems }) { - const adHocItemStrings = adHocItems.map((item) => item.name).join(', '); - return { - limit: adHocItemStrings || 'all', - credentials: [], - module_args: '', - verbosity: 0, - forks: 0, - diff_mode: false, - become_enabled: '', - module_name: '', - extra_vars: '---', - job_type: 'run', - credential_passwords: {}, - execution_environment: '', - }; - }, -})(AdHocCommandsWizard); - -FormikApp.propTypes = { - onLaunch: PropTypes.func.isRequired, - moduleOptions: PropTypes.arrayOf(PropTypes.array).isRequired, - onCloseWizard: PropTypes.func.isRequired, - credentialTypeId: PropTypes.number.isRequired, -}; -export default FormikApp; diff --git a/awx/ui/src/components/AdHocCommands/AdHocCommandsWizard.test.js b/awx/ui/src/components/AdHocCommands/AdHocCommandsWizard.test.js deleted file mode 100644 index 83d7e38bfcbb..000000000000 --- a/awx/ui/src/components/AdHocCommands/AdHocCommandsWizard.test.js +++ /dev/null @@ -1,403 +0,0 @@ -import React from 'react'; -import { act } from 'react-dom/test-utils'; -import { CredentialsAPI, ExecutionEnvironmentsAPI, RootAPI } from 'api'; -import { - mountWithContexts, - waitForElement, -} from '../../../testUtils/enzymeHelpers'; -import AdHocCommandsWizard from './AdHocCommandsWizard'; - -jest.mock('../../api/models/CredentialTypes'); -jest.mock('../../api/models/Inventories'); -jest.mock('../../api/models/Credentials'); -jest.mock('../../api/models/ExecutionEnvironments'); -jest.mock('../../api/models/Root'); - -const moduleOptions = [ - ['command', 'command'], - ['shell', 'shell'], -]; -const adHocItems = [ - { name: 'Inventory 1' }, - { name: 'Inventory 2' }, - { name: 'inventory 3' }, -]; -describe('', () => { - let wrapper; - const onLaunch = jest.fn(); - beforeEach(async () => { - RootAPI.readAssetVariables.mockResolvedValue({ - data: { - BRAND_NAME: 'AWX', - }, - }); - await act(async () => { - wrapper = mountWithContexts( - {}} - credentialTypeId={1} - organizationId={1} - /> - ); - }); - }); - afterEach(() => { - jest.clearAllMocks(); - }); - - test('should mount properly', async () => { - expect(wrapper.find('AdHocCommandsWizard').length).toBe(1); - }); - - test('launch button should be disabled', async () => { - waitForElement(wrapper, 'WizardNavItem', (el) => el.length > 0); - - expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe( - false - ); - act(() => wrapper.find('Button[type="submit"]').prop('onClick')()); - expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe( - false - ); - wrapper.update(); - act(() => wrapper.find('Button[type="submit"]').prop('onClick')()); - expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe( - false - ); - wrapper.update(); - act(() => wrapper.find('Button[type="submit"]').prop('onClick')()); - wrapper.update(); - - expect(wrapper.find('AdHocPreviewStep').prop('hasErrors')).toBe(true); - expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe(true); - }); - - test('launch button should become active', async () => { - ExecutionEnvironmentsAPI.read.mockResolvedValue({ - data: { - results: [ - { id: 1, name: 'EE 1', url: '' }, - { id: 2, name: 'EE 2', url: '' }, - ], - count: 2, - }, - }); - ExecutionEnvironmentsAPI.readOptions.mockResolvedValue({ - data: { actions: { GET: {} } }, - }); - CredentialsAPI.read.mockResolvedValue({ - data: { - results: [ - { id: 1, name: 'Cred 1', url: '' }, - { id: 2, name: 'Cred2', url: '' }, - ], - count: 2, - }, - }); - CredentialsAPI.readOptions.mockResolvedValue({ - data: { actions: { GET: {} } }, - }); - await waitForElement(wrapper, 'WizardNavItem', (el) => el.length > 0); - - await act(async () => { - wrapper.find('AnsibleSelect[name="module_name"]').prop('onChange')( - {}, - 'command' - ); - wrapper.find('input#module_args').simulate('change', { - target: { value: 'foo', name: 'module_args' }, - }); - wrapper.find('AnsibleSelect[name="verbosity"]').prop('onChange')({}, 1); - }); - wrapper.update(); - expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe( - false - ); - await act(async () => - wrapper.find('Button[type="submit"]').prop('onClick')() - ); - - wrapper.update(); - - // step 2 - - await waitForElement(wrapper, 'OptionsList', (el) => el.length > 0); - expect(wrapper.find('CheckboxListItem').length).toBe(2); - expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe( - false - ); - - await act(async () => { - wrapper.find('td#check-action-item-1').find('input').simulate('click'); - }); - - wrapper.update(); - - expect( - wrapper.find('CheckboxListItem[label="EE 1"]').prop('isSelected') - ).toBe(true); - expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe( - false - ); - - await act(async () => - wrapper.find('Button[type="submit"]').prop('onClick')() - ); - - wrapper.update(); - // step 3 - - await waitForElement(wrapper, 'OptionsList', (el) => el.length > 0); - expect(wrapper.find('CheckboxListItem').length).toBe(2); - - await act(async () => { - wrapper.find('td#check-action-item-1').find('input').simulate('click'); - }); - - wrapper.update(); - - expect( - wrapper.find('CheckboxListItem[label="Cred 1"]').prop('isSelected') - ).toBe(true); - - await act(async () => - wrapper.find('Button[type="submit"]').prop('onClick')() - ); - wrapper.update(); - await act(async () => - wrapper.find('Button[type="submit"]').prop('onClick')() - ); - expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe( - false - ); - - expect(onLaunch).toHaveBeenCalledWith({ - become_enabled: '', - credentials: [{ id: 1, name: 'Cred 1', url: '' }], - credential_passwords: {}, - diff_mode: false, - execution_environment: [{ id: 1, name: 'EE 1', url: '' }], - extra_vars: '---', - forks: 0, - job_type: 'run', - limit: 'Inventory 1, Inventory 2, inventory 3', - module_args: 'foo', - module_name: 'command', - verbosity: 1, - }); - }); - - test('should render credential passwords step', async () => { - ExecutionEnvironmentsAPI.read.mockResolvedValue({ - data: { - results: [ - { id: 1, name: 'EE 1', url: '' }, - { id: 2, name: 'EE 2', url: '' }, - ], - count: 2, - }, - }); - ExecutionEnvironmentsAPI.readOptions.mockResolvedValue({ - data: { actions: { GET: {} } }, - }); - CredentialsAPI.read.mockResolvedValue({ - data: { - results: [ - { - id: 1, - name: 'Cred 1', - url: '', - inputs: { password: 'ASK' }, - }, - { id: 2, name: 'Cred2', url: '' }, - ], - count: 2, - }, - }); - CredentialsAPI.readOptions.mockResolvedValue({ - data: { actions: { GET: {} } }, - }); - await waitForElement(wrapper, 'WizardNavItem', (el) => el.length > 0); - - await act(async () => { - wrapper.find('AnsibleSelect[name="module_name"]').prop('onChange')( - {}, - 'command' - ); - wrapper.find('input#module_args').simulate('change', { - target: { value: 'foo', name: 'module_args' }, - }); - wrapper.find('AnsibleSelect[name="verbosity"]').prop('onChange')({}, 1); - }); - wrapper.update(); - expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe( - false - ); - await act(async () => - wrapper.find('Button[type="submit"]').prop('onClick')() - ); - - wrapper.update(); - - // step 2 - - await waitForElement(wrapper, 'OptionsList', (el) => el.length > 0); - expect(wrapper.find('CheckboxListItem').length).toBe(2); - expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe( - false - ); - - await act(async () => { - wrapper.find('td#check-action-item-1').find('input').simulate('click'); - }); - - wrapper.update(); - - expect( - wrapper.find('CheckboxListItem[label="EE 1"]').prop('isSelected') - ).toBe(true); - expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe( - false - ); - - await act(async () => - wrapper.find('Button[type="submit"]').prop('onClick')() - ); - - wrapper.update(); - // step 3 - - await waitForElement(wrapper, 'OptionsList', (el) => el.length > 0); - expect(wrapper.find('CheckboxListItem').length).toBe(2); - - await act(async () => { - wrapper.find('td#check-action-item-1').find('input').simulate('click'); - }); - - wrapper.update(); - - expect( - wrapper.find('CheckboxListItem[label="Cred 1"]').prop('isSelected') - ).toBe(true); - - await act(async () => - wrapper.find('Button[type="submit"]').prop('onClick')() - ); - wrapper.update(); - - // step 4 - - expect(wrapper.find('PasswordInput')).toHaveLength(1); - await act(async () => - wrapper - .find('TextInputBase[name="credential_passwords.ssh_password"]') - .prop('onChange')('', { - target: { - value: 'password', - name: 'credential_passwords.ssh_password', - }, - }) - ); - wrapper.update(); - expect( - wrapper - .find('TextInput[name="credential_passwords.ssh_password"]') - .prop('value') - ).toBe('password'); - await act(async () => - wrapper.find('Button[type="submit"]').prop('onClick')() - ); - await act(async () => - wrapper.find('Button[type="submit"]').prop('onClick')() - ); - wrapper.update(); - - // step 5 - - expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe( - false - ); - - expect(onLaunch).toHaveBeenCalledWith({ - become_enabled: '', - credentials: [ - { id: 1, name: 'Cred 1', url: '', inputs: { password: 'ASK' } }, - ], - credential_passwords: { ssh_password: 'password' }, - diff_mode: false, - execution_environment: [{ id: 1, name: 'EE 1', url: '' }], - extra_vars: '---', - forks: 0, - job_type: 'run', - limit: 'Inventory 1, Inventory 2, inventory 3', - module_args: 'foo', - module_name: 'command', - verbosity: 1, - }); - }); - - test('should show error in navigation bar', async () => { - await waitForElement(wrapper, 'WizardNavItem', (el) => el.length > 0); - - await act(async () => { - wrapper.find('AnsibleSelect[name="module_name"]').prop('onChange')( - {}, - 'command' - ); - wrapper.find('input#module_args').simulate('change', { - target: { value: '', name: 'module_args' }, - }); - }); - waitForElement(wrapper, 'ExclamationCircleIcon', (el) => el.length > 0); - }); - - test('expect credential step to throw error', async () => { - CredentialsAPI.read.mockRejectedValue( - new Error({ - response: { - config: { - method: 'get', - url: '/api/v2/credentials', - }, - data: 'An error occurred', - status: 403, - }, - }) - ); - CredentialsAPI.readOptions.mockResolvedValue({ - data: { actions: { GET: {} } }, - }); - await waitForElement(wrapper, 'WizardNavItem', (el) => el.length > 0); - - await act(async () => { - wrapper.find('AnsibleSelect[name="module_name"]').prop('onChange')( - {}, - 'command' - ); - wrapper.find('input#module_args').simulate('change', { - target: { value: 'foo', name: 'module_args' }, - }); - wrapper.find('AnsibleSelect[name="verbosity"]').prop('onChange')({}, 1); - }); - wrapper.update(); - expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe( - false - ); - - await act(async () => - wrapper.find('Button[type="submit"]').prop('onClick')() - ); - - wrapper.update(); - - await act(async () => - wrapper.find('Button[type="submit"]').prop('onClick')() - ); - - wrapper.update(); - expect(wrapper.find('ContentError').length).toBe(1); - }); -}); diff --git a/awx/ui/src/components/AdHocCommands/AdHocCredentialStep.js b/awx/ui/src/components/AdHocCommands/AdHocCredentialStep.js deleted file mode 100644 index 8001315cbf7f..000000000000 --- a/awx/ui/src/components/AdHocCommands/AdHocCredentialStep.js +++ /dev/null @@ -1,155 +0,0 @@ -import React, { useEffect, useCallback } from 'react'; -import { useHistory } from 'react-router-dom'; -import { t } from '@lingui/macro'; -import styled from 'styled-components'; -import PropTypes from 'prop-types'; -import { useField } from 'formik'; -import { Form, FormGroup, Alert } from '@patternfly/react-core'; -import { CredentialsAPI } from 'api'; -import { getQSConfig, parseQueryString, mergeParams } from 'util/qs'; -import useRequest from 'hooks/useRequest'; -import { required } from 'util/validators'; -import { getSearchableKeys } from 'components/PaginatedTable'; -import Popover from '../Popover'; - -import ContentError from '../ContentError'; -import ContentLoading from '../ContentLoading'; -import OptionsList from '../OptionsList'; - -const CredentialErrorAlert = styled(Alert)` - margin-bottom: 20px; -`; - -const QS_CONFIG = getQSConfig('credentials', { - page: 1, - page_size: 5, - order_by: 'name', -}); - -function AdHocCredentialStep({ credentialTypeId }) { - const history = useHistory(); - const { - error, - isLoading, - request: fetchCredentials, - result: { - credentials, - credentialCount, - relatedSearchableKeys, - searchableKeys, - }, - } = useRequest( - useCallback(async () => { - const params = parseQueryString(QS_CONFIG, history.location.search); - - const [ - { - data: { results, count }, - }, - actionsResponse, - ] = await Promise.all([ - CredentialsAPI.read( - mergeParams(params, { credential_type: credentialTypeId }) - ), - CredentialsAPI.readOptions(), - ]); - - return { - credentials: results, - credentialCount: count, - relatedSearchableKeys: ( - actionsResponse?.data?.related_search_fields || [] - ).map((val) => val.slice(0, -8)), - searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET), - }; - }, [credentialTypeId, history.location.search]), - { - credentials: [], - credentialCount: 0, - relatedSearchableKeys: [], - searchableKeys: [], - } - ); - - useEffect(() => { - fetchCredentials(); - }, [fetchCredentials]); - - const [field, meta, helpers] = useField({ - name: 'credentials', - validate: required(null), - }); - - if (error) { - return ; - } - if (isLoading) { - return ; - } - return ( - <> - {meta.touched && meta.error && ( - - )} - - - } - > - { - helpers.setValue([value]); - }} - deselectItem={() => { - helpers.setValue([]); - }} - searchableKeys={searchableKeys} - relatedSearchableKeys={relatedSearchableKeys} - /> - - - - ); -} - -AdHocCredentialStep.propTypes = { - credentialTypeId: PropTypes.number.isRequired, -}; -export default AdHocCredentialStep; diff --git a/awx/ui/src/components/AdHocCommands/AdHocCredentialStep.test.js b/awx/ui/src/components/AdHocCommands/AdHocCredentialStep.test.js deleted file mode 100644 index b90346f2b304..000000000000 --- a/awx/ui/src/components/AdHocCommands/AdHocCredentialStep.test.js +++ /dev/null @@ -1,53 +0,0 @@ -import React from 'react'; -import { act } from 'react-dom/test-utils'; -import { Formik } from 'formik'; -import { CredentialsAPI } from 'api'; -import { - mountWithContexts, - waitForElement, -} from '../../../testUtils/enzymeHelpers'; -import AdHocCredentialStep from './AdHocCredentialStep'; - -jest.mock('../../api/models/Credentials'); - -describe('', () => { - const onEnableLaunch = jest.fn(); - let wrapper; - beforeEach(async () => { - CredentialsAPI.read.mockResolvedValue({ - data: { - results: [ - { id: 1, name: 'Cred 1', url: 'wwww.google.com' }, - { id: 2, name: 'Cred2', url: 'wwww.google.com' }, - ], - count: 2, - }, - }); - CredentialsAPI.readOptions.mockResolvedValue({ - data: { actions: { GET: {} } }, - }); - await act(async () => { - wrapper = mountWithContexts( - - - - ); - }); - }); - afterEach(() => { - jest.clearAllMocks(); - }); - - test('should mount properly', async () => { - await waitForElement(wrapper, 'OptionsList', (el) => el.length > 0); - }); - - test('should call api', async () => { - await waitForElement(wrapper, 'OptionsList', (el) => el.length > 0); - expect(CredentialsAPI.read).toHaveBeenCalled(); - expect(wrapper.find('CheckboxListItem').length).toBe(2); - }); -}); diff --git a/awx/ui/src/components/AdHocCommands/AdHocDetailsStep.js b/awx/ui/src/components/AdHocCommands/AdHocDetailsStep.js deleted file mode 100644 index 15cf1f82e837..000000000000 --- a/awx/ui/src/components/AdHocCommands/AdHocDetailsStep.js +++ /dev/null @@ -1,285 +0,0 @@ -/* eslint-disable react/no-unescaped-entities */ -import React from 'react'; -import { t } from '@lingui/macro'; -import PropTypes from 'prop-types'; -import { useField } from 'formik'; -import { Form, FormGroup, Switch, Checkbox } from '@patternfly/react-core'; -import styled from 'styled-components'; -import { required } from 'util/validators'; -import useBrandName from 'hooks/useBrandName'; -import { VerbositySelectField } from 'components/VerbositySelectField'; -import AnsibleSelect from '../AnsibleSelect'; -import FormField from '../FormField'; -import { VariablesField } from '../CodeEditor'; -import { - FormColumnLayout, - FormFullWidthLayout, - FormCheckboxLayout, -} from '../FormLayout'; -import Popover from '../Popover'; - -const TooltipWrapper = styled.div` - text-align: left; -`; - -function AdHocDetailsStep({ moduleOptions }) { - const brandName = useBrandName(); - const [moduleNameField, moduleNameMeta, moduleNameHelpers] = useField({ - name: 'module_name', - validate: required(null), - }); - - const [variablesField] = useField('extra_vars'); - const [diffModeField, , diffModeHelpers] = useField('diff_mode'); - const [becomeEnabledField, , becomeEnabledHelpers] = - useField('become_enabled'); - const [, verbosityMeta] = useField({ - name: 'verbosity', - validate: required(null), - }); - - const argumentsRequired = - moduleNameField.value === 'command' || moduleNameField.value === 'shell'; - const [argumentsField, argumentsMeta, argumentsHelpers] = useField({ - name: 'module_args', - validate: argumentsRequired && required(null), - }); - - const isValid = argumentsRequired - ? (!argumentsMeta.error || !argumentsMeta.touched) && argumentsField.value - : true; - - return ( -
- - - - } - > - ({ - value: value[0], - label: value[0], - key: value[0], - })), - ]} - onChange={(event, value) => { - if (value !== 'command' && value !== 'shell') { - argumentsHelpers.setTouched(false); - } - moduleNameHelpers.setValue(value); - }} - /> - - argumentsHelpers.setTouched(true)} - isRequired={argumentsRequired} - tooltip={ - moduleNameField.value ? ( - <> - {t`These arguments are used with the specified module. You can find information about ${moduleNameField.value} by clicking `} - - {' '} - {t`here.`} - - - ) : ( - t`These arguments are used with the specified module.` - ) - } - /> - - - - {t`The pattern used to target hosts in the inventory. Leaving the field blank, all, and * will all target all hosts in the inventory. You can find more information about Ansible's host patterns`}{' '} - - {t`here`} - - - } - /> - - {t`The number of parallel or simultaneous processes to use while executing the playbook. Inputting no value will use the default value from the ansible configuration file. You can find more information`}{' '} - - {t`here.`} - - - } - /> - - - } - > - { - diffModeHelpers.setValue(!diffModeField.value); - }} - ouiaId="diff-mode-switch" - aria-label={t`toggle changes`} - /> - - - - - {t`Enable privilege escalation`} -   - - {t`Enables creation of a provisioning - callback URL. Using the URL a host can contact ${brandName} - and request a configuration update using this job - template`} -   - --become - {t`option to the`}   - ansible - {t`command`} -

- } - /> - - } - id="become_enabled" - ouiaId="become_enabled" - isChecked={becomeEnabledField.value} - onChange={(checked) => { - becomeEnabledHelpers.setValue(checked); - }} - /> -
-
-
- - -

- {t`Pass extra command line changes. There are two ansible command line parameters: `} -
- -e, --extra-vars -
- {t`Provide key/value pairs using either - YAML or JSON.`} -

- JSON: -
- -
-                    {'{'}
-                    {'\n  '}"somevar": "somevalue",
-                    {'\n  '}"password": "magic"
-                    {'\n'}
-                    {'}'}
-                  
-
- YAML: -
- -
-                    ---
-                    {'\n'}somevar: somevalue
-                    {'\n'}password: magic
-                  
-
- - } - label={t`Extra variables`} - aria-label={t`Extra variables`} - /> -
-
-
- ); -} - -AdHocDetailsStep.propTypes = { - moduleOptions: PropTypes.arrayOf(PropTypes.array).isRequired, -}; - -export default AdHocDetailsStep; diff --git a/awx/ui/src/components/AdHocCommands/AdHocDetailsStep.test.js b/awx/ui/src/components/AdHocCommands/AdHocDetailsStep.test.js deleted file mode 100644 index 2a78ffe0d0d1..000000000000 --- a/awx/ui/src/components/AdHocCommands/AdHocDetailsStep.test.js +++ /dev/null @@ -1,139 +0,0 @@ -import React from 'react'; -import { act } from 'react-dom/test-utils'; -import { Formik } from 'formik'; -import { RootAPI } from 'api'; -import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; -import DetailsStep from './AdHocDetailsStep'; - -jest.mock('../../api/models/Credentials'); -jest.mock('../../api/models/Root'); - -const verbosityOptions = [ - { key: -1, value: '', label: '', isDisabled: false }, - { key: 0, value: 0, label: '0', isDisabled: false }, - { key: 1, value: 1, label: '1', isDisabled: false }, -]; -const moduleOptions = [ - ['command', 'command'], - ['shell', 'shell'], -]; -const onLimitChange = jest.fn(); -const initialValues = { - limit: ['Inventory 1', 'inventory 2'], - credential: [], - module_args: '', - arguments: '', - verbosity: '', - forks: 0, - changes: false, - escalation: false, - extra_vars: '---', - module_name: 'shell', -}; - -describe('', () => { - let wrapper; - - beforeEach(() => { - RootAPI.readAssetVariables.mockResolvedValue({ - data: { - BRAND_NAME: 'AWX', - }, - }); - }); - - test('should mount properly', async () => { - await act(async () => { - wrapper = mountWithContexts( - - - - ); - }); - }); - - test('should show all the fields', async () => { - await act(async () => { - wrapper = mountWithContexts( - - - - ); - }); - expect(wrapper.find('FormGroup[label="Module"]').length).toBe(1); - expect(wrapper.find('FormField[label="Arguments"]').length).toBe(1); - expect(wrapper.find('FormGroup[label="Verbosity"]').length).toBe(1); - expect(wrapper.find('FormField[label="Limit"]').length).toBe(1); - expect(wrapper.find('FormField[name="forks"]').length).toBe(1); - expect(wrapper.find('FormGroup[label="Show changes"]').length).toBe(1); - expect(wrapper.find('FormGroup[name="become_enabled"]').length).toBe(1); - expect(wrapper.find('VariablesField').length).toBe(1); - }); - - test('shold update form values', async () => { - await act(async () => { - wrapper = mountWithContexts( - - - - ); - }); - - await act(async () => { - wrapper.find('AnsibleSelect[name="module_name"]').prop('onChange')( - {}, - 'command' - ); - wrapper.find('input#module_args').simulate('change', { - target: { value: 'foo', name: 'module_args' }, - }); - wrapper.find('input#limit').simulate('change', { - target: { - value: 'Inventory 1, inventory 2, new inventory', - name: 'limit', - }, - }); - wrapper.find('AnsibleSelect[name="verbosity"]').prop('onChange')({}, 1); - - wrapper.find('TextInputBase[name="forks"]').simulate('change', { - target: { value: 10, name: 'forks' }, - }); - wrapper.find('Switch').invoke('onChange')(); - wrapper - .find('Checkbox[aria-label="Enable privilege escalation"]') - .invoke('onChange')(true, { - currentTarget: { value: true, type: 'change', checked: true }, - }); - }); - wrapper.update(); - expect( - wrapper.find('AnsibleSelect[name="module_name"]').prop('value') - ).toBe('command'); - expect(wrapper.find('input#module_args').prop('value')).toBe('foo'); - expect(wrapper.find('AnsibleSelect[name="verbosity"]').prop('value')).toBe( - 1 - ); - expect(wrapper.find('TextInputBase[name="forks"]').prop('value')).toBe(10); - expect(wrapper.find('TextInputBase[name="limit"]').prop('value')).toBe( - 'Inventory 1, inventory 2, new inventory' - ); - expect(wrapper.find('Switch').prop('isChecked')).toBe(true); - expect( - wrapper - .find('Checkbox[aria-label="Enable privilege escalation"]') - .prop('isChecked') - ).toBe(true); - }); -}); diff --git a/awx/ui/src/components/AdHocCommands/AdHocExecutionEnironmentStep.test.js b/awx/ui/src/components/AdHocCommands/AdHocExecutionEnironmentStep.test.js deleted file mode 100644 index a270226cdd38..000000000000 --- a/awx/ui/src/components/AdHocCommands/AdHocExecutionEnironmentStep.test.js +++ /dev/null @@ -1,50 +0,0 @@ -import React from 'react'; -import { act } from 'react-dom/test-utils'; -import { Formik } from 'formik'; -import { ExecutionEnvironmentsAPI } from 'api'; -import { - mountWithContexts, - waitForElement, -} from '../../../testUtils/enzymeHelpers'; -import AdHocExecutionEnvironmentStep from './AdHocExecutionEnvironmentStep'; - -jest.mock('../../api/models/ExecutionEnvironments'); - -describe('', () => { - let wrapper; - beforeEach(async () => { - ExecutionEnvironmentsAPI.read.mockResolvedValue({ - data: { - results: [ - { id: 1, name: 'EE1 1', url: 'wwww.google.com' }, - { id: 2, name: 'EE2', url: 'wwww.google.com' }, - ], - count: 2, - }, - }); - ExecutionEnvironmentsAPI.readOptions.mockResolvedValue({ - data: { actions: { GET: {} } }, - }); - await act(async () => { - wrapper = mountWithContexts( - - - - ); - }); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - test('should mount properly', async () => { - await waitForElement(wrapper, 'OptionsList', (el) => el.length > 0); - }); - - test('should call api', async () => { - await waitForElement(wrapper, 'OptionsList', (el) => el.length > 0); - expect(ExecutionEnvironmentsAPI.read).toHaveBeenCalled(); - expect(wrapper.find('CheckboxListItem').length).toBe(2); - }); -}); diff --git a/awx/ui/src/components/AdHocCommands/AdHocExecutionEnvironmentStep.js b/awx/ui/src/components/AdHocCommands/AdHocExecutionEnvironmentStep.js deleted file mode 100644 index 3ced0adbe890..000000000000 --- a/awx/ui/src/components/AdHocCommands/AdHocExecutionEnvironmentStep.js +++ /dev/null @@ -1,140 +0,0 @@ -import React, { useEffect, useCallback } from 'react'; -import { useHistory } from 'react-router-dom'; -import { t } from '@lingui/macro'; -import { useField } from 'formik'; -import { Form, FormGroup } from '@patternfly/react-core'; -import { ExecutionEnvironmentsAPI } from 'api'; - -import { parseQueryString, getQSConfig, mergeParams } from 'util/qs'; -import { getSearchableKeys } from 'components/PaginatedTable'; -import useRequest from 'hooks/useRequest'; -import Popover from '../Popover'; -import ContentError from '../ContentError'; -import ContentLoading from '../ContentLoading'; -import OptionsList from '../OptionsList'; - -const QS_CONFIG = getQSConfig('execution_environments', { - page: 1, - page_size: 5, - order_by: 'name', -}); -function AdHocExecutionEnvironmentStep({ organizationId }) { - const history = useHistory(); - const [executionEnvironmentField, , executionEnvironmentHelpers] = useField( - 'execution_environment' - ); - const { - error, - isLoading, - request: fetchExecutionEnvironments, - result: { - executionEnvironments, - executionEnvironmentsCount, - relatedSearchableKeys, - searchableKeys, - }, - } = useRequest( - useCallback(async () => { - const params = parseQueryString(QS_CONFIG, history.location.search); - const globallyAvailableParams = { or__organization__isnull: 'True' }; - const organizationIdParams = organizationId - ? { or__organization__id: organizationId } - : {}; - - const [ - { - data: { results, count }, - }, - actionsResponse, - ] = await Promise.all([ - ExecutionEnvironmentsAPI.read( - mergeParams(params, { - ...globallyAvailableParams, - ...organizationIdParams, - }) - ), - ExecutionEnvironmentsAPI.readOptions(), - ]); - return { - executionEnvironments: results, - executionEnvironmentsCount: count, - relatedSearchableKeys: ( - actionsResponse?.data?.related_search_fields || [] - ).map((val) => val.slice(0, -8)), - searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET), - }; - }, [history.location.search, organizationId]), - { - executionEnvironments: [], - executionEnvironmentsCount: 0, - relatedSearchableKeys: [], - searchableKeys: [], - } - ); - - useEffect(() => { - fetchExecutionEnvironments(); - }, [fetchExecutionEnvironments]); - - if (error) { - return ; - } - if (isLoading) { - return ; - } - - return ( -
- - } - > - { - executionEnvironmentHelpers.setValue([value]); - }} - deselectItem={() => { - executionEnvironmentHelpers.setValue([]); - }} - /> - -
- ); -} -export default AdHocExecutionEnvironmentStep; diff --git a/awx/ui/src/components/AdHocCommands/AdHocPreviewStep.js b/awx/ui/src/components/AdHocCommands/AdHocPreviewStep.js deleted file mode 100644 index 4e1825091318..000000000000 --- a/awx/ui/src/components/AdHocCommands/AdHocPreviewStep.js +++ /dev/null @@ -1,78 +0,0 @@ -import React from 'react'; -import { t } from '@lingui/macro'; -import { Tooltip } from '@patternfly/react-core'; -import { ExclamationCircleIcon as PFExclamationCircleIcon } from '@patternfly/react-icons'; -import styled from 'styled-components'; -import { VERBOSITY } from '../VerbositySelectField'; -import { toTitleCase } from '../../util/strings'; -import { VariablesDetail } from '../CodeEditor'; -import { jsonToYaml } from '../../util/yaml'; -import { DetailList, Detail } from '../DetailList'; - -const ExclamationCircleIcon = styled(PFExclamationCircleIcon)` - margin-left: 10px; - margin-top: -2px; -`; - -const ErrorMessageWrapper = styled.div` - align-items: center; - color: var(--pf-global--danger-color--200); - display: flex; - font-weight: var(--pf-global--FontWeight--bold); - margin-bottom: 10px; -`; -function AdHocPreviewStep({ hasErrors, values }) { - const { credential, execution_environment, extra_vars, verbosity } = values; - - const items = Object.entries(values); - return ( - <> - {hasErrors && ( - - {t`Some of the previous step(s) have errors`} - - - - - )} - - {items.map( - ([key, value]) => - key !== 'extra_vars' && - key !== 'execution_environment' && - key !== 'credentials' && - key !== 'verbosity' && - !key.startsWith('credential_passwords') && ( - - ) - )} - {credential && ( - - )} - {execution_environment && ( - - )} - {verbosity && ( - - )} - {extra_vars && ( - - )} - - - ); -} - -export default AdHocPreviewStep; diff --git a/awx/ui/src/components/AdHocCommands/index.js b/awx/ui/src/components/AdHocCommands/index.js deleted file mode 100644 index fa981f01e49b..000000000000 --- a/awx/ui/src/components/AdHocCommands/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './AdHocCommands'; diff --git a/awx/ui/src/components/AdHocCommands/useAdHocCredentialPasswordStep.js b/awx/ui/src/components/AdHocCommands/useAdHocCredentialPasswordStep.js deleted file mode 100644 index 3f63a3db71a9..000000000000 --- a/awx/ui/src/components/AdHocCommands/useAdHocCredentialPasswordStep.js +++ /dev/null @@ -1,82 +0,0 @@ -import React from 'react'; -import { useFormikContext } from 'formik'; -import { t } from '@lingui/macro'; -import StepName from '../LaunchPrompt/steps/StepName'; -import CredentialPasswordsStep from '../LaunchPrompt/steps/CredentialPasswordsStep'; - -const STEP_ID = 'credentialPasswords'; - -const isValueMissing = (val) => !val || val === ''; - -export default function useCredentialPasswordsStep(showStep, visitedSteps) { - const { values, setFieldError } = useFormikContext(); - const hasError = - showStep && - Object.keys(visitedSteps).includes(STEP_ID) && - checkForError(values); - return { - step: showStep - ? { - id: STEP_ID, - name: ( - - {t`Credential passwords`} - - ), - component: , - enableNext: true, - } - : null, - isReady: true, - contentError: null, - hasError, - setTouched: (setFieldTouched) => { - Object.keys(values.credential_passwords).forEach((credentialValueKey) => - setFieldTouched( - `credential_passwords['${credentialValueKey}']`, - true, - false - ) - ); - }, - validate: () => { - const setPasswordFieldError = (fieldName) => { - setFieldError(fieldName, t`This field may not be blank`); - }; - - Object.entries(values.credentials[0].inputs).forEach(([key, value]) => { - if ( - value === 'ASK' && - isValueMissing( - key === 'password' - ? values.credential_passwords.ssh_password - : values.credential_passwords[key] - ) - ) { - setPasswordFieldError( - key === 'password' - ? `credential_passwords.ssh_password` - : `credential_passwords.${key}` - ); - } - }); - }, - }; -} - -function checkForError(values) { - let hasError = false; - Object.entries(values.credentials[0]?.inputs).forEach(([key, value]) => { - if ( - value === 'ASK' && - isValueMissing( - key === 'password' - ? values.credential_passwords.ssh_password - : values.credential_passwords[key] - ) - ) { - hasError = true; - } - }); - return hasError; -} diff --git a/awx/ui/src/components/AdHocCommands/useAdHocCredentialStep.js b/awx/ui/src/components/AdHocCommands/useAdHocCredentialStep.js deleted file mode 100644 index 1b98ff94eddb..000000000000 --- a/awx/ui/src/components/AdHocCommands/useAdHocCredentialStep.js +++ /dev/null @@ -1,41 +0,0 @@ -import React from 'react'; -import { useField } from 'formik'; -import { t } from '@lingui/macro'; -import StepName from '../LaunchPrompt/steps/StepName'; -import AdHocCredentialStep from './AdHocCredentialStep'; - -const STEP_ID = 'credentials'; -export default function useAdHocExecutionEnvironmentStep( - visited, - credentialTypeId -) { - const [field, meta, helpers] = useField('credentials'); - const hasError = - Object.keys(visited).includes('credentials') && - !field.value.length && - meta.touched; - - return { - step: { - id: STEP_ID, - key: 3, - name: ( - - {t`Credential`} - - ), - component: , - enableNext: true, - nextButtonText: t`Next`, - }, - hasError, - validate: () => { - if (!meta.value.length) { - helpers.setError('A credential must be selected'); - } - }, - setTouched: (setFieldTouched) => { - setFieldTouched('credentials', true, false); - }, - }; -} diff --git a/awx/ui/src/components/AdHocCommands/useAdHocDetailsStep.js b/awx/ui/src/components/AdHocCommands/useAdHocDetailsStep.js deleted file mode 100644 index d8052817e92a..000000000000 --- a/awx/ui/src/components/AdHocCommands/useAdHocDetailsStep.js +++ /dev/null @@ -1,61 +0,0 @@ -import React from 'react'; -import { t } from '@lingui/macro'; -import { useFormikContext } from 'formik'; -import StepName from '../LaunchPrompt/steps/StepName'; -import AdHocDetailsStep from './AdHocDetailsStep'; - -const STEP_ID = 'details'; -export default function useAdHocDetailsStep(visited, moduleOptions) { - const { values, touched, setFieldError } = useFormikContext(); - - const hasError = () => { - if (!Object.keys(visited).includes(STEP_ID)) { - return false; - } - if (!values.module_name && touched.module_name) { - return true; - } - - if (values.module_name === 'shell' || values.module_name === 'command') { - if (values.module_args) { - return false; - // eslint-disable-next-line no-else-return - } else { - return true; - } - } - return false; - }; - return { - step: { - id: STEP_ID, - key: 1, - name: ( - - {t`Details`} - - ), - component: , - enableNext: true, - nextButtonText: t`Next`, - }, - hasError: hasError(), - validate: () => { - if (Object.keys(touched).includes('module_name' || 'module_args')) { - if (!values.module_name) { - setFieldError('module_name', t`This field must not be blank.`); - } - if ( - values.module_name === ('command' || 'shell') && - !values.module_args - ) { - setFieldError('module_args', t`This field must not be blank`); - } - } - }, - setTouched: (setFieldTouched) => { - setFieldTouched('module_name', true, false); - setFieldTouched('module_args', true, false); - }, - }; -} diff --git a/awx/ui/src/components/AdHocCommands/useAdHocExecutionEnvironmentStep.js b/awx/ui/src/components/AdHocCommands/useAdHocExecutionEnvironmentStep.js deleted file mode 100644 index 95949bce7d8e..000000000000 --- a/awx/ui/src/components/AdHocCommands/useAdHocExecutionEnvironmentStep.js +++ /dev/null @@ -1,28 +0,0 @@ -import React from 'react'; -import { t } from '@lingui/macro'; -import StepName from '../LaunchPrompt/steps/StepName'; -import AdHocExecutionEnvironmentStep from './AdHocExecutionEnvironmentStep'; - -const STEP_ID = 'executionEnvironment'; -export default function useAdHocExecutionEnvironmentStep(organizationId) { - return { - step: { - id: STEP_ID, - key: 2, - stepNavItemProps: { style: { whiteSpace: 'nowrap' } }, - name: ( - - {t`Execution Environment`} - - ), - component: ( - - ), - enableNext: true, - nextButtonText: t`Next`, - }, - hasError: false, - validate: () => {}, - setTouched: () => {}, - }; -} diff --git a/awx/ui/src/components/AdHocCommands/useAdHocLaunchSteps.js b/awx/ui/src/components/AdHocCommands/useAdHocLaunchSteps.js deleted file mode 100644 index 038331e23969..000000000000 --- a/awx/ui/src/components/AdHocCommands/useAdHocLaunchSteps.js +++ /dev/null @@ -1,95 +0,0 @@ -import { useEffect, useState } from 'react'; -import { useFormikContext } from 'formik'; -import useCredentialPasswordsStep from './useAdHocCredentialPasswordStep'; -import useAdHocDetailsStep from './useAdHocDetailsStep'; -import useAdHocExecutionEnvironmentStep from './useAdHocExecutionEnvironmentStep'; -import useAdHocCredentialStep from './useAdHocCredentialStep'; -import useAdHocPreviewStep from './useAdHocPreviewStep'; - -function showCredentialPasswordsStep(credential) { - if (!credential?.inputs) { - return false; - } - const { inputs } = credential; - if ( - inputs?.password === 'ASK' || - inputs?.become_password === 'ASK' || - inputs?.ssh_key_unlock === 'ASK' - ) { - return true; - } - - return false; -} - -export default function useAdHocLaunchSteps( - moduleOptions, - organizationId, - credentialTypeId -) { - const { values, resetForm, touched } = useFormikContext(); - - const [visited, setVisited] = useState({}); - const steps = [ - useAdHocDetailsStep(visited, moduleOptions), - useAdHocExecutionEnvironmentStep(organizationId), - useAdHocCredentialStep(visited, credentialTypeId), - useCredentialPasswordsStep( - showCredentialPasswordsStep(values.credentials[0]), - visited - ), - ]; - - useEffect(() => { - const newFormValues = { ...values }; - - if (!values.credentials[0]?.inputs) { - return; - } - if ( - (values.credentials[0].inputs?.password || - values.credentials[0].inputs?.become_password || - values.credentials[0].inputs?.ssh_key_unlock) === 'ASK' - ) - newFormValues.credential_passwords = {}; - Object.keys(values.credentials[0].inputs).forEach((inputKey) => { - if (inputKey === 'become_password' || inputKey === 'ssh_key_unlock') { - newFormValues.credential_passwords[inputKey] = ''; - } - if (inputKey === 'password') { - newFormValues.credential_passwords.ssh_password = ''; - } - }); - resetForm({ - values: newFormValues, - touched, - }); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [values.credentials.length]); - - const hasErrors = steps.some((step) => step.hasError); - - steps.push(useAdHocPreviewStep(hasErrors)); - return { - steps: steps.map((s) => s.step).filter((s) => s != null), - validateStep: (stepId) => - steps.find((s) => s?.step.id === stepId).validate(), - visitStep: (prevStepId, setFieldTouched) => { - setVisited({ - ...visited, - [prevStepId]: true, - }); - steps.find((s) => s?.step?.id === prevStepId).setTouched(setFieldTouched); - }, - visitAllSteps: (setFieldTouched) => { - setVisited({ - details: true, - executionEnvironment: true, - credentials: true, - credentialPasswords: true, - preview: true, - }); - steps.forEach((s) => s.setTouched(setFieldTouched)); - }, - }; -} diff --git a/awx/ui/src/components/AdHocCommands/useAdHocPreviewStep.js b/awx/ui/src/components/AdHocCommands/useAdHocPreviewStep.js deleted file mode 100644 index bc1d9dd17107..000000000000 --- a/awx/ui/src/components/AdHocCommands/useAdHocPreviewStep.js +++ /dev/null @@ -1,28 +0,0 @@ -import React from 'react'; -import { t } from '@lingui/macro'; -import { useFormikContext } from 'formik'; -import StepName from '../LaunchPrompt/steps/StepName'; -import AdHocPreviewStep from './AdHocPreviewStep'; - -const STEP_ID = 'preview'; -export default function useAdHocPreviewStep(hasErrors) { - const { values } = useFormikContext(); - - return { - step: { - id: STEP_ID, - key: 4, - name: ( - - {t`Preview`} - - ), - component: , - enableNext: !hasErrors, - nextButtonText: t`Launch`, - }, - hasErrors: false, - validate: () => {}, - setTouched: () => {}, - }; -} diff --git a/awx/ui/src/components/AddDropDownButton/AddDropDownButton.js b/awx/ui/src/components/AddDropDownButton/AddDropDownButton.js deleted file mode 100644 index d0e1458c7a67..000000000000 --- a/awx/ui/src/components/AddDropDownButton/AddDropDownButton.js +++ /dev/null @@ -1,57 +0,0 @@ -/* eslint-disable react/jsx-no-useless-fragment */ -import React, { useState, useRef, useEffect } from 'react'; -import { t } from '@lingui/macro'; -import PropTypes from 'prop-types'; -import { Dropdown, DropdownPosition } from '@patternfly/react-core'; -import { useKebabifiedMenu } from 'contexts/Kebabified'; -import { ToolbarAddButton } from '../PaginatedTable'; - -function AddDropDownButton({ dropdownItems, ouiaId }) { - const { isKebabified } = useKebabifiedMenu(); - const [isOpen, setIsOpen] = useState(false); - const element = useRef(null); - - useEffect(() => { - const toggle = (e) => { - if (!isKebabified && (!element || !element.current?.contains(e.target))) { - setIsOpen(false); - } - }; - - document.addEventListener('click', toggle, false); - return () => { - document.removeEventListener('click', toggle); - }; - }, [isKebabified]); - - if (isKebabified) { - return <>{dropdownItems}; - } - - return ( -
- setIsOpen(!isOpen)} - /> - } - dropdownItems={dropdownItems} - ouiaId="add-dropdown" - /> -
- ); -} - -AddDropDownButton.propTypes = { - dropdownItems: PropTypes.arrayOf(PropTypes.element.isRequired).isRequired, -}; - -export { AddDropDownButton as _AddDropDownButton }; -export default AddDropDownButton; diff --git a/awx/ui/src/components/AddDropDownButton/AddDropDownButton.test.js b/awx/ui/src/components/AddDropDownButton/AddDropDownButton.test.js deleted file mode 100644 index d1e16aaa223a..000000000000 --- a/awx/ui/src/components/AddDropDownButton/AddDropDownButton.test.js +++ /dev/null @@ -1,36 +0,0 @@ -import React from 'react'; -import { DropdownItem } from '@patternfly/react-core'; -import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; -import AddDropDownButton from './AddDropDownButton'; - -describe('', () => { - const dropdownItems = [ - Add, - Route, - ]; - test('should be closed initially', () => { - const wrapper = mountWithContexts( - - ); - expect(wrapper.find('Dropdown').prop('isOpen')).toEqual(false); - }); - - test('should render two links', () => { - const wrapper = mountWithContexts( - - ); - wrapper.find('button').simulate('click'); - expect(wrapper.find('Dropdown').prop('isOpen')).toEqual(true); - expect(wrapper.find('DropdownItem')).toHaveLength(dropdownItems.length); - }); - - test('should close when button re-clicked', () => { - const wrapper = mountWithContexts( - - ); - wrapper.find('button').simulate('click'); - expect(wrapper.find('Dropdown').prop('isOpen')).toEqual(true); - wrapper.find('button').simulate('click'); - expect(wrapper.find('Dropdown').prop('isOpen')).toEqual(false); - }); -}); diff --git a/awx/ui/src/components/AddDropDownButton/index.js b/awx/ui/src/components/AddDropDownButton/index.js deleted file mode 100644 index 8c87c7df31db..000000000000 --- a/awx/ui/src/components/AddDropDownButton/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './AddDropDownButton'; diff --git a/awx/ui/src/components/AddRole/AddResourceRole.js b/awx/ui/src/components/AddRole/AddResourceRole.js deleted file mode 100644 index 570c8e82b9c6..000000000000 --- a/awx/ui/src/components/AddRole/AddResourceRole.js +++ /dev/null @@ -1,286 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import PropTypes from 'prop-types'; -import { useHistory } from 'react-router-dom'; -import { t } from '@lingui/macro'; -import { TeamsAPI, UsersAPI } from 'api'; -import useSelected from 'hooks/useSelected'; -import SelectableCard from '../SelectableCard'; -import Wizard from '../Wizard'; -import SelectResourceStep from './SelectResourceStep'; -import SelectRoleStep from './SelectRoleStep'; - -const readUsers = async (queryParams) => - UsersAPI.read(Object.assign(queryParams, { is_superuser: false })); - -const readUsersOptions = async () => UsersAPI.readOptions(); - -const readTeams = async (queryParams) => TeamsAPI.read(queryParams); - -const readTeamsOptions = async () => TeamsAPI.readOptions(); - -const userSearchColumns = [ - { - name: t`Username`, - key: 'username__icontains', - isDefault: true, - }, - { - name: t`First Name`, - key: 'first_name__icontains', - }, - { - name: t`Last Name`, - key: 'last_name__icontains', - }, -]; -const userSortColumns = [ - { - name: t`Username`, - key: 'username', - }, - { - name: t`First Name`, - key: 'first_name', - }, - { - name: t`Last Name`, - key: 'last_name', - }, -]; -const teamSearchColumns = [ - { - name: t`Name`, - key: 'name', - isDefault: true, - }, - { - name: t`Created By (Username)`, - key: 'created_by__username', - }, - { - name: t`Modified By (Username)`, - key: 'modified_by__username', - }, -]; - -const teamSortColumns = [ - { - name: t`Name`, - key: 'name', - }, -]; -function AddResourceRole({ onSave, onClose, roles, resource, onError }) { - const history = useHistory(); - - const { - selected: resourcesSelected, - handleSelect: handleResourceSelect, - clearSelected: clearResources, - } = useSelected([]); - const { - selected: rolesSelected, - handleSelect: handleRoleSelect, - clearSelected: clearRoles, - } = useSelected([]); - - const [resourceType, setResourceType] = useState(null); - const [currentStepId, setCurrentStepId] = useState(1); - const [maxEnabledStep, setMaxEnabledStep] = useState(1); - - useEffect(() => { - if (currentStepId === 1 && maxEnabledStep > 1) { - history.push(history.location.pathname); - } - }, [currentStepId, history, maxEnabledStep]); - - const handleResourceTypeSelect = (type) => { - setResourceType(type); - clearResources(); - clearRoles(); - }; - - const handleWizardNext = (step) => { - setCurrentStepId(step.id); - setMaxEnabledStep(step.id); - }; - - const handleWizardGoToStep = (step) => { - setCurrentStepId(step.id); - }; - - const handleWizardSave = async () => { - try { - const roleRequests = []; - - for (let i = 0; i < resourcesSelected.length; i++) { - for (let j = 0; j < rolesSelected.length; j++) { - if (resourceType === 'users') { - roleRequests.push( - UsersAPI.associateRole( - resourcesSelected[i].id, - rolesSelected[j].id - ) - ); - } else if (resourceType === 'teams') { - roleRequests.push( - TeamsAPI.associateRole( - resourcesSelected[i].id, - rolesSelected[j].id - ) - ); - } - } - } - - await Promise.all(roleRequests); - onSave(); - } catch (err) { - onError(err); - onClose(); - } - }; - - // Object roles can be user only, so we remove them when - // showing role choices for team access - const selectableRoles = { ...roles }; - if (resourceType === 'teams') { - Object.keys(roles).forEach((key) => { - if (selectableRoles[key].user_only) { - delete selectableRoles[key]; - } - }); - } - - let wizardTitle = ''; - - switch (resourceType) { - case 'users': - wizardTitle = t`Add User Roles`; - break; - case 'teams': - wizardTitle = t`Add Team Roles`; - break; - default: - wizardTitle = t`Add Roles`; - } - - const steps = [ - { - id: 1, - name: t`Select a Resource Type`, - component: ( -
-
- {t`Choose the type of resource that will be receiving new roles. For example, if you'd like to add new roles to a set of users please choose Users and click Next. You'll be able to select the specific resources in the next step.`} -
- handleResourceTypeSelect('users')} - /> - {resource?.type === 'team' || - (resource?.type === 'credential' && - !resource?.organization) ? null : ( - handleResourceTypeSelect('teams')} - /> - )} -
- ), - nextButtonText: t`Next`, - enableNext: resourceType !== null, - }, - { - id: 2, - name: t`Select Items from List`, - component: ( - <> - {resourceType === 'users' && ( - - )} - {resourceType === 'teams' && ( - - )} - - ), - enableNext: resourcesSelected.length > 0, - nextButtonText: t`Next`, - canJumpTo: maxEnabledStep >= 2, - }, - { - id: 3, - name: t`Select Roles to Apply`, - component: ( - - ), - nextButtonText: t`Save`, - enableNext: rolesSelected.length > 0, - canJumpTo: maxEnabledStep >= 3, - }, - ]; - - const currentStep = steps.find((step) => step.id === currentStepId); - - return ( - setCurrentStepId(step.id)} - onClose={onClose} - onSave={handleWizardSave} - onGoToStep={(step) => handleWizardGoToStep(step)} - steps={steps} - title={wizardTitle} - nextButtonText={currentStep.nextButtonText || undefined} - backButtonText={t`Back`} - cancelButtonText={t`Cancel`} - /> - ); -} - -AddResourceRole.propTypes = { - onClose: PropTypes.func.isRequired, - onSave: PropTypes.func.isRequired, - roles: PropTypes.shape(), - resource: PropTypes.shape(), -}; - -AddResourceRole.defaultProps = { - roles: {}, - resource: {}, -}; - -export { AddResourceRole as _AddResourceRole }; -export default AddResourceRole; diff --git a/awx/ui/src/components/AddRole/AddResourceRole.test.js b/awx/ui/src/components/AddRole/AddResourceRole.test.js deleted file mode 100644 index 155098ccba53..000000000000 --- a/awx/ui/src/components/AddRole/AddResourceRole.test.js +++ /dev/null @@ -1,426 +0,0 @@ -/* eslint-disable react/jsx-pascal-case */ -import React from 'react'; -import { shallow } from 'enzyme'; -import { createMemoryHistory } from 'history'; -import { act } from 'react-dom/test-utils'; - -import { TeamsAPI, UsersAPI } from 'api'; -import { - mountWithContexts, - waitForElement, -} from '../../../testUtils/enzymeHelpers'; -import AddResourceRole, { _AddResourceRole } from './AddResourceRole'; - -jest.mock('../../api/models/Teams'); -jest.mock('../../api/models/Users'); - -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useHistory: () => ({ push: jest.fn(), location: { pathname: {} } }), -})); -// TODO: Once error handling is functional in -// this component write tests for it - -describe('<_AddResourceRole />', () => { - const roles = { - admin_role: { - description: 'Can manage all aspects of the organization', - id: 1, - name: 'Admin', - }, - execute_role: { - description: 'May run any executable resources in the organization', - id: 2, - name: 'Execute', - }, - }; - - beforeEach(() => { - UsersAPI.read.mockResolvedValue({ - data: { - count: 2, - results: [ - { id: 1, username: 'foo', url: '' }, - { id: 2, username: 'bar', url: '' }, - { id: 3, username: 'baz', url: '' }, - ], - }, - }); - UsersAPI.readOptions.mockResolvedValue({ - data: { related: {}, actions: { GET: {} } }, - }); - TeamsAPI.read.mockResolvedValue({ - data: { - count: 2, - results: [ - { id: 1, name: 'Team foo', url: '' }, - { id: 2, name: 'Team bar', url: '' }, - ], - }, - }); - TeamsAPI.readOptions.mockResolvedValue({ - data: { related: {}, actions: { GET: {} } }, - }); - }); - - test('initially renders without crashing', () => { - shallow( - <_AddResourceRole - onClose={() => {}} - onSave={() => {}} - roles={roles} - i18n={{ _: (val) => val.toString() }} - /> - ); - }); - test('should save properly', async () => { - let wrapper; - act(() => { - wrapper = mountWithContexts( - {}} onSave={() => {}} roles={roles} />, - { context: { network: { handleHttpError: () => {} } } } - ); - }); - wrapper.update(); - - // Step 1 - const selectableCardWrapper = wrapper.find('SelectableCard'); - expect(selectableCardWrapper.length).toBe(2); - act(() => wrapper.find('SelectableCard[label="Users"]').prop('onClick')()); - wrapper.update(); - await act(async () => - wrapper.find('Button[type="submit"]').prop('onClick')() - ); - wrapper.update(); - - // Step 2 - await waitForElement(wrapper, 'EmptyStateBody', (el) => el.length === 0); - expect(wrapper.find('Chip').length).toBe(0); - wrapper.find('CheckboxListItem[name="foo"]').invoke('onSelect')(true); - wrapper.find('CheckboxListItem[name="bar"]').invoke('onSelect')(true); - wrapper.find('CheckboxListItem[name="baz"]').invoke('onSelect')(true); - wrapper.find('CheckboxListItem[name="baz"]').invoke('onSelect')(false); - expect( - wrapper.find('CheckboxListItem[name="foo"]').prop('isSelected') - ).toBe(true); - expect( - wrapper.find('CheckboxListItem[name="bar"]').prop('isSelected') - ).toBe(true); - expect( - wrapper.find('CheckboxListItem[name="baz"]').prop('isSelected') - ).toBe(false); - expect(wrapper.find('Chip').length).toBe(2); - act(() => wrapper.find('Button[type="submit"]').prop('onClick')()); - wrapper.update(); - - // Step 3 - act(() => - wrapper.find('Checkbox[aria-label="Admin"]').invoke('onChange')(true) - ); - wrapper.update(); - expect(wrapper.find('Checkbox[aria-label="Admin"]').prop('isChecked')).toBe( - true - ); - - // Save - await act(async () => - wrapper.find('Button[type="submit"]').prop('onClick')() - ); - expect(UsersAPI.associateRole).toBeCalledWith(1, 1); - expect(UsersAPI.associateRole).toBeCalledWith(2, 1); - expect(UsersAPI.associateRole).toBeCalledTimes(2); - }); - - test('should call on error properly', async () => { - let wrapper; - const onError = jest.fn(); - UsersAPI.associateRole.mockRejectedValue( - new Error({ - response: { - config: { - method: 'post', - url: '/api/v2/users', - }, - data: 'An error occurred', - status: 403, - }, - }) - ); - act(() => { - wrapper = mountWithContexts( - {}} - onError={onError} - onSave={() => {}} - roles={roles} - />, - { context: { network: { handleHttpError: () => {} } } } - ); - }); - wrapper.update(); - - // Step 1 - const selectableCardWrapper = wrapper.find('SelectableCard'); - expect(selectableCardWrapper.length).toBe(2); - act(() => wrapper.find('SelectableCard[label="Users"]').prop('onClick')()); - wrapper.update(); - await act(async () => - wrapper.find('Button[type="submit"]').prop('onClick')() - ); - wrapper.update(); - - // Step 2 - await waitForElement(wrapper, 'EmptyStateBody', (el) => el.length === 0); - act(() => - wrapper.find('CheckboxListItem[name="foo"]').invoke('onSelect')(true) - ); - wrapper.update(); - expect( - wrapper.find('CheckboxListItem[name="foo"]').prop('isSelected') - ).toBe(true); - act(() => wrapper.find('Button[type="submit"]').prop('onClick')()); - wrapper.update(); - - // Step 3 - act(() => - wrapper.find('Checkbox[aria-label="Admin"]').invoke('onChange')(true) - ); - wrapper.update(); - expect(wrapper.find('Checkbox[aria-label="Admin"]').prop('isChecked')).toBe( - true - ); - - // Save - await act(async () => - wrapper.find('Button[type="submit"]').prop('onClick')() - ); - expect(UsersAPI.associateRole).toBeCalledWith(1, 1); - expect(onError).toBeCalled(); - }); - - test('should update history properly', async () => { - let wrapper; - const history = createMemoryHistory({ - initialEntries: ['organizations/2/access?resource.order_by=-username'], - }); - act(() => { - wrapper = mountWithContexts( - {}} onSave={() => {}} roles={roles} />, - { context: { router: { history } } } - ); - }); - wrapper.update(); - - // Step 1 - const selectableCardWrapper = wrapper.find('SelectableCard'); - expect(selectableCardWrapper.length).toBe(2); - act(() => wrapper.find('SelectableCard[label="Users"]').prop('onClick')()); - wrapper.update(); - await act(async () => - wrapper.find('Button[type="submit"]').prop('onClick')() - ); - wrapper.update(); - - // Step 2 - await waitForElement(wrapper, 'EmptyStateBody', (el) => el.length === 0); - act(() => - wrapper.find('CheckboxListItem[name="foo"]').invoke('onSelect')(true) - ); - wrapper.update(); - expect( - wrapper.find('CheckboxListItem[name="foo"]').prop('isSelected') - ).toBe(true); - await act(async () => - wrapper.find('PFWizard').prop('onGoToStep')({ id: 1 }) - ); - wrapper.update(); - expect(history.location.pathname).toEqual('organizations/2/access'); - }); - - test('should successfuly click user/team cards', async () => { - let wrapper; - act(() => { - wrapper = mountWithContexts( - {}} onSave={() => {}} roles={roles} />, - { context: { network: { handleHttpError: () => {} } } } - ); - }); - wrapper.update(); - - const selectableCardWrapper = wrapper.find('SelectableCard'); - expect(selectableCardWrapper.length).toBe(2); - act(() => wrapper.find('SelectableCard[label="Users"]').prop('onClick')()); - wrapper.update(); - - await waitForElement( - wrapper, - 'SelectableCard[label="Users"]', - (el) => el.prop('isSelected') === true - ); - act(() => wrapper.find('SelectableCard[label="Teams"]').prop('onClick')()); - wrapper.update(); - - await waitForElement( - wrapper, - 'SelectableCard[label="Teams"]', - (el) => el.prop('isSelected') === true - ); - }); - - test('should reset values with resource type changes', async () => { - let wrapper; - act(() => { - wrapper = mountWithContexts( - {}} onSave={() => {}} roles={roles} />, - { context: { network: { handleHttpError: () => {} } } } - ); - }); - wrapper.update(); - - // Step 1 - const selectableCardWrapper = wrapper.find('SelectableCard'); - expect(selectableCardWrapper.length).toBe(2); - act(() => wrapper.find('SelectableCard[label="Users"]').prop('onClick')()); - wrapper.update(); - await act(async () => - wrapper.find('Button[type="submit"]').prop('onClick')() - ); - wrapper.update(); - - // Step 2 - await waitForElement(wrapper, 'EmptyStateBody', (el) => el.length === 0); - act(() => - wrapper.find('CheckboxListItem[name="foo"]').invoke('onSelect')(true) - ); - wrapper.update(); - expect( - wrapper.find('CheckboxListItem[name="foo"]').prop('isSelected') - ).toBe(true); - act(() => wrapper.find('Button[type="submit"]').prop('onClick')()); - wrapper.update(); - - // Step 3 - act(() => - wrapper.find('Checkbox[aria-label="Admin"]').invoke('onChange')(true) - ); - wrapper.update(); - expect(wrapper.find('Checkbox[aria-label="Admin"]').prop('isChecked')).toBe( - true - ); - - // Go back to step 1 - act(() => { - wrapper - .find('WizardNavItem[content="Select a Resource Type"]') - .find('button') - .prop('onClick')({ id: 1 }); - }); - wrapper.update(); - expect( - wrapper - .find('WizardNavItem[content="Select a Resource Type"]') - .prop('isCurrent') - ).toBe(true); - - // Go back to step 1 and this time select teams. Doing so should clear following steps - act(() => wrapper.find('SelectableCard[label="Teams"]').prop('onClick')()); - wrapper.update(); - await act(async () => - wrapper.find('Button[type="submit"]').prop('onClick')() - ); - wrapper.update(); - - // Make sure no teams have been selected - await waitForElement(wrapper, 'EmptyStateBody', (el) => el.length === 0); - wrapper - .find('DataListCheck') - .map((item) => expect(item.prop('checked')).toBe(false)); - act(() => wrapper.find('Button[type="submit"]').prop('onClick')()); - wrapper.update(); - - // Make sure that no roles have been selected - wrapper - .find('Checkbox') - .map((card) => expect(card.prop('isChecked')).toBe(false)); - - // Make sure the save button is disabled - expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe(true); - }); - - test('should not display team as a choice in case credential does not have organization', () => { - const wrapper = mountWithContexts( - {}} - onSave={() => {}} - roles={roles} - resource={{ type: 'credential', organization: null }} - />, - { context: { network: { handleHttpError: () => {} } } } - ); - - expect(wrapper.find('SelectableCard').length).toBe(1); - wrapper.find('SelectableCard[label="Users"]').simulate('click'); - wrapper.update(); - expect( - wrapper.find('SelectableCard[label="Users"]').prop('isSelected') - ).toBe(true); - }); - test('should show correct button text', async () => { - let wrapper; - act(() => { - wrapper = mountWithContexts( - {}} onSave={() => {}} roles={roles} />, - { context: { network: { handleHttpError: () => {} } } } - ); - }); - wrapper.update(); - - // Step 1 - const selectableCardWrapper = wrapper.find('SelectableCard'); - expect(selectableCardWrapper.length).toBe(2); - act(() => wrapper.find('SelectableCard[label="Users"]').prop('onClick')()); - wrapper.update(); - await act(async () => - wrapper.find('Button[type="submit"]').prop('onClick')() - ); - expect(wrapper.find('Button[type="submit"]').text()).toBe('Next'); - - wrapper.update(); - - // Step 2 - await waitForElement(wrapper, 'EmptyStateBody', (el) => el.length === 0); - expect(wrapper.find('Chip').length).toBe(0); - act(() => - wrapper.find('CheckboxListItem[name="foo"]').invoke('onSelect')(true) - ); - wrapper.update(); - expect( - wrapper.find('CheckboxListItem[name="foo"]').prop('isSelected') - ).toBe(true); - expect(wrapper.find('Chip').length).toBe(1); - expect(wrapper.find('Button[type="submit"]').text()).toBe('Next'); - act(() => wrapper.find('Button[type="submit"]').prop('onClick')()); - wrapper.update(); - - // Step 3 - act(() => - wrapper.find('Checkbox[aria-label="Admin"]').invoke('onChange')(true) - ); - expect(wrapper.find('Button[type="submit"]').text()).toBe('Save'); - wrapper.update(); - - // Go Back - await act(async () => - wrapper.find('Button[variant="secondary"]').prop('onClick')() - ); - wrapper.update(); - expect(wrapper.find('Button[type="submit"]').text()).toBe('Next'); - - // return to last step - await act(async () => - wrapper.find('Button[type="submit"]').prop('onClick')() - ); - wrapper.update(); - expect(wrapper.find('Button[type="submit"]').text()).toBe('Save'); - }); -}); diff --git a/awx/ui/src/components/AddRole/CheckboxCard.js b/awx/ui/src/components/AddRole/CheckboxCard.js deleted file mode 100644 index b055ee93099b..000000000000 --- a/awx/ui/src/components/AddRole/CheckboxCard.js +++ /dev/null @@ -1,56 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { Checkbox as PFCheckbox } from '@patternfly/react-core'; -import styled from 'styled-components'; - -const CheckboxWrapper = styled.div` - display: flex; - border: 1px solid var(--pf-global--BorderColor--200); - border-radius: var(--pf-global--BorderRadius--sm); - padding: 10px; -`; - -const Checkbox = styled(PFCheckbox)` - width: 100%; - & label { - width: 100%; - } -`; - -function CheckboxCard(props) { - const { name, description, isSelected, onSelect, itemId } = props; - return ( - - -
{name}
-
{description}
- - } - value={itemId} - /> -
- ); -} - -CheckboxCard.propTypes = { - name: PropTypes.string.isRequired, - description: PropTypes.string, - isSelected: PropTypes.bool, - onSelect: PropTypes.func, - itemId: PropTypes.number.isRequired, -}; - -CheckboxCard.defaultProps = { - description: '', - isSelected: false, - onSelect: null, -}; - -export default CheckboxCard; diff --git a/awx/ui/src/components/AddRole/CheckboxCard.test.js b/awx/ui/src/components/AddRole/CheckboxCard.test.js deleted file mode 100644 index 637cbac403eb..000000000000 --- a/awx/ui/src/components/AddRole/CheckboxCard.test.js +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; -import { shallow } from 'enzyme'; -import CheckboxCard from './CheckboxCard'; - -describe('', () => { - let wrapper; - test('initially renders without crashing', () => { - wrapper = shallow(); - expect(wrapper.length).toBe(1); - }); -}); diff --git a/awx/ui/src/components/AddRole/SelectResourceStep.js b/awx/ui/src/components/AddRole/SelectResourceStep.js deleted file mode 100644 index b0e8897320c6..000000000000 --- a/awx/ui/src/components/AddRole/SelectResourceStep.js +++ /dev/null @@ -1,153 +0,0 @@ -import React, { useCallback, useEffect } from 'react'; -import PropTypes from 'prop-types'; -import { useLocation } from 'react-router-dom'; -import { t } from '@lingui/macro'; -import useRequest from 'hooks/useRequest'; -import { SearchColumns, SortColumns } from 'types'; -import { getQSConfig, parseQueryString } from 'util/qs'; -import DataListToolbar from '../DataListToolbar'; -import CheckboxListItem from '../CheckboxListItem'; -import { SelectedList } from '../SelectedList'; -import PaginatedTable, { - HeaderCell, - HeaderRow, - getSearchableKeys, -} from '../PaginatedTable'; - -const QS_Config = (sortColumns) => - getQSConfig('resource', { - page: 1, - page_size: 5, - order_by: `${ - sortColumns.filter((col) => col.key === 'name').length - ? 'name' - : 'username' - }`, - }); -function SelectResourceStep({ - searchColumns, - sortColumns, - displayKey, - onRowClick, - selectedLabel, - selectedResourceRows, - fetchItems, - fetchOptions, -}) { - const location = useLocation(); - - const { - isLoading, - error, - request: readResourceList, - result: { resources, itemCount, relatedSearchableKeys, searchableKeys }, - } = useRequest( - useCallback(async () => { - const queryParams = parseQueryString( - QS_Config(sortColumns), - location.search - ); - - const [ - { - data: { count, results }, - }, - actionsResponse, - ] = await Promise.all([fetchItems(queryParams), fetchOptions()]); - return { - resources: results, - itemCount: count, - relatedSearchableKeys: ( - actionsResponse?.data?.related_search_fields || [] - ).map((val) => val.slice(0, -8)), - searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET), - }; - }, [location, fetchItems, fetchOptions, sortColumns]), - { - resources: [], - itemCount: 0, - relatedSearchableKeys: [], - searchableKeys: [], - } - ); - - useEffect(() => { - readResourceList(); - }, [readResourceList]); - - return ( - <> -
- {t`Choose the resources that will be receiving new roles. You'll be able to select the roles to apply in the next step. Note that the resources chosen here will receive all roles chosen in the next step.`} -
- {selectedResourceRows.length > 0 && ( - - )} - - - {sortColumns.map(({ name, key }) => ( - - {name} - - ))} - - } - renderRow={(item, index) => ( - i.id === item.id)} - itemId={item.id} - item={item} - rowIndex={index} - key={item.id} - columns={sortColumns} - name={item[displayKey]} - label={item[displayKey]} - onSelect={() => onRowClick(item)} - onDeselect={() => onRowClick(item)} - /> - )} - renderToolbar={(props) => } - showPageSizeOptions={false} - /> - - ); -} - -SelectResourceStep.propTypes = { - searchColumns: SearchColumns, - sortColumns: SortColumns, - displayKey: PropTypes.string, - onRowClick: PropTypes.func, - fetchItems: PropTypes.func.isRequired, - selectedLabel: PropTypes.string, - selectedResourceRows: PropTypes.arrayOf(PropTypes.object), -}; - -SelectResourceStep.defaultProps = { - searchColumns: null, - sortColumns: null, - displayKey: 'name', - onRowClick: () => {}, - selectedLabel: null, - selectedResourceRows: [], -}; - -export { SelectResourceStep as _SelectResourceStep }; -export default SelectResourceStep; diff --git a/awx/ui/src/components/AddRole/SelectResourceStep.test.js b/awx/ui/src/components/AddRole/SelectResourceStep.test.js deleted file mode 100644 index 0654558a17fe..000000000000 --- a/awx/ui/src/components/AddRole/SelectResourceStep.test.js +++ /dev/null @@ -1,126 +0,0 @@ -import React from 'react'; -import { act } from 'react-dom/test-utils'; - -import { - mountWithContexts, - shallowWithContexts, - waitForElement, -} from '../../../testUtils/enzymeHelpers'; -import SelectResourceStep from './SelectResourceStep'; - -describe('', () => { - const searchColumns = [ - { - name: 'Username', - key: 'username__icontains', - isDefault: true, - }, - ]; - - const sortColumns = [ - { - name: 'Username', - key: 'username', - }, - ]; - afterEach(() => { - jest.restoreAllMocks(); - }); - test('initially renders without crashing', async () => { - act(() => { - shallowWithContexts( - {}} - fetchItems={() => {}} - fetchOptions={() => {}} - /> - ); - }); - }); - - test('fetches resources on mount and adds items to list', async () => { - const handleSearch = jest.fn().mockResolvedValue({ - data: { - count: 2, - results: [ - { id: 1, username: 'foo', url: 'item/1' }, - { id: 2, username: 'bar', url: 'item/2' }, - ], - }, - }); - const options = jest.fn().mockResolvedValue({ - data: { - actions: { - GET: {}, - POST: {}, - }, - related_search_fields: [], - }, - }); - let wrapper; - await act(async () => { - wrapper = mountWithContexts( - {}} - fetchItems={handleSearch} - fetchOptions={options} - /> - ); - }); - expect(handleSearch).toHaveBeenCalledWith({ - order_by: 'username', - page: 1, - page_size: 5, - }); - waitForElement(wrapper, 'CheckBoxListItem', (el) => el.length === 2); - }); - - test('clicking on row fires callback with correct params', async () => { - const handleRowClick = jest.fn(); - const data = { - count: 2, - results: [ - { id: 1, username: 'foo', url: 'item/1' }, - { id: 2, username: 'bar', url: 'item/2' }, - ], - }; - const options = jest.fn().mockResolvedValue({ - data: { - actions: { - GET: {}, - POST: {}, - }, - related_search_fields: [], - }, - }); - let wrapper; - await act(async () => { - wrapper = mountWithContexts( - ({ data })} - fetchOptions={options} - selectedResourceRows={[]} - /> - ); - }); - wrapper.update(); - const checkboxListItemWrapper = wrapper.find('CheckboxListItem'); - expect(checkboxListItemWrapper.length).toBe(2); - - checkboxListItemWrapper - .first() - .find('input[type="checkbox"]') - .simulate('click'); - expect(handleRowClick).toHaveBeenCalledWith(data.results[0]); - }); -}); diff --git a/awx/ui/src/components/AddRole/SelectRoleStep.js b/awx/ui/src/components/AddRole/SelectRoleStep.js deleted file mode 100644 index e235d4661a35..000000000000 --- a/awx/ui/src/components/AddRole/SelectRoleStep.js +++ /dev/null @@ -1,74 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import { t } from '@lingui/macro'; - -import CheckboxCard from './CheckboxCard'; -import { SelectedList } from '../SelectedList'; - -function RolesStep({ - onRolesClick, - roles, - selectedListKey, - selectedListLabel, - selectedResourceRows, - selectedRoleRows, -}) { - return ( - <> -
- {t`Choose roles to apply to the selected resources. Note that all selected roles will be applied to all selected resources.`} -
-
- {selectedResourceRows.length > 0 && ( - - )} -
-
- {Object.keys(roles).map((role) => ( - item.id === roles[role].id - )} - key={roles[role].id} - name={roles[role].name} - onSelect={() => onRolesClick(roles[role])} - /> - ))} -
- - ); -} - -RolesStep.propTypes = { - onRolesClick: PropTypes.func, - roles: PropTypes.objectOf(PropTypes.object).isRequired, - selectedListKey: PropTypes.string, - selectedListLabel: PropTypes.string, - selectedResourceRows: PropTypes.arrayOf(PropTypes.object), - selectedRoleRows: PropTypes.arrayOf(PropTypes.object), -}; - -RolesStep.defaultProps = { - onRolesClick: () => {}, - selectedListKey: 'name', - selectedListLabel: null, - selectedResourceRows: [], - selectedRoleRows: [], -}; - -export default RolesStep; diff --git a/awx/ui/src/components/AddRole/SelectRoleStep.test.js b/awx/ui/src/components/AddRole/SelectRoleStep.test.js deleted file mode 100644 index c871db337e70..000000000000 --- a/awx/ui/src/components/AddRole/SelectRoleStep.test.js +++ /dev/null @@ -1,68 +0,0 @@ -import React from 'react'; - -import { - mountWithContexts, - shallowWithContexts, -} from '../../../testUtils/enzymeHelpers'; - -import SelectRoleStep from './SelectRoleStep'; - -describe('', () => { - let wrapper; - const roles = { - project_admin_role: { - id: 1, - name: 'Project Admin', - description: 'Can manage all projects of the organization', - }, - execute_role: { - id: 2, - name: 'Execute', - description: 'May run any executable resources in the organization', - }, - }; - const selectedRoles = [ - { - id: 1, - name: 'Project Admin', - description: 'Can manage all projects of the organization', - }, - ]; - const selectedResourceRows = [ - { - id: 1, - name: 'foo', - }, - ]; - - test('initially renders without crashing', () => { - wrapper = shallowWithContexts( - - ); - expect(wrapper.length).toBe(1); - }); - - test('clicking role fires onRolesClick callback', () => { - const onRolesClick = jest.fn(); - wrapper = mountWithContexts( - - ); - const CheckboxCards = wrapper.find('CheckboxCard'); - expect(CheckboxCards.length).toBe(2); - CheckboxCards.first().prop('onSelect')(); - expect(onRolesClick).toBeCalledWith({ - id: 1, - name: 'Project Admin', - description: 'Can manage all projects of the organization', - }); - }); -}); diff --git a/awx/ui/src/components/AddRole/index.js b/awx/ui/src/components/AddRole/index.js deleted file mode 100644 index 52e9ec78d470..000000000000 --- a/awx/ui/src/components/AddRole/index.js +++ /dev/null @@ -1,4 +0,0 @@ -export { default as AddResourceRole } from './AddResourceRole'; -export { default as CheckboxCard } from './CheckboxCard'; -export { default as SelectResourceStep } from './SelectResourceStep'; -export { default as SelectRoleStep } from './SelectRoleStep'; diff --git a/awx/ui/src/components/AlertModal/AlertModal.js b/awx/ui/src/components/AlertModal/AlertModal.js deleted file mode 100644 index df0afb87aa22..000000000000 --- a/awx/ui/src/components/AlertModal/AlertModal.js +++ /dev/null @@ -1,88 +0,0 @@ -import 'styled-components/macro'; -import React from 'react'; -import { Modal, Title } from '@patternfly/react-core'; -import { - CheckCircleIcon, - ExclamationCircleIcon, - ExclamationTriangleIcon, - InfoCircleIcon, - TimesCircleIcon, -} from '@patternfly/react-icons'; - -import { t } from '@lingui/macro'; -import styled from 'styled-components'; - -const Header = styled.div` - display: flex; - svg { - margin-right: 16px; - } -`; - -function AlertModal({ - isOpen = null, - title, - label, - variant, - children, - ...props -}) { - const variantIcons = { - danger: ( - - ), - error: ( - - ), - info: ( - - ), - success: ( - - ), - warning: ( - - ), - }; - - const customHeader = ( -
- {variant ? variantIcons[variant] : null} - - {title} - -
- ); - - return ( - - {children} - - ); -} - -export default AlertModal; diff --git a/awx/ui/src/components/AlertModal/AlertModal.test.js b/awx/ui/src/components/AlertModal/AlertModal.test.js deleted file mode 100644 index 0173e5a378f9..000000000000 --- a/awx/ui/src/components/AlertModal/AlertModal.test.js +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; -import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; - -import AlertModal from './AlertModal'; - -describe('AlertModal', () => { - test('renders the expected content', () => { - const wrapper = mountWithContexts( - Are you sure? - ); - expect(wrapper).toHaveLength(1); - }); -}); diff --git a/awx/ui/src/components/AlertModal/index.js b/awx/ui/src/components/AlertModal/index.js deleted file mode 100644 index f40ad70d3d06..000000000000 --- a/awx/ui/src/components/AlertModal/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './AlertModal'; diff --git a/awx/ui/src/components/AnsibleSelect/AnsibleSelect.js b/awx/ui/src/components/AnsibleSelect/AnsibleSelect.js deleted file mode 100644 index ff1c8395ee46..000000000000 --- a/awx/ui/src/components/AnsibleSelect/AnsibleSelect.js +++ /dev/null @@ -1,84 +0,0 @@ -import React from 'react'; -import { - arrayOf, - oneOfType, - func, - number, - string, - shape, - bool, -} from 'prop-types'; - -import { t } from '@lingui/macro'; -import { FormSelect, FormSelectOption } from '@patternfly/react-core'; - -function AnsibleSelect({ - id, - data, - isValid, - onBlur, - value, - className, - isDisabled, - onChange, - name, -}) { - const onSelectChange = (val, event) => { - event.target.name = name; - onChange(event, val); - }; - - return ( - - {data.map((option) => ( - - {option.label} - - ))} - - ); -} - -const Option = shape({ - key: oneOfType([string, number]).isRequired, - value: oneOfType([string, number]).isRequired, - label: string.isRequired, - isDisabled: bool, -}); - -AnsibleSelect.defaultProps = { - data: [], - isValid: true, - onBlur: () => {}, - className: '', - isDisabled: false, -}; - -AnsibleSelect.propTypes = { - data: arrayOf(Option), - id: string.isRequired, - isValid: bool, - onBlur: func, - onChange: func.isRequired, - value: oneOfType([string, number]).isRequired, - className: string, - isDisabled: bool, -}; - -export { AnsibleSelect as _AnsibleSelect }; -export default AnsibleSelect; diff --git a/awx/ui/src/components/AnsibleSelect/AnsibleSelect.test.js b/awx/ui/src/components/AnsibleSelect/AnsibleSelect.test.js deleted file mode 100644 index f0e2416af41f..000000000000 --- a/awx/ui/src/components/AnsibleSelect/AnsibleSelect.test.js +++ /dev/null @@ -1,61 +0,0 @@ -import React from 'react'; -import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; -import AnsibleSelect from './AnsibleSelect'; - -const mockData = [ - { - key: 'baz', - label: 'Baz', - value: '/var/lib/awx/venv/baz/', - }, - { - key: 'default', - label: 'Default', - value: '/var/lib/awx/venv/ansible/', - }, -]; - -describe('', () => { - const onChange = jest.fn(); - test('initially renders successfully', async () => { - mountWithContexts( - {}} - data={mockData} - /> - ); - }); - - test('calls "onSelectChange" on dropdown select change', () => { - const wrapper = mountWithContexts( - - ); - expect(onChange).not.toHaveBeenCalled(); - wrapper.find('select').simulate('change'); - expect(onChange).toHaveBeenCalled(); - }); - - test('Returns correct select options', () => { - const wrapper = mountWithContexts( - {}} - data={mockData} - /> - ); - - expect(wrapper.find('FormSelect')).toHaveLength(1); - expect(wrapper.find('FormSelectOption')).toHaveLength(2); - }); -}); diff --git a/awx/ui/src/components/AnsibleSelect/index.js b/awx/ui/src/components/AnsibleSelect/index.js deleted file mode 100644 index 647f195bbdb7..000000000000 --- a/awx/ui/src/components/AnsibleSelect/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './AnsibleSelect'; diff --git a/awx/ui/src/components/AppContainer/AppContainer.js b/awx/ui/src/components/AppContainer/AppContainer.js deleted file mode 100644 index f3c07596a6b4..000000000000 --- a/awx/ui/src/components/AppContainer/AppContainer.js +++ /dev/null @@ -1,165 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import { withRouter } from 'react-router-dom'; -import { - Button, - Nav, - NavList, - Page, - PageHeader as PFPageHeader, - PageHeaderTools, - PageHeaderToolsGroup, - PageHeaderToolsItem, - PageSidebar, -} from '@patternfly/react-core'; -import { t, Plural } from '@lingui/macro'; - -import styled from 'styled-components'; - -import { useConfig, useAuthorizedPath } from 'contexts/Config'; -import { useSession } from 'contexts/Session'; -import issuePendoIdentity from 'util/issuePendoIdentity'; -import About from '../About'; -import BrandLogo from './BrandLogo'; -import NavExpandableGroup from './NavExpandableGroup'; -import PageHeaderToolbar from './PageHeaderToolbar'; -import AlertModal from '../AlertModal'; - -const PageHeader = styled(PFPageHeader)` - & .pf-c-page__header-brand-link { - color: inherit; - &:hover { - color: inherit; - } - } -`; - -function AppContainer({ navRouteConfig = [], children }) { - const config = useConfig(); - const { logout, handleSessionContinue, sessionCountdown } = useSession(); - - const isReady = !!config.license_info; - const isSidebarVisible = useAuthorizedPath(); - const [isAboutModalOpen, setIsAboutModalOpen] = useState(false); - - const handleAboutModalOpen = () => setIsAboutModalOpen(true); - const handleAboutModalClose = () => setIsAboutModalOpen(false); - - useEffect(() => { - if ('analytics_status' in config) { - issuePendoIdentity(config); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [config.analytics_status]); - - const brandName = config?.license_info?.product_name; - const alt = brandName ? t`${brandName} logo` : t`brand logo`; - - const header = ( - } - logoProps={{ href: '/' }} - headerTools={ - - } - /> - ); - - const simpleHeader = config.isLoading ? null : ( - } - headerTools={ - - - - - - - - } - /> - ); - - const sidebar = ( - - - {navRouteConfig.map(({ groupId, groupTitle, routes }) => ( - - ))} - - - } - /> - ); - - return ( - <> - - {isReady ? children : null} - - - 0} - onClose={logout} - showClose={false} - variant="warning" - actions={[ - , - , - ]} - > - - - - ); -} - -export { AppContainer as _AppContainer }; -export default withRouter(AppContainer); diff --git a/awx/ui/src/components/AppContainer/AppContainer.test.js b/awx/ui/src/components/AppContainer/AppContainer.test.js deleted file mode 100644 index 7c5a9ee87b2a..000000000000 --- a/awx/ui/src/components/AppContainer/AppContainer.test.js +++ /dev/null @@ -1,204 +0,0 @@ -import React from 'react'; -import { act } from 'react-dom/test-utils'; -import { MeAPI, RootAPI } from 'api'; -import { useAuthorizedPath } from 'contexts/Config'; -import { - mountWithContexts, - waitForElement, -} from '../../../testUtils/enzymeHelpers'; -import AppContainer from './AppContainer'; - -jest.mock('../../api'); -jest.mock('../../util/bootstrapPendo'); - -global.pendo = { - initialize: jest.fn(), -}; - -describe('', () => { - const version = '222'; - - beforeEach(() => { - RootAPI.readAssetVariables.mockResolvedValue({ - data: { - BRAND_NAME: 'AWX', - PENDO_API_KEY: 'some-pendo-key', - }, - }); - MeAPI.read.mockResolvedValue({ data: { results: [{}] } }); - useAuthorizedPath.mockImplementation(() => true); - }); - - afterEach(() => { - jest.clearAllMocks(); - jest.restoreAllMocks(); - }); - - test('expected content is rendered', async () => { - const routeConfig = [ - { - groupTitle: Group One, - groupId: 'group_one', - routes: [ - { title: 'Foo', path: '/foo' }, - { title: 'Bar', path: '/bar' }, - ], - }, - { - groupTitle: Group Two, - groupId: 'group_two', - routes: [{ title: 'Fiz', path: '/fiz' }], - }, - ]; - - let wrapper; - await act(async () => { - wrapper = mountWithContexts( - - {routeConfig.map(({ groupId }) => ( -
- ))} - , - { - context: { - config: { - analytics_status: 'detailed', - ansible_version: null, - custom_virtualenvs: [], - version: '9000', - me: { is_superuser: true }, - toJSON: () => '/config/', - license_info: { - valid_key: true, - }, - }, - }, - } - ); - }); - wrapper.update(); - - // page components - expect(wrapper.length).toBe(1); - expect(wrapper.find('PageHeader').length).toBe(1); - expect(wrapper.find('PageSidebar').length).toBe(1); - - // sidebar groups and route links - expect(wrapper.find('NavExpandableGroup').length).toBe(2); - expect(wrapper.find('a[href="/foo"]').length).toBe(1); - expect(wrapper.find('a[href="/bar"]').length).toBe(1); - expect(wrapper.find('a[href="/fiz"]').length).toBe(1); - - expect(wrapper.find('#group_one').length).toBe(1); - expect(wrapper.find('#group_two').length).toBe(1); - - expect(global.pendo.initialize).toHaveBeenCalledTimes(1); - }); - - test('Pendo not initialized when key is missing', async () => { - RootAPI.readAssetVariables.mockResolvedValue({ - data: { - BRAND_NAME: 'AWX', - PENDO_API_KEY: '', - }, - }); - let wrapper; - await act(async () => { - wrapper = mountWithContexts(, { - context: { - config: { - analytics_status: 'detailed', - ansible_version: null, - custom_virtualenvs: [], - version: '9000', - me: { is_superuser: true }, - toJSON: () => '/config/', - license_info: { - valid_key: true, - }, - }, - }, - }); - }); - wrapper.update(); - expect(global.pendo.initialize).toHaveBeenCalledTimes(0); - }); - - test('Pendo not initialized when status is analytics off', async () => { - let wrapper; - await act(async () => { - wrapper = mountWithContexts(, { - context: { - config: { - analytics_status: 'off', - ansible_version: null, - custom_virtualenvs: [], - version: '9000', - me: { is_superuser: true }, - toJSON: () => '/config/', - license_info: { - valid_key: true, - }, - }, - }, - }); - }); - wrapper.update(); - expect(global.pendo.initialize).toHaveBeenCalledTimes(0); - }); - - test('opening the about modal renders prefetched config data', async () => { - const aboutDropdown = 'Dropdown QuestionCircleIcon'; - const aboutButton = 'DropdownItem li button'; - const aboutModalContent = 'AboutModalBoxContent'; - const aboutModalClose = 'button[aria-label="Close Dialog"]'; - - let wrapper; - await act(async () => { - wrapper = mountWithContexts(, { - context: { config: { version } }, - }); - }); - - // open about dropdown menu - await waitForElement(wrapper, aboutDropdown); - wrapper.find(aboutDropdown).simulate('click'); - - // open about modal - ( - await waitForElement(wrapper, aboutButton, (el) => !el.props().disabled) - ).simulate('click'); - - // check about modal content - const content = await waitForElement(wrapper, aboutModalContent); - expect(content.find('pre').text()).toContain(`< AWX ${version} >`); - - // close about modal - wrapper.find(aboutModalClose).simulate('click'); - expect(wrapper.find(aboutModalContent)).toHaveLength(0); - }); - - test('logout makes expected call to api client', async () => { - const userMenuButton = 'UserIcon'; - const logoutButton = '#logout-button button'; - const logout = jest.fn(); - let wrapper; - await act(async () => { - wrapper = mountWithContexts(, { - context: { - session: { - logout, - }, - }, - }); - }); - // open the user menu - expect(wrapper.find(logoutButton)).toHaveLength(0); - wrapper.find(userMenuButton).simulate('click'); - expect(wrapper.find(logoutButton)).toHaveLength(1); - - // logout - wrapper.find(logoutButton).simulate('click'); - expect(logout).toHaveBeenCalledTimes(1); - }); -}); diff --git a/awx/ui/src/components/AppContainer/BrandLogo.js b/awx/ui/src/components/AppContainer/BrandLogo.js deleted file mode 100644 index b3bb8efdfb69..000000000000 --- a/awx/ui/src/components/AppContainer/BrandLogo.js +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; - -import styled from 'styled-components'; - -const BrandImg = styled.img` - flex: initial; - height: 76px; - width: initial; - padding-left: 0px; - margin: 0px 0px 0px 0px; - max-width: 100px; - max-height: initial; - pointer-events: none; -`; - -const BrandLogo = ({ alt }) => ( - -); - -export default BrandLogo; diff --git a/awx/ui/src/components/AppContainer/BrandLogo.test.js b/awx/ui/src/components/AppContainer/BrandLogo.test.js deleted file mode 100644 index 641332be6663..000000000000 --- a/awx/ui/src/components/AppContainer/BrandLogo.test.js +++ /dev/null @@ -1,22 +0,0 @@ -import React from 'react'; -import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; -import BrandLogo from './BrandLogo'; - -let logoWrapper; -let brandLogoElem; -let imgElem; - -const findChildren = () => { - brandLogoElem = logoWrapper.find('BrandLogo'); - imgElem = logoWrapper.find('img'); -}; - -describe('', () => { - test('initially renders without crashing', () => { - logoWrapper = mountWithContexts(); - findChildren(); - expect(logoWrapper.length).toBe(1); - expect(brandLogoElem.length).toBe(1); - expect(imgElem.length).toBe(1); - }); -}); diff --git a/awx/ui/src/components/AppContainer/NavExpandableGroup.js b/awx/ui/src/components/AppContainer/NavExpandableGroup.js deleted file mode 100644 index a5c162170829..000000000000 --- a/awx/ui/src/components/AppContainer/NavExpandableGroup.js +++ /dev/null @@ -1,52 +0,0 @@ -import React from 'react'; -import PropTypes, { oneOfType, string, arrayOf } from 'prop-types'; -import { matchPath, Link, useHistory } from 'react-router-dom'; -import { NavExpandable, NavItem } from '@patternfly/react-core'; - -function NavExpandableGroup(props) { - const history = useHistory(); - const { groupId, groupTitle, routes } = props; - - // Extract a list of paths from the route params and store them for later. This creates - // an array of url paths associated with any NavItem component rendered by this component. - const navItemPaths = routes.map(({ path }) => path); - - const isActive = navItemPaths.some(isActivePath); - - function isActivePath(path) { - return Boolean(matchPath(history.location.pathname, { path })); - } - - if (routes.length === 1 && groupId === 'settings') { - const [{ path }] = routes; - return ( - - {groupTitle} - - ); - } - - return ( - - {routes.map(({ path, title }) => ( - - {title} - - ))} - - ); -} - -NavExpandableGroup.propTypes = { - groupId: string.isRequired, - groupTitle: oneOfType([PropTypes.element, string]).isRequired, - routes: arrayOf(PropTypes.object).isRequired, -}; - -export default NavExpandableGroup; diff --git a/awx/ui/src/components/AppContainer/NavExpandableGroup.test.js b/awx/ui/src/components/AppContainer/NavExpandableGroup.test.js deleted file mode 100644 index 90c0214ac6ad..000000000000 --- a/awx/ui/src/components/AppContainer/NavExpandableGroup.test.js +++ /dev/null @@ -1,110 +0,0 @@ -import React from 'react'; -import { MemoryRouter, withRouter } from 'react-router-dom'; -import { mount } from 'enzyme'; - -import { Nav } from '@patternfly/react-core'; -import _NavExpandableGroup from './NavExpandableGroup'; - -const NavExpandableGroup = withRouter(_NavExpandableGroup); - -describe('NavExpandableGroup', () => { - test('initialization and render', () => { - const component = mount( - - - - ).find('NavExpandableGroup'); - - expect(component.find('NavItem').length).toEqual(3); - let link = component.find('NavItem').at(0); - expect(component.find('NavItem').at(0).prop('isActive')).toBeTruthy(); - expect(link.find('Link').prop('to')).toBe('/foo'); - - link = component.find('NavItem').at(1); - expect(link.prop('isActive')).toBeFalsy(); - expect(link.find('Link').prop('to')).toBe('/bar'); - - link = component.find('NavItem').at(2); - expect(link.prop('isActive')).toBeFalsy(); - expect(link.find('Link').prop('to')).toBe('/fiz'); - }); - - test('when location is /foo/1/bar/fiz isActive returns false', () => { - const component = mount( - - - - ).find('NavExpandableGroup'); - - expect(component.find('NavItem').length).toEqual(3); - const link = component.find('NavItem').at(0); - expect(component.find('NavItem').at(0).prop('isActive')).toBeTruthy(); - expect(link.find('Link').prop('to')).toBe('/foo'); - }); - - test('when location is /fo isActive returns false', () => { - const component = mount( - - - - ).find('NavExpandableGroup'); - - expect(component.find('NavItem').length).toEqual(3); - const link = component.find('NavItem').at(0); - expect(component.find('NavItem').at(0).prop('isActive')).toBeFalsy(); - expect(link.find('Link').prop('to')).toBe('/foo'); - }); - - test('when location is /foo isActive returns true', () => { - const component = mount( - - - - ).find('NavExpandableGroup'); - - expect(component.find('NavItem').length).toEqual(3); - const link = component.find('NavItem').at(0); - expect(component.find('NavItem').at(0).prop('isActive')).toBeTruthy(); - expect(link.find('Link').prop('to')).toBe('/foo'); - }); -}); diff --git a/awx/ui/src/components/AppContainer/PageHeaderToolbar.js b/awx/ui/src/components/AppContainer/PageHeaderToolbar.js deleted file mode 100644 index 2d87d596a5a2..000000000000 --- a/awx/ui/src/components/AppContainer/PageHeaderToolbar.js +++ /dev/null @@ -1,189 +0,0 @@ -import React, { useCallback, useEffect, useState } from 'react'; -import PropTypes from 'prop-types'; - -import { t } from '@lingui/macro'; -import { Link } from 'react-router-dom'; -import styled from 'styled-components'; -import { - Dropdown, - DropdownItem, - DropdownToggle, - DropdownPosition, - NotificationBadge, - NotificationBadgeVariant, - PageHeaderTools, - PageHeaderToolsGroup, - PageHeaderToolsItem, - Tooltip, -} from '@patternfly/react-core'; -import { QuestionCircleIcon, UserIcon } from '@patternfly/react-icons'; -import { WorkflowApprovalsAPI } from 'api'; -import useRequest from 'hooks/useRequest'; -import getDocsBaseUrl from 'util/getDocsBaseUrl'; -import { useConfig } from 'contexts/Config'; -import useWsPendingApprovalCount from './useWsPendingApprovalCount'; - -const PendingWorkflowApprovals = styled.div` - display: flex; - align-items: center; - padding: 10px; - margin-right: 10px; -`; - -function PageHeaderToolbar({ - isAboutDisabled, - onAboutClick, - onLogoutClick, - loggedInUser, -}) { - const [isHelpOpen, setIsHelpOpen] = useState(false); - const [isUserOpen, setIsUserOpen] = useState(false); - const config = useConfig(); - - const { request: fetchPendingApprovalCount, result: pendingApprovals } = - useRequest( - useCallback(async () => { - const { - data: { count }, - } = await WorkflowApprovalsAPI.read({ - status: 'pending', - page_size: 1, - }); - return count; - }, []), - 0 - ); - - const pendingApprovalsCount = useWsPendingApprovalCount( - pendingApprovals, - fetchPendingApprovalCount - ); - - useEffect(() => { - fetchPendingApprovalCount(); - }, [fetchPendingApprovalCount]); - - const handleHelpSelect = () => { - setIsHelpOpen(!isHelpOpen); - }; - - const handleUserSelect = () => { - setIsUserOpen(!isUserOpen); - }; - return ( - - - - - - - - - - - - - - - - } - dropdownItems={[ - - {t`Help`} - , - - {t`About`} - , - ]} - /> - - - - - {loggedInUser && ( - - {loggedInUser.username} - - )} - - } - dropdownItems={[ - - {t`User Details`} - , - - {t`Logout`} - , - ]} - /> - - - - ); -} - -PageHeaderToolbar.propTypes = { - isAboutDisabled: PropTypes.bool, - onAboutClick: PropTypes.func.isRequired, - onLogoutClick: PropTypes.func.isRequired, -}; - -PageHeaderToolbar.defaultProps = { - isAboutDisabled: false, -}; - -export default PageHeaderToolbar; diff --git a/awx/ui/src/components/AppContainer/PageHeaderToolbar.test.js b/awx/ui/src/components/AppContainer/PageHeaderToolbar.test.js deleted file mode 100644 index 1fd1734c5925..000000000000 --- a/awx/ui/src/components/AppContainer/PageHeaderToolbar.test.js +++ /dev/null @@ -1,86 +0,0 @@ -import React from 'react'; -import { act } from 'react-dom/test-utils'; -import { WorkflowApprovalsAPI } from 'api'; -import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; -import PageHeaderToolbar from './PageHeaderToolbar'; - -jest.mock('../../api'); - -let wrapper; - -describe('PageHeaderToolbar', () => { - const pageHelpDropdownSelector = 'Dropdown QuestionCircleIcon'; - const pageUserDropdownSelector = 'Dropdown UserIcon'; - const onAboutClick = jest.fn(); - const onLogoutClick = jest.fn(); - - test('expected content is rendered on initialization', async () => { - await act(async () => { - wrapper = mountWithContexts( - - ); - }); - - expect( - wrapper.find( - 'Link[to="/workflow_approvals?workflow_approvals.status=pending"]' - ) - ).toHaveLength(1); - expect(wrapper.find(pageHelpDropdownSelector)).toHaveLength(1); - expect(wrapper.find(pageUserDropdownSelector)).toHaveLength(1); - }); - - test('dropdowns have expected items and callbacks', async () => { - await act(async () => { - wrapper = mountWithContexts( - - ); - }); - expect(wrapper.find('DropdownItem')).toHaveLength(0); - wrapper.find(pageHelpDropdownSelector).simulate('click'); - expect(wrapper.find('DropdownItem')).toHaveLength(2); - - const about = wrapper.find('DropdownItem li button'); - about.simulate('click'); - expect(onAboutClick).toHaveBeenCalled(); - - expect(wrapper.find('DropdownItem')).toHaveLength(0); - wrapper.find(pageUserDropdownSelector).simulate('click'); - wrapper.update(); - expect( - wrapper.find('DropdownItem[aria-label="User details"]').prop('href') - ).toBe('#/users/1/details'); - expect(wrapper.find('DropdownItem')).toHaveLength(2); - - const logout = wrapper.find('DropdownItem li button'); - logout.simulate('click'); - expect(onLogoutClick).toHaveBeenCalled(); - }); - - test('pending workflow approvals count set correctly', async () => { - WorkflowApprovalsAPI.read.mockResolvedValueOnce({ - data: { - count: 20, - }, - }); - await act(async () => { - wrapper = mountWithContexts( - - ); - }); - - expect( - wrapper.find('NotificationBadge#toolbar-workflow-approval-badge').text() - ).toEqual('20'); - }); -}); diff --git a/awx/ui/src/components/AppContainer/index.js b/awx/ui/src/components/AppContainer/index.js deleted file mode 100644 index 4fa9f5e563fe..000000000000 --- a/awx/ui/src/components/AppContainer/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import AppContainer from './AppContainer'; - -export default AppContainer; diff --git a/awx/ui/src/components/AppContainer/useWsPendingApprovalCount.js b/awx/ui/src/components/AppContainer/useWsPendingApprovalCount.js deleted file mode 100644 index 0b6866b1ea80..000000000000 --- a/awx/ui/src/components/AppContainer/useWsPendingApprovalCount.js +++ /dev/null @@ -1,39 +0,0 @@ -import { useState, useEffect } from 'react'; -import useWebsocket from 'hooks/useWebsocket'; -import useThrottle from 'hooks/useThrottle'; - -export default function useWsPendingApprovalCount( - initialCount, - fetchApprovalsCount -) { - const [pendingApprovalCount, setPendingApprovalCount] = - useState(initialCount); - const [reloadCount, setReloadCount] = useState(false); - const throttledFetch = useThrottle(reloadCount, 1000); - const lastMessage = useWebsocket({ - jobs: ['status_changed'], - control: ['limit_reached_1'], - }); - - useEffect(() => { - setPendingApprovalCount(initialCount); - }, [initialCount]); - - useEffect(() => { - (async () => { - if (!throttledFetch) { - return; - } - setReloadCount(false); - fetchApprovalsCount(); - })(); - }, [throttledFetch, fetchApprovalsCount]); - - useEffect(() => { - if (lastMessage?.type === 'workflow_approval') { - setReloadCount(true); - } - }, [lastMessage]); - - return pendingApprovalCount; -} diff --git a/awx/ui/src/components/AppContainer/useWsPendingApprovalCount.test.js b/awx/ui/src/components/AppContainer/useWsPendingApprovalCount.test.js deleted file mode 100644 index 3ced90e9df39..000000000000 --- a/awx/ui/src/components/AppContainer/useWsPendingApprovalCount.test.js +++ /dev/null @@ -1,116 +0,0 @@ -import React from 'react'; -import { act } from 'react-dom/test-utils'; -import WS from 'jest-websocket-mock'; -import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; -import useWsPendingApprovalCount from './useWsPendingApprovalCount'; - -function TestInner() { - return
; -} -function Test({ initialCount, fetchApprovalsCount }) { - const updatedWorkflowApprovals = useWsPendingApprovalCount( - initialCount, - fetchApprovalsCount - ); - return ; -} - -describe('useWsPendingApprovalCount hook', () => { - let debug; - let wrapper; - beforeEach(() => { - /* - Jest mock timers don’t play well with jest-websocket-mock, - so we'll stub out throttling to resolve immediately - */ - jest.mock('../../hooks/useThrottle', () => ({ - __esModule: true, - default: jest.fn((val) => val), - })); - debug = global.console.debug; // eslint-disable-line prefer-destructuring - global.console.debug = () => {}; - }); - - afterEach(() => { - global.console.debug = debug; - WS.clean(); - }); - - test('should return workflow approval pending count', () => { - wrapper = mountWithContexts( - {}} /> - ); - - expect(wrapper.find('TestInner').prop('initialCount')).toEqual(2); - }); - - test('should establish websocket connection', async () => { - global.document.cookie = 'csrftoken=abc123'; - const mockServer = new WS('ws://localhost/websocket/'); - - await act(async () => { - wrapper = mountWithContexts( - {}} /> - ); - }); - - await mockServer.connected; - await expect(mockServer).toReceiveMessage( - JSON.stringify({ - xrftoken: 'abc123', - groups: { - jobs: ['status_changed'], - control: ['limit_reached_1'], - }, - }) - ); - }); - - test('should refetch count after approval status changes', async () => { - global.document.cookie = 'csrftoken=abc123'; - const mockServer = new WS('ws://localhost/websocket/'); - const fetchApprovalsCount = jest.fn(() => []); - await act(async () => { - wrapper = await mountWithContexts( - - ); - }); - - await mockServer.connected; - await act(async () => { - mockServer.send( - JSON.stringify({ - unified_job_id: 2, - type: 'workflow_approval', - status: 'pending', - }) - ); - }); - - expect(fetchApprovalsCount).toHaveBeenCalledTimes(1); - }); - - test('should not refetch when message is not workflow approval', async () => { - global.document.cookie = 'csrftoken=abc123'; - const mockServer = new WS('ws://localhost/websocket/'); - const fetchApprovalsCount = jest.fn(() => []); - await act(async () => { - wrapper = await mountWithContexts( - - ); - }); - - await mockServer.connected; - await act(async () => { - mockServer.send( - JSON.stringify({ - unified_job_id: 1, - type: 'job', - status: 'successful', - }) - ); - }); - - expect(fetchApprovalsCount).toHaveBeenCalledTimes(0); - }); -}); diff --git a/awx/ui/src/components/AppendBody/AppendBody.js b/awx/ui/src/components/AppendBody/AppendBody.js deleted file mode 100644 index 9f3ca64d0608..000000000000 --- a/awx/ui/src/components/AppendBody/AppendBody.js +++ /dev/null @@ -1,17 +0,0 @@ -import { useEffect, useState } from 'react'; -import ReactDOM from 'react-dom'; - -function AppendBody({ children }) { - const [el] = useState(document.createElement('div')); - - useEffect(() => { - document.body.appendChild(el); - return () => { - document.body.removeChild(el); - }; - }, [el]); - - return ReactDOM.createPortal(children, el); -} - -export default AppendBody; diff --git a/awx/ui/src/components/AppendBody/index.js b/awx/ui/src/components/AppendBody/index.js deleted file mode 100644 index d2c2b8ef93fa..000000000000 --- a/awx/ui/src/components/AppendBody/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './AppendBody'; diff --git a/awx/ui/src/components/AssociateModal/AssociateModal.js b/awx/ui/src/components/AssociateModal/AssociateModal.js deleted file mode 100644 index 3b42c6691517..000000000000 --- a/awx/ui/src/components/AssociateModal/AssociateModal.js +++ /dev/null @@ -1,165 +0,0 @@ -import React, { useEffect, useCallback } from 'react'; -import { useHistory } from 'react-router-dom'; - -import { t } from '@lingui/macro'; -import { Button, Modal } from '@patternfly/react-core'; -import { getSearchableKeys } from 'components/PaginatedTable'; -import useRequest from 'hooks/useRequest'; -import { getQSConfig, parseQueryString } from 'util/qs'; -import useSelected from 'hooks/useSelected'; -import OptionsList from '../OptionsList'; - -const QS_CONFIG = (order_by = 'name') => - getQSConfig('associate', { - page: 1, - page_size: 5, - order_by, - }); - -function AssociateModal({ - header = t`Items`, - columns = [], - title = t`Select Items`, - onClose, - onAssociate, - fetchRequest, - optionsRequest, - isModalOpen = false, - displayKey = 'name', - ouiaId, -}) { - const history = useHistory(); - const { selected, handleSelect } = useSelected([]); - - const { - request: fetchItems, - result: { items, itemCount, relatedSearchableKeys, searchableKeys }, - error: contentError, - isLoading, - } = useRequest( - useCallback(async () => { - const params = parseQueryString( - QS_CONFIG(displayKey), - history.location.search - ); - const [ - { - data: { count, results }, - }, - actionsResponse, - ] = await Promise.all([fetchRequest(params), optionsRequest()]); - - return { - items: results, - itemCount: count, - relatedSearchableKeys: ( - actionsResponse?.data?.related_search_fields || [] - ).map((val) => val.slice(0, -8)), - searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET), - }; - }, [fetchRequest, optionsRequest, history.location.search, displayKey]), - { - items: [], - itemCount: 0, - relatedSearchableKeys: [], - searchableKeys: [], - } - ); - - useEffect(() => { - fetchItems(); - }, [fetchItems]); - - const clearQSParams = () => { - const parts = history.location.search.replace(/^\?/, '').split('&'); - const { namespace } = QS_CONFIG(displayKey); - const otherParts = parts.filter( - (param) => !param.startsWith(`${namespace}.`) - ); - history.replace(`${history.location.pathname}?${otherParts.join('&')}`); - }; - - const handleSave = async () => { - await onAssociate(selected); - clearQSParams(); - onClose(); - }; - - const handleClose = () => { - clearQSParams(); - onClose(); - }; - - return ( - - {t`Save`} - , - , - ]} - > - - - ); -} - -export default AssociateModal; diff --git a/awx/ui/src/components/AssociateModal/AssociateModal.test.js b/awx/ui/src/components/AssociateModal/AssociateModal.test.js deleted file mode 100644 index e12e9e748300..000000000000 --- a/awx/ui/src/components/AssociateModal/AssociateModal.test.js +++ /dev/null @@ -1,84 +0,0 @@ -import React from 'react'; -import { act } from 'react-dom/test-utils'; - -import { - mountWithContexts, - waitForElement, -} from '../../../testUtils/enzymeHelpers'; -import AssociateModal from './AssociateModal'; -import mockHosts from './data.hosts.json'; - -jest.mock('../../api'); - -describe('', () => { - let wrapper; - let onClose; - let onAssociate; - let fetchRequest; - let optionsRequest; - - beforeEach(async () => { - onClose = jest.fn(); - onAssociate = jest.fn().mockResolvedValue(); - fetchRequest = jest.fn().mockReturnValue({ data: { ...mockHosts } }); - optionsRequest = jest.fn().mockResolvedValue({ - data: { - actions: { - GET: {}, - POST: {}, - }, - related_search_fields: [], - }, - }); - await act(async () => { - wrapper = mountWithContexts( - - ); - }); - await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - test('should render successfully', () => { - expect(wrapper.find('AssociateModal').length).toBe(1); - }); - - test('should fetch and render list items', () => { - expect(fetchRequest).toHaveBeenCalledTimes(1); - expect(optionsRequest).toHaveBeenCalledTimes(1); - expect(wrapper.find('CheckboxListItem').length).toBe(3); - }); - - test('should update selected list chips when items are selected', () => { - expect(wrapper.find('SelectedList Chip')).toHaveLength(0); - act(() => { - wrapper.find('CheckboxListItem').first().invoke('onSelect')(); - }); - wrapper.update(); - expect(wrapper.find('SelectedList Chip')).toHaveLength(1); - wrapper.find('SelectedList Chip button').simulate('click'); - expect(wrapper.find('SelectedList Chip')).toHaveLength(0); - }); - - test('save button should call onAssociate', () => { - act(() => { - wrapper.find('CheckboxListItem').first().invoke('onSelect')(); - }); - wrapper.find('button[aria-label="Save"]').simulate('click'); - expect(onAssociate).toHaveBeenCalledTimes(1); - }); - - test('cancel button should call onClose', () => { - wrapper.find('button[aria-label="Cancel"]').simulate('click'); - expect(onClose).toHaveBeenCalledTimes(1); - }); -}); diff --git a/awx/ui/src/components/AssociateModal/data.hosts.json b/awx/ui/src/components/AssociateModal/data.hosts.json deleted file mode 100644 index 07c6ef7d9f8d..000000000000 --- a/awx/ui/src/components/AssociateModal/data.hosts.json +++ /dev/null @@ -1,393 +0,0 @@ - -{ - "count": 3, - "results": [ - { - "id": 2, - "type": "host", - "url": "/api/v2/hosts/2/", - "related": { - "created_by": "/api/v2/users/10/", - "modified_by": "/api/v2/users/19/", - "variable_data": "/api/v2/hosts/2/variable_data/", - "groups": "/api/v2/hosts/2/groups/", - "all_groups": "/api/v2/hosts/2/all_groups/", - "job_events": "/api/v2/hosts/2/job_events/", - "job_host_summaries": "/api/v2/hosts/2/job_host_summaries/", - "activity_stream": "/api/v2/hosts/2/activity_stream/", - "inventory_sources": "/api/v2/hosts/2/inventory_sources/", - "smart_inventories": "/api/v2/hosts/2/smart_inventories/", - "ad_hoc_commands": "/api/v2/hosts/2/ad_hoc_commands/", - "ad_hoc_command_events": "/api/v2/hosts/2/ad_hoc_command_events/", - "insights": "/api/v2/hosts/2/insights/", - "ansible_facts": "/api/v2/hosts/2/ansible_facts/", - "inventory": "/api/v2/inventories/2/", - "last_job": "/api/v2/jobs/236/", - "last_job_host_summary": "/api/v2/job_host_summaries/2202/" - }, - "summary_fields": { - "inventory": { - "id": 2, - "name": " Inventory 1 Org 0", - "description": "", - "has_active_failures": false, - "total_hosts": 33, - "hosts_with_active_failures": 0, - "total_groups": 4, - "has_inventory_sources": false, - "total_inventory_sources": 0, - "inventory_sources_with_failures": 0, - "organization_id": 2, - "kind": "" - }, - "last_job": { - "id": 236, - "name": " Job Template 1 Project 0", - "description": "", - "finished": "2020-02-26T03:15:21.471439Z", - "status": "successful", - "failed": false, - "job_template_id": 18, - "job_template_name": " Job Template 1 Project 0" - }, - "last_job_host_summary": { - "id": 2202, - "failed": false - }, - "created_by": { - "id": 10, - "username": "user-3", - "first_name": "", - "last_name": "" - }, - "modified_by": { - "id": 19, - "username": "all", - "first_name": "", - "last_name": "" - }, - "user_capabilities": { - "edit": true, - "delete": true - }, - "groups": { - "count": 2, - "results": [ - { - "id": 1, - "name": " Group 1 Inventory 0" - }, - { - "id": 2, - "name": " Group 2 Inventory 0" - } - ] - }, - "recent_jobs": [ - { - "id": 236, - "name": " Job Template 1 Project 0", - "status": "successful", - "finished": "2020-02-26T03:15:21.471439Z" - }, - { - "id": 232, - "name": " Job Template 1 Project 0", - "status": "successful", - "finished": "2020-02-25T21:20:33.593789Z" - }, - { - "id": 229, - "name": " Job Template 1 Project 0", - "status": "successful", - "finished": "2020-02-25T16:19:46.364134Z" - }, - { - "id": 228, - "name": " Job Template 1 Project 0", - "status": "successful", - "finished": "2020-02-25T16:18:54.138363Z" - }, - { - "id": 225, - "name": " Job Template 1 Project 0", - "status": "successful", - "finished": "2020-02-25T15:55:32.247652Z" - } - ] - }, - "created": "2020-02-24T15:10:58.922179Z", - "modified": "2020-02-26T21:52:43.428530Z", - "name": ".host-000001.group-00000.dummy", - "description": "", - "inventory": 2, - "enabled": false, - "instance_id": "", - "variables": "", - "has_active_failures": false, - "has_inventory_sources": false, - "last_job": 236, - "last_job_host_summary": 2202, - "insights_system_id": null, - "ansible_facts_modified": null - }, - { - "id": 3, - "type": "host", - "url": "/api/v2/hosts/3/", - "related": { - "created_by": "/api/v2/users/11/", - "modified_by": "/api/v2/users/1/", - "variable_data": "/api/v2/hosts/3/variable_data/", - "groups": "/api/v2/hosts/3/groups/", - "all_groups": "/api/v2/hosts/3/all_groups/", - "job_events": "/api/v2/hosts/3/job_events/", - "job_host_summaries": "/api/v2/hosts/3/job_host_summaries/", - "activity_stream": "/api/v2/hosts/3/activity_stream/", - "inventory_sources": "/api/v2/hosts/3/inventory_sources/", - "smart_inventories": "/api/v2/hosts/3/smart_inventories/", - "ad_hoc_commands": "/api/v2/hosts/3/ad_hoc_commands/", - "ad_hoc_command_events": "/api/v2/hosts/3/ad_hoc_command_events/", - "insights": "/api/v2/hosts/3/insights/", - "ansible_facts": "/api/v2/hosts/3/ansible_facts/", - "inventory": "/api/v2/inventories/2/", - "last_job": "/api/v2/jobs/236/", - "last_job_host_summary": "/api/v2/job_host_summaries/2195/" - }, - "summary_fields": { - "inventory": { - "id": 2, - "name": " Inventory 1 Org 0", - "description": "", - "has_active_failures": false, - "total_hosts": 33, - "hosts_with_active_failures": 0, - "total_groups": 4, - "has_inventory_sources": false, - "total_inventory_sources": 0, - "inventory_sources_with_failures": 0, - "organization_id": 2, - "kind": "" - }, - "last_job": { - "id": 236, - "name": " Job Template 1 Project 0", - "description": "", - "finished": "2020-02-26T03:15:21.471439Z", - "status": "successful", - "failed": false, - "job_template_id": 18, - "job_template_name": " Job Template 1 Project 0" - }, - "last_job_host_summary": { - "id": 2195, - "failed": false - }, - "created_by": { - "id": 11, - "username": "user-4", - "first_name": "", - "last_name": "" - }, - "modified_by": { - "id": 1, - "username": "admin", - "first_name": "", - "last_name": "" - }, - "user_capabilities": { - "edit": true, - "delete": true - }, - "groups": { - "count": 2, - "results": [ - { - "id": 1, - "name": " Group 1 Inventory 0" - }, - { - "id": 2, - "name": " Group 2 Inventory 0" - } - ] - }, - "recent_jobs": [ - { - "id": 236, - "name": " Job Template 1 Project 0", - "status": "successful", - "finished": "2020-02-26T03:15:21.471439Z" - }, - { - "id": 232, - "name": " Job Template 1 Project 0", - "status": "successful", - "finished": "2020-02-25T21:20:33.593789Z" - }, - { - "id": 229, - "name": " Job Template 1 Project 0", - "status": "successful", - "finished": "2020-02-25T16:19:46.364134Z" - }, - { - "id": 228, - "name": " Job Template 1 Project 0", - "status": "successful", - "finished": "2020-02-25T16:18:54.138363Z" - }, - { - "id": 225, - "name": " Job Template 1 Project 0", - "status": "successful", - "finished": "2020-02-25T15:55:32.247652Z" - } - ] - }, - "created": "2020-02-24T15:10:58.945113Z", - "modified": "2020-02-27T03:43:43.635871Z", - "name": ".host-000002.group-00000.dummy", - "description": "", - "inventory": 2, - "enabled": false, - "instance_id": "", - "variables": "", - "has_active_failures": false, - "has_inventory_sources": false, - "last_job": 236, - "last_job_host_summary": 2195, - "insights_system_id": null, - "ansible_facts_modified": null - }, - { - "id": 4, - "type": "host", - "url": "/api/v2/hosts/4/", - "related": { - "created_by": "/api/v2/users/12/", - "modified_by": "/api/v2/users/1/", - "variable_data": "/api/v2/hosts/4/variable_data/", - "groups": "/api/v2/hosts/4/groups/", - "all_groups": "/api/v2/hosts/4/all_groups/", - "job_events": "/api/v2/hosts/4/job_events/", - "job_host_summaries": "/api/v2/hosts/4/job_host_summaries/", - "activity_stream": "/api/v2/hosts/4/activity_stream/", - "inventory_sources": "/api/v2/hosts/4/inventory_sources/", - "smart_inventories": "/api/v2/hosts/4/smart_inventories/", - "ad_hoc_commands": "/api/v2/hosts/4/ad_hoc_commands/", - "ad_hoc_command_events": "/api/v2/hosts/4/ad_hoc_command_events/", - "insights": "/api/v2/hosts/4/insights/", - "ansible_facts": "/api/v2/hosts/4/ansible_facts/", - "inventory": "/api/v2/inventories/2/", - "last_job": "/api/v2/jobs/236/", - "last_job_host_summary": "/api/v2/job_host_summaries/2192/" - }, - "summary_fields": { - "inventory": { - "id": 2, - "name": " Inventory 1 Org 0", - "description": "", - "has_active_failures": false, - "total_hosts": 33, - "hosts_with_active_failures": 0, - "total_groups": 4, - "has_inventory_sources": false, - "total_inventory_sources": 0, - "inventory_sources_with_failures": 0, - "organization_id": 2, - "kind": "" - }, - "last_job": { - "id": 236, - "name": " Job Template 1 Project 0", - "description": "", - "finished": "2020-02-26T03:15:21.471439Z", - "status": "successful", - "failed": false, - "job_template_id": 18, - "job_template_name": " Job Template 1 Project 0" - }, - "last_job_host_summary": { - "id": 2192, - "failed": false - }, - "created_by": { - "id": 12, - "username": "user-5", - "first_name": "", - "last_name": "" - }, - "modified_by": { - "id": 1, - "username": "admin", - "first_name": "", - "last_name": "" - }, - "user_capabilities": { - "edit": true, - "delete": true - }, - "groups": { - "count": 2, - "results": [ - { - "id": 1, - "name": " Group 1 Inventory 0" - }, - { - "id": 2, - "name": " Group 2 Inventory 0" - } - ] - }, - "recent_jobs": [ - { - "id": 236, - "name": " Job Template 1 Project 0", - "status": "successful", - "finished": "2020-02-26T03:15:21.471439Z" - }, - { - "id": 232, - "name": " Job Template 1 Project 0", - "status": "successful", - "finished": "2020-02-25T21:20:33.593789Z" - }, - { - "id": 229, - "name": " Job Template 1 Project 0", - "status": "successful", - "finished": "2020-02-25T16:19:46.364134Z" - }, - { - "id": 228, - "name": " Job Template 1 Project 0", - "status": "successful", - "finished": "2020-02-25T16:18:54.138363Z" - }, - { - "id": 225, - "name": " Job Template 1 Project 0", - "status": "successful", - "finished": "2020-02-25T15:55:32.247652Z" - } - ] - }, - "created": "2020-02-24T15:10:58.962312Z", - "modified": "2020-02-27T03:43:45.528882Z", - "name": ".host-000003.group-00000.dummy", - "description": "", - "inventory": 2, - "enabled": false, - "instance_id": "", - "variables": "", - "has_active_failures": false, - "has_inventory_sources": false, - "last_job": 236, - "last_job_host_summary": 2192, - "insights_system_id": null, - "ansible_facts_modified": null - } - ] -} diff --git a/awx/ui/src/components/AssociateModal/index.js b/awx/ui/src/components/AssociateModal/index.js deleted file mode 100644 index 1a9df3aa33c8..000000000000 --- a/awx/ui/src/components/AssociateModal/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './AssociateModal'; diff --git a/awx/ui/src/components/Background/Background.js b/awx/ui/src/components/Background/Background.js deleted file mode 100644 index c6521168b5b4..000000000000 --- a/awx/ui/src/components/Background/Background.js +++ /dev/null @@ -1,10 +0,0 @@ -import React from 'react'; - -import { BackgroundImage } from '@patternfly/react-core'; - -export default ({ children }) => ( - <> - - {children} - -); diff --git a/awx/ui/src/components/Background/Background.test.js b/awx/ui/src/components/Background/Background.test.js deleted file mode 100644 index 4d306f79a5a1..000000000000 --- a/awx/ui/src/components/Background/Background.test.js +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react'; -import { mount } from 'enzyme'; - -import Background from './Background'; - -describe('Background', () => { - test('renders the expected content', () => { - const wrapper = mount( - -
- - ); - expect(wrapper).toHaveLength(1); - expect(wrapper.find('.pf-c-background-image')).toHaveLength(1); - expect(wrapper.find('#test')).toHaveLength(1); - }); -}); diff --git a/awx/ui/src/components/Background/index.js b/awx/ui/src/components/Background/index.js deleted file mode 100644 index 5f61d4bc31ce..000000000000 --- a/awx/ui/src/components/Background/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Background'; diff --git a/awx/ui/src/components/Card/CardActionsRow.js b/awx/ui/src/components/Card/CardActionsRow.js deleted file mode 100644 index 3652692a8150..000000000000 --- a/awx/ui/src/components/Card/CardActionsRow.js +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; -import { CardActions } from '@patternfly/react-core'; -import styled from 'styled-components'; - -const CardActionsWrapper = styled.div` - margin-top: 20px; - --pf-c-card__actions--PaddingLeft: 0; -`; - -function CardActionsRow({ children }) { - return ( - - {children} - - ); -} - -export default CardActionsRow; diff --git a/awx/ui/src/components/Card/CardBody.js b/awx/ui/src/components/Card/CardBody.js deleted file mode 100644 index 095eece1429c..000000000000 --- a/awx/ui/src/components/Card/CardBody.js +++ /dev/null @@ -1,9 +0,0 @@ -import styled from 'styled-components'; -import { CardBody } from '@patternfly/react-core'; - -const TabbedCardBody = styled(CardBody)` - padding-top: var(--pf-c-card--first-child--PaddingTop); -`; -CardBody.displayName = 'PFCardBody'; - -export default TabbedCardBody; diff --git a/awx/ui/src/components/Card/index.js b/awx/ui/src/components/Card/index.js deleted file mode 100644 index 93de96efcabf..000000000000 --- a/awx/ui/src/components/Card/index.js +++ /dev/null @@ -1,2 +0,0 @@ -export { default as CardBody } from './CardBody'; -export { default as CardActionsRow } from './CardActionsRow'; diff --git a/awx/ui/src/components/CheckboxListItem/CheckboxListItem.js b/awx/ui/src/components/CheckboxListItem/CheckboxListItem.js deleted file mode 100644 index bce6a322c2e4..000000000000 --- a/awx/ui/src/components/CheckboxListItem/CheckboxListItem.js +++ /dev/null @@ -1,90 +0,0 @@ -import 'styled-components/macro'; -import React from 'react'; -import PropTypes from 'prop-types'; -import { t } from '@lingui/macro'; -import { Td, Tr } from '@patternfly/react-table'; -import { ActionsTd } from 'components/PaginatedTable'; - -const CheckboxListItem = ({ - isRadio = false, - isSelected = false, - itemId, - label, - name, - onDeselect, - rowIndex, - onSelect, - columns, - item, - rowActions, -}) => { - const handleRowClick = () => { - if (isSelected && !isRadio) { - onDeselect(itemId); - } else { - onSelect(itemId); - } - }; - - return ( - - - - {columns?.length > 0 ? ( - columns.map((col) => ( - - {item[col.key]} - - )) - ) : ( - - {label} - - )} - {rowActions && ( - - {rowActions.map((rowAction) => { - const { - props: { id }, - } = rowAction; - return {rowAction}; - })} - - )} - - ); -}; - -CheckboxListItem.propTypes = { - isSelected: PropTypes.bool.isRequired, - itemId: PropTypes.number.isRequired, - label: PropTypes.string.isRequired, - name: PropTypes.string.isRequired, - onDeselect: PropTypes.func.isRequired, - onSelect: PropTypes.func.isRequired, -}; - -export default CheckboxListItem; diff --git a/awx/ui/src/components/CheckboxListItem/CheckboxListItem.test.js b/awx/ui/src/components/CheckboxListItem/CheckboxListItem.test.js deleted file mode 100644 index fe54582de28c..000000000000 --- a/awx/ui/src/components/CheckboxListItem/CheckboxListItem.test.js +++ /dev/null @@ -1,53 +0,0 @@ -import React from 'react'; -import { mount } from 'enzyme'; - -import CheckboxListItem from './CheckboxListItem'; - -describe('CheckboxListItem', () => { - test('renders the expected content', () => { - const wrapper = mount( - - - {}} - onDeselect={() => {}} - /> - -
- ); - expect(wrapper).toHaveLength(1); - }); - - test('should render row actions', () => { - const wrapper = mount( - - - {}} - onDeselect={() => {}} - rowActions={[ -
action_1
, -
action_2
, - ]} - /> -
-
- ); - expect( - wrapper - .find('ActionsTd') - .containsAllMatchingElements([ -
action_1
, -
action_2
, - ]) - ).toEqual(true); - }); -}); diff --git a/awx/ui/src/components/CheckboxListItem/index.js b/awx/ui/src/components/CheckboxListItem/index.js deleted file mode 100644 index f1c4287a66b5..000000000000 --- a/awx/ui/src/components/CheckboxListItem/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './CheckboxListItem'; diff --git a/awx/ui/src/components/ChipGroup/ChipGroup.js b/awx/ui/src/components/ChipGroup/ChipGroup.js deleted file mode 100644 index a4ad262b89ad..000000000000 --- a/awx/ui/src/components/ChipGroup/ChipGroup.js +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react'; - -import { t } from '@lingui/macro'; -import { ChipGroup as PFChipGroup } from '@patternfly/react-core'; -import { number } from 'prop-types'; - -function ChipGroup({ numChips, totalChips, ...props }) { - return ( - - ); -} - -ChipGroup.propTypes = { - numChips: number.isRequired, - totalChips: number.isRequired, -}; - -export default ChipGroup; diff --git a/awx/ui/src/components/ChipGroup/ChipGroup.test.js b/awx/ui/src/components/ChipGroup/ChipGroup.test.js deleted file mode 100644 index e9d843e77133..000000000000 --- a/awx/ui/src/components/ChipGroup/ChipGroup.test.js +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; -import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; -import ChipGroup from './ChipGroup'; - -describe('ChipGroup', () => { - test('should mount properly', () => { - const wrapper = mountWithContexts( - - ); - expect(wrapper.find('ChipGroup').at(1).props().collapsedText).toEqual( - '5 more' - ); - }); -}); diff --git a/awx/ui/src/components/ChipGroup/index.js b/awx/ui/src/components/ChipGroup/index.js deleted file mode 100644 index e38952cc63bd..000000000000 --- a/awx/ui/src/components/ChipGroup/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './ChipGroup'; diff --git a/awx/ui/src/components/CodeEditor/CodeEditor.js b/awx/ui/src/components/CodeEditor/CodeEditor.js deleted file mode 100644 index d7cc1f5e9f65..000000000000 --- a/awx/ui/src/components/CodeEditor/CodeEditor.js +++ /dev/null @@ -1,206 +0,0 @@ -import React, { useEffect, useRef, useCallback } from 'react'; -import { oneOf, bool, number, string, func, oneOfType } from 'prop-types'; - -import ReactAce from 'react-ace'; -import 'ace-builds/src-noconflict/mode-json'; -import 'ace-builds/src-noconflict/mode-javascript'; -import 'ace-builds/src-noconflict/mode-yaml'; -import 'ace-builds/src-noconflict/mode-django'; -import 'ace-builds/src-noconflict/theme-github'; - -import { t } from '@lingui/macro'; -import styled from 'styled-components'; -import debounce from 'util/debounce'; - -const LINE_HEIGHT = 24; -const PADDING = 12; - -const FocusWrapper = styled.div` - && + .keyboard-help-text { - opacity: 0; - transition: opacity 0.1s linear; - } - - &:focus-within + .keyboard-help-text { - opacity: 1; - } - - & .ace_hidden-cursors .ace_cursor { - opacity: 0; - } -`; - -const AceEditor = styled(ReactAce)` - font-family: var(--pf-global--FontFamily--monospace); - max-height: 90vh; - - & .ace_gutter, - & .ace_scroller { - padding-top: 4px; - padding-bottom: 4px; - } - - & .ace_mobile-menu { - display: none; - } - - ${(props) => - props.hasErrors && - ` - && { - --pf-c-form-control--PaddingRight: var(--pf-c-form-control--invalid--PaddingRight); - --pf-c-form-control--BorderBottomColor: var(--pf-c-form-control--invalid--BorderBottomColor); - padding-right: 24px; - padding-bottom: var(--pf-c-form-control--invalid--PaddingBottom); - background: var(--pf-c-form-control--invalid--Background); - border-bottom-width: var(--pf-c-form-control--invalid--BorderBottomWidth); - }`} - - ${(props) => - props.setOptions.readOnly && - ` - && .ace_cursor { - opacity: 0; - } - `} -`; -AceEditor.displayName = 'AceEditor'; - -function CodeEditor({ - id, - value, - onChange, - onFocus, - onBlur, - mode, - readOnly, - hasErrors, - rows, - fullHeight, - className, -}) { - if (rows && typeof rows !== 'number' && rows !== 'auto') { - // eslint-disable-next-line no-console - console.warn( - `CodeEditor: Unexpected value for 'rows': ${rows}; expected number or 'auto'` - ); - } - - const wrapper = useRef(null); - const editor = useRef(null); - - useEffect(() => { - const editorInput = editor.current.refEditor?.querySelector('textarea'); - if (!editorInput) { - return; - } - if (!readOnly) { - editorInput.tabIndex = -1; - } - editorInput.id = id; - }, [readOnly, id]); - - const listen = useCallback((event) => { - if (wrapper.current === document.activeElement && event.key === 'Enter') { - const editorInput = editor.current.refEditor?.querySelector('textarea'); - if (!editorInput) { - return; - } - event.preventDefault(); - event.stopPropagation(); - editorInput.focus(); - } - }, []); - - useEffect(() => { - const wrapperEl = wrapper.current; - wrapperEl.addEventListener('keydown', listen); - - return () => { - wrapperEl.removeEventListener('keydown', listen); - }; - }); - - const aceModes = { - javascript: 'json', - yaml: 'yaml', - jinja2: 'django', - }; - - const numRows = rows === 'auto' ? value.split('\n').length : rows; - const height = fullHeight ? '50vh' : `${numRows * LINE_HEIGHT + PADDING}px`; - - return ( - <> - - { - wrapper.current.focus(); - }, - }, - { - name: 'tab escape', - bindKey: { win: 'Shift-Tab', mac: 'Shift-Tab' }, - exec: () => { - wrapper.current.focus(); - }, - }, - ]} - ref={editor} - /> - - {!readOnly && ( -
- {t`Press Enter to edit. Press ESC to stop editing.`} -
- )} - - ); -} -CodeEditor.propTypes = { - value: string.isRequired, - onChange: func, - mode: oneOf(['javascript', 'yaml', 'jinja2']).isRequired, - readOnly: bool, - hasErrors: bool, - fullHeight: bool, - rows: oneOfType([number, string]), - className: string, -}; -CodeEditor.defaultProps = { - readOnly: false, - onChange: () => {}, - rows: 6, - fullHeight: false, - hasErrors: false, - className: '', -}; - -export default CodeEditor; diff --git a/awx/ui/src/components/CodeEditor/CodeEditor.test.js b/awx/ui/src/components/CodeEditor/CodeEditor.test.js deleted file mode 100644 index 876106a090d6..000000000000 --- a/awx/ui/src/components/CodeEditor/CodeEditor.test.js +++ /dev/null @@ -1,44 +0,0 @@ -import React from 'react'; -import debounce from 'util/debounce'; -import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; -import CodeEditor from './CodeEditor'; - -jest.mock('../../util/debounce'); - -describe('CodeEditor', () => { - beforeEach(() => { - document.body.createTextRange = jest.fn(); - }); - - it('should pass value and mode through to ace editor', () => { - const onChange = jest.fn(); - const wrapper = mountWithContexts( - - ); - const aceEditor = wrapper.find('AceEditor'); - expect(aceEditor.prop('mode')).toEqual('yaml'); - expect(aceEditor.prop('setOptions').readOnly).toEqual(false); - expect(aceEditor.prop('value')).toEqual('---\nfoo: bar'); - }); - - it('should trigger onChange prop', () => { - debounce.mockImplementation((fn) => fn); - const onChange = jest.fn(); - const wrapper = mountWithContexts( - - ); - const aceEditor = wrapper.find('AceEditor'); - aceEditor.prop('onChange')('newvalue'); - expect(onChange).toHaveBeenCalledWith('newvalue'); - }); - - it('should render in read only mode', () => { - const onChange = jest.fn(); - const wrapper = mountWithContexts( - - ); - const aceEditor = wrapper.find('AceEditor'); - expect(aceEditor.prop('setOptions').readOnly).toEqual(true); - expect(aceEditor.prop('value')).toEqual('---'); - }); -}); diff --git a/awx/ui/src/components/CodeEditor/CodeEditorField.js b/awx/ui/src/components/CodeEditor/CodeEditorField.js deleted file mode 100644 index ee7f4d9cd4a0..000000000000 --- a/awx/ui/src/components/CodeEditor/CodeEditorField.js +++ /dev/null @@ -1,74 +0,0 @@ -import React from 'react'; -import { - string, - oneOfType, - object, - func, - bool, - node, - oneOf, - number, -} from 'prop-types'; -import { useField } from 'formik'; -import { FormGroup } from '@patternfly/react-core'; -import CodeEditor from './CodeEditor'; -import Popover from '../Popover'; - -function CodeEditorField({ - id, - name, - label, - tooltip, - helperText, - validate, - isRequired, - mode, - ...rest -}) { - const [field, meta, helpers] = useField({ name, validate }); - const isValid = !(meta.touched && meta.error); - - return ( - } - > - { - helpers.setValue(value); - }} - mode={mode} - /> - - ); -} -CodeEditorField.propTypes = { - helperText: string, - id: string.isRequired, - name: string.isRequired, - label: oneOfType([object, string]).isRequired, - validate: func, - isRequired: bool, - tooltip: node, - mode: oneOf(['javascript', 'yaml', 'jinja2']).isRequired, - rows: number, -}; - -CodeEditorField.defaultProps = { - helperText: '', - validate: () => {}, - isRequired: false, - tooltip: null, - rows: 5, -}; - -export default CodeEditorField; diff --git a/awx/ui/src/components/CodeEditor/VariablesDetail.js b/awx/ui/src/components/CodeEditor/VariablesDetail.js deleted file mode 100644 index c1f69fbf82d0..000000000000 --- a/awx/ui/src/components/CodeEditor/VariablesDetail.js +++ /dev/null @@ -1,224 +0,0 @@ -import 'styled-components/macro'; -import React, { useState } from 'react'; -import { node, number, oneOfType, shape, string, arrayOf } from 'prop-types'; - -import { t } from '@lingui/macro'; -import { - Split, - SplitItem, - TextListItemVariants, - Button, - Modal, -} from '@patternfly/react-core'; -import { ExpandArrowsAltIcon } from '@patternfly/react-icons'; -import { yamlToJson, jsonToYaml, isJsonObject, isJsonString } from 'util/yaml'; -import { DetailName, DetailValue } from '../DetailList'; -import MultiButtonToggle from '../MultiButtonToggle'; -import Popover from '../Popover'; -import CodeEditor from './CodeEditor'; -import { JSON_MODE, YAML_MODE } from './constants'; - -function VariablesDetail({ - dataCy, - helpText, - value, - label, - rows, - fullHeight, - name, -}) { - const [mode, setMode] = useState( - isJsonObject(value) || isJsonString(value) ? JSON_MODE : YAML_MODE - ); - const [isExpanded, setIsExpanded] = useState(false); - - let currentValue = value; - let error; - - const getValueInCurrentMode = () => { - if (!value) { - if (mode === JSON_MODE) { - return '{}'; - } - return '---'; - } - const modeMatches = isJsonString(value) === (mode === JSON_MODE); - if (modeMatches) { - if (mode === JSON_MODE) { - return JSON.stringify(JSON.parse(value), null, 2); - } - return value; - } - return mode === YAML_MODE ? jsonToYaml(value) : yamlToJson(value); - }; - - try { - currentValue = getValueInCurrentMode(); - } catch (err) { - error = err; - } - - const labelCy = dataCy ? `${dataCy}-label` : null; - const valueCy = dataCy ? `${dataCy}-value` : null; - - return ( - <> - - setIsExpanded(true)} - name={name} - /> - - - - {error && ( -
- {t`Error:`} {error.message} -
- )} -
- setIsExpanded(false)} - actions={[ - , - ]} - > -
- - -
-
- - ); -} -VariablesDetail.propTypes = { - value: oneOfType([shape({}), arrayOf(string), string]).isRequired, - label: node.isRequired, - rows: oneOfType([number, string]), - dataCy: string, - helpText: oneOfType([node, string]), - name: string.isRequired, -}; -VariablesDetail.defaultProps = { - rows: null, - dataCy: '', - helpText: '', -}; - -function ModeToggle({ - id, - label, - helpText, - dataCy, - mode, - setMode, - onExpand, - name, -}) { - return ( - - - - - - - - { - setMode(newMode); - }} - name={name} - /> - - - - {onExpand && ( - - - - )} - - ); -} - -export default VariablesDetail; diff --git a/awx/ui/src/components/CodeEditor/VariablesDetail.test.js b/awx/ui/src/components/CodeEditor/VariablesDetail.test.js deleted file mode 100644 index 0ad9fed51bde..000000000000 --- a/awx/ui/src/components/CodeEditor/VariablesDetail.test.js +++ /dev/null @@ -1,96 +0,0 @@ -import React from 'react'; -import { act } from 'react-dom/test-utils'; -import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; -import VariablesDetail from './VariablesDetail'; - -jest.mock('../../api'); - -describe('', () => { - test('should render readonly CodeEditor', () => { - const wrapper = mountWithContexts( - - ); - const input = wrapper.find('VariablesDetail___StyledCodeEditor'); - expect(input).toHaveLength(1); - expect(input.prop('mode')).toEqual('yaml'); - expect(input.prop('value')).toEqual('---foo: bar'); - expect(input.prop('readOnly')).toEqual(true); - }); - - test('should detect JSON', () => { - const wrapper = mountWithContexts( - - ); - const input = wrapper.find('VariablesDetail___StyledCodeEditor'); - expect(input).toHaveLength(1); - expect(input.prop('mode')).toEqual('javascript'); - }); - - test('should format JSON', () => { - const wrapper = mountWithContexts( - - ); - const input = wrapper.find('VariablesDetail___StyledCodeEditor'); - expect(input).toHaveLength(1); - expect(input.prop('value')).toEqual('{\n "foo": "bar"\n}'); - }); - - test('should convert between modes', () => { - const wrapper = mountWithContexts( - - ); - wrapper.find('MultiButtonToggle').invoke('onChange')('javascript'); - const input = wrapper.find('VariablesDetail___StyledCodeEditor'); - expect(input.prop('mode')).toEqual('javascript'); - expect(input.prop('value')).toEqual('{\n "foo": "bar"\n}'); - - wrapper.find('MultiButtonToggle').invoke('onChange')('yaml'); - const input2 = wrapper.find('VariablesDetail___StyledCodeEditor'); - expect(input2.prop('mode')).toEqual('yaml'); - expect(input2.prop('value')).toEqual('---foo: bar'); - }); - - test('should render label and value --- when there are no values', () => { - const wrapper = mountWithContexts( - - ); - expect(wrapper.find('VariablesDetail___StyledCodeEditor').length).toBe(1); - expect(wrapper.find('.pf-c-form__label').text()).toBe('Variables'); - }); - - test('should update value if prop changes', () => { - const wrapper = mountWithContexts( - - ); - act(() => { - wrapper.find('MultiButtonToggle').invoke('onChange')('javascript'); - }); - wrapper.setProps({ - value: '---bar: baz', - }); - wrapper.update(); - const input = wrapper.find('VariablesDetail___StyledCodeEditor'); - expect(input.prop('mode')).toEqual('javascript'); - expect(input.prop('value')).toEqual('{\n "bar": "baz"\n}'); - }); - - test('should default yaml value to "---"', () => { - const wrapper = mountWithContexts( - - ); - const input = wrapper.find('VariablesDetail___StyledCodeEditor'); - expect(input.prop('value')).toEqual('---'); - }); - - test('should default empty json to "{}"', () => { - const wrapper = mountWithContexts( - - ); - act(() => { - wrapper.find('MultiButtonToggle').invoke('onChange')('javascript'); - }); - wrapper.setProps({ value: '' }); - const input = wrapper.find('VariablesDetail___StyledCodeEditor'); - expect(input.prop('value')).toEqual('{}'); - }); -}); diff --git a/awx/ui/src/components/CodeEditor/VariablesField.js b/awx/ui/src/components/CodeEditor/VariablesField.js deleted file mode 100644 index 02ede84f7d64..000000000000 --- a/awx/ui/src/components/CodeEditor/VariablesField.js +++ /dev/null @@ -1,271 +0,0 @@ -import React, { useState, useEffect, useCallback } from 'react'; -import { string, bool, func, oneOf } from 'prop-types'; - -import { t } from '@lingui/macro'; -import { useField } from 'formik'; -import styled from 'styled-components'; -import { Split, SplitItem, Button, Modal } from '@patternfly/react-core'; -import { ExpandArrowsAltIcon } from '@patternfly/react-icons'; -import { yamlToJson, jsonToYaml, isJsonString } from 'util/yaml'; -import { CheckboxField } from '../FormField'; -import MultiButtonToggle from '../MultiButtonToggle'; -import CodeEditor from './CodeEditor'; -import Popover from '../Popover'; -import { JSON_MODE, YAML_MODE } from './constants'; - -const FieldHeader = styled.div` - display: flex; - justify-content: space-between; - padding-bottom: var(--pf-c-form__group-label--PaddingBottom); -`; - -const StyledCheckboxField = styled(CheckboxField)` - --pf-c-check__label--FontSize: var(--pf-c-form__label--FontSize); - margin-left: auto; -`; - -function VariablesField({ - id, - name, - label, - readOnly, - promptId, - tooltip, - initialMode, - onModeChange, -}) { - // track focus manually, because the Code Editor library doesn't wire - // into Formik completely - const [shouldValidate, setShouldValidate] = useState(false); - const [mode, setMode] = useState(initialMode || YAML_MODE); - const validate = useCallback( - (value) => { - if (!shouldValidate) { - return undefined; - } - try { - if (mode === YAML_MODE) { - yamlToJson(value); - } else { - JSON.parse(value); - } - } catch (error) { - return error.message; - } - return undefined; - }, - [shouldValidate, mode] - ); - const [field, meta, helpers] = useField({ name, validate }); - - useEffect(() => { - if (isJsonString(field.value)) { - // mode's useState above couldn't be initialized to JSON_MODE because - // the field value had to be defined below it - setMode(JSON_MODE); - onModeChange(JSON_MODE); - helpers.setValue(JSON.stringify(JSON.parse(field.value), null, 2)); - } - }, []); // eslint-disable-line react-hooks/exhaustive-deps - - useEffect( - () => { - if (shouldValidate) { - helpers.setError(validate(field.value)); - } - }, - [shouldValidate, validate] // eslint-disable-line react-hooks/exhaustive-deps - ); - const [lastYamlValue, setLastYamlValue] = useState( - mode === YAML_MODE ? field.value : null - ); - const [isJsonEdited, setIsJsonEdited] = useState(false); - const [isExpanded, setIsExpanded] = useState(false); - - const handleModeChange = (newMode) => { - if (newMode === YAML_MODE && !isJsonEdited && lastYamlValue !== null) { - helpers.setValue(lastYamlValue, false); - setMode(newMode); - onModeChange(newMode); - return; - } - - try { - const newVal = - newMode === YAML_MODE - ? jsonToYaml(field.value) - : yamlToJson(field.value); - helpers.setValue(newVal, false); - setMode(newMode); - onModeChange(newMode); - } catch (err) { - helpers.setError(err.message); - } - }; - - const handleChange = (newVal) => { - helpers.setValue(newVal); - if (mode === JSON_MODE) { - setIsJsonEdited(true); - } else { - setLastYamlValue(newVal); - setIsJsonEdited(false); - } - }; - - return ( -
- setIsExpanded(true)} - mode={mode} - setMode={handleModeChange} - setShouldValidate={setShouldValidate} - handleChange={handleChange} - /> - setIsExpanded(false)} - actions={[ - , - ]} - > -
- -
-
- {meta.error ? ( -
- {meta.error} -
- ) : null} -
- ); -} -VariablesField.propTypes = { - id: string.isRequired, - name: string.isRequired, - label: string.isRequired, - readOnly: bool, - promptId: string, - initialMode: oneOf([YAML_MODE, JSON_MODE]), - onModeChange: func, -}; -VariablesField.defaultProps = { - readOnly: false, - promptId: null, - initialMode: YAML_MODE, - onModeChange: () => {}, -}; - -function VariablesFieldInternals({ - id, - name, - label, - readOnly, - promptId, - tooltip, - fullHeight, - mode, - setMode, - onExpand, - setShouldValidate, - handleChange, -}) { - const [field, meta, helpers] = useField(name); - - useEffect(() => { - if (mode === YAML_MODE) { - return; - } - try { - helpers.setValue(JSON.stringify(JSON.parse(field.value), null, 2)); - } catch (e) { - helpers.setError(e.message); - } - }, []); // eslint-disable-line react-hooks/exhaustive-deps - - return ( -
- - - - - {tooltip && } - - - - - - {promptId && ( - - )} - {onExpand && ( - - )} - - setShouldValidate(false)} - onBlur={() => setShouldValidate(true)} - hasErrors={!!meta.error} - /> -
- ); -} - -export default VariablesField; diff --git a/awx/ui/src/components/CodeEditor/VariablesField.test.js b/awx/ui/src/components/CodeEditor/VariablesField.test.js deleted file mode 100644 index 551de4fe3fed..000000000000 --- a/awx/ui/src/components/CodeEditor/VariablesField.test.js +++ /dev/null @@ -1,270 +0,0 @@ -import React from 'react'; -import { act } from 'react-dom/test-utils'; -import { Formik } from 'formik'; -import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; -import VariablesField from './VariablesField'; - -describe('VariablesField', () => { - it('should render code editor', () => { - const value = '---\n'; - const wrapper = mountWithContexts( - - {() => ( - - )} - - ); - const codeEditor = wrapper.find('CodeEditor'); - expect(codeEditor.prop('value')).toEqual(value); - }); - - it('should toggle between yaml/json', async () => { - const value = '---\nfoo: bar\nbaz: 3'; - const wrapper = mountWithContexts( - - {() => ( - - )} - - ); - const buttons = wrapper.find('Button'); - expect(buttons).toHaveLength(3); - expect(buttons.at(0).prop('variant')).toEqual('primary'); - expect(buttons.at(1).prop('variant')).toEqual('secondary'); - await act(async () => { - buttons.at(1).simulate('click'); - }); - wrapper.update(); - expect(wrapper.find('CodeEditor').prop('mode')).toEqual('javascript'); - expect(wrapper.find('CodeEditor').prop('value')).toEqual( - '{\n "foo": "bar",\n "baz": 3\n}' - ); - const buttons2 = wrapper.find('Button'); - expect(buttons2.at(0).prop('variant')).toEqual('secondary'); - expect(buttons2.at(1).prop('variant')).toEqual('primary'); - await act(async () => { - buttons2.at(0).simulate('click'); - }); - wrapper.update(); - expect(wrapper.find('CodeEditor').prop('mode')).toEqual('yaml'); - expect(wrapper.find('CodeEditor').prop('value')).toEqual( - '---\nfoo: bar\nbaz: 3' - ); - }); - - it('should retain non-expanded yaml if JSON value not edited', async () => { - const value = '---\na: &aa [a,b,c]\nb: *aa'; - const wrapper = mountWithContexts( - - {() => ( - - )} - - ); - const jsButton = wrapper.find('Button.toggle-button-javascript'); - await act(async () => { - jsButton.simulate('click'); - }); - wrapper.update(); - const yamlButton = wrapper.find('Button.toggle-button-yaml'); - await act(async () => { - yamlButton.simulate('click'); - }); - wrapper.update(); - expect(wrapper.find('CodeEditor').prop('mode')).toEqual('yaml'); - expect(wrapper.find('CodeEditor').prop('value')).toEqual(value); - }); - - it('should retain expanded yaml if JSON value is edited', async () => { - const value = '---\na: &aa [a,b,c]\nb: *aa'; - const wrapper = mountWithContexts( - - {() => ( - - )} - - ); - const jsButton = wrapper.find('Button.toggle-button-javascript'); - await act(async () => { - jsButton.simulate('click'); - }); - wrapper.update(); - wrapper.find('CodeEditor').invoke('onChange')( - '{\n "foo": "bar",\n "baz": 3\n}' - ); - const yamlButton = wrapper.find('Button.toggle-button-yaml'); - await act(async () => { - yamlButton.simulate('click'); - }); - wrapper.update(); - expect(wrapper.find('CodeEditor').prop('mode')).toEqual('yaml'); - expect(wrapper.find('CodeEditor').prop('value')).toEqual( - 'foo: bar\nbaz: 3\n' - ); - }); - - it('should retain non-expanded yaml if YAML value is edited', async () => { - const value = '---\na: &aa [a,b,c]\nb: *aa'; - const wrapper = mountWithContexts( - - {() => ( - - )} - - ); - wrapper.find('CodeEditor').invoke('onChange')( - '---\na: &aa [a,b,c]\nb: *aa\n' - ); - const buttons = wrapper.find('Button'); - await act(async () => { - buttons.at(1).simulate('click'); - }); - wrapper.update(); - const buttons2 = wrapper.find('Button'); - await act(async () => { - buttons2.at(0).simulate('click'); - }); - wrapper.update(); - expect(wrapper.find('CodeEditor').prop('mode')).toEqual('yaml'); - expect(wrapper.find('CodeEditor').prop('value')).toEqual( - '---\na: &aa [a,b,c]\nb: *aa\n' - ); - }); - - it('should set Formik error if yaml is invalid', async () => { - const value = '---\nfoo bar\n'; - const wrapper = mountWithContexts( - - {() => ( - - )} - - ); - wrapper.find('Button').at(1).simulate('click'); - wrapper.update(); - - const field = wrapper.find('CodeEditor'); - expect(field.prop('hasErrors')).toEqual(true); - expect(wrapper.find('.pf-m-error')).toHaveLength(1); - }); - - it('should render tooltip', () => { - const value = '---\n'; - const wrapper = mountWithContexts( - - {() => ( - - )} - - ); - expect(wrapper.find('Popover[data-cy="the-field-tooltip"]').length).toBe(1); - }); - - it('should submit value through Formik', async () => { - const value = '---\nfoo: bar\n'; - const handleSubmit = jest.fn(); - const wrapper = mountWithContexts( - - {(formik) => ( -
- - - - )} -
- ); - await act(async () => { - wrapper.find('CodeEditor').invoke('onChange')('---\nnewval: changed'); - wrapper.find('form').simulate('submit'); - }); - - expect(handleSubmit).toHaveBeenCalled(); - expect(handleSubmit.mock.calls[0][0]).toEqual({ - variables: '---\nnewval: changed', - }); - }); - - it('should initialize to JSON if value is JSON', async () => { - const value = '{"foo": "bar"}'; - let wrapper; - await act(async () => { - wrapper = mountWithContexts( - - {(formik) => ( -
- - - - )} -
- ); - }); - wrapper.update(); - - expect(wrapper.find('CodeEditor').prop('mode')).toEqual('javascript'); - }); - - it('should open modal when expanded', async () => { - const value = '---'; - const wrapper = mountWithContexts( - - {(formik) => ( -
- - - - )} -
- ); - expect(wrapper.find('Modal').prop('isOpen')).toEqual(false); - - wrapper.find('Button[variant="plain"]').invoke('onClick')(); - wrapper.update(); - - expect(wrapper.find('Modal').prop('isOpen')).toEqual(true); - expect(wrapper.find('Modal CodeEditor')).toHaveLength(1); - }); - - it('should format JSON for code editor', async () => { - const value = '{"foo": "bar"}'; - let wrapper; - await act(async () => { - wrapper = mountWithContexts( - - {(formik) => ( -
- - - - )} -
- ); - }); - wrapper.update(); - - expect(wrapper.find('CodeEditor').prop('value')).toEqual( - '{\n "foo": "bar"\n}' - ); - }); -}); diff --git a/awx/ui/src/components/CodeEditor/constants.js b/awx/ui/src/components/CodeEditor/constants.js deleted file mode 100644 index 79f71887e2bf..000000000000 --- a/awx/ui/src/components/CodeEditor/constants.js +++ /dev/null @@ -1,2 +0,0 @@ -export const YAML_MODE = 'yaml'; -export const JSON_MODE = 'javascript'; diff --git a/awx/ui/src/components/CodeEditor/index.js b/awx/ui/src/components/CodeEditor/index.js deleted file mode 100644 index 0339137c2921..000000000000 --- a/awx/ui/src/components/CodeEditor/index.js +++ /dev/null @@ -1,6 +0,0 @@ -import CodeEditor from './CodeEditor'; - -export default CodeEditor; -export { default as CodeEditorField } from './CodeEditorField'; -export { default as VariablesDetail } from './VariablesDetail'; -export { default as VariablesField } from './VariablesField'; diff --git a/awx/ui/src/components/ContentEmpty/ContentEmpty.js b/awx/ui/src/components/ContentEmpty/ContentEmpty.js deleted file mode 100644 index d74ee46dc610..000000000000 --- a/awx/ui/src/components/ContentEmpty/ContentEmpty.js +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react'; -import { t } from '@lingui/macro'; -import { - Title, - EmptyState, - EmptyStateIcon, - EmptyStateBody, -} from '@patternfly/react-core'; -import { CubesIcon } from '@patternfly/react-icons'; - -const ContentEmpty = ({ - title = '', - message = '', - icon = CubesIcon, - className = '', -}) => ( - - - - {title || t`No items found.`} - - {message} - -); - -export { ContentEmpty as _ContentEmpty }; -export default ContentEmpty; diff --git a/awx/ui/src/components/ContentEmpty/ContentEmpty.test.js b/awx/ui/src/components/ContentEmpty/ContentEmpty.test.js deleted file mode 100644 index 6498dc76cc78..000000000000 --- a/awx/ui/src/components/ContentEmpty/ContentEmpty.test.js +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; -import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; - -import ContentEmpty from './ContentEmpty'; - -describe('ContentEmpty', () => { - test('renders the expected content', () => { - const wrapper = mountWithContexts(); - expect(wrapper).toHaveLength(1); - }); -}); diff --git a/awx/ui/src/components/ContentEmpty/index.js b/awx/ui/src/components/ContentEmpty/index.js deleted file mode 100644 index cdf62bc88112..000000000000 --- a/awx/ui/src/components/ContentEmpty/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './ContentEmpty'; diff --git a/awx/ui/src/components/ContentError/ContentError.js b/awx/ui/src/components/ContentError/ContentError.js deleted file mode 100644 index 4be6a44042c9..000000000000 --- a/awx/ui/src/components/ContentError/ContentError.js +++ /dev/null @@ -1,61 +0,0 @@ -/* eslint-disable react/jsx-no-useless-fragment */ -import React from 'react'; -import { Link, Redirect } from 'react-router-dom'; -import { bool, instanceOf } from 'prop-types'; -import { t } from '@lingui/macro'; - -import { - Title, - EmptyState, - EmptyStateIcon, - EmptyStateBody, -} from '@patternfly/react-core'; -import { ExclamationTriangleIcon } from '@patternfly/react-icons'; -import { useSession } from 'contexts/Session'; -import ErrorDetail from '../ErrorDetail'; - -function ContentError({ error, children, isNotFound }) { - const { logout } = useSession(); - - if (error && error.response && error.response.status === 401) { - if (!error.response.headers['session-timeout']) { - logout(); - return null; - } - } - const is404 = - isNotFound || (error && error.response && error.response.status === 404); - const is401 = error && error.response && error.response.status === 401; - return ( - <> - {is401 ? ( - - ) : ( - - - - {is404 ? t`Not Found` : t`Something went wrong...`} - - - {is404 - ? t`The page you requested could not be found.` - : t`There was an error loading this content. Please reload the page.`}{' '} - {children || {t`Back to Dashboard.`}} - - {error && } - - )} - - ); -} -ContentError.propTypes = { - error: instanceOf(Error), - isNotFound: bool, -}; -ContentError.defaultProps = { - error: null, - isNotFound: false, -}; - -export { ContentError as _ContentError }; -export default ContentError; diff --git a/awx/ui/src/components/ContentError/ContentError.test.js b/awx/ui/src/components/ContentError/ContentError.test.js deleted file mode 100644 index 518f0ae8c65d..000000000000 --- a/awx/ui/src/components/ContentError/ContentError.test.js +++ /dev/null @@ -1,24 +0,0 @@ -import React from 'react'; -import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; - -import ContentError from './ContentError'; - -describe('ContentError', () => { - test('renders the expected content', () => { - const wrapper = mountWithContexts( - - ); - expect(wrapper).toHaveLength(1); - }); -}); diff --git a/awx/ui/src/components/ContentError/index.js b/awx/ui/src/components/ContentError/index.js deleted file mode 100644 index 14587f410d50..000000000000 --- a/awx/ui/src/components/ContentError/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './ContentError'; diff --git a/awx/ui/src/components/ContentLoading/ContentLoading.js b/awx/ui/src/components/ContentLoading/ContentLoading.js deleted file mode 100644 index 451ce2ba4bc2..000000000000 --- a/awx/ui/src/components/ContentLoading/ContentLoading.js +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react'; - -import styled from 'styled-components'; -import { - EmptyState as PFEmptyState, - EmptyStateIcon, - Spinner, -} from '@patternfly/react-core'; - -const EmptyState = styled(PFEmptyState)` - --pf-c-empty-state--m-lg--MaxWidth: none; - min-height: 250px; -`; - -// TODO: Better loading state - skeleton lines / spinner, etc. -const ContentLoading = ({ className }) => ( - - - -); - -export { ContentLoading as _ContentLoading }; -export default ContentLoading; diff --git a/awx/ui/src/components/ContentLoading/ContentLoading.test.js b/awx/ui/src/components/ContentLoading/ContentLoading.test.js deleted file mode 100644 index c2816e258272..000000000000 --- a/awx/ui/src/components/ContentLoading/ContentLoading.test.js +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; -import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; - -import ContentLoading from './ContentLoading'; - -describe('ContentLoading', () => { - test('renders the expected content', () => { - const wrapper = mountWithContexts(); - expect(wrapper).toHaveLength(1); - }); -}); diff --git a/awx/ui/src/components/ContentLoading/index.js b/awx/ui/src/components/ContentLoading/index.js deleted file mode 100644 index 0e87a3fb97db..000000000000 --- a/awx/ui/src/components/ContentLoading/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './ContentLoading'; diff --git a/awx/ui/src/components/CopyButton/CopyButton.js b/awx/ui/src/components/CopyButton/CopyButton.js deleted file mode 100644 index 9ea5216f51ab..000000000000 --- a/awx/ui/src/components/CopyButton/CopyButton.js +++ /dev/null @@ -1,76 +0,0 @@ -import React, { useEffect } from 'react'; -import { t } from '@lingui/macro'; -import PropTypes from 'prop-types'; -import { Button } from '@patternfly/react-core'; -import { CopyIcon } from '@patternfly/react-icons'; -import useRequest, { useDismissableError } from 'hooks/useRequest'; -import AlertModal from '../AlertModal'; -import ErrorDetail from '../ErrorDetail'; - -function CopyButton({ - id, - copyItem, - isDisabled, - onCopyStart, - onCopyFinish, - errorMessage, - ouiaId, -}) { - const { - isLoading, - error: copyError, - request: copyItemToAPI, - } = useRequest(copyItem); - - useEffect(() => { - if (isLoading) { - return onCopyStart(); - } - return onCopyFinish(); - }, [isLoading, onCopyStart, onCopyFinish]); - - const { error, dismissError } = useDismissableError(copyError); - - return ( - <> - - {error && ( - - {errorMessage} - - - )} - - ); -} - -CopyButton.propTypes = { - copyItem: PropTypes.func.isRequired, - onCopyStart: PropTypes.func.isRequired, - onCopyFinish: PropTypes.func.isRequired, - errorMessage: PropTypes.string.isRequired, - isDisabled: PropTypes.bool, - ouiaId: PropTypes.string, -}; - -CopyButton.defaultProps = { - isDisabled: false, - ouiaId: null, -}; - -export default CopyButton; diff --git a/awx/ui/src/components/CopyButton/CopyButton.test.js b/awx/ui/src/components/CopyButton/CopyButton.test.js deleted file mode 100644 index d1926945c4cf..000000000000 --- a/awx/ui/src/components/CopyButton/CopyButton.test.js +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react'; -import { act } from 'react-dom/test-utils'; -import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; -import CopyButton from './CopyButton'; - -jest.mock('../../api'); - -let wrapper; - -describe('', () => { - test('should mount properly', async () => { - await act(async () => { - wrapper = mountWithContexts( - {}} - onCopyFinish={() => {}} - copyItem={() => {}} - errorMessage="Failed to copy template." - /> - ); - }); - expect(wrapper.find('CopyButton').length).toBe(1); - }); - - test('should call the correct function on button click', async () => { - const copyItem = jest.fn(); - await act(async () => { - wrapper = mountWithContexts( - {}} - onCopyFinish={() => {}} - copyItem={copyItem} - errorMessage="Failed to copy template." - /> - ); - }); - await act(async () => { - wrapper.find('button').simulate('click'); - }); - expect(copyItem).toHaveBeenCalledTimes(1); - }); -}); diff --git a/awx/ui/src/components/CopyButton/index.js b/awx/ui/src/components/CopyButton/index.js deleted file mode 100644 index 90e9e6d2043d..000000000000 --- a/awx/ui/src/components/CopyButton/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './CopyButton'; diff --git a/awx/ui/src/components/CredentialChip/CredentialChip.js b/awx/ui/src/components/CredentialChip/CredentialChip.js deleted file mode 100644 index 43acf57fd048..000000000000 --- a/awx/ui/src/components/CredentialChip/CredentialChip.js +++ /dev/null @@ -1,39 +0,0 @@ -import React from 'react'; - -import { t } from '@lingui/macro'; -import { Chip } from '@patternfly/react-core'; -import { Credential } from 'types'; -import { toTitleCase } from 'util/strings'; - -function CredentialChip({ credential, ...props }) { - let type; - if (credential.cloud) { - type = t`Cloud`; - } else if (credential.kind === 'gpg_public_key') { - type = t`GPG Public Key`; - } else if (credential.kind === 'aws' || credential.kind === 'ssh') { - type = credential.kind.toUpperCase(); - } else { - type = toTitleCase(credential.kind); - } - - const buildCredentialName = () => { - if (credential.kind === 'vault' && credential.inputs?.vault_id) { - return `${credential.name} | ${credential.inputs.vault_id}`; - } - return `${credential.name}`; - }; - - return ( - - {type}: - {buildCredentialName()} - - ); -} -CredentialChip.propTypes = { - credential: Credential.isRequired, -}; - -export { CredentialChip as _CredentialChip }; -export default CredentialChip; diff --git a/awx/ui/src/components/CredentialChip/CredentialChip.test.js b/awx/ui/src/components/CredentialChip/CredentialChip.test.js deleted file mode 100644 index df678d5d23ce..000000000000 --- a/awx/ui/src/components/CredentialChip/CredentialChip.test.js +++ /dev/null @@ -1,58 +0,0 @@ -import React from 'react'; -import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; -import CredentialChip from './CredentialChip'; - -describe('CredentialChip', () => { - test('should render SSH kind', () => { - const credential = { - id: 1, - kind: 'ssh', - name: 'foo', - }; - - const wrapper = mountWithContexts( - - ); - expect(wrapper.find('CredentialChip').text()).toEqual('SSH: foo'); - }); - - test('should render AWS kind', () => { - const credential = { - id: 1, - kind: 'aws', - name: 'foo', - }; - - const wrapper = mountWithContexts( - - ); - expect(wrapper.find('CredentialChip').text()).toEqual('AWS: foo'); - }); - - test('should render with "Cloud"', () => { - const credential = { - id: 1, - cloud: true, - kind: 'other', - name: 'foo', - }; - - const wrapper = mountWithContexts( - - ); - expect(wrapper.find('CredentialChip').text()).toEqual('Cloud: foo'); - }); - - test('should render with other kind', () => { - const credential = { - id: 1, - kind: 'other', - name: 'foo', - }; - - const wrapper = mountWithContexts( - - ); - expect(wrapper.find('CredentialChip').text()).toEqual('Other: foo'); - }); -}); diff --git a/awx/ui/src/components/CredentialChip/index.js b/awx/ui/src/components/CredentialChip/index.js deleted file mode 100644 index c4cb5cc38a55..000000000000 --- a/awx/ui/src/components/CredentialChip/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './CredentialChip'; diff --git a/awx/ui/src/components/DataListToolbar/DataListToolbar.js b/awx/ui/src/components/DataListToolbar/DataListToolbar.js deleted file mode 100644 index 40deda10a151..000000000000 --- a/awx/ui/src/components/DataListToolbar/DataListToolbar.js +++ /dev/null @@ -1,248 +0,0 @@ -import React, { useEffect, useMemo, useState } from 'react'; -import PropTypes from 'prop-types'; -import styled from 'styled-components'; -import { t } from '@lingui/macro'; -import { - Button, - Checkbox, - Toolbar, - ToolbarContent as PFToolbarContent, - ToolbarGroup, - ToolbarItem, - ToolbarToggleGroup, - Tooltip, - Dropdown, - DropdownPosition, - KebabToggle, -} from '@patternfly/react-core'; -import { - AngleDownIcon, - AngleRightIcon, - SearchIcon, -} from '@patternfly/react-icons'; -import { SearchColumns, SortColumns, QSConfig, SearchableKeys } from 'types'; -import { KebabifiedProvider } from 'contexts/Kebabified'; -import ExpandCollapse from '../ExpandCollapse'; -import Search from '../Search'; -import Sort from '../Sort'; - -const ToolbarContent = styled(PFToolbarContent)` - & > .pf-c-toolbar__content-section { - flex-wrap: nowrap; - } -`; - -function DataListToolbar({ - isAllExpanded, - onExpandAll, - itemCount, - clearAllFilters, - searchColumns, - searchableKeys, - relatedSearchableKeys, - sortColumns, - isAllSelected, - onSelectAll, - isCompact, - onSort, - onSearch, - onReplaceSearch, - onRemove, - onCompact, - onExpand, - additionalControls, - qsConfig, - pagination, - enableNegativeFiltering, - enableRelatedFuzzyFiltering, - handleIsAnsibleFactsSelected, - isFilterCleared, -}) { - const showExpandCollapse = onCompact && onExpand; - const [isKebabOpen, setIsKebabOpen] = useState(false); - const [isKebabModalOpen, setIsKebabModalOpen] = useState(false); - const [isAdvancedSearchShown, setIsAdvancedSearchShown] = useState(false); - - const viewportWidth = - window.innerWidth || document.documentElement.clientWidth; - const dropdownPosition = - viewportWidth >= 992 ? DropdownPosition.right : DropdownPosition.left; - - const onShowAdvancedSearch = (shown) => { - setIsAdvancedSearchShown(shown); - setIsKebabOpen(false); - }; - - useEffect(() => { - if (!isKebabModalOpen) { - setIsKebabOpen(false); - } - }, [isKebabModalOpen]); - - const kebabProviderValue = useMemo( - () => ({ - isKebabified: true, - onKebabModalChange: setIsKebabModalOpen, - }), - [setIsKebabModalOpen] - ); - return ( - - - {onExpandAll && ( - - - - - - )} - {onSelectAll && ( - - - - - - - - )} - } breakpoint="lg"> - - - - {sortColumns && ( - - - - )} - - {showExpandCollapse && ( - - - - - - )} - {isAdvancedSearchShown && additionalControls.length > 0 && ( - - - { - if (!isKebabModalOpen) { - setIsKebabOpen(isOpen); - } - }} - /> - } - isOpen={isKebabOpen} - position={dropdownPosition} - isPlain - dropdownItems={additionalControls} - ouiaId="actions-dropdown" - /> - - - )} - {!isAdvancedSearchShown && ( - - {additionalControls.map((control) => ( - {control} - ))} - - )} - {!isAdvancedSearchShown && pagination && itemCount > 0 && ( - {pagination} - )} - - - ); -} - -DataListToolbar.propTypes = { - itemCount: PropTypes.number, - clearAllFilters: PropTypes.func, - qsConfig: QSConfig.isRequired, - searchColumns: SearchColumns.isRequired, - searchableKeys: SearchableKeys, - relatedSearchableKeys: PropTypes.arrayOf(PropTypes.string), - sortColumns: SortColumns, - isAllSelected: PropTypes.bool, - isCompact: PropTypes.bool, - onCompact: PropTypes.func, - onExpand: PropTypes.func, - onSearch: PropTypes.func, - onReplaceSearch: PropTypes.func, - onSelectAll: PropTypes.func, - onSort: PropTypes.func, - additionalControls: PropTypes.arrayOf(PropTypes.node), - enableNegativeFiltering: PropTypes.bool, - enableRelatedFuzzyFiltering: PropTypes.bool, -}; - -DataListToolbar.defaultProps = { - itemCount: 0, - searchableKeys: [], - relatedSearchableKeys: [], - sortColumns: null, - clearAllFilters: null, - isAllSelected: false, - isCompact: false, - onCompact: null, - onExpand: null, - onSearch: null, - onReplaceSearch: null, - onSelectAll: null, - onSort: null, - additionalControls: [], - enableNegativeFiltering: true, - enableRelatedFuzzyFiltering: true, -}; - -export default DataListToolbar; diff --git a/awx/ui/src/components/DataListToolbar/DataListToolbar.test.js b/awx/ui/src/components/DataListToolbar/DataListToolbar.test.js deleted file mode 100644 index 6ff3001740ca..000000000000 --- a/awx/ui/src/components/DataListToolbar/DataListToolbar.test.js +++ /dev/null @@ -1,346 +0,0 @@ -import React from 'react'; -import { act } from 'react-dom/test-utils'; -import { shallow } from 'enzyme'; -import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; -import DataListToolbar from './DataListToolbar'; -import AddDropDownButton from '../AddDropDownButton/AddDropDownButton'; - -describe('', () => { - let toolbar; - - const QS_CONFIG = { - namespace: 'organization', - dateFields: ['modified', 'created'], - defaultParams: { page: 1, page_size: 5, order_by: 'name' }, - integerFields: ['page', 'page_size'], - }; - - const onSearch = jest.fn(); - const onReplaceSearch = jest.fn(); - const onSort = jest.fn(); - const onSelectAll = jest.fn(); - const onExpandAll = jest.fn(); - - test('it triggers the expected callbacks', () => { - const searchColumns = [ - { name: 'Name', key: 'name__icontains', isDefault: true }, - ]; - const sortColumns = [{ name: 'Name', key: 'name' }]; - const search = 'button[aria-label="Search submit button"]'; - const searchTextInput = 'input[aria-label="Search text input"]'; - const selectAll = 'input[aria-label="Select all"]'; - const sort = 'button[aria-label="Sort"]'; - - toolbar = mountWithContexts( - - ); - - toolbar.find(sort).simulate('click'); - toolbar.find(selectAll).simulate('change', { target: { checked: false } }); - - expect(onSelectAll).toHaveBeenCalledTimes(1); - expect(onSort).toHaveBeenCalledTimes(1); - expect(onSort).toBeCalledWith('name', 'descending'); - - expect(onSelectAll).toHaveBeenCalledTimes(1); - expect(onSelectAll.mock.calls[0][0]).toBe(false); - - toolbar.find(searchTextInput).instance().value = 'test-321'; - toolbar.find(searchTextInput).simulate('change'); - toolbar.find(search).simulate('click'); - - expect(onSearch).toHaveBeenCalledTimes(1); - expect(onSearch).toBeCalledWith('name__icontains', 'test-321'); - }); - - test('dropdown items sortable/searchable columns work', () => { - const sortDropdownToggleSelector = 'button[id="awx-sort"]'; - const searchDropdownToggleSelector = - 'Select[aria-label="Simple key select"] SelectToggle'; - const sortDropdownMenuItems = - 'DropdownMenu > ul[aria-labelledby="awx-sort"]'; - const searchDropdownMenuItems = - 'Select[aria-label="Simple key select"] SelectOption'; - - const NEW_QS_CONFIG = { - namespace: 'organization', - dateFields: ['modified', 'created'], - defaultParams: { page: 1, page_size: 5, order_by: 'foo' }, - integerFields: ['page', 'page_size'], - }; - - const searchColumns = [ - { name: 'Foo', key: 'foo', isDefault: true }, - { name: 'Bar', key: 'bar' }, - ]; - const sortColumns = [ - { name: 'Foo', key: 'foo' }, - { name: 'Bar', key: 'bar' }, - { name: 'Bakery', key: 'Bakery' }, - ]; - - toolbar = mountWithContexts( - {}} - /> - ); - const sortDropdownToggle = toolbar.find(sortDropdownToggleSelector); - expect(sortDropdownToggle.length).toBe(1); - sortDropdownToggle.simulate('click'); - toolbar.update(); - const sortDropdownItems = toolbar.find(sortDropdownMenuItems).children(); - expect(sortDropdownItems.length).toBe(2); - let searchDropdownToggle = toolbar.find(searchDropdownToggleSelector); - expect(searchDropdownToggle.length).toBe(1); - searchDropdownToggle.simulate('click'); - toolbar.update(); - let searchDropdownItems = toolbar.find(searchDropdownMenuItems).children(); - expect(searchDropdownItems.length).toBe(2); - const mockedSortEvent = { target: { innerText: 'Bar' } }; - searchDropdownItems.at(0).simulate('click', mockedSortEvent); - toolbar = mountWithContexts( - {}} - /> - ); - toolbar.update(); - - const sortDropdownToggleDescending = toolbar.find( - sortDropdownToggleSelector - ); - expect(sortDropdownToggleDescending.length).toBe(1); - sortDropdownToggleDescending.simulate('click'); - toolbar.update(); - - const sortDropdownItemsDescending = toolbar - .find(sortDropdownMenuItems) - .children(); - expect(sortDropdownItemsDescending.length).toBe(2); - sortDropdownToggleDescending.simulate('click'); // toggle close the sort dropdown - - const mockedSortEventDescending = { target: { innerText: 'Bar' } }; - sortDropdownItems.at(0).simulate('click', mockedSortEventDescending); - toolbar.update(); - - searchDropdownToggle = toolbar.find(searchDropdownToggleSelector); - expect(searchDropdownToggle.length).toBe(1); - searchDropdownToggle.simulate('click'); - toolbar.update(); - - searchDropdownItems = toolbar.find(searchDropdownMenuItems).children(); - expect(searchDropdownItems.length).toBe(2); - - const mockedSearchEvent = { target: { innerText: 'Bar' } }; - searchDropdownItems.at(0).simulate('click', mockedSearchEvent); - }); - - test('should render sort icon', () => { - const qsConfig = { - namespace: 'organization', - dateFields: ['modified', 'created'], - defaultParams: { page: 1, page_size: 5, order_by: 'id' }, - integerFields: ['page', 'page_size', 'id'], - }; - const sortColumns = [{ name: 'Name', key: 'name' }]; - - const wrapper = shallow( - - ); - - const sort = wrapper.find('Sort'); - expect(sort.prop('qsConfig')).toEqual(qsConfig); - expect(sort.prop('columns')).toEqual(sortColumns); - expect(sort.prop('onSort')).toEqual(onSort); - }); - - test('should render additionalControls', () => { - const searchColumns = [{ name: 'Name', key: 'name', isDefault: true }]; - const sortColumns = [{ name: 'Name', key: 'name' }]; - - toolbar = mountWithContexts( - - click - , - ]} - /> - ); - - const button = toolbar.find('#test'); - expect(button).toHaveLength(1); - expect(button.text()).toEqual('click'); - }); - - test('it triggers the expected callbacks', () => { - const searchColumns = [{ name: 'Name', key: 'name', isDefault: true }]; - const sortColumns = [{ name: 'Name', key: 'name' }]; - toolbar = mountWithContexts( - - ); - const checkbox = toolbar.find('Checkbox'); - expect(checkbox.prop('isChecked')).toBe(true); - }); - - test('always adds advanced item to search column array', () => { - const searchColumns = [{ name: 'Name', key: 'name', isDefault: true }]; - const sortColumns = [{ name: 'Name', key: 'name' }]; - - toolbar = mountWithContexts( - - click - , - ]} - /> - ); - - const search = toolbar.find('Search'); - expect( - search.prop('columns').filter((col) => col.key === 'advanced').length - ).toBe(1); - }); - - test('should properly render toolbar buttons when in advanced search mode', async () => { - const searchColumns = [{ name: 'Name', key: 'name', isDefault: true }]; - const sortColumns = [{ name: 'Name', key: 'name' }]; - - const newToolbar = mountWithContexts( - - Add Contaner -
, -
- Add Instance Group -
, - ]} - />, - ]} - /> - ); - act(() => newToolbar.find('Search').prop('onShowAdvancedSearch')(true)); - newToolbar.update(); - expect(newToolbar.find('KebabToggle').length).toBe(1); - act(() => newToolbar.find('KebabToggle').prop('onToggle')(true)); - newToolbar.update(); - expect(newToolbar.find('div[aria-label="add container"]').length).toBe(1); - expect(newToolbar.find('div[aria-label="add instance group"]').length).toBe( - 1 - ); - }); - - test('should handle expanded rows', async () => { - const searchColumns = [ - { name: 'Name', key: 'name__icontains', isDefault: true }, - ]; - const sortColumns = [{ name: 'Name', key: 'name' }]; - - const newtoolbar = mountWithContexts( - - ); - await act(async () => - newtoolbar.find('Button[aria-label="Expand all rows"]').prop('onClick')() - ); - expect(newtoolbar.find('AngleRightIcon')).toHaveLength(1); - expect(newtoolbar.find('AngleDownIcon')).toHaveLength(0); - expect(onExpandAll).toBeCalledWith(true); - }); - - test('should render angle down icon', async () => { - const searchColumns = [ - { name: 'Name', key: 'name__icontains', isDefault: true }, - ]; - const sortColumns = [{ name: 'Name', key: 'name' }]; - - const newtoolbar = mountWithContexts( - - ); - - expect(newtoolbar.find('AngleDownIcon')).toHaveLength(1); - expect(newtoolbar.find('AngleRightIcon')).toHaveLength(0); - }); -}); diff --git a/awx/ui/src/components/DataListToolbar/index.js b/awx/ui/src/components/DataListToolbar/index.js deleted file mode 100644 index 038f0690174c..000000000000 --- a/awx/ui/src/components/DataListToolbar/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './DataListToolbar'; diff --git a/awx/ui/src/components/DeleteButton/DeleteButton.js b/awx/ui/src/components/DeleteButton/DeleteButton.js deleted file mode 100644 index a3e4b0ad9455..000000000000 --- a/awx/ui/src/components/DeleteButton/DeleteButton.js +++ /dev/null @@ -1,160 +0,0 @@ -import React, { useState } from 'react'; -import PropTypes from 'prop-types'; - -import { t } from '@lingui/macro'; -import styled from 'styled-components'; -import { Button, Badge, Alert, Tooltip } from '@patternfly/react-core'; -import { getRelatedResourceDeleteCounts } from 'util/getRelatedResourceDeleteDetails'; -import AlertModal from '../AlertModal'; -import ErrorDetail from '../ErrorDetail'; - -const WarningMessage = styled(Alert)` - margin-top: 10px; -`; -const Label = styled.span` - && { - margin-right: 10px; - } -`; -function DeleteButton({ - onConfirm, - modalTitle, - name, - variant, - children, - isDisabled, - ouiaId, - deleteMessage, - deleteDetailsRequests, - disabledTooltip, -}) { - const [isOpen, setIsOpen] = useState(false); - const [deleteMessageError, setDeleteMessageError] = useState(); - const [deleteDetails, setDeleteDetails] = useState({}); - const [isLoading, setIsLoading] = useState(false); - - const toggleModal = async (isModalOpen) => { - setIsLoading(true); - if (deleteDetailsRequests?.length && isModalOpen) { - const { results, error } = await getRelatedResourceDeleteCounts( - deleteDetailsRequests - ); - if (error) { - setDeleteMessageError(error); - } else { - setDeleteDetails(results); - } - } - setIsLoading(false); - setIsOpen(isModalOpen); - }; - - if (deleteMessageError) { - return ( - { - toggleModal(false); - setDeleteMessageError(); - }} - > - - - ); - } - return ( - <> - {disabledTooltip ? ( - -
- -
-
- ) : ( - - )} - toggleModal(false)} - actions={[ - , - , - ]} - > - {t`Are you sure you want to delete:`} -
- {name} - {Object.values(deleteDetails).length > 0 && ( - -
{deleteMessage}
-
- {Object.entries(deleteDetails).map(([key, value]) => ( -
- {value} -
- ))} -
- } - /> - )} - - - ); -} - -DeleteButton.propTypes = { - ouiaId: PropTypes.string, -}; - -DeleteButton.defaultProps = { - ouiaId: null, -}; - -export default DeleteButton; diff --git a/awx/ui/src/components/DeleteButton/DeleteButton.test.js b/awx/ui/src/components/DeleteButton/DeleteButton.test.js deleted file mode 100644 index 12744cfe5bea..000000000000 --- a/awx/ui/src/components/DeleteButton/DeleteButton.test.js +++ /dev/null @@ -1,112 +0,0 @@ -import React from 'react'; -import { act } from 'react-dom/test-utils'; -import { CredentialsAPI } from 'api'; -import { - mountWithContexts, - waitForElement, -} from '../../../testUtils/enzymeHelpers'; -import DeleteButton from './DeleteButton'; - -jest.mock('../../api'); - -describe('', () => { - test('should render button', () => { - const wrapper = mountWithContexts( - {}} name="Foo" /> - ); - expect(wrapper.find('button')).toHaveLength(1); - }); - - test('should open confirmation modal', async () => { - let wrapper; - await act(async () => { - wrapper = mountWithContexts( - {}} - name="Foo" - deleteDetailsRequests={[ - { - label: 'job', - request: CredentialsAPI.read.mockResolvedValue({ - data: { count: 1 }, - }), - }, - ]} - deleteMessage="Delete this?" - warningMessage="Are you sure to want to delete this" - /> - ); - }); - - await act(async () => { - wrapper.find('button').prop('onClick')(); - }); - - await waitForElement(wrapper, 'Modal', (el) => el.length > 0); - expect(wrapper.find('Modal')).toHaveLength(1); - - expect(wrapper.find('div[aria-label="Delete this?"]')).toHaveLength(1); - }); - - test('should invoke onConfirm prop', async () => { - const onConfirm = jest.fn(); - const wrapper = mountWithContexts( - - ); - await act(async () => wrapper.find('button').simulate('click')); - wrapper.update(); - await act(async () => - wrapper - .find('ModalBoxFooter button[aria-label="Confirm Delete"]') - .simulate('click') - ); - wrapper.update(); - expect(onConfirm).toHaveBeenCalled(); - }); - - test('should show delete details error', async () => { - const onConfirm = jest.fn(); - let wrapper; - await act(async () => { - wrapper = mountWithContexts( - - ); - }); - await act(async () => wrapper.find('button').simulate('click')); - wrapper.update(); - - expect(wrapper.find('AlertModal[title="Error!"]')).toHaveLength(1); - }); -}); diff --git a/awx/ui/src/components/DeleteButton/index.js b/awx/ui/src/components/DeleteButton/index.js deleted file mode 100644 index 991ad79b298d..000000000000 --- a/awx/ui/src/components/DeleteButton/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './DeleteButton'; diff --git a/awx/ui/src/components/DetailList/ArrayDetail.js b/awx/ui/src/components/DetailList/ArrayDetail.js deleted file mode 100644 index 619217b50b0a..000000000000 --- a/awx/ui/src/components/DetailList/ArrayDetail.js +++ /dev/null @@ -1,37 +0,0 @@ -import 'styled-components/macro'; -import React from 'react'; -import styled from 'styled-components'; -import { TextListItemVariants } from '@patternfly/react-core'; -import { DetailName, DetailValue } from './Detail'; -import Popover from '../Popover'; - -const Value = styled(DetailValue)` - margin-top: var(--pf-global--spacer--xs); - padding: var(--pf-global--spacer--xs); - border: 1px solid var(--pf-global--BorderColor--100); - max-height: 5.5em; - overflow: auto; -`; - -function ArrayDetail({ label, helpText, value, dataCy }) { - const labelCy = dataCy ? `${dataCy}-label` : null; - const valueCy = dataCy ? `${dataCy}-value` : null; - - const vals = Array.isArray(value) ? value : [value]; - - return ( -
- - {label} - {helpText && } - - - {vals.map((v) => ( -
{v}
- ))} -
-
- ); -} - -export default ArrayDetail; diff --git a/awx/ui/src/components/DetailList/CodeDetail.js b/awx/ui/src/components/DetailList/CodeDetail.js deleted file mode 100644 index 5e926c6f6481..000000000000 --- a/awx/ui/src/components/DetailList/CodeDetail.js +++ /dev/null @@ -1,75 +0,0 @@ -import 'styled-components/macro'; -import React from 'react'; -import { - arrayOf, - oneOf, - oneOfType, - node, - number, - shape, - string, -} from 'prop-types'; -import { TextListItemVariants } from '@patternfly/react-core'; -import { DetailName, DetailValue } from './Detail'; -import CodeEditor from '../CodeEditor'; -import Popover from '../Popover'; - -function CodeDetail({ value, label, mode, rows, helpText, dataCy }) { - const labelCy = dataCy ? `${dataCy}-label` : null; - const valueCy = dataCy ? `${dataCy}-value` : null; - const editorId = dataCy ? `${dataCy}-editor` : 'code-editor'; - - return ( - <> - -
- - {helpText && ( - - )} -
-
- - - - - ); -} -CodeDetail.propTypes = { - value: oneOfType([shape({}), arrayOf(string), string]).isRequired, - label: node.isRequired, - dataCy: string, - helpText: string, - rows: oneOfType([number, string]), - mode: oneOf(['javascript', 'yaml', 'jinja2']).isRequired, -}; -CodeDetail.defaultProps = { - rows: null, - helpText: '', - dataCy: '', -}; - -export default CodeDetail; diff --git a/awx/ui/src/components/DetailList/DeletedDetail.js b/awx/ui/src/components/DetailList/DeletedDetail.js deleted file mode 100644 index ec0961d3948f..000000000000 --- a/awx/ui/src/components/DetailList/DeletedDetail.js +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react'; - -import { t } from '@lingui/macro'; -import { node } from 'prop-types'; -import styled from 'styled-components'; -import _Detail from './Detail'; - -const Detail = styled(_Detail)` - dd& { - color: red; - } -`; - -function DeletedDetail({ label, dataCy, helpText }) { - return ( - - ); -} - -DeletedDetail.propTypes = { - label: node.isRequired, -}; - -export default DeletedDetail; diff --git a/awx/ui/src/components/DetailList/Detail.js b/awx/ui/src/components/DetailList/Detail.js deleted file mode 100644 index 8f56f4ad40ae..000000000000 --- a/awx/ui/src/components/DetailList/Detail.js +++ /dev/null @@ -1,101 +0,0 @@ -import React from 'react'; - -import { oneOfType, node, bool, string } from 'prop-types'; -import { TextListItem, TextListItemVariants } from '@patternfly/react-core'; -import styled from 'styled-components'; -import Popover from '../Popover'; - -const DetailName = styled(({ fullWidth, ...props }) => ( - -))` - font-weight: var(--pf-global--FontWeight--bold); - ${(props) => - props.fullWidth && - ` - grid-column: 1; - `} -`; - -const DetailValue = styled( - ({ fullWidth, isEncrypted, isNotConfigured, ...props }) => ( - - ) -)` - overflow-wrap: break-word; - ${(props) => - props.fullWidth && - ` - grid-column: 2 / -1; - `} - ${(props) => - (props.isEncrypted || props.isNotConfigured) && - ` - color: var(--pf-global--disabled-color--100); - `} -`; - -const Detail = ({ - label, - value, - fullWidth, - className, - dataCy, - alwaysVisible, - isEmpty, - helpText, - isEncrypted, - isNotConfigured, -}) => { - if (!value && typeof value !== 'number' && !alwaysVisible) { - return null; - } - - if (isEmpty && !alwaysVisible) { - return null; - } - - const labelCy = dataCy ? `${dataCy}-label` : null; - const valueCy = dataCy ? `${dataCy}-value` : null; - - return ( - <> - - {label} - {helpText && } - - - {value} - - - ); -}; -Detail.propTypes = { - label: node.isRequired, - value: node, - fullWidth: bool, - alwaysVisible: bool, - helpText: oneOfType([string, node]), -}; -Detail.defaultProps = { - value: null, - fullWidth: false, - alwaysVisible: false, - helpText: null, -}; - -export default Detail; -export { DetailName }; -export { DetailValue }; diff --git a/awx/ui/src/components/DetailList/Detail.test.js b/awx/ui/src/components/DetailList/Detail.test.js deleted file mode 100644 index d78cf285668e..000000000000 --- a/awx/ui/src/components/DetailList/Detail.test.js +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; -import { mount } from 'enzyme'; - -import Detail from './Detail'; - -describe('Detail', () => { - test('renders the expected content', () => { - const wrapper = mount(); - expect(wrapper).toHaveLength(1); - }); -}); diff --git a/awx/ui/src/components/DetailList/DetailBadge.js b/awx/ui/src/components/DetailList/DetailBadge.js deleted file mode 100644 index 1482ae4adc07..000000000000 --- a/awx/ui/src/components/DetailList/DetailBadge.js +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react'; -import { node } from 'prop-types'; -import styled from 'styled-components'; -import { Badge } from '@patternfly/react-core'; - -import _Detail from './Detail'; - -const Detail = styled(_Detail)` - word-break: break-word; -`; - -function DetailBadge({ label, helpText, content, dataCy = null }) { - return ( - {content}} - /> - ); -} -DetailBadge.propTypes = { - label: node.isRequired, - content: node.isRequired, -}; - -export default DetailBadge; diff --git a/awx/ui/src/components/DetailList/DetailList.js b/awx/ui/src/components/DetailList/DetailList.js deleted file mode 100644 index dceaa1cba947..000000000000 --- a/awx/ui/src/components/DetailList/DetailList.js +++ /dev/null @@ -1,36 +0,0 @@ -import React from 'react'; -import { TextList, TextListVariants } from '@patternfly/react-core'; -import styled from 'styled-components'; - -const DetailList = ({ children, stacked, ...props }) => ( - - {children} - -); - -export default styled(DetailList)` - display: grid; - align-items: start; - ${(props) => (props.compact ? `column-gap: 20px;` : `grid-gap: 20px;`)} - ${(props) => - props.stacked - ? ` - grid-template-columns: auto 1fr; - ` - : ` - --column-count: 1; - grid-template-columns: repeat(var(--column-count), auto minmax(10em, 1fr)); - - @media (min-width: 920px) { - --column-count: 2; - } - - @media (min-width: 1210px) { - --column-count: 3; - } - `} - - & + & { - margin-top: 20px; - } -`; diff --git a/awx/ui/src/components/DetailList/DetailList.test.js b/awx/ui/src/components/DetailList/DetailList.test.js deleted file mode 100644 index 5e41f75de6ec..000000000000 --- a/awx/ui/src/components/DetailList/DetailList.test.js +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; -import { mount } from 'enzyme'; - -import DetailList from './DetailList'; - -describe('DetailList', () => { - test('renders the expected content', () => { - const wrapper = mount(); - expect(wrapper).toHaveLength(1); - }); -}); diff --git a/awx/ui/src/components/DetailList/LaunchedByDetail.js b/awx/ui/src/components/DetailList/LaunchedByDetail.js deleted file mode 100644 index 6f542231c527..000000000000 --- a/awx/ui/src/components/DetailList/LaunchedByDetail.js +++ /dev/null @@ -1,64 +0,0 @@ -import React from 'react'; -import { Link } from 'react-router-dom'; -import { t } from '@lingui/macro'; -import getScheduleUrl from 'util/getScheduleUrl'; -import Detail from './Detail'; - -const getLaunchedByDetails = (job) => { - const { - created_by: createdBy, - job_template: jobTemplate, - workflow_job_template: workflowJT, - schedule, - } = job.summary_fields; - - if (!createdBy && !schedule) { - return {}; - } - - let link; - let value; - - switch (job.launch_type) { - case 'webhook': - value = t`Webhook`; - link = - (jobTemplate && `/templates/job_template/${jobTemplate.id}/details`) || - (workflowJT && - `/templates/workflow_job_template/${workflowJT.id}/details`); - break; - case 'scheduled': - value = schedule.name; - link = getScheduleUrl(job); - break; - case 'manual': - link = `/users/${createdBy.id}/details`; - value = createdBy.username; - break; - default: - link = createdBy && `/users/${createdBy.id}/details`; - value = createdBy && createdBy.username; - break; - } - - return { link, value }; -}; - -export default function LaunchedByDetail({ job, dataCy = null }) { - const { value: launchedByValue, link: launchedByLink } = - getLaunchedByDetails(job) || {}; - - return ( - {launchedByValue} - ) : ( - launchedByValue - ) - } - /> - ); -} diff --git a/awx/ui/src/components/DetailList/UserDateDetail.js b/awx/ui/src/components/DetailList/UserDateDetail.js deleted file mode 100644 index 407fb6d7eea3..000000000000 --- a/awx/ui/src/components/DetailList/UserDateDetail.js +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react'; -import { node, string } from 'prop-types'; -import { Trans } from '@lingui/macro'; -import { Link } from 'react-router-dom'; -import styled from 'styled-components'; -import { formatDateString } from 'util/dates'; -import { SummaryFieldUser } from 'types'; -import _Detail from './Detail'; - -const Detail = styled(_Detail)` - word-break: break-word; -`; - -function UserDateDetail({ label, date, user }) { - const dateStr = formatDateString(date); - const username = user ? user.username : ''; - return ( - - {dateStr} by {username} - - ) : ( - dateStr - ) - } - /> - ); -} -UserDateDetail.propTypes = { - label: node.isRequired, - date: string.isRequired, - user: SummaryFieldUser, -}; -UserDateDetail.defaultProps = { - user: null, -}; - -export default UserDateDetail; diff --git a/awx/ui/src/components/DetailList/index.js b/awx/ui/src/components/DetailList/index.js deleted file mode 100644 index a393fe72a027..000000000000 --- a/awx/ui/src/components/DetailList/index.js +++ /dev/null @@ -1,12 +0,0 @@ -export { default as DetailList } from './DetailList'; -export { default as Detail, DetailName, DetailValue } from './Detail'; -export { default as DeletedDetail } from './DeletedDetail'; -export { default as UserDateDetail } from './UserDateDetail'; -export { default as DetailBadge } from './DetailBadge'; -export { default as ArrayDetail } from './ArrayDetail'; -export { default as LaunchedByDetail } from './LaunchedByDetail'; -/* - NOTE: CodeDetail cannot be imported here, as it causes circular - dependencies in testing environment. Import it directly from - DetailList/ObjectDetail -*/ diff --git a/awx/ui/src/components/DisassociateButton/DisassociateButton.js b/awx/ui/src/components/DisassociateButton/DisassociateButton.js deleted file mode 100644 index 9b0c8278b136..000000000000 --- a/awx/ui/src/components/DisassociateButton/DisassociateButton.js +++ /dev/null @@ -1,188 +0,0 @@ -import React, { useState, useEffect, useContext } from 'react'; -import { arrayOf, func, shape, string, oneOfType, number } from 'prop-types'; - -import { t } from '@lingui/macro'; -import { Button, Tooltip, DropdownItem } from '@patternfly/react-core'; -import styled from 'styled-components'; -import { KebabifiedContext } from 'contexts/Kebabified'; - -import AlertModal from '../AlertModal'; - -const ModalNote = styled.div` - margin-bottom: var(--pf-global--spacer--xl); -`; - -function DisassociateButton({ - itemsToDisassociate = [], - modalNote = '', - modalTitle = t`Disassociate?`, - onDisassociate, - verifyCannotDisassociate = true, - isProtectedInstanceGroup = false, -}) { - const [isOpen, setIsOpen] = useState(false); - const { isKebabified, onKebabModalChange } = useContext(KebabifiedContext); - - const handleDisassociate = () => { - onDisassociate(); - setIsOpen(false); - }; - - useEffect(() => { - if (isKebabified) { - onKebabModalChange(isOpen); - } - }, [isKebabified, isOpen, onKebabModalChange]); - - function cannotDisassociateAllOthers(item) { - return !item.summary_fields?.user_capabilities?.delete; - } - function cannotDisassociateInstances(item) { - return ( - item.node_type === 'control' || - (isProtectedInstanceGroup && item.node_type === 'hybrid') - ); - } - - const cannotDisassociate = itemsToDisassociate.some( - (i) => i.type === 'instance' - ) - ? cannotDisassociateInstances - : cannotDisassociateAllOthers; - - function renderTooltip() { - if (verifyCannotDisassociate) { - const itemsUnableToDisassociate = itemsToDisassociate - .filter(cannotDisassociate) - .map((item) => item.name ?? item.hostname) - .join(', '); - if ( - cannotDisassociate - ? itemsToDisassociate.some(cannotDisassociateInstances) - : itemsToDisassociate.some(cannotDisassociateAllOthers) - ) { - return ( -
- {t`You do not have permission to disassociate the following: ${itemsUnableToDisassociate}`} -
- ); - } - } - - if (itemsToDisassociate.length) { - return t`Disassociate`; - } - return t`Select a row to disassociate`; - } - - let isDisabled = false; - if (verifyCannotDisassociate) { - isDisabled = itemsToDisassociate.some(cannotDisassociate); - } - - // NOTE: Once PF supports tooltips on disabled elements, - // we can delete the extra
around the below. - // See: https://github.com/patternfly/patternfly-react/issues/1894 - return ( - <> - {isKebabified ? ( - setIsOpen(true)} - > - {t`Disassociate`} - - ) : ( - -
- -
-
- )} - - {isOpen && ( - setIsOpen(false)} - actions={[ - , - , - ]} - > - {modalNote && {modalNote}} - -
{t`This action will disassociate the following:`}
- - {itemsToDisassociate.map((item) => ( - - {item.hostname ? item.hostname : item.name} -
-
- ))} -
- )} - - ); -} - -DisassociateButton.defaultProps = { - itemsToDisassociate: [], - modalNote: '', - modalTitle: '', -}; - -DisassociateButton.propTypes = { - itemsToDisassociate: oneOfType([ - arrayOf( - shape({ - id: number.isRequired, - name: string.isRequired, - }) - ), - arrayOf( - shape({ - id: number.isRequired, - hostname: string.isRequired, - }) - ), - ]), - modalNote: string, - modalTitle: string, - onDisassociate: func.isRequired, -}; - -export default DisassociateButton; diff --git a/awx/ui/src/components/DisassociateButton/DisassociateButton.test.js b/awx/ui/src/components/DisassociateButton/DisassociateButton.test.js deleted file mode 100644 index 6a1cf5b040da..000000000000 --- a/awx/ui/src/components/DisassociateButton/DisassociateButton.test.js +++ /dev/null @@ -1,144 +0,0 @@ -import React from 'react'; -import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; -import DisassociateButton from './DisassociateButton'; - -describe('', () => { - describe('User has disassociate permissions', () => { - let wrapper; - const handleDisassociate = jest.fn(); - const mockHosts = [ - { - id: 1, - name: 'foo', - summary_fields: { - user_capabilities: { - delete: true, - }, - }, - }, - { - id: 2, - name: 'bar', - summary_fields: { - user_capabilities: { - delete: true, - }, - }, - }, - ]; - - beforeAll(() => { - wrapper = mountWithContexts( - - ); - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - test('should render button', () => { - expect(wrapper.find('button')).toHaveLength(1); - expect(wrapper.find('button').text()).toEqual('Disassociate'); - }); - - test('should open confirmation modal', () => { - wrapper.find('button').simulate('click'); - expect(wrapper.find('AlertModal')).toHaveLength(1); - }); - - test('cancel button should close confirmation modal', () => { - expect(wrapper.find('AlertModal')).toHaveLength(1); - wrapper.find('button[aria-label="Cancel"]').simulate('click'); - expect(wrapper.find('AlertModal')).toHaveLength(0); - }); - - test('should render expected modal content', () => { - wrapper.find('button').simulate('click'); - expect( - wrapper - .find('AlertModal') - .containsMatchingElement(
custom note
) - ).toEqual(true); - expect( - wrapper - .find('AlertModal') - .containsMatchingElement( -
This action will disassociate the following:
- ) - ).toEqual(true); - expect(wrapper.find('Title').text()).toEqual('custom title'); - wrapper.find('button[aria-label="Close"]').simulate('click'); - }); - - test('disassociate button should call handleDisassociate on click', () => { - wrapper.find('button').simulate('click'); - expect(handleDisassociate).toHaveBeenCalledTimes(0); - wrapper - .find('button[aria-label="confirm disassociate"]') - .simulate('click'); - expect(handleDisassociate).toHaveBeenCalledTimes(1); - }); - }); - - describe('User does not have disassociate permissions', () => { - const readOnlyHost = [ - { - id: 1, - name: 'foo', - summary_fields: { - user_capabilities: { - delete: false, - }, - }, - }, - ]; - - test('should disable button when no delete permissions', () => { - const wrapper = mountWithContexts( - {}} - itemsToDelete={readOnlyHost} - /> - ); - expect(wrapper.find('button[disabled]')).toHaveLength(1); - }); - - test('should disable button for control instance', () => { - const wrapper = mountWithContexts( - {}} - itemsToDelete={[ - { - id: 1, - hostname: 'awx', - node_type: 'control', - }, - ]} - /> - ); - expect(wrapper.find('button[disabled]')).toHaveLength(1); - }); - test('should disable button when selected items contain instances thaat are hybrid and are inside a protected instances', () => { - const wrapper = mountWithContexts( - {}} - isProectedInstanceGroup - itemsToDelete={[ - { - id: 1, - hostname: 'awx', - node_type: 'control', - }, - ]} - /> - ); - expect(wrapper.find('button[disabled]')).toHaveLength(1); - }); - }); -}); diff --git a/awx/ui/src/components/DisassociateButton/index.js b/awx/ui/src/components/DisassociateButton/index.js deleted file mode 100644 index c64669bc235a..000000000000 --- a/awx/ui/src/components/DisassociateButton/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './DisassociateButton'; diff --git a/awx/ui/src/components/DocsLink/DocsLink.js b/awx/ui/src/components/DocsLink/DocsLink.js deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/awx/ui/src/components/DocsLink/index.js b/awx/ui/src/components/DocsLink/index.js deleted file mode 100644 index e1344df9d2e9..000000000000 --- a/awx/ui/src/components/DocsLink/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './DocsLink'; diff --git a/awx/ui/src/components/ErrorDetail/ErrorDetail.js b/awx/ui/src/components/ErrorDetail/ErrorDetail.js deleted file mode 100644 index 4f24e93d62f3..000000000000 --- a/awx/ui/src/components/ErrorDetail/ErrorDetail.js +++ /dev/null @@ -1,108 +0,0 @@ -import 'styled-components/macro'; -import React, { useState } from 'react'; -import PropTypes from 'prop-types'; -import styled from 'styled-components'; - -import { t } from '@lingui/macro'; - -import { - Card as PFCard, - CardBody as PFCardBody, - ExpandableSection as PFExpandable, -} from '@patternfly/react-core'; -import getErrorMessage from './getErrorMessage'; - -const Card = styled(PFCard)` - background-color: var(--pf-global--BackgroundColor--200); - overflow-wrap: break-word; -`; - -const CardBody = styled(PFCardBody)` - max-height: 200px; - overflow: scroll; -`; - -const Expandable = styled(PFExpandable)` - text-align: left; - max-width: 75vw; - - & .pf-c-expandable__toggle { - padding-left: 10px; - margin-left: 5px; - margin-top: 10px; - margin-bottom: 10px; - } -`; - -function ErrorDetail({ error }) { - const { response } = error; - const [isExpanded, setIsExpanded] = useState(false); - - if (!error) { - return null; - } - - const handleToggle = () => { - setIsExpanded(!isExpanded); - }; - - const renderNetworkError = () => { - const message = getErrorMessage(response); - - return ( - <> - - {response?.config?.method.toUpperCase()} {response?.config?.url}{' '} - {response?.status} - - - {Array.isArray(message) ? ( -
    - {message.map((m) => - typeof m === 'string' ?
  • {m}
  • : null - )} -
- ) : ( - message - )} -
- - ); - }; - - const renderStack = () => ( - <> - - - {error.name}: {error.message} - - - - {error.stack} - - - ); - - return ( - - - {Object.prototype.hasOwnProperty.call(error, 'response') - ? renderNetworkError() - : renderStack()} - - - ); -} - -ErrorDetail.propTypes = { - error: PropTypes.instanceOf(Error), -}; -ErrorDetail.defaultProps = { - error: null, -}; - -export default ErrorDetail; diff --git a/awx/ui/src/components/ErrorDetail/ErrorDetail.test.js b/awx/ui/src/components/ErrorDetail/ErrorDetail.test.js deleted file mode 100644 index 1816f4a2dd78..000000000000 --- a/awx/ui/src/components/ErrorDetail/ErrorDetail.test.js +++ /dev/null @@ -1,46 +0,0 @@ -import React from 'react'; -import { act } from 'react-dom/test-utils'; -import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; - -import ErrorDetail from './ErrorDetail'; - -describe('ErrorDetail', () => { - test('renders the expected content', () => { - const wrapper = mountWithContexts( - - ); - expect(wrapper).toHaveLength(1); - }); - test('testing errors', () => { - const wrapper = mountWithContexts( - - ); - act(() => wrapper.find('ExpandableSection').prop('onToggle')()); - wrapper.update(); - }); -}); diff --git a/awx/ui/src/components/ErrorDetail/getErrorMessage.js b/awx/ui/src/components/ErrorDetail/getErrorMessage.js deleted file mode 100644 index 1c2450a64d75..000000000000 --- a/awx/ui/src/components/ErrorDetail/getErrorMessage.js +++ /dev/null @@ -1,15 +0,0 @@ -export default function getErrorMessage(response) { - if (!response?.data) { - return null; - } - if (typeof response.data === 'string') { - return response.data; - } - if (response.data.detail) { - return response.data.detail; - } - return Object.values(response.data).reduce( - (acc, currentValue) => acc.concat(currentValue), - [] - ); -} diff --git a/awx/ui/src/components/ErrorDetail/getErrorMessage.test.js b/awx/ui/src/components/ErrorDetail/getErrorMessage.test.js deleted file mode 100644 index c67728f00bc8..000000000000 --- a/awx/ui/src/components/ErrorDetail/getErrorMessage.test.js +++ /dev/null @@ -1,60 +0,0 @@ -import getErrorMessage from './getErrorMessage'; - -describe('getErrorMessage', () => { - test('should return data string', () => { - const response = { - data: 'error response', - }; - expect(getErrorMessage(response)).toEqual('error response'); - }); - test('should return detail string', () => { - const response = { - data: { - detail: 'detail string', - }, - }; - expect(getErrorMessage(response)).toEqual('detail string'); - }); - test('should return an array of strings', () => { - const response = { - data: { - project: ['project error response'], - }, - }; - expect(getErrorMessage(response)).toEqual(['project error response']); - }); - test('should consolidate error messages from multiple keys into an array', () => { - const response = { - data: { - project: ['project error response'], - inventory: ['inventory error response'], - organization: ['org error response'], - }, - }; - expect(getErrorMessage(response)).toEqual([ - 'project error response', - 'inventory error response', - 'org error response', - ]); - }); - test('should handle no response.data', () => { - const response = {}; - expect(getErrorMessage(response)).toEqual(null); - }); - test('should consolidate multiple error messages from multiple keys into an array', () => { - const response = { - data: { - project: ['project error response'], - inventory: [ - 'inventory error response', - 'another inventory error response', - ], - }, - }; - expect(getErrorMessage(response)).toEqual([ - 'project error response', - 'inventory error response', - 'another inventory error response', - ]); - }); -}); diff --git a/awx/ui/src/components/ErrorDetail/index.js b/awx/ui/src/components/ErrorDetail/index.js deleted file mode 100644 index 0f380db7abaa..000000000000 --- a/awx/ui/src/components/ErrorDetail/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './ErrorDetail'; diff --git a/awx/ui/src/components/ExecutionEnvironmentDetail/ExecutionEnvironmentDetail.js b/awx/ui/src/components/ExecutionEnvironmentDetail/ExecutionEnvironmentDetail.js deleted file mode 100644 index f4029a19bd43..000000000000 --- a/awx/ui/src/components/ExecutionEnvironmentDetail/ExecutionEnvironmentDetail.js +++ /dev/null @@ -1,145 +0,0 @@ -import React from 'react'; -import { bool, string } from 'prop-types'; -import { Link } from 'react-router-dom'; -import { t, Trans } from '@lingui/macro'; -import { Popover, Tooltip } from '@patternfly/react-core'; -import styled from 'styled-components'; -import { ExclamationTriangleIcon as PFExclamationTriangleIcon } from '@patternfly/react-icons'; -import { ExecutionEnvironment } from 'types'; -import getDocsBaseUrl from 'util/getDocsBaseUrl'; -import { useConfig } from 'contexts/Config'; -import { Detail } from '../DetailList'; - -const ExclamationTriangleIcon = styled(PFExclamationTriangleIcon)` - color: var(--pf-global--warning-color--100); - margin-left: 18px; - cursor: pointer; -`; - -const ExclamationTrianglePopover = styled(PFExclamationTriangleIcon)` - color: var(--pf-global--warning-color--100); - margin-left: 18px; - cursor: pointer; -`; - -ExclamationTrianglePopover.displayName = 'ExclamationTrianglePopover'; - -function ExecutionEnvironmentDetail({ - executionEnvironment, - isDefaultEnvironment, - virtualEnvironment, - verifyMissingVirtualEnv, - helpText, - dataCy, -}) { - const config = useConfig(); - const docsLink = `${getDocsBaseUrl( - config - )}/html/upgrade-migration-guide/upgrade_to_ees.html`; - const label = isDefaultEnvironment - ? t`Default Execution Environment` - : t`Execution Environment`; - - if (executionEnvironment) { - return ( - - {executionEnvironment.name} - - } - helpText={helpText} - dataCy={dataCy} - /> - ); - } - if (verifyMissingVirtualEnv && virtualEnvironment && !executionEnvironment) { - return ( - - {t`Missing resource`} - - {t`Execution Environment Missing`}
} - bodyContent={ -
- - Custom virtual environment {virtualEnvironment} must be - replaced by an execution environment. For more information - about migrating to execution environments see{' '} - - the documentation. - - -
- } - position="right" - > - - - - - } - dataCy={`missing-${dataCy}`} - /> - ); - } - if ( - !verifyMissingVirtualEnv && - !virtualEnvironment && - !executionEnvironment - ) { - return ( - - {t`Missing resource`} - - - - - - - } - dataCy={dataCy} - /> - ); - } - - return null; -} - -ExecutionEnvironmentDetail.propTypes = { - executionEnvironment: ExecutionEnvironment, - isDefaultEnvironment: bool, - virtualEnvironment: string, - verifyMissingVirtualEnv: bool, - helpText: string, - dataCy: string, -}; - -ExecutionEnvironmentDetail.defaultProps = { - isDefaultEnvironment: false, - executionEnvironment: null, - virtualEnvironment: '', - verifyMissingVirtualEnv: true, - helpText: '', - dataCy: 'execution-environment-detail', -}; - -export default ExecutionEnvironmentDetail; diff --git a/awx/ui/src/components/ExecutionEnvironmentDetail/ExecutionEnvironmentDetail.test.js b/awx/ui/src/components/ExecutionEnvironmentDetail/ExecutionEnvironmentDetail.test.js deleted file mode 100644 index a0e84e686bad..000000000000 --- a/awx/ui/src/components/ExecutionEnvironmentDetail/ExecutionEnvironmentDetail.test.js +++ /dev/null @@ -1,78 +0,0 @@ -import React from 'react'; -import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; - -import ExecutionEnvironmentDetail from './ExecutionEnvironmentDetail'; - -const mockExecutionEnvironment = { - id: 2, - name: 'Foo', - image: 'quay.io/ansible/awx-ee', - pull: 'missing', - description: '', -}; - -const virtualEnvironment = 'var/lib/awx/custom_env'; - -describe('', () => { - test('should display execution environment detail', async () => { - const wrapper = mountWithContexts( - - ); - const executionEnvironment = wrapper.find('ExecutionEnvironmentDetail'); - expect(executionEnvironment).toHaveLength(1); - expect(executionEnvironment.find('dt').text()).toEqual( - 'Execution Environment' - ); - expect(executionEnvironment.find('dd').text()).toEqual( - mockExecutionEnvironment.name - ); - }); - - test('should display execution environment detail even with a previous virtual env present', async () => { - const wrapper = mountWithContexts( - - ); - const executionEnvironment = wrapper.find('ExecutionEnvironmentDetail'); - expect(executionEnvironment).toHaveLength(1); - expect(executionEnvironment.find('dt').text()).toEqual( - 'Execution Environment' - ); - expect(executionEnvironment.find('dd').text()).toEqual( - mockExecutionEnvironment.name - ); - }); - - test('should display warning missing execution environment', async () => { - const wrapper = mountWithContexts( - - ); - const executionEnvironment = wrapper.find('ExecutionEnvironmentDetail'); - expect(executionEnvironment).toHaveLength(1); - expect(executionEnvironment.find('dt').text()).toEqual( - 'Execution Environment' - ); - expect(executionEnvironment.find('dd').text()).toEqual('Missing resource'); - expect(wrapper.find('ExclamationTrianglePopover').length).toBe(1); - expect(wrapper.find('Popover').length).toBe(1); - }); - - test('should display warning deleted execution environment', async () => { - const wrapper = mountWithContexts( - - ); - const executionEnvironment = wrapper.find('ExecutionEnvironmentDetail'); - expect(executionEnvironment).toHaveLength(1); - expect(executionEnvironment.find('dt').text()).toEqual( - 'Execution Environment' - ); - expect(executionEnvironment.find('dd').text()).toEqual('Missing resource'); - expect(wrapper.find('Tooltip').prop('content')).toEqual( - `Execution environment is missing or deleted.` - ); - }); -}); diff --git a/awx/ui/src/components/ExecutionEnvironmentDetail/index.js b/awx/ui/src/components/ExecutionEnvironmentDetail/index.js deleted file mode 100644 index 7c5efd15b45d..000000000000 --- a/awx/ui/src/components/ExecutionEnvironmentDetail/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './ExecutionEnvironmentDetail'; diff --git a/awx/ui/src/components/ExpandCollapse/ExpandCollapse.js b/awx/ui/src/components/ExpandCollapse/ExpandCollapse.js deleted file mode 100644 index 770e29198f96..000000000000 --- a/awx/ui/src/components/ExpandCollapse/ExpandCollapse.js +++ /dev/null @@ -1,73 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import { t } from '@lingui/macro'; -import { - Button as PFButton, - ToolbarItem as PFToolbarItem, -} from '@patternfly/react-core'; -import { BarsIcon, EqualsIcon } from '@patternfly/react-icons'; -import styled from 'styled-components'; - -const Button = styled(PFButton)` - padding: 0; - margin: 0; - height: 30px; - width: 30px; - ${(props) => - props.isActive - ? ` - background-color: #007bba; - --pf-c-button--m-plain--active--Color: white; - --pf-c-button--m-plain--focus--Color: white;` - : null}; -`; - -const ToolbarItem = styled(PFToolbarItem)` - & :not(:last-child) { - margin-right: 20px; - } -`; - -// TODO: Recommend renaming this component to avoid confusion -// with ExpandingContainer -function ExpandCollapse({ isCompact, onCompact, onExpand }) { - return ( - <> - - - - - - - - ); -} - -ExpandCollapse.propTypes = { - onCompact: PropTypes.func.isRequired, - onExpand: PropTypes.func.isRequired, - isCompact: PropTypes.bool, -}; - -ExpandCollapse.defaultProps = { - isCompact: true, -}; - -export default ExpandCollapse; diff --git a/awx/ui/src/components/ExpandCollapse/ExpandCollapse.test.js b/awx/ui/src/components/ExpandCollapse/ExpandCollapse.test.js deleted file mode 100644 index eb06b49c519b..000000000000 --- a/awx/ui/src/components/ExpandCollapse/ExpandCollapse.test.js +++ /dev/null @@ -1,19 +0,0 @@ -import React from 'react'; -import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; -import ExpandCollapse from './ExpandCollapse'; - -describe('', () => { - const onCompact = jest.fn(); - const onExpand = jest.fn(); - const isCompact = false; - test('initially renders without crashing', () => { - const wrapper = mountWithContexts( - - ); - expect(wrapper.length).toBe(1); - }); -}); diff --git a/awx/ui/src/components/ExpandCollapse/index.js b/awx/ui/src/components/ExpandCollapse/index.js deleted file mode 100644 index 997c5b618120..000000000000 --- a/awx/ui/src/components/ExpandCollapse/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './ExpandCollapse'; diff --git a/awx/ui/src/components/FieldWithPrompt/FieldWithPrompt.js b/awx/ui/src/components/FieldWithPrompt/FieldWithPrompt.js deleted file mode 100644 index d58fca986b3c..000000000000 --- a/awx/ui/src/components/FieldWithPrompt/FieldWithPrompt.js +++ /dev/null @@ -1,70 +0,0 @@ -import React from 'react'; -import { bool, node, string } from 'prop-types'; - -import { t } from '@lingui/macro'; -import styled from 'styled-components'; -import { CheckboxField } from '../FormField'; -import Popover from '../Popover'; - -const FieldHeader = styled.div` - display: flex; - padding-bottom: var(--pf-c-form__group-label--PaddingBottom); -`; - -const StyledCheckboxField = styled(CheckboxField)` - --pf-c-check__label--FontSize: var(--pf-c-form__label--FontSize); - margin-left: auto; -`; - -function FieldWithPrompt({ - children, - fieldId, - isRequired, - label, - promptId, - promptName, - tooltip, - isDisabled, -}) { - return ( -
- -
- - {tooltip && } -
- -
- {children} -
- ); -} - -FieldWithPrompt.propTypes = { - fieldId: string.isRequired, - isRequired: bool, - label: string.isRequired, - promptId: string.isRequired, - promptName: string.isRequired, - tooltip: node, -}; - -FieldWithPrompt.defaultProps = { - isRequired: false, - tooltip: null, -}; - -export default FieldWithPrompt; diff --git a/awx/ui/src/components/FieldWithPrompt/FieldWithPrompt.test.js b/awx/ui/src/components/FieldWithPrompt/FieldWithPrompt.test.js deleted file mode 100644 index e3361a9576f1..000000000000 --- a/awx/ui/src/components/FieldWithPrompt/FieldWithPrompt.test.js +++ /dev/null @@ -1,64 +0,0 @@ -import React from 'react'; -import { Field, Formik } from 'formik'; -import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; -import FieldWithPrompt from './FieldWithPrompt'; - -describe('FieldWithPrompt', () => { - let wrapper; - - test('Required asterisk and Popover hidden when not required and tooltip not provided', () => { - wrapper = mountWithContexts( - - {() => ( - - - {() => } - - - )} - - ); - expect(wrapper.find('.pf-c-form__label-required')).toHaveLength(0); - expect(wrapper.find('Popover')).toHaveLength(0); - }); - - test('Required asterisk and Popover shown when required and tooltip provided', () => { - wrapper = mountWithContexts( - - {() => ( - - - {() => } - - - )} - - ); - expect(wrapper.find('.pf-c-form__label-required')).toHaveLength(1); - expect( - wrapper.find('Popover[data-cy="job-template-limit-tooltip"]').length - ).toBe(1); - }); -}); diff --git a/awx/ui/src/components/FieldWithPrompt/index.js b/awx/ui/src/components/FieldWithPrompt/index.js deleted file mode 100644 index 77c1d5bda6c3..000000000000 --- a/awx/ui/src/components/FieldWithPrompt/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './FieldWithPrompt'; diff --git a/awx/ui/src/components/FormActionGroup/FormActionGroup.js b/awx/ui/src/components/FormActionGroup/FormActionGroup.js deleted file mode 100644 index e0d6631ef860..000000000000 --- a/awx/ui/src/components/FormActionGroup/FormActionGroup.js +++ /dev/null @@ -1,45 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import { t } from '@lingui/macro'; -import { ActionGroup, Button } from '@patternfly/react-core'; -import { FormFullWidthLayout } from '../FormLayout'; - -const FormActionGroup = ({ onCancel, onSubmit, submitDisabled }) => ( - - - - - - -); - -FormActionGroup.propTypes = { - onCancel: PropTypes.func.isRequired, - onSubmit: PropTypes.func.isRequired, - submitDisabled: PropTypes.bool, -}; - -FormActionGroup.defaultProps = { - submitDisabled: false, -}; - -export default FormActionGroup; diff --git a/awx/ui/src/components/FormActionGroup/FormActionGroup.test.js b/awx/ui/src/components/FormActionGroup/FormActionGroup.test.js deleted file mode 100644 index 5068a85226dc..000000000000 --- a/awx/ui/src/components/FormActionGroup/FormActionGroup.test.js +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; -import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; - -import FormActionGroup from './FormActionGroup'; - -describe('FormActionGroup', () => { - test('should render the expected content', () => { - const wrapper = mountWithContexts( - {}} onCancel={() => {}} /> - ); - expect(wrapper).toHaveLength(1); - }); -}); diff --git a/awx/ui/src/components/FormActionGroup/index.js b/awx/ui/src/components/FormActionGroup/index.js deleted file mode 100644 index 30c9e11f1a6b..000000000000 --- a/awx/ui/src/components/FormActionGroup/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './FormActionGroup'; diff --git a/awx/ui/src/components/FormField/ArrayTextField.js b/awx/ui/src/components/FormField/ArrayTextField.js deleted file mode 100644 index f96505682aad..000000000000 --- a/awx/ui/src/components/FormField/ArrayTextField.js +++ /dev/null @@ -1,74 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { useField } from 'formik'; -import { FormGroup, TextArea } from '@patternfly/react-core'; -import Popover from '../Popover'; - -function ArrayTextField(props) { - const { - id, - helperText, - name, - label, - tooltip, - tooltipMaxWidth, - validate, - isRequired, - type, - ...rest - } = props; - - const [field, meta, helpers] = useField({ name, validate }); - const isValid = !(meta.touched && meta.error); - const value = field.value || []; - - return ( - } - > - - - - ); -} -export default EulaStep; diff --git a/awx/ui/src/screens/Setting/Subscription/SubscriptionEdit/EulaStep.test.js b/awx/ui/src/screens/Setting/Subscription/SubscriptionEdit/EulaStep.test.js deleted file mode 100644 index 889b57a7e14b..000000000000 --- a/awx/ui/src/screens/Setting/Subscription/SubscriptionEdit/EulaStep.test.js +++ /dev/null @@ -1,37 +0,0 @@ -import React from 'react'; -import { act } from 'react-dom/test-utils'; -import { Formik } from 'formik'; -import { mountWithContexts } from '../../../../../testUtils/enzymeHelpers'; -import EulaStep from './EulaStep'; - -describe('', () => { - let wrapper; - - beforeEach(async () => { - await act(async () => { - wrapper = mountWithContexts( - - - - ); - }); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - test('initially renders without crashing', async () => { - expect(wrapper.find('EulaStep').length).toBe(1); - }); -}); diff --git a/awx/ui/src/screens/Setting/Subscription/SubscriptionEdit/SubscriptionEdit.js b/awx/ui/src/screens/Setting/Subscription/SubscriptionEdit/SubscriptionEdit.js deleted file mode 100644 index 1ad850408e92..000000000000 --- a/awx/ui/src/screens/Setting/Subscription/SubscriptionEdit/SubscriptionEdit.js +++ /dev/null @@ -1,273 +0,0 @@ -import React, { useCallback, useEffect } from 'react'; -import { useHistory, Link, useRouteMatch } from 'react-router-dom'; -import { t, Trans } from '@lingui/macro'; -import { Formik, useFormikContext } from 'formik'; -import { - Alert, - AlertGroup, - Button, - Form, - Wizard, - WizardContextConsumer, - WizardFooter, -} from '@patternfly/react-core'; -import { ConfigAPI, SettingsAPI, RootAPI } from 'api'; -import useRequest, { useDismissableError } from 'hooks/useRequest'; -import ContentLoading from 'components/ContentLoading'; -import ContentError from 'components/ContentError'; -import { FormSubmitError } from 'components/FormField'; -import { useConfig } from 'contexts/Config'; -import SubscriptionStep from './SubscriptionStep'; -import AnalyticsStep from './AnalyticsStep'; -import EulaStep from './EulaStep'; - -const CustomFooter = ({ isSubmitLoading }) => { - const { values, errors } = useFormikContext(); - const { me, license_info } = useConfig(); - const history = useHistory(); - - return ( - - - {({ activeStep, onNext, onBack }) => ( - <> - {activeStep.id === 'eula-step' ? ( - - ) : ( - - )} - - {license_info?.valid_key && ( - - )} - - )} - - - ); -}; - -function SubscriptionEdit() { - const history = useHistory(); - const { request: updateConfig, license_info } = useConfig(); - const hasValidKey = Boolean(license_info?.valid_key); - const subscriptionMgmtRoute = useRouteMatch({ - path: '/subscription_management', - }); - - const { - isLoading: isContentLoading, - error: contentError, - request: fetchContent, - result: { brandName }, - } = useRequest( - useCallback(async () => { - const { - data: { BRAND_NAME }, - } = await RootAPI.readAssetVariables(); - return { - brandName: BRAND_NAME, - }; - }, []), - { - brandName: null, - } - ); - - useEffect(() => { - if (subscriptionMgmtRoute && hasValidKey) { - history.push('/settings/subscription/edit'); - } - fetchContent(); - }, [fetchContent]); // eslint-disable-line react-hooks/exhaustive-deps - - const { - error: submitError, - isLoading: submitLoading, - result: submitSuccessful, - request: submitRequest, - } = useRequest( - useCallback(async (form) => { - if (form.manifest_file) { - await ConfigAPI.create({ - manifest: form.manifest_file, - }); - } else if (form.subscription) { - await ConfigAPI.attach({ pool_id: form.subscription.pool_id }); - } - - if (!hasValidKey) { - if (form.pendo) { - await SettingsAPI.updateCategory('ui', { - PENDO_TRACKING_STATE: 'detailed', - }); - } else { - await SettingsAPI.updateCategory('ui', { - PENDO_TRACKING_STATE: 'off', - }); - } - - if (form.insights) { - await SettingsAPI.updateCategory('system', { - INSIGHTS_TRACKING_STATE: true, - }); - } else { - await SettingsAPI.updateCategory('system', { - INSIGHTS_TRACKING_STATE: false, - }); - } - } - - await updateConfig(); - - return true; - }, []) // eslint-disable-line react-hooks/exhaustive-deps - ); - - useEffect(() => { - if (submitSuccessful) { - setTimeout(() => { - history.push( - subscriptionMgmtRoute ? '/home' : '/settings/subscription/details' - ); - }, 3000); - } - }, [submitSuccessful, history, subscriptionMgmtRoute]); - - const { error, dismissError } = useDismissableError(submitError); - const handleSubmit = async (values) => { - dismissError(); - await submitRequest(values); - }; - - if (isContentLoading) { - return ; - } - - if (contentError) { - return ; - } - - const steps = [ - { - name: hasValidKey - ? t`Subscription Management` - : `${brandName} ${t`Subscription`}`, - id: 'subscription-step', - component: , - }, - ...(!hasValidKey - ? [ - { - name: t`User and Automation Analytics`, - id: 'analytics-step', - component: , - }, - ] - : []), - { - name: t`End user license agreement`, - component: , - id: 'eula-step', - nextButtonText: t`Submit`, - }, - ]; - - return ( - <> - - {(formik) => ( -
{ - e.preventDefault(); - }} - > - } - height="fit-content" - /> - {error && ( -
- -
- )} - - )} -
- - {submitSuccessful && ( - - {subscriptionMgmtRoute ? ( - - Redirecting to dashboard - - ) : ( - - Redirecting to subscription detail - - )} - - )} - - - ); -} - -export default SubscriptionEdit; diff --git a/awx/ui/src/screens/Setting/Subscription/SubscriptionEdit/SubscriptionEdit.test.js b/awx/ui/src/screens/Setting/Subscription/SubscriptionEdit/SubscriptionEdit.test.js deleted file mode 100644 index eba1891c6e38..000000000000 --- a/awx/ui/src/screens/Setting/Subscription/SubscriptionEdit/SubscriptionEdit.test.js +++ /dev/null @@ -1,406 +0,0 @@ -import React from 'react'; -import { act } from 'react-dom/test-utils'; -import { createMemoryHistory } from 'history'; -import { ConfigAPI, MeAPI, SettingsAPI, RootAPI, UsersAPI } from 'api'; -import { - mountWithContexts, - waitForElement, -} from '../../../../../testUtils/enzymeHelpers'; -import SubscriptionEdit from './SubscriptionEdit'; - -jest.mock('../../../../api'); - -const mockConfig = { - me: { - is_superuser: true, - }, - license_info: { - compliant: true, - current_instances: 1, - date_expired: false, - date_warning: true, - free_instances: 1000, - grace_period_remaining: 2904229, - instance_count: 1001, - license_date: '1614401999', - license_type: 'enterprise', - pool_id: '123', - product_name: 'Red Hat Ansible Automation, Standard (5000 Managed Nodes)', - satellite: false, - sku: 'ABC', - subscription_name: - 'Red Hat Ansible Automation, Standard (1001 Managed Nodes)', - support_level: null, - time_remaining: 312229, - trial: false, - valid_key: true, - }, - analytics_status: 'detailed', - version: '1.2.3', -}; - -const emptyConfig = { - me: { - is_superuser: true, - }, - license_info: { - valid_key: false, - }, - request: jest.fn(), -}; - -describe('', () => { - describe('installing a fresh subscription', () => { - let wrapper; - let history; - - beforeAll(async () => { - jest.resetAllMocks(); - RootAPI.readAssetVariables = async () => ({ - data: { - BRAND_NAME: 'Mock', - PENDO_API_KEY: '', - }, - }); - SettingsAPI.readCategory = async () => ({ - data: {}, - }); - history = createMemoryHistory({ - initialEntries: ['/settings/subscription_managment'], - }); - await act(async () => { - wrapper = mountWithContexts(, { - context: { - config: emptyConfig, - router: { history }, - }, - }); - }); - await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0); - }); - - test('initially renders without crashing', () => { - expect(wrapper.find('SubscriptionEdit').length).toBe(1); - }); - - test('should show all wizard steps when it is a trial or a fresh installation', () => { - expect( - wrapper.find('WizardNavItem[content="Mock Subscription"]').length - ).toBe(1); - expect( - wrapper.find('WizardNavItem[content="User and Automation Analytics"]') - .length - ).toBe(1); - expect( - wrapper.find('WizardNavItem[content="End user license agreement"]') - .length - ).toBe(1); - expect( - wrapper.find('button[aria-label="Cancel subscription edit"]').length - ).toBe(0); - }); - - test('subscription selection type toggle should default to manifest', () => { - expect(wrapper.find('ToggleGroupItem').first().text()).toBe( - 'Subscription manifest' - ); - expect(wrapper.find('ToggleGroupItem').first().props().isSelected).toBe( - true - ); - expect(wrapper.find('ToggleGroupItem').last().text()).toBe( - 'Username / password' - ); - expect(wrapper.find('ToggleGroupItem').last().props().isSelected).toBe( - false - ); - }); - - test('file upload field should upload manifest file', async () => { - expect(wrapper.find('FileUploadField').prop('filename')).toEqual(''); - const mockFile = new Blob(['123'], { type: 'application/zip' }); - mockFile.name = 'mock.zip'; - mockFile.date = new Date(); - await act(async () => { - wrapper.find('FileUpload').invoke('onChange')(mockFile, 'mock.zip'); - }); - await act(async () => { - wrapper.update(); - }); - await act(async () => { - wrapper.update(); - }); - expect(wrapper.find('FileUploadField').prop('filename')).toEqual( - 'mock.zip' - ); - }); - - test('clicking next button should show analytics step', async () => { - wrapper.update(); - await act(async () => { - wrapper.find('button#subscription-wizard-next').simulate('click'); - }); - wrapper.update(); - expect(wrapper.find('AnalyticsStep').length).toBe(1); - expect(wrapper.find('CheckboxField').length).toBe(2); - expect(wrapper.find('FormField').length).toBe(1); - expect(wrapper.find('PasswordField').length).toBe(1); - }); - - test('deselecting insights checkbox should hide username and password fields', async () => { - expect(wrapper.find('input#username-field')).toHaveLength(1); - expect(wrapper.find('input#password-field')).toHaveLength(1); - await act(async () => { - wrapper.find('Checkbox[name="pendo"] input').simulate('change', { - target: { value: false, name: 'pendo' }, - }); - wrapper.find('Checkbox[name="insights"] input').simulate('change', { - target: { value: false, name: 'insights' }, - }); - }); - wrapper.update(); - expect(wrapper.find('input#username-field')).toHaveLength(0); - expect(wrapper.find('input#password-field')).toHaveLength(0); - }); - - test('clicking next button should show eula step', async () => { - await act(async () => { - wrapper.find('button#subscription-wizard-next').simulate('click'); - }); - wrapper.update(); - expect(wrapper.find('EulaStep').length).toBe(1); - expect(wrapper.find('button#subscription-wizard-submit').length).toBe(1); - expect( - wrapper.find('button#subscription-wizard-submit').prop('disabled') - ).toBe(false); - }); - - test('should successfully save on form submission', async () => { - const { window } = global; - global.window.pendo = { initialize: async () => ({}) }; - ConfigAPI.read = async () => ({ - data: mockConfig, - }); - MeAPI.read = async () => ({ - data: { - results: [ - { - is_superuser: true, - }, - ], - }, - }); - ConfigAPI.attach = async () => ({}); - ConfigAPI.create = async () => ({ - data: mockConfig, - }); - UsersAPI.readAdminOfOrganizations({ - data: {}, - }); - expect(wrapper.find('Alert[title="Save successful"]')).toHaveLength(0); - await act(async () => - wrapper.find('button[aria-label="Submit"]').simulate('click') - ); - wrapper.update(); - waitForElement(wrapper, 'Alert[title="Save successful"]'); - global.window = window; - }); - }); - - describe('editing with a valid subscription', () => { - let wrapper; - let history; - - beforeAll(async () => { - SettingsAPI.readCategory = async () => ({ - data: { - SUBSCRIPTIONS_PASSWORD: 'mock_password', - SUBSCRIPTIONS_USERNAME: 'mock_username', - INSIGHTS_TRACKING_STATE: false, - PENDO: 'off', - }, - }); - ConfigAPI.readSubscriptions = async () => ({ - data: [ - { - subscription_name: 'mock subscription 50 instances', - instance_count: 50, - license_date: new Date(), - pool_id: 999, - }, - ], - }); - history = createMemoryHistory({ - initialEntries: ['/settings/subscription/edit'], - }); - await act(async () => { - wrapper = mountWithContexts(, { - context: { - config: { - mockConfig, - request: jest.fn(), - }, - me: { - is_superuser: true, - }, - router: { history }, - }, - }); - }); - await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0); - }); - - test('should hide analytics step when editing a current subscription', async () => { - expect( - wrapper.find('WizardNavItem[content="Subscription Management"]').length - ).toBe(1); - expect( - wrapper.find('WizardNavItem[content="User and Automation Analytics"]') - .length - ).toBe(0); - expect( - wrapper.find('WizardNavItem[content="End user license agreement"]') - .length - ).toBe(1); - }); - - test('Username/password toggle button should show username credential fields', async () => { - expect(wrapper.find('ToggleGroupItem').last().props().isSelected).toBe( - false - ); - wrapper - .find('ToggleGroupItem[text="Username / password"] button') - .simulate('click'); - wrapper.update(); - expect(wrapper.find('ToggleGroupItem').last().props().isSelected).toBe( - true - ); - expect(wrapper.find('input#username-field').prop('value')).toEqual(''); - expect(wrapper.find('input#password-field').prop('value')).toEqual(''); - await act(async () => { - wrapper.find('input#username-field').simulate('change', { - target: { value: 'username-cred', name: 'username' }, - }); - wrapper.find('input#password-field').simulate('change', { - target: { value: 'password-cred', name: 'password' }, - }); - }); - wrapper.update(); - expect(wrapper.find('input#username-field').prop('value')).toEqual( - 'username-cred' - ); - expect(wrapper.find('input#password-field').prop('value')).toEqual( - 'password-cred' - ); - }); - - test('should open subscription selection modal', async () => { - expect(wrapper.find('Flex[id="selected-subscription-file"]').length).toBe( - 0 - ); - await act(async () => { - wrapper - .find('SubscriptionStep button[aria-label="Get subscriptions"]') - .simulate('click'); - }); - wrapper.update(); - await waitForElement(wrapper, 'SubscriptionModal'); - await act(async () => { - wrapper - .find('SubscriptionModal SelectColumn') - .first() - .invoke('onSelect')(); - }); - wrapper.update(); - await act(async () => - wrapper.find('Button[aria-label="Confirm selection"]').prop('onClick')() - ); - wrapper.update(); - await waitForElement( - wrapper, - 'SubscriptionModal', - (el) => el.length === 0 - ); - }); - - test('should show selected subscription name', () => { - expect(wrapper.find('Flex[id="selected-subscription"]').length).toBe(1); - expect(wrapper.find('Flex[id="selected-subscription"] i').text()).toBe( - 'mock subscription 50 instances' - ); - }); - test('next should skip analytics step and navigate to eula step', async () => { - await act(async () => { - wrapper.find('button#subscription-wizard-next').simulate('click'); - }); - wrapper.update(); - expect(wrapper.find('SubscriptionStep').length).toBe(0); - expect(wrapper.find('AnalyticsStep').length).toBe(0); - expect(wrapper.find('EulaStep').length).toBe(1); - expect( - wrapper.find('button#subscription-wizard-submit').prop('disabled') - ).toBe(false); - }); - - test('should successfully send request to api on form submission', async () => { - expect(wrapper.find('EulaStep').length).toBe(1); - ConfigAPI.read = async () => ({ - data: { - mockConfig, - }, - }); - MeAPI.read = async () => ({ - data: { - results: [ - { - is_superuser: true, - }, - ], - }, - }); - ConfigAPI.attach = async () => ({}); - ConfigAPI.create = async () => ({}); - UsersAPI.readAdminOfOrganizations = async () => ({ - data: {}, - }); - waitForElement( - wrapper, - 'Alert[title="Save successful"]', - (el) => el.length === 0 - ); - await act(async () => - wrapper.find('button#subscription-wizard-submit').prop('onClick')() - ); - wrapper.update(); - waitForElement(wrapper, 'Alert[title="Save successful"]'); - }); - - test('should navigate to subscription details on cancel', async () => { - expect( - wrapper.find('button[aria-label="Cancel subscription edit"]').length - ).toBe(1); - await act(async () => { - wrapper - .find('button[aria-label="Cancel subscription edit"]') - .invoke('onClick')(); - }); - expect(history.location.pathname).toEqual( - '/settings/subscription/details' - ); - }); - }); - - test('should throw a content error', async () => { - RootAPI.readAssetVariables = jest.fn(); - RootAPI.readAssetVariables.mockRejectedValueOnce(new Error()); - let wrapper; - await act(async () => { - wrapper = mountWithContexts(, { - context: { - config: emptyConfig, - }, - }); - }); - await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0); - await waitForElement(wrapper, 'ContentError', (el) => el.length === 1); - }); -}); diff --git a/awx/ui/src/screens/Setting/Subscription/SubscriptionEdit/SubscriptionModal.js b/awx/ui/src/screens/Setting/Subscription/SubscriptionEdit/SubscriptionModal.js deleted file mode 100644 index 99a9c993af9f..000000000000 --- a/awx/ui/src/screens/Setting/Subscription/SubscriptionEdit/SubscriptionModal.js +++ /dev/null @@ -1,187 +0,0 @@ -import React, { useCallback, useEffect } from 'react'; - -import { t, Trans } from '@lingui/macro'; -import { - Button, - EmptyState, - EmptyStateIcon, - EmptyStateBody, - Modal, - Title, -} from '@patternfly/react-core'; -import { - TableComposable, - Tbody, - Td, - Th, - Thead, - Tr, -} from '@patternfly/react-table'; -import { ExclamationTriangleIcon } from '@patternfly/react-icons'; - -import { ConfigAPI } from 'api'; -import { formatDateString } from 'util/dates'; -import useRequest from 'hooks/useRequest'; -import useSelected from 'hooks/useSelected'; -import ErrorDetail from 'components/ErrorDetail'; -import ContentEmpty from 'components/ContentEmpty'; -import ContentLoading from 'components/ContentLoading'; - -function SubscriptionModal({ - subscriptionCreds = {}, - selectedSubscription = null, - onClose, - onConfirm, -}) { - const { - isLoading, - error, - request: fetchSubscriptions, - result: subscriptions, - } = useRequest( - useCallback(async () => { - if (!subscriptionCreds.username || !subscriptionCreds.password) { - return []; - } - const { data } = await ConfigAPI.readSubscriptions( - subscriptionCreds.username, - subscriptionCreds.password - ); - - // Ensure unique ids for each subscription - // because it is possible to have multiple - // subscriptions with the same pool_id - let repeatId = 1; - data.forEach((i) => { - i.id = repeatId++; - }); - - return data; - }, []), // eslint-disable-line react-hooks/exhaustive-deps - [] - ); - - const { selected, setSelected } = useSelected(subscriptions); - - const handleConfirm = () => { - const [subscription] = selected; - onConfirm(subscription); - onClose(); - }; - - useEffect(() => { - fetchSubscriptions(); - }, [fetchSubscriptions]); - - useEffect(() => { - if (selectedSubscription?.id) { - setSelected([selectedSubscription]); - } - }, []); // eslint-disable-line react-hooks/exhaustive-deps - - return ( - - Select - , - , - ]} - > - {isLoading && } - {!isLoading && error && ( - - - - <Trans>No subscriptions found</Trans> - - - - We were unable to locate licenses associated with this account. - {' '} - - - - - )} - {!isLoading && !error && subscriptions?.length === 0 && ( - - )} - {!isLoading && !error && subscriptions?.length > 0 && ( - - - - - {t`Name`} - {t`Managed nodes`} - {t`Expires`} - - - - {subscriptions.map((subscription) => ( - - setSelected([subscription]), - isSelected: selected.some( - (row) => row.id === subscription.id - ), - variant: 'radio', - rowIndex: `row-${subscription.id}`, - }} - /> - {subscription.subscription_name} - - {subscription.instance_count} - - - {formatDateString( - new Date(subscription.license_date * 1000).toISOString(), - 'UTC' - )} - - - ))} - - - )} - - ); -} - -export default SubscriptionModal; diff --git a/awx/ui/src/screens/Setting/Subscription/SubscriptionEdit/SubscriptionModal.test.js b/awx/ui/src/screens/Setting/Subscription/SubscriptionEdit/SubscriptionModal.test.js deleted file mode 100644 index 4c8fa843f225..000000000000 --- a/awx/ui/src/screens/Setting/Subscription/SubscriptionEdit/SubscriptionModal.test.js +++ /dev/null @@ -1,155 +0,0 @@ -import React from 'react'; -import { act } from 'react-dom/test-utils'; -import { ConfigAPI } from 'api'; -import { - mountWithContexts, - waitForElement, -} from '../../../../../testUtils/enzymeHelpers'; -import SubscriptionModal from './SubscriptionModal'; - -jest.mock('../../../../api'); - -describe('', () => { - let wrapper; - const onConfirm = jest.fn(); - const onClose = jest.fn(); - - beforeAll(async () => { - ConfigAPI.readSubscriptions = async () => ({ - data: [ - { - subscription_name: 'mock A', - instance_count: 100, - license_date: 1714000271, - pool_id: 7, - }, - { - subscription_name: 'mock B', - instance_count: 200, - license_date: 1714000271, - pool_id: 8, - }, - { - subscription_name: 'mock C', - instance_count: 30, - license_date: 1714000271, - pool_id: 9, - }, - ], - }); - await act(async () => { - wrapper = mountWithContexts( - - ); - await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0); - }); - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - test('initially renders without crashing', async () => { - expect(wrapper.find('SubscriptionModal').length).toBe(1); - }); - - test('should render header', async () => { - wrapper.update(); - const header = wrapper.find('tr').first().find('th'); - expect(header.at(0).text()).toEqual(''); - expect(header.at(1).text()).toEqual('Name'); - expect(header.at(2).text()).toEqual('Managed nodes'); - expect(header.at(3).text()).toEqual('Expires'); - }); - - test('should render subscription rows', async () => { - const rows = wrapper.find('tbody tr'); - expect(rows).toHaveLength(3); - const firstRow = rows.at(0).find('td'); - expect(firstRow.at(0).find('input[type="radio"]')).toHaveLength(1); - expect(firstRow.at(1).text()).toEqual('mock A'); - expect(firstRow.at(2).text()).toEqual('100'); - expect(firstRow.at(3).text()).toEqual('4/24/2024, 11:11:11 PM'); - }); - - test('submit button should call onConfirm', async () => { - expect( - wrapper.find('Button[aria-label="Confirm selection"]').prop('isDisabled') - ).toBe(true); - await act(async () => { - wrapper - .find('SubscriptionModal SelectColumn') - .first() - .invoke('onSelect')(); - }); - wrapper.update(); - expect( - wrapper.find('Button[aria-label="Confirm selection"]').prop('isDisabled') - ).toBe(false); - expect(onConfirm).toHaveBeenCalledTimes(0); - expect(onClose).toHaveBeenCalledTimes(0); - await act(async () => - wrapper.find('Button[aria-label="Confirm selection"]').prop('onClick')() - ); - expect(onConfirm).toHaveBeenCalledTimes(1); - expect(onClose).toHaveBeenCalledTimes(1); - }); - - test('should show empty content', async () => { - await act(async () => { - wrapper = mountWithContexts( - - ); - await waitForElement(wrapper, 'ContentEmpty', (el) => el.length === 1); - }); - }); - - test('should auto-select current selected subscription', async () => { - await act(async () => { - wrapper = mountWithContexts( - - ); - await waitForElement(wrapper, 'table'); - expect(wrapper.find('tr[id="row-1"] input').prop('checked')).toBe(false); - expect(wrapper.find('tr[id="row-2"] input').prop('checked')).toBe(true); - expect(wrapper.find('tr[id="row-3"] input').prop('checked')).toBe(false); - }); - }); - - test('should display error detail message', async () => { - ConfigAPI.readSubscriptions = jest.fn(); - ConfigAPI.readSubscriptions.mockRejectedValueOnce(new Error()); - await act(async () => { - wrapper = mountWithContexts( - - ); - }); - await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0); - await waitForElement(wrapper, 'ErrorDetail', (el) => el.length === 1); - }); -}); diff --git a/awx/ui/src/screens/Setting/Subscription/SubscriptionEdit/SubscriptionStep.js b/awx/ui/src/screens/Setting/Subscription/SubscriptionEdit/SubscriptionStep.js deleted file mode 100644 index 333a7939fdac..000000000000 --- a/awx/ui/src/screens/Setting/Subscription/SubscriptionEdit/SubscriptionStep.js +++ /dev/null @@ -1,266 +0,0 @@ -import React, { useState } from 'react'; - -import { Trans, t } from '@lingui/macro'; -import { useField, useFormikContext } from 'formik'; -import styled from 'styled-components'; -import { TimesIcon } from '@patternfly/react-icons'; -import { - Button, - Divider, - FileUpload, - Flex, - FlexItem, - FormGroup, - ToggleGroup, - ToggleGroupItem, - Tooltip, -} from '@patternfly/react-core'; -import { useConfig } from 'contexts/Config'; -import getDocsBaseUrl from 'util/getDocsBaseUrl'; -import useModal from 'hooks/useModal'; -import FormField, { PasswordField } from 'components/FormField'; -import Popover from 'components/Popover'; -import SubscriptionModal from './SubscriptionModal'; - -const LICENSELINK = 'https://www.ansible.com/license'; -const FileUploadField = styled(FormGroup)` - && { - max-width: 500px; - width: 100%; - } -`; - -function SubscriptionStep() { - const config = useConfig(); - const hasValidKey = Boolean(config?.license_info?.valid_key); - - const { values } = useFormikContext(); - - const [isSelected, setIsSelected] = useState( - values.subscription ? 'selectSubscription' : 'uploadManifest' - ); - const { isModalOpen, toggleModal, closeModal } = useModal(); - const [manifest, manifestMeta, manifestHelpers] = useField('manifest_file'); - const [manifestFilename, , manifestFilenameHelpers] = - useField('manifest_filename'); - const [subscription, , subscriptionHelpers] = useField('subscription'); - const [username, usernameMeta, usernameHelpers] = useField('username'); - const [password, passwordMeta, passwordHelpers] = useField('password'); - - return ( - - {!hasValidKey && ( - <> - - {t`Welcome to Red Hat Ansible Automation Platform! - Please complete the steps below to activate your subscription.`} - -

- {t`If you do not have a subscription, you can visit - Red Hat to obtain a trial subscription.`} -

- - - - )} -

{t`Select your Ansible Automation Platform subscription to use.`}

- - setIsSelected('uploadManifest')} - id="subscription-manifest" - /> - setIsSelected('selectSubscription')} - id="username-password" - /> - - {isSelected === 'uploadManifest' ? ( - <> -

- - Upload a Red Hat Subscription Manifest containing your - subscription. To generate your subscription manifest, go to{' '} - {' '} - on the Red Hat Customer Portal. - -

- - A subscription manifest is an export of a Red Hat - Subscription. To generate a subscription manifest, go to{' '} - - . For more information, see the{' '} - - . - - } - /> - } - > - manifestHelpers.setError(true), - }} - onChange={(value, filename) => { - if (!value) { - manifestHelpers.setValue(null); - manifestFilenameHelpers.setValue(''); - usernameHelpers.setValue(usernameMeta.initialValue); - passwordHelpers.setValue(passwordMeta.initialValue); - return; - } - - try { - const raw = new FileReader(); - raw.readAsBinaryString(value); - raw.onload = () => { - const rawValue = btoa(raw.result); - manifestHelpers.setValue(rawValue); - manifestFilenameHelpers.setValue(filename); - }; - } catch (err) { - manifestHelpers.setError(err); - } - }} - /> - - - ) : ( - <> -

- {t`Provide your Red Hat or Red Hat Satellite credentials - below and you can choose from a list of your available subscriptions. - The credentials you use will be stored for future use in - retrieving renewal or expanded subscriptions.`} -

- - - - - {isModalOpen && ( - subscriptionHelpers.setValue(value)} - /> - )} - - {subscription.value && ( - - {t`Selected`} - - {subscription?.value?.subscription_name} - - - - - - )} - - )} -
- ); -} -export default SubscriptionStep; diff --git a/awx/ui/src/screens/Setting/Subscription/SubscriptionEdit/SubscriptionStep.test.js b/awx/ui/src/screens/Setting/Subscription/SubscriptionEdit/SubscriptionStep.test.js deleted file mode 100644 index e539a06e08f5..000000000000 --- a/awx/ui/src/screens/Setting/Subscription/SubscriptionEdit/SubscriptionStep.test.js +++ /dev/null @@ -1,120 +0,0 @@ -import React from 'react'; -import { act } from 'react-dom/test-utils'; -import { Formik } from 'formik'; -import { mountWithContexts } from '../../../../../testUtils/enzymeHelpers'; -import SubscriptionStep from './SubscriptionStep'; - -describe('', () => { - let wrapper; - - beforeAll(async () => { - await act(async () => { - wrapper = mountWithContexts( - - - - ); - }); - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - test('initially renders without crashing', async () => { - expect(wrapper.find('SubscriptionStep').length).toBe(1); - }); - - test('should update filename when a manifest zip file is uploaded', async () => { - expect(wrapper.find('FileUploadField')).toHaveLength(1); - expect(wrapper.find('label').text()).toEqual( - 'Red Hat subscription manifest' - ); - expect(wrapper.find('FileUploadField').prop('value')).toEqual(null); - expect(wrapper.find('FileUploadField').prop('filename')).toEqual(''); - const mockFile = new Blob(['123'], { type: 'application/zip' }); - mockFile.name = 'new file name'; - mockFile.date = new Date(); - await act(async () => { - wrapper.find('FileUpload').invoke('onChange')(mockFile, 'new file name'); - }); - await act(async () => { - wrapper.update(); - }); - await act(async () => { - wrapper.update(); - }); - expect(wrapper.find('FileUploadField').prop('value')).toEqual( - expect.stringMatching(/^[\x00-\x7F]+$/) // eslint-disable-line no-control-regex - ); - expect(wrapper.find('FileUploadField').prop('filename')).toEqual( - 'new file name' - ); - }); - - test('clear button should clear manifest value and filename', async () => { - await act(async () => { - wrapper - .find('FileUpload .pf-c-input-group button') - .last() - .simulate('click'); - }); - wrapper.update(); - expect(wrapper.find('FileUploadField').prop('value')).toEqual(null); - expect(wrapper.find('FileUploadField').prop('filename')).toEqual(''); - }); - - test('FileUpload should throw an error', async () => { - expect( - wrapper.find('div#subscription-manifest-helper.pf-m-error') - ).toHaveLength(0); - await act(async () => { - wrapper.find('FileUpload').invoke('onChange')('✓', 'new file name'); - }); - wrapper.update(); - expect( - wrapper.find('div#subscription-manifest-helper.pf-m-error') - ).toHaveLength(1); - expect(wrapper.find('div#subscription-manifest-helper').text()).toContain( - 'Invalid file format. Please upload a valid Red Hat Subscription Manifest.' - ); - }); - - test('Username/password toggle button should show username credential fields', async () => { - expect(wrapper.find('ToggleGroupItem').last().props().isSelected).toBe( - false - ); - wrapper - .find('ToggleGroupItem[text="Username / password"] button') - .simulate('click'); - wrapper.update(); - expect(wrapper.find('ToggleGroupItem').last().props().isSelected).toBe( - true - ); - await act(async () => { - wrapper.find('input#username-field').simulate('change', { - target: { value: 'username-cred', name: 'username' }, - }); - wrapper.find('input#password-field').simulate('change', { - target: { value: 'password-cred', name: 'password' }, - }); - }); - wrapper.update(); - expect(wrapper.find('input#username-field').prop('value')).toEqual( - 'username-cred' - ); - expect(wrapper.find('input#password-field').prop('value')).toEqual( - 'password-cred' - ); - }); -}); diff --git a/awx/ui/src/screens/Setting/Subscription/SubscriptionEdit/index.js b/awx/ui/src/screens/Setting/Subscription/SubscriptionEdit/index.js deleted file mode 100644 index 1b9aeadaec11..000000000000 --- a/awx/ui/src/screens/Setting/Subscription/SubscriptionEdit/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './SubscriptionEdit'; diff --git a/awx/ui/src/screens/Setting/Subscription/index.js b/awx/ui/src/screens/Setting/Subscription/index.js deleted file mode 100644 index 41a92af34fa3..000000000000 --- a/awx/ui/src/screens/Setting/Subscription/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Subscription'; diff --git a/awx/ui/src/screens/Setting/TACACS/TACACS.js b/awx/ui/src/screens/Setting/TACACS/TACACS.js deleted file mode 100644 index 720ac4d1ca7b..000000000000 --- a/awx/ui/src/screens/Setting/TACACS/TACACS.js +++ /dev/null @@ -1,34 +0,0 @@ -import React from 'react'; -import { Link, Redirect, Route, Switch } from 'react-router-dom'; - -import { t } from '@lingui/macro'; -import { PageSection, Card } from '@patternfly/react-core'; -import ContentError from 'components/ContentError'; -import TACACSDetail from './TACACSDetail'; -import TACACSEdit from './TACACSEdit'; - -function TACACS() { - const baseURL = '/settings/tacacs'; - return ( - - - - - - - - - - - - - {t`View TACACS+ settings`} - - - - - - ); -} - -export default TACACS; diff --git a/awx/ui/src/screens/Setting/TACACS/TACACS.test.js b/awx/ui/src/screens/Setting/TACACS/TACACS.test.js deleted file mode 100644 index 4a44ac73a794..000000000000 --- a/awx/ui/src/screens/Setting/TACACS/TACACS.test.js +++ /dev/null @@ -1,73 +0,0 @@ -import React from 'react'; -import { act } from 'react-dom/test-utils'; -import { createMemoryHistory } from 'history'; -import { SettingsProvider } from 'contexts/Settings'; -import { SettingsAPI } from 'api'; -import { mountWithContexts } from '../../../../testUtils/enzymeHelpers'; -import mockAllOptions from '../shared/data.allSettingOptions.json'; -import TACACS from './TACACS'; - -jest.mock('../../../api/models/Settings'); -SettingsAPI.readCategory.mockResolvedValue({ - data: { - TACACSPLUS_HOST: 'mockhost', - TACACSPLUS_PORT: 49, - TACACSPLUS_SECRET: '$encrypted$', - TACACSPLUS_SESSION_TIMEOUT: 5, - TACACSPLUS_AUTH_PROTOCOL: 'ascii', - }, -}); - -describe('', () => { - let wrapper; - - afterEach(() => { - jest.clearAllMocks(); - }); - - test('should render TACACS+ details', async () => { - const history = createMemoryHistory({ - initialEntries: ['/settings/tacacs/details'], - }); - await act(async () => { - wrapper = mountWithContexts( - - - , - { - context: { router: { history } }, - } - ); - }); - expect(wrapper.find('TACACSDetail').length).toBe(1); - }); - - test('should render TACACS+ edit', async () => { - const history = createMemoryHistory({ - initialEntries: ['/settings/tacacs/edit'], - }); - await act(async () => { - wrapper = mountWithContexts( - - - , - { - context: { router: { history } }, - } - ); - }); - expect(wrapper.find('TACACSEdit').length).toBe(1); - }); - - test('should show content error when user navigates to erroneous route', async () => { - const history = createMemoryHistory({ - initialEntries: ['/settings/tacacs/foo'], - }); - await act(async () => { - wrapper = mountWithContexts(, { - context: { router: { history } }, - }); - }); - expect(wrapper.find('ContentError').length).toBe(1); - }); -}); diff --git a/awx/ui/src/screens/Setting/TACACS/TACACSDetail/TACACSDetail.js b/awx/ui/src/screens/Setting/TACACS/TACACSDetail/TACACSDetail.js deleted file mode 100644 index 2311759d5a11..000000000000 --- a/awx/ui/src/screens/Setting/TACACS/TACACSDetail/TACACSDetail.js +++ /dev/null @@ -1,117 +0,0 @@ -import React, { useEffect, useCallback } from 'react'; -import { Link } from 'react-router-dom'; - -import { t } from '@lingui/macro'; -import { Button, Alert as PFAlert } from '@patternfly/react-core'; -import { CaretLeftIcon } from '@patternfly/react-icons'; -import styled from 'styled-components'; -import { CardBody, CardActionsRow } from 'components/Card'; -import ContentLoading from 'components/ContentLoading'; -import ContentError from 'components/ContentError'; -import RoutedTabs from 'components/RoutedTabs'; -import { SettingsAPI } from 'api'; -import useRequest from 'hooks/useRequest'; -import { DetailList } from 'components/DetailList'; -import { useConfig } from 'contexts/Config'; -import { useSettings } from 'contexts/Settings'; -import { SettingDetail } from '../../shared'; - -const Alert = styled(PFAlert)` - margin-bottom: 20px; -`; - -function TACACSDetail() { - const { me } = useConfig(); - const { GET: options } = useSettings(); - - const { - isLoading, - error, - request, - result: tacacs, - } = useRequest( - useCallback(async () => { - const { data } = await SettingsAPI.readCategory('tacacsplus'); - return data; - }, []), - null - ); - - useEffect(() => { - request(); - }, [request]); - - const tabsArray = [ - { - name: ( - <> - - {t`Back to Settings`} - - ), - link: `/settings`, - id: 99, - }, - { - name: t`Details`, - link: `/settings/tacacs/details`, - id: 0, - }, - ]; - if (isLoading) { - return ; - } - if (!isLoading && error) { - return ; - } - return ( - <> - - - {isLoading && } - {!isLoading && error && } - {!isLoading && tacacs && ( - <> - - - {Object.keys(tacacs).map((key) => { - const record = options?.[key]; - return ( - - ); - })} - - - )} - {me?.is_superuser && ( - - - - )} - - - ); -} - -export default TACACSDetail; diff --git a/awx/ui/src/screens/Setting/TACACS/TACACSDetail/TACACSDetail.test.js b/awx/ui/src/screens/Setting/TACACS/TACACSDetail/TACACSDetail.test.js deleted file mode 100644 index 3244c1110d26..000000000000 --- a/awx/ui/src/screens/Setting/TACACS/TACACSDetail/TACACSDetail.test.js +++ /dev/null @@ -1,99 +0,0 @@ -import React from 'react'; -import { act } from 'react-dom/test-utils'; -import { SettingsProvider } from 'contexts/Settings'; -import { SettingsAPI } from 'api'; -import { - mountWithContexts, - waitForElement, -} from '../../../../../testUtils/enzymeHelpers'; -import { assertDetail } from '../../shared/settingTestUtils'; -import mockAllOptions from '../../shared/data.allSettingOptions.json'; -import TACACSDetail from './TACACSDetail'; - -jest.mock('../../../../api'); - -describe('', () => { - let wrapper; - - beforeEach(() => { - SettingsAPI.readCategory.mockResolvedValue({ - data: { - TACACSPLUS_HOST: 'mockhost', - TACACSPLUS_PORT: 49, - TACACSPLUS_SECRET: '$encrypted$', - TACACSPLUS_SESSION_TIMEOUT: 5, - TACACSPLUS_AUTH_PROTOCOL: 'ascii', - }, - }); - }); - - beforeEach(async () => { - await act(async () => { - wrapper = mountWithContexts( - - - - ); - }); - await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0); - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - test('initially renders without crashing', () => { - expect(wrapper.find('TACACSDetail').length).toBe(1); - }); - - test('should render expected tabs', () => { - const expectedTabs = ['Back to Settings', 'Details']; - wrapper.find('RoutedTabs li').forEach((tab, index) => { - expect(tab.text()).toEqual(expectedTabs[index]); - }); - }); - - test('should render expected details', () => { - expect(wrapper.find('Alert').prop('title')).toBe( - 'This feature is deprecated and will be removed in a future release.' - ); - assertDetail(wrapper, 'TACACS+ Server', 'mockhost'); - assertDetail(wrapper, 'TACACS+ Port', '49'); - assertDetail(wrapper, 'TACACS+ Secret', 'Encrypted'); - assertDetail(wrapper, 'TACACS+ Auth Session Timeout', '5 seconds'); - assertDetail(wrapper, 'TACACS+ Authentication Protocol', 'ascii'); - }); - - test('should hide edit button from non-superusers', async () => { - const config = { - me: { - is_superuser: false, - }, - }; - await act(async () => { - wrapper = mountWithContexts( - - - , - { - context: { config }, - } - ); - }); - await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0); - expect(wrapper.find('Button[aria-label="Edit"]').exists()).toBeFalsy(); - }); - - test('should display content error when api throws error on initial render', async () => { - SettingsAPI.readCategory.mockRejectedValue(new Error()); - await act(async () => { - wrapper = mountWithContexts( - - - - ); - }); - await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0); - expect(wrapper.find('ContentError').length).toBe(1); - }); -}); diff --git a/awx/ui/src/screens/Setting/TACACS/TACACSDetail/index.js b/awx/ui/src/screens/Setting/TACACS/TACACSDetail/index.js deleted file mode 100644 index 1720e8b92180..000000000000 --- a/awx/ui/src/screens/Setting/TACACS/TACACSDetail/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './TACACSDetail'; diff --git a/awx/ui/src/screens/Setting/TACACS/TACACSEdit/TACACSEdit.js b/awx/ui/src/screens/Setting/TACACS/TACACSEdit/TACACSEdit.js deleted file mode 100644 index d1894b53c807..000000000000 --- a/awx/ui/src/screens/Setting/TACACS/TACACSEdit/TACACSEdit.js +++ /dev/null @@ -1,141 +0,0 @@ -import React, { useCallback, useEffect } from 'react'; -import { useHistory } from 'react-router-dom'; -import { Formik } from 'formik'; -import { Form } from '@patternfly/react-core'; -import { CardBody } from 'components/Card'; -import ContentError from 'components/ContentError'; -import ContentLoading from 'components/ContentLoading'; -import { FormSubmitError } from 'components/FormField'; -import { FormColumnLayout } from 'components/FormLayout'; -import { useSettings } from 'contexts/Settings'; -import useModal from 'hooks/useModal'; -import useRequest from 'hooks/useRequest'; -import { SettingsAPI } from 'api'; -import { - ChoiceField, - EncryptedField, - InputField, -} from '../../shared/SharedFields'; -import { RevertAllAlert, RevertFormActionGroup } from '../../shared'; - -function TACACSEdit() { - const history = useHistory(); - const { isModalOpen, toggleModal, closeModal } = useModal(); - const { PUT: options } = useSettings(); - - const { - isLoading, - error, - request: fetchTACACS, - result: tacacs, - } = useRequest( - useCallback(async () => { - const { data } = await SettingsAPI.readCategory('tacacsplus'); - const mergedData = {}; - Object.keys(data).forEach((key) => { - mergedData[key] = options[key]; - mergedData[key].value = data[key]; - }); - return mergedData; - }, [options]), - null - ); - - useEffect(() => { - fetchTACACS(); - }, [fetchTACACS]); - - const { error: submitError, request: submitForm } = useRequest( - useCallback( - async (values) => { - await SettingsAPI.updateAll(values); - history.push('/settings/tacacs/details'); - }, - [history] - ), - null - ); - - const { error: revertError, request: revertAll } = useRequest( - useCallback(async () => { - await SettingsAPI.revertCategory('tacacsplus'); - }, []), - null - ); - - const handleSubmit = async (form) => { - await submitForm(form); - }; - - const handleRevertAll = async () => { - await revertAll(); - - closeModal(); - - history.push('/settings/tacacs/details'); - }; - - const handleCancel = () => { - history.push('/settings/tacacs/details'); - }; - - const initialValues = (fields) => - Object.keys(fields).reduce((acc, key) => { - acc[key] = fields[key].value ?? ''; - return acc; - }, {}); - - return ( - - {isLoading && } - {!isLoading && error && } - {!isLoading && tacacs && ( - - {(formik) => ( -
- - - - - - - {submitError && } - {revertError && } - - - {isModalOpen && ( - - )} - - )} -
- )} -
- ); -} - -export default TACACSEdit; diff --git a/awx/ui/src/screens/Setting/TACACS/TACACSEdit/TACACSEdit.test.js b/awx/ui/src/screens/Setting/TACACS/TACACSEdit/TACACSEdit.test.js deleted file mode 100644 index 4e41ddd58b5f..000000000000 --- a/awx/ui/src/screens/Setting/TACACS/TACACSEdit/TACACSEdit.test.js +++ /dev/null @@ -1,163 +0,0 @@ -import React from 'react'; -import { act } from 'react-dom/test-utils'; -import { createMemoryHistory } from 'history'; -import { SettingsProvider } from 'contexts/Settings'; -import { SettingsAPI } from 'api'; -import { - mountWithContexts, - waitForElement, -} from '../../../../../testUtils/enzymeHelpers'; -import mockAllOptions from '../../shared/data.allSettingOptions.json'; -import TACACSEdit from './TACACSEdit'; - -jest.mock('../../../../api/'); - -describe('', () => { - let wrapper; - let history; - - beforeEach(() => { - SettingsAPI.revertCategory.mockResolvedValue({}); - SettingsAPI.updateAll.mockResolvedValue({}); - SettingsAPI.readCategory.mockResolvedValue({ - data: { - TACACSPLUS_HOST: 'mockhost', - TACACSPLUS_PORT: 49, - TACACSPLUS_SECRET: '$encrypted$', - TACACSPLUS_SESSION_TIMEOUT: 123, - TACACSPLUS_AUTH_PROTOCOL: 'ascii', - }, - }); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - beforeEach(async () => { - history = createMemoryHistory({ - initialEntries: ['/settings/tacacs/edit'], - }); - await act(async () => { - wrapper = mountWithContexts( - - - , - { - context: { router: { history } }, - } - ); - }); - await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0); - }); - - test('initially renders without crashing', () => { - expect(wrapper.find('TACACSEdit').length).toBe(1); - }); - - test('should display expected form fields', async () => { - expect(wrapper.find('FormGroup[label="TACACS+ Server"]').length).toBe(1); - expect(wrapper.find('FormGroup[label="TACACS+ Port"]').length).toBe(1); - expect(wrapper.find('FormGroup[label="TACACS+ Secret"]').length).toBe(1); - expect( - wrapper.find('FormGroup[label="TACACS+ Auth Session Timeout"]').length - ).toBe(1); - expect( - wrapper.find('FormGroup[label="TACACS+ Authentication Protocol"]').length - ).toBe(1); - }); - - test('should successfully send default values to api on form revert all', async () => { - expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(0); - expect(wrapper.find('RevertAllAlert')).toHaveLength(0); - await act(async () => { - wrapper - .find('button[aria-label="Revert all to default"]') - .invoke('onClick')(); - }); - wrapper.update(); - expect(wrapper.find('RevertAllAlert')).toHaveLength(1); - await act(async () => { - wrapper - .find('RevertAllAlert button[aria-label="Confirm revert all"]') - .invoke('onClick')(); - }); - wrapper.update(); - expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1); - expect(SettingsAPI.revertCategory).toHaveBeenCalledWith('tacacsplus'); - }); - - test('should successfully send request to api on form submission', async () => { - act(() => { - wrapper.find('input#TACACSPLUS_HOST').simulate('change', { - target: { value: 'new_host', name: 'TACACSPLUS_HOST' }, - }); - wrapper.find('input#TACACSPLUS_PORT').simulate('change', { - target: { value: 999, name: 'TACACSPLUS_PORT' }, - }); - wrapper - .find( - 'FormGroup[fieldId="TACACSPLUS_SECRET"] button[aria-label="Revert"]' - ) - .invoke('onClick')(); - }); - wrapper.update(); - await act(async () => { - wrapper.find('Form').invoke('onSubmit')(); - }); - expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1); - expect(SettingsAPI.updateAll).toHaveBeenCalledWith({ - TACACSPLUS_HOST: 'new_host', - TACACSPLUS_PORT: 999, - TACACSPLUS_SECRET: '', - TACACSPLUS_SESSION_TIMEOUT: 123, - TACACSPLUS_AUTH_PROTOCOL: 'ascii', - }); - }); - - test('should navigate to tacacs detail on successful submission', async () => { - await act(async () => { - wrapper.find('Form').invoke('onSubmit')(); - }); - expect(history.location.pathname).toEqual('/settings/tacacs/details'); - }); - - test('should navigate to tacacs detail when cancel is clicked', async () => { - await act(async () => { - wrapper.find('button[aria-label="Cancel"]').invoke('onClick')(); - }); - expect(history.location.pathname).toEqual('/settings/tacacs/details'); - }); - - test('should display error message on unsuccessful submission', async () => { - const error = { - response: { - data: { detail: 'An error occurred' }, - }, - }; - SettingsAPI.updateAll.mockImplementation(() => Promise.reject(error)); - expect(wrapper.find('FormSubmitError').length).toBe(0); - expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(0); - await act(async () => { - wrapper.find('Form').invoke('onSubmit')(); - }); - wrapper.update(); - expect(wrapper.find('FormSubmitError').length).toBe(1); - expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1); - }); - - test('should display ContentError on throw', async () => { - SettingsAPI.readCategory.mockImplementationOnce(() => - Promise.reject(new Error()) - ); - await act(async () => { - wrapper = mountWithContexts( - - - - ); - }); - await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0); - expect(wrapper.find('ContentError').length).toBe(1); - }); -}); diff --git a/awx/ui/src/screens/Setting/TACACS/TACACSEdit/index.js b/awx/ui/src/screens/Setting/TACACS/TACACSEdit/index.js deleted file mode 100644 index 2b95f71aa8b6..000000000000 --- a/awx/ui/src/screens/Setting/TACACS/TACACSEdit/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './TACACSEdit'; diff --git a/awx/ui/src/screens/Setting/TACACS/index.js b/awx/ui/src/screens/Setting/TACACS/index.js deleted file mode 100644 index d1cb31279ef7..000000000000 --- a/awx/ui/src/screens/Setting/TACACS/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './TACACS'; diff --git a/awx/ui/src/screens/Setting/UI/UI.js b/awx/ui/src/screens/Setting/UI/UI.js deleted file mode 100644 index a2e683e15d22..000000000000 --- a/awx/ui/src/screens/Setting/UI/UI.js +++ /dev/null @@ -1,36 +0,0 @@ -import React from 'react'; -import { Link, Redirect, Route, Switch } from 'react-router-dom'; - -import { t } from '@lingui/macro'; -import { PageSection, Card } from '@patternfly/react-core'; -import ContentError from 'components/ContentError'; -import UIDetail from './UIDetail'; -import UIEdit from './UIEdit'; - -function UI() { - const baseURL = '/settings/ui'; - return ( - - - - - - - - - - - - - - {t`View User Interface settings`} - - - - - - - ); -} - -export default UI; diff --git a/awx/ui/src/screens/Setting/UI/UI.test.js b/awx/ui/src/screens/Setting/UI/UI.test.js deleted file mode 100644 index 84e1d63a54ef..000000000000 --- a/awx/ui/src/screens/Setting/UI/UI.test.js +++ /dev/null @@ -1,76 +0,0 @@ -import React from 'react'; -import { act } from 'react-dom/test-utils'; -import { createMemoryHistory } from 'history'; -import { SettingsAPI } from 'api'; -import { SettingsProvider } from 'contexts/Settings'; -import { - mountWithContexts, - waitForElement, -} from '../../../../testUtils/enzymeHelpers'; -import mockAllOptions from '../shared/data.allSettingOptions.json'; -import UI from './UI'; - -jest.mock('../../../api/models/Settings'); -SettingsAPI.readCategory.mockResolvedValue({ - data: { - CUSTOM_LOGIN_INFO: '', - CUSTOM_LOGO: '', - PENDO_TRACKING_STATE: 'off', - }, -}); - -describe('', () => { - let wrapper; - - afterEach(() => { - jest.clearAllMocks(); - }); - - test('should render user interface details', async () => { - const history = createMemoryHistory({ - initialEntries: ['/settings/ui/details'], - }); - await act(async () => { - wrapper = mountWithContexts( - - - , - { - context: { router: { history } }, - } - ); - }); - await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0); - expect(wrapper.find('UIDetail').length).toBe(1); - }); - - test('should render user interface edit', async () => { - const history = createMemoryHistory({ - initialEntries: ['/settings/ui/edit'], - }); - await act(async () => { - wrapper = mountWithContexts( - - - , - { - context: { router: { history } }, - } - ); - }); - await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0); - expect(wrapper.find('UIEdit').length).toBe(1); - }); - - test('should show content error when user navigates to erroneous route', async () => { - const history = createMemoryHistory({ - initialEntries: ['/settings/ui/foo'], - }); - await act(async () => { - wrapper = mountWithContexts(, { - context: { router: { history } }, - }); - }); - expect(wrapper.find('ContentError').length).toBe(1); - }); -}); diff --git a/awx/ui/src/screens/Setting/UI/UIDetail/UIDetail.js b/awx/ui/src/screens/Setting/UI/UIDetail/UIDetail.js deleted file mode 100644 index f02f78d4f743..000000000000 --- a/awx/ui/src/screens/Setting/UI/UIDetail/UIDetail.js +++ /dev/null @@ -1,119 +0,0 @@ -import React, { useEffect, useCallback } from 'react'; -import { Link, useHistory, useLocation } from 'react-router-dom'; - -import { t } from '@lingui/macro'; -import { Button } from '@patternfly/react-core'; -import { CaretLeftIcon } from '@patternfly/react-icons'; -import { CardBody, CardActionsRow } from 'components/Card'; -import ContentLoading from 'components/ContentLoading'; -import ContentError from 'components/ContentError'; -import RoutedTabs from 'components/RoutedTabs'; -import { SettingsAPI } from 'api'; -import useRequest from 'hooks/useRequest'; -import { DetailList } from 'components/DetailList'; -import { useConfig } from 'contexts/Config'; -import { useSettings } from 'contexts/Settings'; -import { pluck } from '../../shared/settingUtils'; -import { SettingDetail } from '../../shared'; - -function UIDetail() { - const { me } = useConfig(); - const { GET: options } = useSettings(); - const history = useHistory(); - const { hardReload } = useLocation(); - - if (hardReload) { - history.go(); - } - - const { - isLoading, - error, - request, - result: ui, - } = useRequest( - useCallback(async () => { - const { data } = await SettingsAPI.readCategory('ui'); - - const uiData = pluck( - data, - 'PENDO_TRACKING_STATE', - 'CUSTOM_LOGO', - 'CUSTOM_LOGIN_INFO' - ); - - return uiData; - }, []), - null - ); - - useEffect(() => { - request(); - }, [request]); - - const tabsArray = [ - { - name: ( - <> - - {t`Back to Settings`} - - ), - link: `/settings`, - id: 99, - }, - { - name: t`Details`, - link: `/settings/ui/details`, - id: 0, - }, - ]; - - // Change CUSTOM_LOGO type from string to image - // to help SettingDetail render it as an - if (options?.CUSTOM_LOGO) { - options.CUSTOM_LOGO.type = 'image'; - } - - return ( - <> - - - {isLoading && } - {!isLoading && error && } - {!isLoading && ui && ( - - {Object.keys(ui).map((key) => { - const record = options?.[key]; - return ( - - ); - })} - - )} - {me?.is_superuser && ( - - - - )} - - - ); -} - -export default UIDetail; diff --git a/awx/ui/src/screens/Setting/UI/UIDetail/UIDetail.test.js b/awx/ui/src/screens/Setting/UI/UIDetail/UIDetail.test.js deleted file mode 100644 index 39249cfb051d..000000000000 --- a/awx/ui/src/screens/Setting/UI/UIDetail/UIDetail.test.js +++ /dev/null @@ -1,95 +0,0 @@ -import React from 'react'; -import { act } from 'react-dom/test-utils'; -import { SettingsProvider } from 'contexts/Settings'; -import { SettingsAPI } from 'api'; -import { - mountWithContexts, - waitForElement, -} from '../../../../../testUtils/enzymeHelpers'; -import { assertDetail } from '../../shared/settingTestUtils'; -import mockAllOptions from '../../shared/data.allSettingOptions.json'; -import UIDetail from './UIDetail'; - -jest.mock('../../../../api'); - -describe('', () => { - let wrapper; - - beforeEach(() => { - SettingsAPI.readCategory.mockResolvedValue({ - data: { - CUSTOM_LOGIN_INFO: 'mock info', - CUSTOM_LOGO: 'data:image/png', - PENDO_TRACKING_STATE: 'off', - }, - }); - }); - - beforeEach(async () => { - await act(async () => { - wrapper = mountWithContexts( - - - - ); - }); - await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0); - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - test('initially renders without crashing', () => { - expect(wrapper.find('UIDetail').length).toBe(1); - }); - - test('should render expected tabs', () => { - const expectedTabs = ['Back to Settings', 'Details']; - wrapper.find('RoutedTabs li').forEach((tab, index) => { - expect(tab.text()).toEqual(expectedTabs[index]); - }); - }); - - test('should render expected details', () => { - assertDetail(wrapper, 'User Analytics Tracking State', 'off'); - assertDetail(wrapper, 'Custom Login Info', 'mock info'); - expect(wrapper.find('Detail[label="Custom Logo"] dt').text()).toBe( - 'Custom Logo' - ); - expect(wrapper.find('Detail[label="Custom Logo"] dd img').length).toBe(1); - }); - - test('should hide edit button from non-superusers', async () => { - const config = { - me: { - is_superuser: false, - }, - }; - await act(async () => { - wrapper = mountWithContexts( - - - , - { - context: { config }, - } - ); - }); - await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0); - expect(wrapper.find('Button[aria-label="Edit"]').exists()).toBeFalsy(); - }); - - test('should display content error when api throws error on initial render', async () => { - SettingsAPI.readCategory.mockRejectedValue(new Error()); - await act(async () => { - wrapper = mountWithContexts( - - - - ); - }); - await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0); - expect(wrapper.find('ContentError').length).toBe(1); - }); -}); diff --git a/awx/ui/src/screens/Setting/UI/UIDetail/index.js b/awx/ui/src/screens/Setting/UI/UIDetail/index.js deleted file mode 100644 index 791d1d88734d..000000000000 --- a/awx/ui/src/screens/Setting/UI/UIDetail/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './UIDetail'; diff --git a/awx/ui/src/screens/Setting/UI/UIEdit/UIEdit.js b/awx/ui/src/screens/Setting/UI/UIEdit/UIEdit.js deleted file mode 100644 index a86d94829312..000000000000 --- a/awx/ui/src/screens/Setting/UI/UIEdit/UIEdit.js +++ /dev/null @@ -1,152 +0,0 @@ -import React, { useCallback, useEffect } from 'react'; -import { useHistory } from 'react-router-dom'; -import { Formik } from 'formik'; -import { Form } from '@patternfly/react-core'; -import { CardBody } from 'components/Card'; -import ContentError from 'components/ContentError'; -import ContentLoading from 'components/ContentLoading'; -import { FormSubmitError } from 'components/FormField'; -import { FormColumnLayout } from 'components/FormLayout'; -import { useSettings } from 'contexts/Settings'; -import { useConfig } from 'contexts/Config'; -import useModal from 'hooks/useModal'; -import useRequest from 'hooks/useRequest'; -import { SettingsAPI } from 'api'; -import { - ChoiceField, - FileUploadField, - TextAreaField, -} from '../../shared/SharedFields'; -import { RevertAllAlert, RevertFormActionGroup } from '../../shared'; - -function UIEdit() { - const history = useHistory(); - const { isModalOpen, toggleModal, closeModal } = useModal(); - const { PUT: options } = useSettings(); - const { license_info } = useConfig(); - - const { - isLoading, - error, - request: fetchUI, - result: uiData, - } = useRequest( - useCallback(async () => { - const { data } = await SettingsAPI.readCategory('ui'); - const mergedData = {}; - Object.keys(data).forEach((key) => { - if (!options[key]) { - return; - } - mergedData[key] = options[key]; - mergedData[key].value = data[key]; - }); - return mergedData; - }, [options]), - null - ); - - useEffect(() => { - fetchUI(); - }, [fetchUI]); - - const { error: submitError, request: submitForm } = useRequest( - useCallback( - async (values) => { - await SettingsAPI.updateAll(values); - if ( - values?.PENDO_TRACKING_STATE !== uiData?.PENDO_TRACKING_STATE?.value - ) { - history.push({ - pathname: '/settings/ui/details', - hardReload: true, - }); - } else { - history.push('/settings/ui/details'); - } - }, - [history, uiData] - ), - null - ); - - const { error: revertError, request: revertAll } = useRequest( - useCallback(async () => { - await SettingsAPI.revertCategory('ui'); - }, []), - null - ); - - const handleSubmit = async (form) => { - await submitForm(form); - }; - - const handleRevertAll = async () => { - await revertAll(); - - closeModal(); - - history.push({ - pathname: '/settings/ui/details', - hardReload: true, - }); - }; - - const handleCancel = () => { - history.push('/settings/ui/details'); - }; - - return ( - - {isLoading && } - {!isLoading && error && } - {!isLoading && uiData && ( - - {(formik) => ( -
- - - - - {submitError && } - {revertError && } - - - {isModalOpen && ( - - )} - - )} -
- )} -
- ); -} - -export default UIEdit; diff --git a/awx/ui/src/screens/Setting/UI/UIEdit/UIEdit.test.js b/awx/ui/src/screens/Setting/UI/UIEdit/UIEdit.test.js deleted file mode 100644 index fa3f0f57adf3..000000000000 --- a/awx/ui/src/screens/Setting/UI/UIEdit/UIEdit.test.js +++ /dev/null @@ -1,165 +0,0 @@ -import React from 'react'; -import { act } from 'react-dom/test-utils'; -import { createMemoryHistory } from 'history'; -import { SettingsProvider } from 'contexts/Settings'; -import { SettingsAPI } from 'api'; -import { - mountWithContexts, - waitForElement, -} from '../../../../../testUtils/enzymeHelpers'; -import mockAllOptions from '../../shared/data.allSettingOptions.json'; -import UIEdit from './UIEdit'; - -jest.mock('../../../../api'); - -describe('', () => { - let wrapper; - let history; - - beforeEach(() => { - SettingsAPI.revertCategory.mockResolvedValue({}); - SettingsAPI.updateAll.mockResolvedValue({}); - SettingsAPI.readCategory.mockResolvedValue({ - data: { - CUSTOM_LOGIN_INFO: 'mock info', - CUSTOM_LOGO: 'data:mock/jpeg;', - PENDO_TRACKING_STATE: 'detailed', - }, - }); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - beforeEach(async () => { - history = createMemoryHistory({ - initialEntries: ['/settings/ui/edit'], - }); - await act(async () => { - wrapper = mountWithContexts( - - - , - { - context: { router: { history } }, - } - ); - }); - await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0); - }); - - test('initially renders without crashing', () => { - expect(wrapper.find('UIEdit').length).toBe(1); - }); - - test('should display expected form fields', async () => { - expect(wrapper.find('FormGroup[label="Custom Login Info"]').length).toBe(1); - expect(wrapper.find('FormGroup[label="Custom Logo"]').length).toBe(1); - expect( - wrapper.find('FormGroup[label="User Analytics Tracking State"]').length - ).toBe(1); - }); - - test('should successfully send default values to api on form revert all', async () => { - expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(0); - expect(wrapper.find('RevertAllAlert')).toHaveLength(0); - await act(async () => { - wrapper - .find('button[aria-label="Revert all to default"]') - .invoke('onClick')(); - }); - wrapper.update(); - expect(wrapper.find('RevertAllAlert')).toHaveLength(1); - await act(async () => { - wrapper - .find('RevertAllAlert button[aria-label="Confirm revert all"]') - .invoke('onClick')(); - }); - wrapper.update(); - expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1); - expect(SettingsAPI.revertCategory).toHaveBeenCalledWith('ui'); - }); - - test('should successfully send request to api on form submission', async () => { - act(() => { - wrapper.find('textarea#CUSTOM_LOGIN_INFO').simulate('change', { - target: { value: 'new login info', name: 'CUSTOM_LOGIN_INFO' }, - }); - wrapper - .find('FormGroup[fieldId="CUSTOM_LOGO"] button[aria-label="Revert"]') - .invoke('onClick')(); - }); - wrapper.update(); - await act(async () => { - wrapper.find('Form').invoke('onSubmit')(); - }); - expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1); - expect(SettingsAPI.updateAll).toHaveBeenCalledWith({ - CUSTOM_LOGIN_INFO: 'new login info', - CUSTOM_LOGO: '', - PENDO_TRACKING_STATE: 'detailed', - }); - }); - - test('should navigate to ui detail on successful submission', async () => { - await act(async () => { - wrapper.find('Form').invoke('onSubmit')(); - }); - expect(history.location.pathname).toEqual('/settings/ui/details'); - expect(history.location.hardReload).toEqual(undefined); - }); - - test('should navigate to ui detail with reload param on successful submission where PENDO_TRACKING_STATE changes', async () => { - act(() => { - wrapper.find('select#PENDO_TRACKING_STATE').simulate('change', { - target: { value: 'off', name: 'CUSTOM_LOGIN_INFO' }, - }); - }); - wrapper.update(); - await act(async () => { - wrapper.find('Form').invoke('onSubmit')(); - }); - expect(history.location.pathname).toEqual('/settings/ui/details'); - expect(history.location.hardReload).toEqual(true); - }); - - test('should navigate to ui detail when cancel is clicked', async () => { - await act(async () => { - wrapper.find('button[aria-label="Cancel"]').invoke('onClick')(); - }); - expect(history.location.pathname).toEqual('/settings/ui/details'); - }); - - test('should display error message on unsuccessful submission', async () => { - const error = { - response: { - data: { detail: 'An error occurred' }, - }, - }; - SettingsAPI.updateAll.mockImplementation(() => Promise.reject(error)); - expect(wrapper.find('FormSubmitError').length).toBe(0); - expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(0); - await act(async () => { - wrapper.find('Form').invoke('onSubmit')(); - }); - wrapper.update(); - expect(wrapper.find('FormSubmitError').length).toBe(1); - expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1); - }); - - test('should display ContentError on throw', async () => { - SettingsAPI.readCategory.mockImplementationOnce(() => - Promise.reject(new Error()) - ); - await act(async () => { - wrapper = mountWithContexts( - - - - ); - }); - await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0); - expect(wrapper.find('ContentError').length).toBe(1); - }); -}); diff --git a/awx/ui/src/screens/Setting/UI/UIEdit/index.js b/awx/ui/src/screens/Setting/UI/UIEdit/index.js deleted file mode 100644 index affad29bf8da..000000000000 --- a/awx/ui/src/screens/Setting/UI/UIEdit/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './UIEdit'; diff --git a/awx/ui/src/screens/Setting/UI/index.js b/awx/ui/src/screens/Setting/UI/index.js deleted file mode 100644 index a33b447adfa2..000000000000 --- a/awx/ui/src/screens/Setting/UI/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './UI'; diff --git a/awx/ui/src/screens/Setting/index.js b/awx/ui/src/screens/Setting/index.js deleted file mode 100644 index 63a5e968e443..000000000000 --- a/awx/ui/src/screens/Setting/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Settings'; diff --git a/awx/ui/src/screens/Setting/shared/RevertAllAlert.js b/awx/ui/src/screens/Setting/shared/RevertAllAlert.js deleted file mode 100644 index 496f71731827..000000000000 --- a/awx/ui/src/screens/Setting/shared/RevertAllAlert.js +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react'; - -import { t } from '@lingui/macro'; -import { Button } from '@patternfly/react-core'; -import AlertModal from 'components/AlertModal'; - -function RevertAllAlert({ onClose, onRevertAll }) { - return ( - - {t`Revert all`} - , - , - ]} - > - {t`This will revert all configuration values on this page to - their factory defaults. Are you sure you want to proceed?`} - - ); -} - -export default RevertAllAlert; diff --git a/awx/ui/src/screens/Setting/shared/RevertAllAlert.test.js b/awx/ui/src/screens/Setting/shared/RevertAllAlert.test.js deleted file mode 100644 index dea34403ccb3..000000000000 --- a/awx/ui/src/screens/Setting/shared/RevertAllAlert.test.js +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; -import { mountWithContexts } from '../../../../testUtils/enzymeHelpers'; -import RevertAllAlert from './RevertAllAlert'; - -describe('RevertAllAlert', () => { - test('renders the expected content', async () => { - const wrapper = mountWithContexts( - {}} onRevertAll={() => {}} /> - ); - expect(wrapper).toHaveLength(1); - }); -}); diff --git a/awx/ui/src/screens/Setting/shared/RevertButton.js b/awx/ui/src/screens/Setting/shared/RevertButton.js deleted file mode 100644 index 9a0eb40f7117..000000000000 --- a/awx/ui/src/screens/Setting/shared/RevertButton.js +++ /dev/null @@ -1,73 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import { t } from '@lingui/macro'; -import { useField } from 'formik'; -import { Button, Tooltip } from '@patternfly/react-core'; -import styled from 'styled-components'; - -const ButtonWrapper = styled.div` - margin-left: auto; - &&& { - --pf-c-button--FontSize: var(--pf-c-button--m-small--FontSize); - } -`; - -function RevertButton({ - id, - defaultValue, - isDisabled = false, - onRevertCallback = () => null, -}) { - const [field, meta, helpers] = useField(id); - const initialValue = meta.initialValue ?? ''; - const currentValue = field.value; - let isRevertable = true; - let isMatch = false; - - if (currentValue === defaultValue && currentValue !== initialValue) { - isRevertable = false; - } - - if (currentValue === defaultValue && currentValue === initialValue) { - isMatch = true; - } - - const handleConfirm = () => { - helpers.setValue(isRevertable ? defaultValue : initialValue); - onRevertCallback(); - }; - - const revertTooltipContent = isRevertable - ? t`Revert to factory default.` - : t`Restore initial value.`; - const tooltipContent = - isDisabled || isMatch - ? t`Setting matches factory default.` - : revertTooltipContent; - - return ( - - - - - - ); -} - -RevertButton.propTypes = { - id: PropTypes.string.isRequired, -}; - -export default RevertButton; diff --git a/awx/ui/src/screens/Setting/shared/RevertButton.test.js b/awx/ui/src/screens/Setting/shared/RevertButton.test.js deleted file mode 100644 index e2801843fe7f..000000000000 --- a/awx/ui/src/screens/Setting/shared/RevertButton.test.js +++ /dev/null @@ -1,73 +0,0 @@ -import React from 'react'; -import { Formik } from 'formik'; -import { act } from 'react-dom/test-utils'; -import { mountWithContexts } from '../../../../testUtils/enzymeHelpers'; -import RevertButton from './RevertButton'; - -describe('RevertButton', () => { - let wrapper; - - test('button text should display "Revert"', async () => { - wrapper = mountWithContexts( - - - - ); - expect(wrapper.find('button').text()).toEqual('Revert'); - }); - - test('button text should display "Undo"', async () => { - wrapper = mountWithContexts( - - - - ); - expect(wrapper.find('button').text()).toEqual('Revert'); - }); - - test('should revert value to default on button click', async () => { - wrapper = mountWithContexts( - - - - ); - expect(wrapper.find('button').text()).toEqual('Revert'); - await act(async () => { - wrapper.find('button[aria-label="Revert"]').invoke('onClick')(); - }); - wrapper.update(); - expect(wrapper.find('button').text()).toEqual('Undo'); - }); - - test('should be disabled when current value equals the initial and default values', async () => { - wrapper = mountWithContexts( - - - - ); - expect(wrapper.find('button').text()).toEqual('Revert'); - expect(wrapper.find('button').props().disabled).toBe(true); - }); -}); diff --git a/awx/ui/src/screens/Setting/shared/RevertFormActionGroup.js b/awx/ui/src/screens/Setting/shared/RevertFormActionGroup.js deleted file mode 100644 index 7d5d213bbf4c..000000000000 --- a/awx/ui/src/screens/Setting/shared/RevertFormActionGroup.js +++ /dev/null @@ -1,49 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import { t } from '@lingui/macro'; -import { ActionGroup, Button } from '@patternfly/react-core'; -import { FormFullWidthLayout } from 'components/FormLayout'; - -const RevertFormActionGroup = ({ children, onCancel, onRevert, onSubmit }) => ( - - - - - {children} - - - -); - -RevertFormActionGroup.propTypes = { - onCancel: PropTypes.func.isRequired, - onRevert: PropTypes.func.isRequired, - onSubmit: PropTypes.func.isRequired, -}; - -export default RevertFormActionGroup; diff --git a/awx/ui/src/screens/Setting/shared/RevertFormActionGroup.test.js b/awx/ui/src/screens/Setting/shared/RevertFormActionGroup.test.js deleted file mode 100644 index 658491c5b361..000000000000 --- a/awx/ui/src/screens/Setting/shared/RevertFormActionGroup.test.js +++ /dev/null @@ -1,16 +0,0 @@ -import React from 'react'; -import { mountWithContexts } from '../../../../testUtils/enzymeHelpers'; -import RevertFormActionGroup from './RevertFormActionGroup'; - -describe('RevertFormActionGroup', () => { - test('should render the expected content', () => { - const wrapper = mountWithContexts( - {}} - onCancel={() => {}} - onRevert={() => {}} - /> - ); - expect(wrapper).toHaveLength(1); - }); -}); diff --git a/awx/ui/src/screens/Setting/shared/SettingDetail.js b/awx/ui/src/screens/Setting/shared/SettingDetail.js deleted file mode 100644 index c133bfbe065c..000000000000 --- a/awx/ui/src/screens/Setting/shared/SettingDetail.js +++ /dev/null @@ -1,131 +0,0 @@ -import React from 'react'; - -import { t } from '@lingui/macro'; -import { Detail } from 'components/DetailList'; -import CodeDetail from 'components/DetailList/CodeDetail'; - -function sortObj(obj) { - if (typeof obj !== 'object' || Array.isArray(obj) || obj === null) { - return obj; - } - const sorted = {}; - Object.keys(obj) - .sort() - .forEach((key) => { - sorted[key] = sortObj(obj[key]); - }); - return sorted; -} - -export default ({ helpText, id, label, type, unit = '', value }) => { - const dataType = value === '$encrypted$' ? 'encrypted' : type; - let detail = null; - - switch (dataType) { - case 'nested object': - detail = ( - - ); - break; - case 'list': - detail = ( - - ); - break; - case 'certificate': - detail = ( - - ); - break; - case 'image': - detail = ( - - ) - } - /> - ); - break; - case 'encrypted': - detail = ( - - ); - break; - case 'boolean': - detail = ( - - ); - break; - case 'choice': - case 'field': - case 'string': - detail = ( - - ); - break; - case 'integer': - detail = ( - - ); - break; - default: - detail = null; - } - return detail; -}; diff --git a/awx/ui/src/screens/Setting/shared/SharedFields.js b/awx/ui/src/screens/Setting/shared/SharedFields.js deleted file mode 100644 index 06851e3b9e95..000000000000 --- a/awx/ui/src/screens/Setting/shared/SharedFields.js +++ /dev/null @@ -1,562 +0,0 @@ -import React, { useState } from 'react'; -import { shape, string } from 'prop-types'; -import { t } from '@lingui/macro'; -import { useField } from 'formik'; -import { - Button, - FileUpload, - FormGroup as PFFormGroup, - InputGroup, - Switch, - TextArea, - TextInput, - Tooltip, - ButtonVariant, -} from '@patternfly/react-core'; -import FileUploadIcon from '@patternfly/react-icons/dist/js/icons/file-upload-icon'; -import { ExclamationCircleIcon as PFExclamationCircleIcon } from '@patternfly/react-icons'; -import styled from 'styled-components'; -import AnsibleSelect from 'components/AnsibleSelect'; -import { ExecutionEnvironmentLookup } from 'components/Lookup'; -import CodeEditor from 'components/CodeEditor'; -import { PasswordInput } from 'components/FormField'; -import { FormFullWidthLayout } from 'components/FormLayout'; -import Popover from 'components/Popover'; -import { combine, minMaxValue, required, url, number } from 'util/validators'; -import AlertModal from 'components/AlertModal'; -import RevertButton from './RevertButton'; - -const ExclamationCircleIcon = styled(PFExclamationCircleIcon)` - && { - color: var(--pf-global--danger-color--100); - } -`; - -const FormGroup = styled(PFFormGroup)` - .pf-c-form__group-label { - display: inline-flex; - align-items: center; - width: 100%; - } -`; - -const Selected = styled.div` - display: flex; - justify-content: space-between; - background-color: white; - border-bottom-color: var(--pf-global--BorderColor--200); -`; - -const SettingGroup = ({ - children, - defaultValue, - fieldId, - helperTextInvalid, - isDisabled, - isRequired, - label, - onRevertCallback, - popoverContent, - validated, -}) => ( - - - - - } - > - {children} - -); -const BooleanField = ({ - ariaLabel = '', - name, - config, - disabled = false, - needsConfirmationModal, - modalTitle, -}) => { - const [field, meta, helpers] = useField(name); - const [isModalOpen, setIsModalOpen] = useState(false); - - return config ? ( - - {isModalOpen && ( - { - setIsModalOpen(false); - }} - actions={[ - , - , - ]} - >{t`Are you sure you want to disable local authentication? Doing so could impact users' ability to log in and the system administrator's ability to reverse this change.`} - )} - { - if (needsConfirmationModal && isOn) { - setIsModalOpen(true); - } - helpers.setValue(!field.value); - }} - aria-label={ariaLabel || config.label} - /> - - ) : null; -}; -BooleanField.propTypes = { - name: string.isRequired, - config: shape({}).isRequired, -}; - -const ChoiceField = ({ name, config, isRequired = false }) => { - const validate = isRequired ? required(null) : null; - const [field, meta] = useField({ name, validate }); - const isValid = !meta.error || !meta.touched; - - return config ? ( - - ({ - label, - value: value ?? '', - key: value ?? index, - })), - ]} - /> - - ) : null; -}; -ChoiceField.propTypes = { - name: string.isRequired, - config: shape({}).isRequired, -}; - -const EncryptedField = ({ name, config, isRequired = false }) => { - const validate = isRequired ? required(null) : null; - const [, meta] = useField({ name, validate }); - const isValid = !(meta.touched && meta.error); - - return config ? ( - - - - - - ) : null; -}; -EncryptedField.propTypes = { - name: string.isRequired, - config: shape({}).isRequired, -}; - -const ExecutionEnvField = ({ name, config, isRequired = false }) => { - const [field, meta, helpers] = useField({ name }); - return config ? ( - helpers.setValue(config.default)} - > - { - helpers.setValue(value, false); - }} - overrideLabel - fieldName={name} - /> - - ) : null; -}; -ExecutionEnvField.propTypes = { - name: string.isRequired, - config: shape({}).isRequired, -}; - -const InputAlertField = ({ name, config }) => { - const [field, meta] = useField({ name }); - const isValid = !(meta.touched && meta.error); - const [isModalOpen, setIsModalOpen] = useState(false); - const [isDisable, setIsDisable] = useState(true); - - const handleSetIsOpen = () => { - setIsModalOpen(true); - }; - - const handleEnableTextInput = () => { - setIsDisable(false); - }; - - return config ? ( - <> - - - {isDisable && ( - - - - )} - { - field.onChange(event); - }} - isDisabled={isDisable} - /> - - - {isModalOpen && isDisable && ( - { - setIsModalOpen(false); - }} - actions={[ - , - , - ]} - > - {t`Are you sure you want to edit login redirect override URL? Doing so could impact users' ability to log in to the system once local authentication is also disabled.`} - - )} - - ) : null; -}; - -InputAlertField.propTypes = { - name: string.isRequired, - config: shape({}).isRequired, -}; - -const InputField = ({ name, config, type = 'text', isRequired = false }) => { - const min_value = config?.min_value ?? Number.MIN_SAFE_INTEGER; - const max_value = config?.max_value ?? Number.MAX_SAFE_INTEGER; - const validators = [ - ...(isRequired ? [required(null)] : []), - ...(type === 'url' ? [url()] : []), - ...(type === 'number' ? [number(), minMaxValue(min_value, max_value)] : []), - ]; - const [field, meta] = useField({ name, validate: combine(validators) }); - const isValid = !(meta.touched && meta.error); - - return config ? ( - - { - field.onChange(event); - }} - /> - - ) : null; -}; -InputField.propTypes = { - name: string.isRequired, - config: shape({}), -}; -InputField.defaultProps = { - config: null, -}; - -const TextAreaField = ({ name, config, isRequired = false }) => { - const validate = isRequired ? required(null) : null; - const [field, meta] = useField({ name, validate }); - const isValid = !(meta.touched && meta.error); - - return config ? ( - - \n
\n
\n )\n }\n\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/curl.jsx","import React from \"react\"\nimport PropTypes from \"prop-types\"\n\nexport const DeepLink = ({ enabled, path, text }) => {\n return (\n e.preventDefault() : null}\n href={enabled ? `#/${path}` : null}>\n {text}\n \n )\n}\nDeepLink.propTypes = {\n enabled: PropTypes.bool,\n isShown: PropTypes.bool,\n path: PropTypes.string,\n text: PropTypes.string\n}\n\nexport default DeepLink\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/deep-link.jsx","import React from \"react\"\nimport ImPropTypes from \"react-immutable-proptypes\"\n\nconst EnumModel = ({ value, getComponent }) => {\n let ModelCollapse = getComponent(\"ModelCollapse\")\n let collapsedContent = Array [ { value.count() } ]\n return \n Enum:
\n \n [ { value.join(\", \") } ]\n \n
\n}\nEnumModel.propTypes = {\n value: ImPropTypes.iterable,\n getComponent: ImPropTypes.func\n}\n\nexport default EnumModel\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/enum-model.jsx","import React from \"react\"\nimport PropTypes from \"prop-types\"\nimport { List } from \"immutable\"\nimport { Collapse } from \"react-collapse\"\n\nexport default class Errors extends React.Component {\n\n static propTypes = {\n editorActions: PropTypes.object,\n errSelectors: PropTypes.object.isRequired,\n layoutSelectors: PropTypes.object.isRequired,\n layoutActions: PropTypes.object.isRequired\n }\n\n render() {\n let { editorActions, errSelectors, layoutSelectors, layoutActions } = this.props\n\n if(editorActions && editorActions.jumpToLine) {\n var jumpToLine = editorActions.jumpToLine\n }\n\n let errors = errSelectors.allErrors()\n\n // all thrown errors, plus error-level everything else\n let allErrorsToDisplay = errors.filter(err => err.get(\"type\") === \"thrown\" ? true :err.get(\"level\") === \"error\")\n\n if(!allErrorsToDisplay || allErrorsToDisplay.count() < 1) {\n return null\n }\n\n let isVisible = layoutSelectors.isShown([\"errorPane\"], true)\n let toggleVisibility = () => layoutActions.show([\"errorPane\"], !isVisible)\n\n let sortedJSErrors = allErrorsToDisplay.sortBy(err => err.get(\"line\"))\n\n return (\n
\n        
\n

Errors

\n \n
\n \n
\n { sortedJSErrors.map((err, i) => {\n let type = err.get(\"type\")\n if(type === \"thrown\" || type === \"auth\") {\n return \n }\n if(type === \"spec\") {\n return \n }\n }) }\n
\n
\n
\n )\n }\n}\n\nconst ThrownErrorItem = ( { error, jumpToLine } ) => {\n if(!error) {\n return null\n }\n let errorLine = error.get(\"line\")\n\n return (\n
\n { !error ? null :\n
\n

{ (error.get(\"source\") && error.get(\"level\")) ?\n toTitleCase(error.get(\"source\")) + \" \" + error.get(\"level\") : \"\" }\n { error.get(\"path\") ? at {error.get(\"path\")}: null }

\n \n { error.get(\"message\") }\n \n
\n { errorLine && jumpToLine ? Jump to line { errorLine } : null }\n
\n
\n }\n
\n )\n }\n\nconst SpecErrorItem = ( { error, jumpToLine } ) => {\n let locationMessage = null\n\n if(error.get(\"path\")) {\n if(List.isList(error.get(\"path\"))) {\n locationMessage = at { error.get(\"path\").join(\".\") }\n } else {\n locationMessage = at { error.get(\"path\") }\n }\n } else if(error.get(\"line\") && !jumpToLine) {\n locationMessage = on line { error.get(\"line\") }\n }\n\n return (\n
\n { !error ? null :\n
\n

{ toTitleCase(error.get(\"source\")) + \" \" + error.get(\"level\") } { locationMessage }

\n { error.get(\"message\") }\n
\n { jumpToLine ? (\n Jump to line { error.get(\"line\") }\n ) : null }\n
\n
\n }\n
\n )\n }\n\nfunction toTitleCase(str) {\n return (str || \"\")\n .split(\" \")\n .map(substr => substr[0].toUpperCase() + substr.slice(1))\n .join(\" \")\n}\n\nThrownErrorItem.propTypes = {\n error: PropTypes.object.isRequired,\n jumpToLine: PropTypes.func\n}\n\nThrownErrorItem.defaultProps = {\n jumpToLine: null\n}\n\nSpecErrorItem.propTypes = {\n error: PropTypes.object.isRequired,\n jumpToLine: PropTypes.func\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/errors.jsx","import React, { Component } from \"react\"\nimport PropTypes from \"prop-types\"\n\nexport default class Execute extends Component {\n\n static propTypes = {\n specSelectors: PropTypes.object.isRequired,\n specActions: PropTypes.object.isRequired,\n operation: PropTypes.object.isRequired,\n path: PropTypes.string.isRequired,\n method: PropTypes.string.isRequired,\n onExecute: PropTypes.func\n }\n\n onClick=()=>{\n let { specSelectors, specActions, operation, path, method } = this.props\n\n specActions.validateParams( [path, method] )\n\n if ( specSelectors.validateBeforeExecute([path, method]) ) {\n if(this.props.onExecute) {\n this.props.onExecute()\n }\n specActions.execute( { operation, path, method } )\n }\n }\n\n onChangeProducesWrapper = ( val ) => this.props.specActions.changeProducesValue([this.props.path, this.props.method], val)\n\n render(){\n return (\n \n )\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/execute.jsx","import React from \"react\"\n\nexport default class Footer extends React.Component {\n render() {\n return (\n
\n )\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/footer.jsx","import React from \"react\"\nimport PropTypes from \"prop-types\"\nimport Im from \"immutable\"\n\nconst propStyle = { color: \"#999\", fontStyle: \"italic\" }\n\nexport default class Headers extends React.Component {\n\n static propTypes = {\n headers: PropTypes.object.isRequired,\n getComponent: PropTypes.func.isRequired\n };\n\n render() {\n\n let { headers, getComponent } = this.props\n const Property = getComponent(\"Property\")\n\n if ( !headers || !headers.size )\n return null\n\n return (\n
\n

Headers:

\n \n \n \n \n \n \n \n \n \n {\n headers.entrySeq().map( ([ key, header ]) => {\n if(!Im.Map.isMap(header)) {\n return null\n }\n const type = header.getIn([\"schema\"]) ? header.getIn([\"schema\", \"type\"]) : header.getIn([\"type\"])\n const schemaExample = header.getIn([\"schema\", \"example\"])\n\n return (\n \n \n \n )\n }).toArray()\n }\n \n
NameDescriptionType
{ key }{ header.get( \"description\" ) }{ type } { schemaExample ? : null }
\n
\n )\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/headers.jsx","import React, { Component } from \"react\"\nimport PropTypes from \"prop-types\"\nimport { highlight } from \"core/utils\"\n\nexport default class HighlightCode extends Component {\n static propTypes = {\n value: PropTypes.string.isRequired,\n className: PropTypes.string\n }\n\n componentDidMount() {\n highlight(this.el)\n }\n\n componentDidUpdate() {\n highlight(this.el)\n }\n\n initializeComponent = (c) => {\n this.el = c\n }\n\n render () {\n let { value, className } = this.props\n className = className || \"\"\n\n return
{ value }
\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/highlight-code.jsx","import React from \"react\"\nimport PropTypes from \"prop-types\"\nimport { fromJS } from \"immutable\"\nimport ImPropTypes from \"react-immutable-proptypes\"\nimport { sanitizeUrl } from \"core/utils\"\n\n\nclass Path extends React.Component {\n static propTypes = {\n host: PropTypes.string,\n basePath: PropTypes.string\n }\n\n render() {\n let { host, basePath } = this.props\n\n return (\n
\n        [ Base URL: {host}{basePath} ]\n      
\n )\n }\n}\n\n\nclass Contact extends React.Component {\n static propTypes = {\n data: PropTypes.object\n }\n\n render(){\n let { data } = this.props\n let name = data.get(\"name\") || \"the developer\"\n let url = data.get(\"url\")\n let email = data.get(\"email\")\n\n return (\n \n )\n }\n}\n\nclass License extends React.Component {\n static propTypes = {\n license: PropTypes.object\n }\n\n render(){\n let { license } = this.props\n let name = license.get(\"name\") || \"License\"\n let url = license.get(\"url\")\n\n return (\n
\n {\n url ? { name }\n : { name }\n }\n
\n )\n }\n}\n\nexport default class Info extends React.Component {\n static propTypes = {\n info: PropTypes.object,\n url: PropTypes.string,\n host: PropTypes.string,\n basePath: PropTypes.string,\n externalDocs: ImPropTypes.map,\n getComponent: PropTypes.func.isRequired,\n }\n\n render() {\n let { info, url, host, basePath, getComponent, externalDocs } = this.props\n let version = info.get(\"version\")\n let description = info.get(\"description\")\n let title = info.get(\"title\")\n let termsOfService = info.get(\"termsOfService\")\n let contact = info.get(\"contact\")\n let license = info.get(\"license\")\n const { url:externalDocsUrl, description:externalDocsDescription } = (externalDocs || fromJS({})).toJS()\n\n const Markdown = getComponent(\"Markdown\")\n const VersionStamp = getComponent(\"VersionStamp\")\n\n return (\n
\n
\n

{ title }\n { version && }\n

\n { host || basePath ? : null }\n { url && { url } }\n
\n\n
\n \n
\n\n {\n termsOfService && \n }\n\n { contact && contact.size ? : null }\n { license && license.size ? : null }\n { externalDocsUrl ?\n {externalDocsDescription || externalDocsUrl}\n : null }\n\n
\n )\n }\n\n}\n\nInfo.propTypes = {\n title: PropTypes.any,\n description: PropTypes.any,\n version: PropTypes.any,\n url: PropTypes.string\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/info.jsx","import React from \"react\"\nimport PropTypes from \"prop-types\"\n\nexport default class BaseLayout extends React.Component {\n\n static propTypes = {\n errSelectors: PropTypes.object.isRequired,\n errActions: PropTypes.object.isRequired,\n specActions: PropTypes.object.isRequired,\n specSelectors: PropTypes.object.isRequired,\n oas3Selectors: PropTypes.object.isRequired,\n oas3Actions: PropTypes.object.isRequired,\n layoutSelectors: PropTypes.object.isRequired,\n layoutActions: PropTypes.object.isRequired,\n getComponent: PropTypes.func.isRequired\n }\n\n onFilterChange =(e) => {\n let {target: {value}} = e\n this.props.layoutActions.updateFilter(value)\n }\n\n render() {\n let {\n specSelectors,\n specActions,\n getComponent,\n layoutSelectors,\n oas3Selectors,\n oas3Actions\n } = this.props\n\n let info = specSelectors.info()\n let url = specSelectors.url()\n let basePath = specSelectors.basePath()\n let host = specSelectors.host()\n let securityDefinitions = specSelectors.securityDefinitions()\n let externalDocs = specSelectors.externalDocs()\n let schemes = specSelectors.schemes()\n let servers = specSelectors.servers()\n\n let Info = getComponent(\"info\")\n let Operations = getComponent(\"operations\", true)\n let Models = getComponent(\"Models\", true)\n let AuthorizeBtn = getComponent(\"authorizeBtn\", true)\n let Row = getComponent(\"Row\")\n let Col = getComponent(\"Col\")\n let Servers = getComponent(\"Servers\")\n let Errors = getComponent(\"errors\", true)\n\n let isLoading = specSelectors.loadingStatus() === \"loading\"\n let isFailed = specSelectors.loadingStatus() === \"failed\"\n let filter = layoutSelectors.currentFilter()\n\n let inputStyle = {}\n if(isFailed) inputStyle.color = \"red\"\n if(isLoading) inputStyle.color = \"#aaa\"\n\n const Schemes = getComponent(\"schemes\")\n\n const isSpecEmpty = !specSelectors.specStr()\n\n if(isSpecEmpty) {\n let loadingMessage\n if(isLoading) {\n loadingMessage =
\n } else {\n loadingMessage =

No API definition provided.

\n }\n\n return
\n
\n {loadingMessage}\n
\n
\n }\n\n return (\n\n
\n
\n \n \n \n { info.count() ? (\n \n ) : null }\n \n \n { schemes && schemes.size || securityDefinitions ? (\n
\n \n { schemes && schemes.size ? (\n \n ) : null }\n\n { securityDefinitions ? (\n \n ) : null }\n \n
\n ) : null }\n\n { servers && servers.size ? (\n
\n \n Server\n \n \n
\n\n ) : null}\n\n {\n filter === null || filter === false ? null :\n
\n \n \n \n
\n }\n\n \n \n \n \n \n \n \n \n \n \n
\n
\n )\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/layouts/base.jsx","import React from \"react\"\nimport PropTypes from \"prop-types\"\nimport ImPropTypes from \"react-immutable-proptypes\"\nimport { Iterable } from \"immutable\"\n\nconst Headers = ( { headers } )=>{\n return (\n
\n
Response headers
\n
{headers}
\n
)\n}\nHeaders.propTypes = {\n headers: PropTypes.array.isRequired\n}\n\nconst Duration = ( { duration } ) => {\n return (\n
\n
Request duration
\n
{duration} ms
\n
\n )\n}\nDuration.propTypes = {\n duration: PropTypes.number.isRequired\n}\n\n\nexport default class LiveResponse extends React.Component {\n static propTypes = {\n response: PropTypes.instanceOf(Iterable).isRequired,\n path: PropTypes.string.isRequired,\n method: PropTypes.string.isRequired,\n displayRequestDuration: PropTypes.bool.isRequired,\n specSelectors: PropTypes.object.isRequired,\n getComponent: PropTypes.func.isRequired,\n getConfigs: PropTypes.func.isRequired\n }\n\n shouldComponentUpdate(nextProps) {\n // BUG: props.response is always coming back as a new Immutable instance\n // same issue as responses.jsx (tryItOutResponse)\n return this.props.response !== nextProps.response\n || this.props.path !== nextProps.path\n || this.props.method !== nextProps.method\n || this.props.displayRequestDuration !== nextProps.displayRequestDuration\n }\n\n render() {\n const { response, getComponent, getConfigs, displayRequestDuration, specSelectors, path, method } = this.props\n const { showMutatedRequest } = getConfigs()\n\n const curlRequest = showMutatedRequest ? specSelectors.mutatedRequestFor(path, method) : specSelectors.requestFor(path, method)\n const status = response.get(\"status\")\n const url = response.get(\"url\")\n const headers = response.get(\"headers\").toJS()\n const notDocumented = response.get(\"notDocumented\")\n const isError = response.get(\"error\")\n const body = response.get(\"text\")\n const duration = response.get(\"duration\")\n const headersKeys = Object.keys(headers)\n const contentType = headers[\"content-type\"]\n\n const Curl = getComponent(\"curl\")\n const ResponseBody = getComponent(\"responseBody\")\n const returnObject = headersKeys.map(key => {\n return {key}: {headers[key]} \n })\n const hasHeaders = returnObject.length !== 0\n\n return (\n
\n { curlRequest && }\n { url &&
\n

Request URL

\n
\n
{url}
\n
\n
\n }\n

Server response

\n \n \n \n \n \n \n \n \n \n \n \n \n \n
CodeDetails
\n { status }\n {\n notDocumented ?
\n Undocumented \n
\n : null\n }\n
\n {\n isError ? \n {`${response.get(\"name\")}: ${response.get(\"message\")}`}\n \n : null\n }\n {\n body ? \n : null\n }\n {\n hasHeaders ? : null\n }\n {\n displayRequestDuration && duration ? : null\n }\n
\n
\n )\n }\n\n static propTypes = {\n getComponent: PropTypes.func.isRequired,\n response: ImPropTypes.map\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/live-response.jsx","import React, { Component } from \"react\"\nimport PropTypes from \"prop-types\"\n\nexport default class ModelCollapse extends Component {\n static propTypes = {\n collapsedContent: PropTypes.any,\n expanded: PropTypes.bool,\n children: PropTypes.any,\n title: PropTypes.element,\n modelName: PropTypes.string,\n onToggle: PropTypes.func\n }\n\n static defaultProps = {\n collapsedContent: \"{...}\",\n expanded: false,\n title: null,\n onToggle: () => {}\n }\n\n constructor(props, context) {\n super(props, context)\n\n let { expanded, collapsedContent } = this.props\n\n this.state = {\n expanded : expanded,\n collapsedContent: collapsedContent || ModelCollapse.defaultProps.collapsedContent\n }\n }\n\n componentWillReceiveProps(nextProps){\n\n if(this.props.expanded!= nextProps.expanded){\n this.setState({expanded: nextProps.expanded})\n }\n\n }\n\n toggleCollapsed=()=>{\n\n\n if(this.props.onToggle){\n this.props.onToggle(this.props.modelName,!this.state.expanded)\n }\n\n this.setState({\n expanded: !this.state.expanded\n })\n }\n\n render () {\n const {title} = this.props\n return (\n \n { title && {title} }\n \n \n \n { this.state.expanded ? this.props.children :this.state.collapsedContent }\n \n )\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/model-collapse.jsx","import React from \"react\"\nimport PropTypes from \"prop-types\"\nimport ImPropTypes from \"react-immutable-proptypes\"\n\nexport default class ModelExample extends React.Component {\n static propTypes = {\n getComponent: PropTypes.func.isRequired,\n specSelectors: PropTypes.object.isRequired,\n schema: PropTypes.object.isRequired,\n example: PropTypes.any.isRequired,\n isExecute: PropTypes.bool,\n getConfigs: PropTypes.func.isRequired,\n specPath: ImPropTypes.list.isRequired,\n }\n\n constructor(props, context) {\n super(props, context)\n let { getConfigs } = this.props\n let { defaultModelRendering } = getConfigs()\n if (defaultModelRendering !== \"example\" && defaultModelRendering !== \"model\") {\n defaultModelRendering = \"example\"\n }\n this.state = {\n activeTab: defaultModelRendering\n }\n }\n\n activeTab =( e ) => {\n let { target : { dataset : { name } } } = e\n\n this.setState({\n activeTab: name\n })\n }\n\n render() {\n let { getComponent, specSelectors, schema, example, isExecute, getConfigs, specPath } = this.props\n let { defaultModelExpandDepth } = getConfigs()\n const ModelWrapper = getComponent(\"ModelWrapper\")\n\n return
\n \n
\n {\n (isExecute || this.state.activeTab === \"example\") && example\n }\n {\n !isExecute && this.state.activeTab === \"model\" && \n\n\n }\n
\n
\n }\n\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/model-example.jsx","import React, { Component, } from \"react\"\nimport PropTypes from \"prop-types\"\n//import layoutActions from \"actions/layout\"\n\n\nexport default class ModelWrapper extends Component {\n\n\n static propTypes = {\n schema: PropTypes.object.isRequired,\n name: PropTypes.string,\n getComponent: PropTypes.func.isRequired,\n getConfigs: PropTypes.func.isRequired,\n specSelectors: PropTypes.object.isRequired,\n expandDepth: PropTypes.number,\n layoutActions: PropTypes.object,\n layoutSelectors: PropTypes.object.isRequired\n }\n\n onToggle = (name,isShown) => {\n // If this prop is present, we'll have deepLinking for it\n if(this.props.layoutActions) {\n this.props.layoutActions.show([\"models\", name],isShown)\n }\n }\n\n render(){\n let { getComponent, getConfigs } = this.props\n const Model = getComponent(\"Model\")\n\n let expanded\n if(this.props.layoutSelectors) {\n // If this is prop is present, we'll have deepLinking for it\n expanded = this.props.layoutSelectors.isShown([\"models\",this.props.name])\n }\n\n return
\n \n
\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/model-wrapper.jsx","import React, { Component } from \"react\"\nimport Im from \"immutable\"\nimport PropTypes from \"prop-types\"\n\nexport default class Models extends Component {\n static propTypes = {\n getComponent: PropTypes.func,\n specSelectors: PropTypes.object,\n layoutSelectors: PropTypes.object,\n layoutActions: PropTypes.object,\n getConfigs: PropTypes.func.isRequired\n }\n\n render(){\n let { specSelectors, getComponent, layoutSelectors, layoutActions, getConfigs } = this.props\n let definitions = specSelectors.definitions()\n let { docExpansion, defaultModelsExpandDepth } = getConfigs()\n if (!definitions.size || defaultModelsExpandDepth < 0) return null\n\n let showModels = layoutSelectors.isShown(\"models\", defaultModelsExpandDepth > 0 && docExpansion !== \"none\")\n const specPathBase = specSelectors.isOAS3() ? [\"components\", \"schemas\"] : [\"definitions\"]\n\n const ModelWrapper = getComponent(\"ModelWrapper\")\n const Collapse = getComponent(\"Collapse\")\n\n return
\n

layoutActions.show(\"models\", !showModels)}>\n Models\n \n \n \n

\n \n {\n definitions.entrySeq().map( ( [ name, model ])=>{\n\n return
\n \n
\n }).toArray()\n }\n
\n
\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/models.jsx","import React, { Component, } from \"react\"\nimport PropTypes from \"prop-types\"\nimport { List } from \"immutable\"\nimport ImPropTypes from \"react-immutable-proptypes\"\n\nconst braceOpen = \"{\"\nconst braceClose = \"}\"\n\nexport default class ObjectModel extends Component {\n static propTypes = {\n schema: PropTypes.object.isRequired,\n getComponent: PropTypes.func.isRequired,\n getConfigs: PropTypes.func.isRequired,\n expanded: PropTypes.bool,\n onToggle: PropTypes.func,\n specSelectors: PropTypes.object.isRequired,\n name: PropTypes.string,\n isRef: PropTypes.bool,\n expandDepth: PropTypes.number,\n depth: PropTypes.number,\n specPath: ImPropTypes.list.isRequired\n }\n\n render(){\n let { schema, name, isRef, getComponent, getConfigs, depth, onToggle, expanded, specPath, ...otherProps } = this.props\n let { specSelectors,expandDepth } = otherProps\n const { isOAS3 } = specSelectors\n\n if(!schema) {\n return null\n }\n\n const { showExtensions } = getConfigs()\n\n let description = schema.get(\"description\")\n let properties = schema.get(\"properties\")\n let additionalProperties = schema.get(\"additionalProperties\")\n let title = schema.get(\"title\") || name\n let requiredProperties = schema.get(\"required\")\n\n const JumpToPath = getComponent(\"JumpToPath\", true)\n const Markdown = getComponent(\"Markdown\")\n const Model = getComponent(\"Model\")\n const ModelCollapse = getComponent(\"ModelCollapse\")\n\n const JumpToPathSection = () => {\n return \n }\n const collapsedContent = (\n { braceOpen }...{ braceClose }\n {\n isRef ? : \"\"\n }\n )\n\n const anyOf = specSelectors.isOAS3() ? schema.get(\"anyOf\") : null\n const oneOf = specSelectors.isOAS3() ? schema.get(\"oneOf\") : null\n const not = specSelectors.isOAS3() ? schema.get(\"not\") : null\n\n const titleEl = title && \n { isRef && schema.get(\"$$ref\") && { schema.get(\"$$ref\") } }\n { title }\n \n\n return \n \n\n { braceOpen }\n {\n !isRef ? null : \n }\n \n {\n \n {\n !description ? null : \n \n \n \n }\n {\n !(properties && properties.size) ? null : properties.entrySeq().map(\n ([key, value]) => {\n let isDeprecated = isOAS3() && value.get(\"deprecated\")\n let isRequired = List.isList(requiredProperties) && requiredProperties.contains(key)\n let propertyStyle = { verticalAlign: \"top\", paddingRight: \"0.2em\" }\n if ( isRequired ) {\n propertyStyle.fontWeight = \"bold\"\n }\n\n return (\n \n \n )\n }).toArray()\n }\n {\n // empty row befor extensions...\n !showExtensions ? null :  \n }\n {\n !showExtensions ? null :\n schema.entrySeq().map(\n ([key, value]) => {\n if(key.slice(0,2) !== \"x-\") {\n return\n }\n\n const normalizedValue = !value ? null : value.toJS ? value.toJS() : value\n\n return (\n \n \n )\n }).toArray()\n }\n {\n !additionalProperties || !additionalProperties.size ? null\n : \n \n \n \n }\n {\n !anyOf ? null\n : \n \n \n \n }\n {\n !oneOf ? null\n : \n \n \n \n }\n {\n !not ? null\n : \n \n \n \n }\n
description:\n \n
\n { key }{ isRequired && * }\n \n \n
\n { key }\n \n { JSON.stringify(normalizedValue) }\n
{ \"< * >:\" }\n \n
{ \"anyOf ->\" }\n {anyOf.map((schema, k) => {\n return
\n })}\n
{ \"oneOf ->\" }\n {oneOf.map((schema, k) => {\n return
\n })}\n
{ \"not ->\" }\n
\n \n
\n
\n }\n
\n { braceClose }\n \n
\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/object-model.jsx","import React from \"react\"\nimport PropTypes from \"prop-types\"\nimport { sanitizeUrl } from \"core/utils\"\n\nexport default class OnlineValidatorBadge extends React.Component {\n static propTypes = {\n getComponent: PropTypes.func.isRequired,\n getConfigs: PropTypes.func.isRequired,\n specSelectors: PropTypes.object.isRequired\n }\n\n constructor(props, context) {\n super(props, context)\n let { specSelectors, getConfigs } = props\n let { validatorUrl } = getConfigs()\n this.state = {\n url: specSelectors.url(),\n validatorUrl: validatorUrl === undefined ? \"https://online.swagger.io/validator\" : validatorUrl\n }\n }\n\n componentWillReceiveProps(nextProps) {\n let { specSelectors, getConfigs } = nextProps\n let { validatorUrl } = getConfigs()\n\n this.setState({\n url: specSelectors.url(),\n validatorUrl: validatorUrl === undefined ? \"https://online.swagger.io/validator\" : validatorUrl\n })\n }\n\n render() {\n let { getConfigs } = this.props\n let { spec } = getConfigs()\n\n let sanitizedValidatorUrl = sanitizeUrl(this.state.validatorUrl)\n\n if ( typeof spec === \"object\" && Object.keys(spec).length) return null\n\n if (!this.state.url || !this.state.validatorUrl || this.state.url.indexOf(\"localhost\") >= 0\n || this.state.url.indexOf(\"127.0.0.1\") >= 0) {\n return null\n }\n\n return (\n \n \n \n )\n }\n}\n\n\nclass ValidatorImage extends React.Component {\n static propTypes = {\n src: PropTypes.string,\n alt: PropTypes.string\n }\n\n constructor(props) {\n super(props)\n this.state = {\n loaded: false,\n error: false\n }\n }\n\n componentDidMount() {\n const img = new Image()\n img.onload = () => {\n this.setState({\n loaded: true\n })\n }\n img.onerror = () => {\n this.setState({\n error: true\n })\n }\n img.src = this.props.src\n }\n\n componentWillReceiveProps(nextProps) {\n if (nextProps.src !== this.props.src) {\n const img = new Image()\n img.onload = () => {\n this.setState({\n loaded: true\n })\n }\n img.onerror = () => {\n this.setState({\n error: true\n })\n }\n img.src = nextProps.src\n }\n }\n\n render() {\n if (this.state.error) {\n return {\"Error\"}\n } else if (!this.state.loaded) {\n return {\"Loading...\"}\n }\n return {this.props.alt}\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/online-validator-badge.jsx","import React from \"react\"\nimport PropTypes from \"prop-types\"\n\nexport const OperationExtRow = ({ xKey, xVal }) => {\n const xNormalizedValue = !xVal ? null : xVal.toJS ? xVal.toJS() : xVal\n\n return (\n { xKey }\n { JSON.stringify(xNormalizedValue) }\n )\n}\nOperationExtRow.propTypes = {\n xKey: PropTypes.string,\n xVal: PropTypes.any\n}\n\nexport default OperationExtRow\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/operation-extension-row.jsx","import React from \"react\"\nimport PropTypes from \"prop-types\"\n\nexport const OperationExt = ({ extensions, getComponent }) => {\n let OperationExtRow = getComponent(\"OperationExtRow\")\n return (\n
\n
\n

Extensions

\n
\n
\n\n \n \n \n \n \n \n \n \n {\n extensions.entrySeq().map(([k, v]) => )\n }\n \n
FieldValue
\n
\n
\n )\n}\nOperationExt.propTypes = {\n extensions: PropTypes.object.isRequired,\n getComponent: PropTypes.func.isRequired\n}\n\nexport default OperationExt\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/operation-extensions.jsx","import React, { PureComponent } from \"react\"\nimport PropTypes from \"prop-types\"\nimport { getList } from \"core/utils\"\nimport { getExtensions, sanitizeUrl } from \"core/utils\"\nimport { Iterable, List } from \"immutable\"\nimport ImPropTypes from \"react-immutable-proptypes\"\n\nexport default class Operation extends PureComponent {\n static propTypes = {\n specPath: ImPropTypes.list.isRequired,\n operation: PropTypes.instanceOf(Iterable).isRequired,\n response: PropTypes.instanceOf(Iterable),\n request: PropTypes.instanceOf(Iterable),\n\n toggleShown: PropTypes.func.isRequired,\n onTryoutClick: PropTypes.func.isRequired,\n onCancelClick: PropTypes.func.isRequired,\n onExecute: PropTypes.func.isRequired,\n\n getComponent: PropTypes.func.isRequired,\n getConfigs: PropTypes.func.isRequired,\n authActions: PropTypes.object,\n authSelectors: PropTypes.object,\n specActions: PropTypes.object.isRequired,\n specSelectors: PropTypes.object.isRequired,\n oas3Actions: PropTypes.object.isRequired,\n oas3Selectors: PropTypes.object.isRequired,\n layoutActions: PropTypes.object.isRequired,\n layoutSelectors: PropTypes.object.isRequired,\n fn: PropTypes.object.isRequired\n }\n\n static defaultProps = {\n operation: null,\n response: null,\n request: null,\n specPath: List()\n }\n\n render() {\n let {\n specPath,\n response,\n request,\n toggleShown,\n onTryoutClick,\n onCancelClick,\n onExecute,\n fn,\n getComponent,\n getConfigs,\n specActions,\n specSelectors,\n authActions,\n authSelectors,\n oas3Actions,\n oas3Selectors\n } = this.props\n let operationProps = this.props.operation\n\n let {\n isShown,\n isAuthorized,\n path,\n method,\n op,\n tag,\n showSummary,\n operationId,\n allowTryItOut,\n displayOperationId,\n displayRequestDuration,\n isDeepLinkingEnabled,\n tryItOutEnabled,\n executeInProgress\n } = operationProps.toJS()\n\n let {\n summary,\n description,\n deprecated,\n externalDocs,\n schemes\n } = op.operation\n\n let operation = operationProps.getIn([\"op\", \"operation\"])\n let security = operationProps.get(\"security\")\n let responses = operation.get(\"responses\")\n let produces = operation.get(\"produces\")\n let parameters = getList(operation, [\"parameters\"])\n let operationScheme = specSelectors.operationScheme(path, method)\n let isShownKey = [\"operations\", tag, operationId]\n let extensions = getExtensions(operation)\n\n const Responses = getComponent(\"responses\")\n const Parameters = getComponent( \"parameters\" )\n const Execute = getComponent( \"execute\" )\n const Clear = getComponent( \"clear\" )\n const AuthorizeOperationBtn = getComponent( \"authorizeOperationBtn\" )\n const JumpToPath = getComponent(\"JumpToPath\", true)\n const Collapse = getComponent( \"Collapse\" )\n const Markdown = getComponent( \"Markdown\" )\n const Schemes = getComponent( \"schemes\" )\n const OperationServers = getComponent( \"OperationServers\" )\n const OperationExt = getComponent( \"OperationExt\" )\n const DeepLink = getComponent( \"DeepLink\" )\n\n const { showExtensions } = getConfigs()\n\n // Merge in Live Response\n if(responses && response && response.size > 0) {\n let notDocumented = !responses.get(String(response.get(\"status\"))) && !responses.get(\"default\")\n response = response.set(\"notDocumented\", notDocumented)\n }\n\n let onChangeKey = [ path, method ] // Used to add values to _this_ operation ( indexed by path and method )\n\n return (\n
\n
\n {/*TODO: convert this into a component, that can be wrapped\n and pulled in with getComponent */}\n {method.toUpperCase()}\n \n \n {/*TODO: use wrapComponents here, swagger-ui doesn't care about jumpToPath */}\n \n\n { !showSummary ? null :\n
\n { summary }\n
\n }\n\n { displayOperationId && operationId ? {operationId} : null }\n\n {\n (!security || !security.count()) ? null :\n {\n const applicableDefinitions = authSelectors.definitionsForRequirements(security)\n authActions.showDefinitions(applicableDefinitions)\n }}\n />\n }\n
\n\n \n
\n { deprecated &&

Warning: Deprecated

}\n { description &&\n
\n
\n \n
\n
\n }\n {\n externalDocs && externalDocs.url ?\n
\n

Find more details

\n
\n \n \n \n { externalDocs.url }\n
\n
: null\n }\n\n \n\n { !tryItOutEnabled ? null :\n \n }\n\n {!tryItOutEnabled || !allowTryItOut ? null : schemes && schemes.size ?
\n \n
: null\n }\n\n
\n { !tryItOutEnabled || !allowTryItOut ? null :\n\n \n }\n\n { (!tryItOutEnabled || !response || !allowTryItOut) ? null :\n \n }\n
\n\n {executeInProgress ?
: null}\n\n { !responses ? null :\n \n }\n\n { !showExtensions || !extensions.size ? null :\n \n }\n
\n
\n
\n )\n }\n\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/operation.jsx","import React from \"react\"\nimport PropTypes from \"prop-types\"\nimport Im from \"immutable\"\nimport { createDeepLinkPath, sanitizeUrl } from \"core/utils\"\n\nconst SWAGGER2_OPERATION_METHODS = [\n \"get\", \"put\", \"post\", \"delete\", \"options\", \"head\", \"patch\"\n]\n\nconst OAS3_OPERATION_METHODS = SWAGGER2_OPERATION_METHODS.concat([\"trace\"])\n\n\nexport default class Operations extends React.Component {\n\n static propTypes = {\n specSelectors: PropTypes.object.isRequired,\n specActions: PropTypes.object.isRequired,\n oas3Actions: PropTypes.object.isRequired,\n getComponent: PropTypes.func.isRequired,\n layoutSelectors: PropTypes.object.isRequired,\n layoutActions: PropTypes.object.isRequired,\n authActions: PropTypes.object.isRequired,\n authSelectors: PropTypes.object.isRequired,\n getConfigs: PropTypes.func.isRequired\n };\n\n render() {\n let {\n specSelectors,\n getComponent,\n layoutSelectors,\n layoutActions,\n getConfigs\n } = this.props\n\n let taggedOps = specSelectors.taggedOperations()\n\n const OperationContainer = getComponent(\"OperationContainer\", true)\n const Collapse = getComponent(\"Collapse\")\n const Markdown = getComponent(\"Markdown\")\n const DeepLink = getComponent(\"DeepLink\")\n\n let {\n docExpansion,\n maxDisplayedTags,\n deepLinking\n } = getConfigs()\n\n const isDeepLinkingEnabled = deepLinking && deepLinking !== \"false\"\n\n let filter = layoutSelectors.currentFilter()\n\n if (filter) {\n if (filter !== true) {\n taggedOps = taggedOps.filter((tagObj, tag) => {\n return tag.indexOf(filter) !== -1\n })\n }\n }\n\n if (maxDisplayedTags && !isNaN(maxDisplayedTags) && maxDisplayedTags >= 0) {\n taggedOps = taggedOps.slice(0, maxDisplayedTags)\n }\n\n return (\n
\n {\n taggedOps.map( (tagObj, tag) => {\n let operations = tagObj.get(\"operations\")\n let tagDescription = tagObj.getIn([\"tagDetails\", \"description\"], null)\n let tagExternalDocsDescription = tagObj.getIn([\"tagDetails\", \"externalDocs\", \"description\"])\n let tagExternalDocsUrl = tagObj.getIn([\"tagDetails\", \"externalDocs\", \"url\"])\n\n let isShownKey = [\"operations-tag\", createDeepLinkPath(tag)]\n let showTag = layoutSelectors.isShown(isShownKey, docExpansion === \"full\" || docExpansion === \"list\")\n\n return (\n
\n\n layoutActions.show(isShownKey, !showTag)}\n className={!tagDescription ? \"opblock-tag no-desc\" : \"opblock-tag\" }\n id={isShownKey.join(\"-\")}>\n \n { !tagDescription ? :\n \n \n \n }\n\n
\n { !tagExternalDocsDescription ? null :\n \n { tagExternalDocsDescription }\n { tagExternalDocsUrl ? \": \" : null }\n { tagExternalDocsUrl ?\n e.stopPropagation()}\n target={\"_blank\"}\n >{tagExternalDocsUrl} : null\n }\n \n }\n
\n\n \n \n\n \n {\n operations.map( op => {\n const path = op.get(\"path\")\n const method = op.get(\"method\")\n const specPath = Im.List([\"paths\", path, method])\n\n\n // FIXME: (someday) this logic should probably be in a selector,\n // but doing so would require further opening up\n // selectors to the plugin system, to allow for dynamic\n // overriding of low-level selectors that other selectors\n // rely on. --KS, 12/17\n const validMethods = specSelectors.isOAS3() ?\n OAS3_OPERATION_METHODS : SWAGGER2_OPERATION_METHODS\n\n if(validMethods.indexOf(method) === -1) {\n return null\n }\n\n return \n }).toArray()\n }\n \n
\n )\n }).toArray()\n }\n\n { taggedOps.size < 1 ?

No operations defined in spec!

: null }\n
\n )\n }\n\n}\n\nOperations.propTypes = {\n layoutActions: PropTypes.object.isRequired,\n specSelectors: PropTypes.object.isRequired,\n specActions: PropTypes.object.isRequired,\n layoutSelectors: PropTypes.object.isRequired,\n getComponent: PropTypes.func.isRequired,\n fn: PropTypes.object.isRequired\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/operations.jsx","import React from \"react\"\nimport PropTypes from \"prop-types\"\nimport { Link } from \"core/components/layout-utils\"\n\nexport default class Overview extends React.Component {\n\n constructor(...args) {\n super(...args)\n this.setTagShown = this._setTagShown.bind(this)\n }\n\n _setTagShown(showTagId, shown) {\n this.props.layoutActions.show(showTagId, shown)\n }\n\n showOp(key, shown) {\n let { layoutActions } = this.props\n layoutActions.show(key, shown)\n }\n\n render() {\n let { specSelectors, layoutSelectors, layoutActions, getComponent } = this.props\n let taggedOps = specSelectors.taggedOperations()\n\n const Collapse = getComponent(\"Collapse\")\n\n return (\n
\n

Overview

\n\n {\n taggedOps.map( (tagObj, tag) => {\n let operations = tagObj.get(\"operations\")\n\n let showTagId = [\"overview-tags\", tag]\n let showTag = layoutSelectors.isShown(showTagId, true)\n let toggleShow = ()=> layoutActions.show(showTagId, !showTag)\n\n return (\n
\n\n\n

{showTag ? \"-\" : \"+\"}{tag}

\n\n \n {\n operations.map( op => {\n let { path, method, id } = op.toObject() // toObject is shallow\n let showOpIdPrefix = \"operations\"\n let showOpId = id\n let shown = layoutSelectors.isShown([showOpIdPrefix, showOpId])\n return \n }).toArray()\n }\n \n\n
\n )\n }).toArray()\n }\n\n { taggedOps.size < 1 &&

No operations defined in spec!

}\n
\n )\n }\n\n}\n\nOverview.propTypes = {\n layoutSelectors: PropTypes.object.isRequired,\n specSelectors: PropTypes.object.isRequired,\n layoutActions: PropTypes.object.isRequired,\n getComponent: PropTypes.func.isRequired\n}\n\nexport class OperationLink extends React.Component {\n\n constructor(props) {\n super(props)\n this.onClick = this._onClick.bind(this)\n }\n\n _onClick() {\n let { showOpId, showOpIdPrefix, onClick, shown } = this.props\n onClick([showOpIdPrefix, showOpId], !shown)\n }\n\n render() {\n let { id, method, shown, href } = this.props\n\n return (\n \n
\n {method.toUpperCase()}\n {id}\n
\n \n )\n }\n\n}\n\nOperationLink.propTypes = {\n href: PropTypes.string,\n onClick: PropTypes.func,\n id: PropTypes.string.isRequired,\n method: PropTypes.string.isRequired,\n shown: PropTypes.bool.isRequired,\n showOpId: PropTypes.string.isRequired,\n showOpIdPrefix: PropTypes.string.isRequired\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/overview.jsx","import React, { PureComponent } from \"react\"\nimport PropTypes from \"prop-types\"\nimport { fromJS, List } from \"immutable\"\nimport { getSampleSchema } from \"core/utils\"\n\nconst NOOP = Function.prototype\n\nexport default class ParamBody extends PureComponent {\n\n static propTypes = {\n param: PropTypes.object,\n onChange: PropTypes.func,\n onChangeConsumes: PropTypes.func,\n consumes: PropTypes.object,\n consumesValue: PropTypes.string,\n fn: PropTypes.object.isRequired,\n getComponent: PropTypes.func.isRequired,\n isExecute: PropTypes.bool,\n specSelectors: PropTypes.object.isRequired,\n pathMethod: PropTypes.array.isRequired\n };\n\n static defaultProp = {\n consumes: fromJS([\"application/json\"]),\n param: fromJS({}),\n onChange: NOOP,\n onChangeConsumes: NOOP,\n };\n\n constructor(props, context) {\n super(props, context)\n\n this.state = {\n isEditBox: false,\n value: \"\"\n }\n\n }\n\n componentDidMount() {\n this.updateValues.call(this, this.props)\n }\n\n componentWillReceiveProps(nextProps) {\n this.updateValues.call(this, nextProps)\n }\n\n updateValues = (props) => {\n let { specSelectors, pathMethod, param, isExecute, consumesValue=\"\" } = props\n let parameter = specSelectors ? specSelectors.getParameter(pathMethod, param.get(\"name\"), param.get(\"in\")) : fromJS({})\n let isXml = /xml/i.test(consumesValue)\n let isJson = /json/i.test(consumesValue)\n let paramValue = isXml ? parameter.get(\"value_xml\") : parameter.get(\"value\")\n\n if ( paramValue !== undefined ) {\n let val = !paramValue && isJson ? \"{}\" : paramValue\n this.setState({ value: val })\n this.onChange(val, {isXml: isXml, isEditBox: isExecute})\n } else {\n if (isXml) {\n this.onChange(this.sample(\"xml\"), {isXml: isXml, isEditBox: isExecute})\n } else {\n this.onChange(this.sample(), {isEditBox: isExecute})\n }\n }\n }\n\n sample = (xml) => {\n let { param, fn:{inferSchema} } = this.props\n let schema = inferSchema(param.toJS())\n\n return getSampleSchema(schema, xml, {\n includeWriteOnly: true\n })\n }\n\n onChange = (value, { isEditBox, isXml }) => {\n this.setState({value, isEditBox})\n this._onChange(value, isXml)\n }\n\n _onChange = (val, isXml) => { (this.props.onChange || NOOP)(this.props.param, val, isXml) }\n\n handleOnChange = e => {\n const {consumesValue} = this.props\n const isJson = /json/i.test(consumesValue)\n const isXml = /xml/i.test(consumesValue)\n const inputValue = isJson ? e.target.value.trim() : e.target.value\n this.onChange(inputValue, {isXml})\n }\n\n toggleIsEditBox = () => this.setState( state => ({isEditBox: !state.isEditBox}))\n\n render() {\n let {\n onChangeConsumes,\n param,\n isExecute,\n specSelectors,\n pathMethod,\n\n getComponent,\n } = this.props\n\n const Button = getComponent(\"Button\")\n const TextArea = getComponent(\"TextArea\")\n const HighlightCode = getComponent(\"highlightCode\")\n const ContentType = getComponent(\"contentType\")\n // for domains where specSelectors not passed\n let parameter = specSelectors ? specSelectors.getParameter(pathMethod, param.get(\"name\"), param.get(\"in\")) : param\n let errors = parameter.get(\"errors\", List())\n let consumesValue = specSelectors.contentTypeValues(pathMethod).get(\"requestContentType\")\n let consumes = this.props.consumes && this.props.consumes.size ? this.props.consumes : ParamBody.defaultProp.consumes\n\n let { value, isEditBox } = this.state\n\n return (\n
\n {\n isEditBox && isExecute\n ? \n
\n
\n )\n }\n\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/curl.jsx","import React from \"react\"\nimport PropTypes from \"prop-types\"\n\nexport const DeepLink = ({ enabled, path, text }) => {\n return (\n e.preventDefault() : null}\n href={enabled ? `#/${path}` : null}>\n {text}\n \n )\n}\nDeepLink.propTypes = {\n enabled: PropTypes.bool,\n isShown: PropTypes.bool,\n path: PropTypes.string,\n text: PropTypes.string\n}\n\nexport default DeepLink\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/deep-link.jsx","import React from \"react\"\nimport ImPropTypes from \"react-immutable-proptypes\"\n\nconst EnumModel = ({ value, getComponent }) => {\n let ModelCollapse = getComponent(\"ModelCollapse\")\n let collapsedContent = Array [ { value.count() } ]\n return \n Enum:
\n \n [ { value.join(\", \") } ]\n \n
\n}\nEnumModel.propTypes = {\n value: ImPropTypes.iterable,\n getComponent: ImPropTypes.func\n}\n\nexport default EnumModel\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/enum-model.jsx","import React from \"react\"\nimport PropTypes from \"prop-types\"\nimport { List } from \"immutable\"\nimport { Collapse } from \"react-collapse\"\n\nexport default class Errors extends React.Component {\n\n static propTypes = {\n editorActions: PropTypes.object,\n errSelectors: PropTypes.object.isRequired,\n layoutSelectors: PropTypes.object.isRequired,\n layoutActions: PropTypes.object.isRequired\n }\n\n render() {\n let { editorActions, errSelectors, layoutSelectors, layoutActions } = this.props\n\n if(editorActions && editorActions.jumpToLine) {\n var jumpToLine = editorActions.jumpToLine\n }\n\n let errors = errSelectors.allErrors()\n\n // all thrown errors, plus error-level everything else\n let allErrorsToDisplay = errors.filter(err => err.get(\"type\") === \"thrown\" ? true :err.get(\"level\") === \"error\")\n\n if(!allErrorsToDisplay || allErrorsToDisplay.count() < 1) {\n return null\n }\n\n let isVisible = layoutSelectors.isShown([\"errorPane\"], true)\n let toggleVisibility = () => layoutActions.show([\"errorPane\"], !isVisible)\n\n let sortedJSErrors = allErrorsToDisplay.sortBy(err => err.get(\"line\"))\n\n return (\n
\n        
\n

Errors

\n \n
\n \n
\n { sortedJSErrors.map((err, i) => {\n let type = err.get(\"type\")\n if(type === \"thrown\" || type === \"auth\") {\n return \n }\n if(type === \"spec\") {\n return \n }\n }) }\n
\n
\n
\n )\n }\n}\n\nconst ThrownErrorItem = ( { error, jumpToLine } ) => {\n if(!error) {\n return null\n }\n let errorLine = error.get(\"line\")\n\n return (\n
\n { !error ? null :\n
\n

{ (error.get(\"source\") && error.get(\"level\")) ?\n toTitleCase(error.get(\"source\")) + \" \" + error.get(\"level\") : \"\" }\n { error.get(\"path\") ? at {error.get(\"path\")}: null }

\n \n { error.get(\"message\") }\n \n
\n { errorLine && jumpToLine ? Jump to line { errorLine } : null }\n
\n
\n }\n
\n )\n }\n\nconst SpecErrorItem = ( { error, jumpToLine } ) => {\n let locationMessage = null\n\n if(error.get(\"path\")) {\n if(List.isList(error.get(\"path\"))) {\n locationMessage = at { error.get(\"path\").join(\".\") }\n } else {\n locationMessage = at { error.get(\"path\") }\n }\n } else if(error.get(\"line\") && !jumpToLine) {\n locationMessage = on line { error.get(\"line\") }\n }\n\n return (\n
\n { !error ? null :\n
\n

{ toTitleCase(error.get(\"source\")) + \" \" + error.get(\"level\") } { locationMessage }

\n { error.get(\"message\") }\n
\n { jumpToLine ? (\n Jump to line { error.get(\"line\") }\n ) : null }\n
\n
\n }\n
\n )\n }\n\nfunction toTitleCase(str) {\n return (str || \"\")\n .split(\" \")\n .map(substr => substr[0].toUpperCase() + substr.slice(1))\n .join(\" \")\n}\n\nThrownErrorItem.propTypes = {\n error: PropTypes.object.isRequired,\n jumpToLine: PropTypes.func\n}\n\nThrownErrorItem.defaultProps = {\n jumpToLine: null\n}\n\nSpecErrorItem.propTypes = {\n error: PropTypes.object.isRequired,\n jumpToLine: PropTypes.func\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/errors.jsx","import React, { Component } from \"react\"\nimport PropTypes from \"prop-types\"\n\nexport default class Execute extends Component {\n\n static propTypes = {\n specSelectors: PropTypes.object.isRequired,\n specActions: PropTypes.object.isRequired,\n operation: PropTypes.object.isRequired,\n path: PropTypes.string.isRequired,\n method: PropTypes.string.isRequired,\n onExecute: PropTypes.func\n }\n\n onClick=()=>{\n let { specSelectors, specActions, operation, path, method } = this.props\n\n specActions.validateParams( [path, method] )\n\n if ( specSelectors.validateBeforeExecute([path, method]) ) {\n if(this.props.onExecute) {\n this.props.onExecute()\n }\n specActions.execute( { operation, path, method } )\n }\n }\n\n onChangeProducesWrapper = ( val ) => this.props.specActions.changeProducesValue([this.props.path, this.props.method], val)\n\n render(){\n return (\n \n )\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/execute.jsx","import React from \"react\"\n\nexport default class Footer extends React.Component {\n render() {\n return (\n
\n )\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/footer.jsx","import React from \"react\"\nimport PropTypes from \"prop-types\"\nimport Im from \"immutable\"\n\nconst propStyle = { color: \"#999\", fontStyle: \"italic\" }\n\nexport default class Headers extends React.Component {\n\n static propTypes = {\n headers: PropTypes.object.isRequired,\n getComponent: PropTypes.func.isRequired\n };\n\n render() {\n\n let { headers, getComponent } = this.props\n const Property = getComponent(\"Property\")\n\n if ( !headers || !headers.size )\n return null\n\n return (\n
\n

Headers:

\n \n \n \n \n \n \n \n \n \n {\n headers.entrySeq().map( ([ key, header ]) => {\n if(!Im.Map.isMap(header)) {\n return null\n }\n const type = header.getIn([\"schema\"]) ? header.getIn([\"schema\", \"type\"]) : header.getIn([\"type\"])\n const schemaExample = header.getIn([\"schema\", \"example\"])\n\n return (\n \n \n \n )\n }).toArray()\n }\n \n
NameDescriptionType
{ key }{ header.get( \"description\" ) }{ type } { schemaExample ? : null }
\n
\n )\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/headers.jsx","import React, { Component } from \"react\"\nimport PropTypes from \"prop-types\"\nimport { highlight } from \"core/utils\"\n\nexport default class HighlightCode extends Component {\n static propTypes = {\n value: PropTypes.string.isRequired,\n className: PropTypes.string\n }\n\n componentDidMount() {\n highlight(this.el)\n }\n\n componentDidUpdate() {\n highlight(this.el)\n }\n\n initializeComponent = (c) => {\n this.el = c\n }\n\n render () {\n let { value, className } = this.props\n className = className || \"\"\n\n return
{ value }
\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/highlight-code.jsx","import React from \"react\"\nimport PropTypes from \"prop-types\"\nimport { fromJS } from \"immutable\"\nimport ImPropTypes from \"react-immutable-proptypes\"\nimport { sanitizeUrl } from \"core/utils\"\n\n\nclass Path extends React.Component {\n static propTypes = {\n host: PropTypes.string,\n basePath: PropTypes.string\n }\n\n render() {\n let { host, basePath } = this.props\n\n return (\n
\n        [ Base URL: {host}{basePath} ]\n      
\n )\n }\n}\n\n\nclass Contact extends React.Component {\n static propTypes = {\n data: PropTypes.object\n }\n\n render(){\n let { data } = this.props\n let name = data.get(\"name\") || \"the developer\"\n let url = data.get(\"url\")\n let email = data.get(\"email\")\n\n return (\n \n )\n }\n}\n\nclass License extends React.Component {\n static propTypes = {\n license: PropTypes.object\n }\n\n render(){\n let { license } = this.props\n let name = license.get(\"name\") || \"License\"\n let url = license.get(\"url\")\n\n return (\n
\n {\n url ? { name }\n : { name }\n }\n
\n )\n }\n}\n\nexport default class Info extends React.Component {\n static propTypes = {\n info: PropTypes.object,\n url: PropTypes.string,\n host: PropTypes.string,\n basePath: PropTypes.string,\n externalDocs: ImPropTypes.map,\n getComponent: PropTypes.func.isRequired,\n }\n\n render() {\n let { info, url, host, basePath, getComponent, externalDocs } = this.props\n let version = info.get(\"version\")\n let description = info.get(\"description\")\n let title = info.get(\"title\")\n let termsOfService = info.get(\"termsOfService\")\n let contact = info.get(\"contact\")\n let license = info.get(\"license\")\n const { url:externalDocsUrl, description:externalDocsDescription } = (externalDocs || fromJS({})).toJS()\n\n const Markdown = getComponent(\"Markdown\")\n const VersionStamp = getComponent(\"VersionStamp\")\n\n return (\n
\n
\n

{ title }\n { version && }\n

\n { host || basePath ? : null }\n { url && { url } }\n
\n\n
\n \n
\n\n {\n termsOfService && \n }\n\n { contact && contact.size ? : null }\n { license && license.size ? : null }\n { externalDocsUrl ?\n {externalDocsDescription || externalDocsUrl}\n : null }\n\n
\n )\n }\n\n}\n\nInfo.propTypes = {\n title: PropTypes.any,\n description: PropTypes.any,\n version: PropTypes.any,\n url: PropTypes.string\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/info.jsx","import React from \"react\"\nimport PropTypes from \"prop-types\"\n\nexport default class BaseLayout extends React.Component {\n\n static propTypes = {\n errSelectors: PropTypes.object.isRequired,\n errActions: PropTypes.object.isRequired,\n specActions: PropTypes.object.isRequired,\n specSelectors: PropTypes.object.isRequired,\n oas3Selectors: PropTypes.object.isRequired,\n oas3Actions: PropTypes.object.isRequired,\n layoutSelectors: PropTypes.object.isRequired,\n layoutActions: PropTypes.object.isRequired,\n getComponent: PropTypes.func.isRequired\n }\n\n onFilterChange =(e) => {\n let {target: {value}} = e\n this.props.layoutActions.updateFilter(value)\n }\n\n render() {\n let {\n specSelectors,\n specActions,\n getComponent,\n layoutSelectors,\n oas3Selectors,\n oas3Actions\n } = this.props\n\n let info = specSelectors.info()\n let url = specSelectors.url()\n let basePath = specSelectors.basePath()\n let host = specSelectors.host()\n let securityDefinitions = specSelectors.securityDefinitions()\n let externalDocs = specSelectors.externalDocs()\n let schemes = specSelectors.schemes()\n let servers = specSelectors.servers()\n\n let Info = getComponent(\"info\")\n let Operations = getComponent(\"operations\", true)\n let Models = getComponent(\"Models\", true)\n let AuthorizeBtn = getComponent(\"authorizeBtn\", true)\n let Row = getComponent(\"Row\")\n let Col = getComponent(\"Col\")\n let Servers = getComponent(\"Servers\")\n let Errors = getComponent(\"errors\", true)\n\n let isLoading = specSelectors.loadingStatus() === \"loading\"\n let isFailed = specSelectors.loadingStatus() === \"failed\"\n let filter = layoutSelectors.currentFilter()\n\n let inputStyle = {}\n if(isFailed) inputStyle.color = \"red\"\n if(isLoading) inputStyle.color = \"#aaa\"\n\n const Schemes = getComponent(\"schemes\")\n\n const isSpecEmpty = !specSelectors.specStr()\n\n if(isSpecEmpty) {\n let loadingMessage\n if(isLoading) {\n loadingMessage =
\n } else {\n loadingMessage =

No API definition provided.

\n }\n\n return
\n
\n {loadingMessage}\n
\n
\n }\n\n return (\n\n
\n
\n \n \n \n { info.count() ? (\n \n ) : null }\n \n \n { schemes && schemes.size || securityDefinitions ? (\n
\n \n { schemes && schemes.size ? (\n \n ) : null }\n\n { securityDefinitions ? (\n \n ) : null }\n \n
\n ) : null }\n\n { servers && servers.size ? (\n
\n \n Server\n \n \n
\n\n ) : null}\n\n {\n filter === null || filter === false ? null :\n
\n \n \n \n
\n }\n\n \n \n \n \n \n \n \n \n \n \n
\n
\n )\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/layouts/base.jsx","import React from \"react\"\nimport PropTypes from \"prop-types\"\nimport ImPropTypes from \"react-immutable-proptypes\"\nimport { Iterable } from \"immutable\"\n\nconst Headers = ( { headers } )=>{\n return (\n
\n
Response headers
\n
{headers}
\n
)\n}\nHeaders.propTypes = {\n headers: PropTypes.array.isRequired\n}\n\nconst Duration = ( { duration } ) => {\n return (\n
\n
Request duration
\n
{duration} ms
\n
\n )\n}\nDuration.propTypes = {\n duration: PropTypes.number.isRequired\n}\n\n\nexport default class LiveResponse extends React.Component {\n static propTypes = {\n response: PropTypes.instanceOf(Iterable).isRequired,\n path: PropTypes.string.isRequired,\n method: PropTypes.string.isRequired,\n displayRequestDuration: PropTypes.bool.isRequired,\n specSelectors: PropTypes.object.isRequired,\n getComponent: PropTypes.func.isRequired,\n getConfigs: PropTypes.func.isRequired\n }\n\n shouldComponentUpdate(nextProps) {\n // BUG: props.response is always coming back as a new Immutable instance\n // same issue as responses.jsx (tryItOutResponse)\n return this.props.response !== nextProps.response\n || this.props.path !== nextProps.path\n || this.props.method !== nextProps.method\n || this.props.displayRequestDuration !== nextProps.displayRequestDuration\n }\n\n render() {\n const { response, getComponent, getConfigs, displayRequestDuration, specSelectors, path, method } = this.props\n const { showMutatedRequest } = getConfigs()\n\n const curlRequest = showMutatedRequest ? specSelectors.mutatedRequestFor(path, method) : specSelectors.requestFor(path, method)\n const status = response.get(\"status\")\n const url = response.get(\"url\")\n const headers = response.get(\"headers\").toJS()\n const notDocumented = response.get(\"notDocumented\")\n const isError = response.get(\"error\")\n const body = response.get(\"text\")\n const duration = response.get(\"duration\")\n const headersKeys = Object.keys(headers)\n const contentType = headers[\"content-type\"]\n\n const Curl = getComponent(\"curl\")\n const ResponseBody = getComponent(\"responseBody\")\n const returnObject = headersKeys.map(key => {\n return {key}: {headers[key]} \n })\n const hasHeaders = returnObject.length !== 0\n\n return (\n
\n { curlRequest && }\n { url &&
\n

Request URL

\n
\n
{url}
\n
\n
\n }\n

Server response

\n \n \n \n \n \n \n \n \n \n \n \n \n \n
CodeDetails
\n { status }\n {\n notDocumented ?
\n Undocumented \n
\n : null\n }\n
\n {\n isError ? \n {`${response.get(\"name\")}: ${response.get(\"message\")}`}\n \n : null\n }\n {\n body ? \n : null\n }\n {\n hasHeaders ? : null\n }\n {\n displayRequestDuration && duration ? : null\n }\n
\n
\n )\n }\n\n static propTypes = {\n getComponent: PropTypes.func.isRequired,\n response: ImPropTypes.map\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/live-response.jsx","import React, { Component } from \"react\"\nimport PropTypes from \"prop-types\"\n\nexport default class ModelCollapse extends Component {\n static propTypes = {\n collapsedContent: PropTypes.any,\n expanded: PropTypes.bool,\n children: PropTypes.any,\n title: PropTypes.element,\n modelName: PropTypes.string,\n onToggle: PropTypes.func\n }\n\n static defaultProps = {\n collapsedContent: \"{...}\",\n expanded: false,\n title: null,\n onToggle: () => {}\n }\n\n constructor(props, context) {\n super(props, context)\n\n let { expanded, collapsedContent } = this.props\n\n this.state = {\n expanded : expanded,\n collapsedContent: collapsedContent || ModelCollapse.defaultProps.collapsedContent\n }\n }\n\n componentWillReceiveProps(nextProps){\n\n if(this.props.expanded!= nextProps.expanded){\n this.setState({expanded: nextProps.expanded})\n }\n\n }\n\n toggleCollapsed=()=>{\n\n\n if(this.props.onToggle){\n this.props.onToggle(this.props.modelName,!this.state.expanded)\n }\n\n this.setState({\n expanded: !this.state.expanded\n })\n }\n\n render () {\n const {title} = this.props\n return (\n \n { title && {title} }\n \n \n \n { this.state.expanded ? this.props.children :this.state.collapsedContent }\n \n )\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/model-collapse.jsx","import React from \"react\"\nimport PropTypes from \"prop-types\"\nimport ImPropTypes from \"react-immutable-proptypes\"\n\nexport default class ModelExample extends React.Component {\n static propTypes = {\n getComponent: PropTypes.func.isRequired,\n specSelectors: PropTypes.object.isRequired,\n schema: PropTypes.object.isRequired,\n example: PropTypes.any.isRequired,\n isExecute: PropTypes.bool,\n getConfigs: PropTypes.func.isRequired,\n specPath: ImPropTypes.list.isRequired,\n }\n\n constructor(props, context) {\n super(props, context)\n let { getConfigs } = this.props\n let { defaultModelRendering } = getConfigs()\n if (defaultModelRendering !== \"example\" && defaultModelRendering !== \"model\") {\n defaultModelRendering = \"example\"\n }\n this.state = {\n activeTab: defaultModelRendering\n }\n }\n\n activeTab =( e ) => {\n let { target : { dataset : { name } } } = e\n\n this.setState({\n activeTab: name\n })\n }\n\n render() {\n let { getComponent, specSelectors, schema, example, isExecute, getConfigs, specPath } = this.props\n let { defaultModelExpandDepth } = getConfigs()\n const ModelWrapper = getComponent(\"ModelWrapper\")\n\n return
\n \n
\n {\n (isExecute || this.state.activeTab === \"example\") && example\n }\n {\n !isExecute && this.state.activeTab === \"model\" && \n\n\n }\n
\n
\n }\n\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/model-example.jsx","import React, { Component, } from \"react\"\nimport PropTypes from \"prop-types\"\n//import layoutActions from \"actions/layout\"\n\n\nexport default class ModelWrapper extends Component {\n\n\n static propTypes = {\n schema: PropTypes.object.isRequired,\n name: PropTypes.string,\n getComponent: PropTypes.func.isRequired,\n getConfigs: PropTypes.func.isRequired,\n specSelectors: PropTypes.object.isRequired,\n expandDepth: PropTypes.number,\n layoutActions: PropTypes.object,\n layoutSelectors: PropTypes.object.isRequired\n }\n\n onToggle = (name,isShown) => {\n // If this prop is present, we'll have deepLinking for it\n if(this.props.layoutActions) {\n this.props.layoutActions.show([\"models\", name],isShown)\n }\n }\n\n render(){\n let { getComponent, getConfigs } = this.props\n const Model = getComponent(\"Model\")\n\n let expanded\n if(this.props.layoutSelectors) {\n // If this is prop is present, we'll have deepLinking for it\n expanded = this.props.layoutSelectors.isShown([\"models\",this.props.name])\n }\n\n return
\n \n
\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/model-wrapper.jsx","import React, { Component } from \"react\"\nimport Im from \"immutable\"\nimport PropTypes from \"prop-types\"\n\nexport default class Models extends Component {\n static propTypes = {\n getComponent: PropTypes.func,\n specSelectors: PropTypes.object,\n layoutSelectors: PropTypes.object,\n layoutActions: PropTypes.object,\n getConfigs: PropTypes.func.isRequired\n }\n\n render(){\n let { specSelectors, getComponent, layoutSelectors, layoutActions, getConfigs } = this.props\n let definitions = specSelectors.definitions()\n let { docExpansion, defaultModelsExpandDepth } = getConfigs()\n if (!definitions.size || defaultModelsExpandDepth < 0) return null\n\n let showModels = layoutSelectors.isShown(\"models\", defaultModelsExpandDepth > 0 && docExpansion !== \"none\")\n const specPathBase = specSelectors.isOAS3() ? [\"components\", \"schemas\"] : [\"definitions\"]\n\n const ModelWrapper = getComponent(\"ModelWrapper\")\n const Collapse = getComponent(\"Collapse\")\n\n return
\n

layoutActions.show(\"models\", !showModels)}>\n Models\n \n \n \n

\n \n {\n definitions.entrySeq().map( ( [ name, model ])=>{\n\n return
\n \n
\n }).toArray()\n }\n
\n
\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/models.jsx","import React, { Component, } from \"react\"\nimport PropTypes from \"prop-types\"\nimport { List } from \"immutable\"\nimport ImPropTypes from \"react-immutable-proptypes\"\n\nconst braceOpen = \"{\"\nconst braceClose = \"}\"\n\nexport default class ObjectModel extends Component {\n static propTypes = {\n schema: PropTypes.object.isRequired,\n getComponent: PropTypes.func.isRequired,\n getConfigs: PropTypes.func.isRequired,\n expanded: PropTypes.bool,\n onToggle: PropTypes.func,\n specSelectors: PropTypes.object.isRequired,\n name: PropTypes.string,\n isRef: PropTypes.bool,\n expandDepth: PropTypes.number,\n depth: PropTypes.number,\n specPath: ImPropTypes.list.isRequired\n }\n\n render(){\n let { schema, name, isRef, getComponent, getConfigs, depth, onToggle, expanded, specPath, ...otherProps } = this.props\n let { specSelectors,expandDepth } = otherProps\n const { isOAS3 } = specSelectors\n\n if(!schema) {\n return null\n }\n\n const { showExtensions } = getConfigs()\n\n let description = schema.get(\"description\")\n let properties = schema.get(\"properties\")\n let additionalProperties = schema.get(\"additionalProperties\")\n let title = schema.get(\"title\") || name\n let requiredProperties = schema.get(\"required\")\n\n const JumpToPath = getComponent(\"JumpToPath\", true)\n const Markdown = getComponent(\"Markdown\")\n const Model = getComponent(\"Model\")\n const ModelCollapse = getComponent(\"ModelCollapse\")\n\n const JumpToPathSection = () => {\n return \n }\n const collapsedContent = (\n { braceOpen }...{ braceClose }\n {\n isRef ? : \"\"\n }\n )\n\n const anyOf = specSelectors.isOAS3() ? schema.get(\"anyOf\") : null\n const oneOf = specSelectors.isOAS3() ? schema.get(\"oneOf\") : null\n const not = specSelectors.isOAS3() ? schema.get(\"not\") : null\n\n const titleEl = title && \n { isRef && schema.get(\"$$ref\") && { schema.get(\"$$ref\") } }\n { title }\n \n\n return \n \n\n { braceOpen }\n {\n !isRef ? null : \n }\n \n {\n \n {\n !description ? null : \n \n \n \n }\n {\n !(properties && properties.size) ? null : properties.entrySeq().map(\n ([key, value]) => {\n let isDeprecated = isOAS3() && value.get(\"deprecated\")\n let isRequired = List.isList(requiredProperties) && requiredProperties.contains(key)\n let propertyStyle = { verticalAlign: \"top\", paddingRight: \"0.2em\" }\n if ( isRequired ) {\n propertyStyle.fontWeight = \"bold\"\n }\n\n return (\n \n \n )\n }).toArray()\n }\n {\n // empty row befor extensions...\n !showExtensions ? null :  \n }\n {\n !showExtensions ? null :\n schema.entrySeq().map(\n ([key, value]) => {\n if(key.slice(0,2) !== \"x-\") {\n return\n }\n\n const normalizedValue = !value ? null : value.toJS ? value.toJS() : value\n\n return (\n \n \n )\n }).toArray()\n }\n {\n !additionalProperties || !additionalProperties.size ? null\n : \n \n \n \n }\n {\n !anyOf ? null\n : \n \n \n \n }\n {\n !oneOf ? null\n : \n \n \n \n }\n {\n !not ? null\n : \n \n \n \n }\n
description:\n \n
\n { key }{ isRequired && * }\n \n \n
\n { key }\n \n { JSON.stringify(normalizedValue) }\n
{ \"< * >:\" }\n \n
{ \"anyOf ->\" }\n {anyOf.map((schema, k) => {\n return
\n })}\n
{ \"oneOf ->\" }\n {oneOf.map((schema, k) => {\n return
\n })}\n
{ \"not ->\" }\n
\n \n
\n
\n }\n
\n { braceClose }\n \n
\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/object-model.jsx","import React from \"react\"\nimport PropTypes from \"prop-types\"\nimport { sanitizeUrl } from \"core/utils\"\n\nexport default class OnlineValidatorBadge extends React.Component {\n static propTypes = {\n getComponent: PropTypes.func.isRequired,\n getConfigs: PropTypes.func.isRequired,\n specSelectors: PropTypes.object.isRequired\n }\n\n constructor(props, context) {\n super(props, context)\n let { specSelectors, getConfigs } = props\n let { validatorUrl } = getConfigs()\n this.state = {\n url: specSelectors.url(),\n validatorUrl: validatorUrl === undefined ? \"https://online.swagger.io/validator\" : validatorUrl\n }\n }\n\n componentWillReceiveProps(nextProps) {\n let { specSelectors, getConfigs } = nextProps\n let { validatorUrl } = getConfigs()\n\n this.setState({\n url: specSelectors.url(),\n validatorUrl: validatorUrl === undefined ? \"https://online.swagger.io/validator\" : validatorUrl\n })\n }\n\n render() {\n let { getConfigs } = this.props\n let { spec } = getConfigs()\n\n let sanitizedValidatorUrl = sanitizeUrl(this.state.validatorUrl)\n\n if ( typeof spec === \"object\" && Object.keys(spec).length) return null\n\n if (!this.state.url || !this.state.validatorUrl || this.state.url.indexOf(\"localhost\") >= 0\n || this.state.url.indexOf(\"127.0.0.1\") >= 0) {\n return null\n }\n\n return (\n \n \n \n )\n }\n}\n\n\nclass ValidatorImage extends React.Component {\n static propTypes = {\n src: PropTypes.string,\n alt: PropTypes.string\n }\n\n constructor(props) {\n super(props)\n this.state = {\n loaded: false,\n error: false\n }\n }\n\n componentDidMount() {\n const img = new Image()\n img.onload = () => {\n this.setState({\n loaded: true\n })\n }\n img.onerror = () => {\n this.setState({\n error: true\n })\n }\n img.src = this.props.src\n }\n\n componentWillReceiveProps(nextProps) {\n if (nextProps.src !== this.props.src) {\n const img = new Image()\n img.onload = () => {\n this.setState({\n loaded: true\n })\n }\n img.onerror = () => {\n this.setState({\n error: true\n })\n }\n img.src = nextProps.src\n }\n }\n\n render() {\n if (this.state.error) {\n return {\"Error\"}\n } else if (!this.state.loaded) {\n return {\"Loading...\"}\n }\n return {this.props.alt}\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/online-validator-badge.jsx","import React from \"react\"\nimport PropTypes from \"prop-types\"\n\nexport const OperationExtRow = ({ xKey, xVal }) => {\n const xNormalizedValue = !xVal ? null : xVal.toJS ? xVal.toJS() : xVal\n\n return (\n { xKey }\n { JSON.stringify(xNormalizedValue) }\n )\n}\nOperationExtRow.propTypes = {\n xKey: PropTypes.string,\n xVal: PropTypes.any\n}\n\nexport default OperationExtRow\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/operation-extension-row.jsx","import React from \"react\"\nimport PropTypes from \"prop-types\"\n\nexport const OperationExt = ({ extensions, getComponent }) => {\n let OperationExtRow = getComponent(\"OperationExtRow\")\n return (\n
\n
\n

Extensions

\n
\n
\n\n \n \n \n \n \n \n \n \n {\n extensions.entrySeq().map(([k, v]) => )\n }\n \n
FieldValue
\n
\n
\n )\n}\nOperationExt.propTypes = {\n extensions: PropTypes.object.isRequired,\n getComponent: PropTypes.func.isRequired\n}\n\nexport default OperationExt\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/operation-extensions.jsx","import React, { PureComponent } from \"react\"\nimport PropTypes from \"prop-types\"\nimport { getList } from \"core/utils\"\nimport { getExtensions, sanitizeUrl } from \"core/utils\"\nimport { Iterable, List } from \"immutable\"\nimport ImPropTypes from \"react-immutable-proptypes\"\n\nexport default class Operation extends PureComponent {\n static propTypes = {\n specPath: ImPropTypes.list.isRequired,\n operation: PropTypes.instanceOf(Iterable).isRequired,\n response: PropTypes.instanceOf(Iterable),\n request: PropTypes.instanceOf(Iterable),\n\n toggleShown: PropTypes.func.isRequired,\n onTryoutClick: PropTypes.func.isRequired,\n onCancelClick: PropTypes.func.isRequired,\n onExecute: PropTypes.func.isRequired,\n\n getComponent: PropTypes.func.isRequired,\n getConfigs: PropTypes.func.isRequired,\n authActions: PropTypes.object,\n authSelectors: PropTypes.object,\n specActions: PropTypes.object.isRequired,\n specSelectors: PropTypes.object.isRequired,\n oas3Actions: PropTypes.object.isRequired,\n oas3Selectors: PropTypes.object.isRequired,\n layoutActions: PropTypes.object.isRequired,\n layoutSelectors: PropTypes.object.isRequired,\n fn: PropTypes.object.isRequired\n }\n\n static defaultProps = {\n operation: null,\n response: null,\n request: null,\n specPath: List()\n }\n\n render() {\n let {\n specPath,\n response,\n request,\n toggleShown,\n onTryoutClick,\n onCancelClick,\n onExecute,\n fn,\n getComponent,\n getConfigs,\n specActions,\n specSelectors,\n authActions,\n authSelectors,\n oas3Actions,\n oas3Selectors\n } = this.props\n let operationProps = this.props.operation\n\n let {\n isShown,\n isAuthorized,\n path,\n method,\n op,\n tag,\n showSummary,\n operationId,\n allowTryItOut,\n displayOperationId,\n displayRequestDuration,\n isDeepLinkingEnabled,\n tryItOutEnabled,\n executeInProgress\n } = operationProps.toJS()\n\n let {\n summary,\n description,\n deprecated,\n externalDocs,\n schemes\n } = op.operation\n\n let operation = operationProps.getIn([\"op\", \"operation\"])\n let security = operationProps.get(\"security\")\n let responses = operation.get(\"responses\")\n let produces = operation.get(\"produces\")\n let parameters = getList(operation, [\"parameters\"])\n let operationScheme = specSelectors.operationScheme(path, method)\n let isShownKey = [\"operations\", tag, operationId]\n let extensions = getExtensions(operation)\n\n const Responses = getComponent(\"responses\")\n const Parameters = getComponent( \"parameters\" )\n const Execute = getComponent( \"execute\" )\n const Clear = getComponent( \"clear\" )\n const AuthorizeOperationBtn = getComponent( \"authorizeOperationBtn\" )\n const JumpToPath = getComponent(\"JumpToPath\", true)\n const Collapse = getComponent( \"Collapse\" )\n const Markdown = getComponent( \"Markdown\" )\n const Schemes = getComponent( \"schemes\" )\n const OperationServers = getComponent( \"OperationServers\" )\n const OperationExt = getComponent( \"OperationExt\" )\n const DeepLink = getComponent( \"DeepLink\" )\n\n const { showExtensions } = getConfigs()\n\n // Merge in Live Response\n if(responses && response && response.size > 0) {\n let notDocumented = !responses.get(String(response.get(\"status\"))) && !responses.get(\"default\")\n response = response.set(\"notDocumented\", notDocumented)\n }\n\n let onChangeKey = [ path, method ] // Used to add values to _this_ operation ( indexed by path and method )\n\n return (\n
\n
\n {/*TODO: convert this into a component, that can be wrapped\n and pulled in with getComponent */}\n {method.toUpperCase()}\n \n \n {/*TODO: use wrapComponents here, swagger-ui doesn't care about jumpToPath */}\n \n\n { !showSummary ? null :\n
\n { summary }\n
\n }\n\n { displayOperationId && operationId ? {operationId} : null }\n\n {\n (!security || !security.count()) ? null :\n {\n const applicableDefinitions = authSelectors.definitionsForRequirements(security)\n authActions.showDefinitions(applicableDefinitions)\n }}\n />\n }\n
\n\n \n
\n { deprecated &&

Warning: Deprecated

}\n { description &&\n
\n
\n \n
\n
\n }\n {\n externalDocs && externalDocs.url ?\n
\n

Find more details

\n
\n \n \n \n { externalDocs.url }\n
\n
: null\n }\n\n \n\n { !tryItOutEnabled ? null :\n \n }\n\n {!tryItOutEnabled || !allowTryItOut ? null : schemes && schemes.size ?
\n \n
: null\n }\n\n
\n { !tryItOutEnabled || !allowTryItOut ? null :\n\n \n }\n\n { (!tryItOutEnabled || !response || !allowTryItOut) ? null :\n \n }\n
\n\n {executeInProgress ?
: null}\n\n { !responses ? null :\n \n }\n\n { !showExtensions || !extensions.size ? null :\n \n }\n
\n
\n
\n )\n }\n\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/operation.jsx","import React from \"react\"\nimport PropTypes from \"prop-types\"\nimport Im from \"immutable\"\nimport { createDeepLinkPath, sanitizeUrl } from \"core/utils\"\n\nconst SWAGGER2_OPERATION_METHODS = [\n \"get\", \"put\", \"post\", \"delete\", \"options\", \"head\", \"patch\"\n]\n\nconst OAS3_OPERATION_METHODS = SWAGGER2_OPERATION_METHODS.concat([\"trace\"])\n\n\nexport default class Operations extends React.Component {\n\n static propTypes = {\n specSelectors: PropTypes.object.isRequired,\n specActions: PropTypes.object.isRequired,\n oas3Actions: PropTypes.object.isRequired,\n getComponent: PropTypes.func.isRequired,\n layoutSelectors: PropTypes.object.isRequired,\n layoutActions: PropTypes.object.isRequired,\n authActions: PropTypes.object.isRequired,\n authSelectors: PropTypes.object.isRequired,\n getConfigs: PropTypes.func.isRequired\n };\n\n render() {\n let {\n specSelectors,\n getComponent,\n layoutSelectors,\n layoutActions,\n getConfigs\n } = this.props\n\n let taggedOps = specSelectors.taggedOperations()\n\n const OperationContainer = getComponent(\"OperationContainer\", true)\n const Collapse = getComponent(\"Collapse\")\n const Markdown = getComponent(\"Markdown\")\n const DeepLink = getComponent(\"DeepLink\")\n\n let {\n docExpansion,\n maxDisplayedTags,\n deepLinking\n } = getConfigs()\n\n const isDeepLinkingEnabled = deepLinking && deepLinking !== \"false\"\n\n let filter = layoutSelectors.currentFilter()\n\n if (filter) {\n if (filter !== true) {\n taggedOps = taggedOps.filter((tagObj, tag) => {\n return tag.indexOf(filter) !== -1\n })\n }\n }\n\n if (maxDisplayedTags && !isNaN(maxDisplayedTags) && maxDisplayedTags >= 0) {\n taggedOps = taggedOps.slice(0, maxDisplayedTags)\n }\n\n return (\n
\n {\n taggedOps.map( (tagObj, tag) => {\n let operations = tagObj.get(\"operations\")\n let tagDescription = tagObj.getIn([\"tagDetails\", \"description\"], null)\n let tagExternalDocsDescription = tagObj.getIn([\"tagDetails\", \"externalDocs\", \"description\"])\n let tagExternalDocsUrl = tagObj.getIn([\"tagDetails\", \"externalDocs\", \"url\"])\n\n let isShownKey = [\"operations-tag\", createDeepLinkPath(tag)]\n let showTag = layoutSelectors.isShown(isShownKey, docExpansion === \"full\" || docExpansion === \"list\")\n\n return (\n
\n\n layoutActions.show(isShownKey, !showTag)}\n className={!tagDescription ? \"opblock-tag no-desc\" : \"opblock-tag\" }\n id={isShownKey.join(\"-\")}>\n \n { !tagDescription ? :\n \n \n \n }\n\n
\n { !tagExternalDocsDescription ? null :\n \n { tagExternalDocsDescription }\n { tagExternalDocsUrl ? \": \" : null }\n { tagExternalDocsUrl ?\n e.stopPropagation()}\n target={\"_blank\"}\n >{tagExternalDocsUrl} : null\n }\n \n }\n
\n\n \n \n\n \n {\n operations.map( op => {\n const path = op.get(\"path\")\n const method = op.get(\"method\")\n const specPath = Im.List([\"paths\", path, method])\n\n\n // FIXME: (someday) this logic should probably be in a selector,\n // but doing so would require further opening up\n // selectors to the plugin system, to allow for dynamic\n // overriding of low-level selectors that other selectors\n // rely on. --KS, 12/17\n const validMethods = specSelectors.isOAS3() ?\n OAS3_OPERATION_METHODS : SWAGGER2_OPERATION_METHODS\n\n if(validMethods.indexOf(method) === -1) {\n return null\n }\n\n return \n }).toArray()\n }\n \n
\n )\n }).toArray()\n }\n\n { taggedOps.size < 1 ?

No operations defined in spec!

: null }\n
\n )\n }\n\n}\n\nOperations.propTypes = {\n layoutActions: PropTypes.object.isRequired,\n specSelectors: PropTypes.object.isRequired,\n specActions: PropTypes.object.isRequired,\n layoutSelectors: PropTypes.object.isRequired,\n getComponent: PropTypes.func.isRequired,\n fn: PropTypes.object.isRequired\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/operations.jsx","import React from \"react\"\nimport PropTypes from \"prop-types\"\nimport { Link } from \"core/components/layout-utils\"\n\nexport default class Overview extends React.Component {\n\n constructor(...args) {\n super(...args)\n this.setTagShown = this._setTagShown.bind(this)\n }\n\n _setTagShown(showTagId, shown) {\n this.props.layoutActions.show(showTagId, shown)\n }\n\n showOp(key, shown) {\n let { layoutActions } = this.props\n layoutActions.show(key, shown)\n }\n\n render() {\n let { specSelectors, layoutSelectors, layoutActions, getComponent } = this.props\n let taggedOps = specSelectors.taggedOperations()\n\n const Collapse = getComponent(\"Collapse\")\n\n return (\n
\n

Overview

\n\n {\n taggedOps.map( (tagObj, tag) => {\n let operations = tagObj.get(\"operations\")\n\n let showTagId = [\"overview-tags\", tag]\n let showTag = layoutSelectors.isShown(showTagId, true)\n let toggleShow = ()=> layoutActions.show(showTagId, !showTag)\n\n return (\n
\n\n\n

{showTag ? \"-\" : \"+\"}{tag}

\n\n \n {\n operations.map( op => {\n let { path, method, id } = op.toObject() // toObject is shallow\n let showOpIdPrefix = \"operations\"\n let showOpId = id\n let shown = layoutSelectors.isShown([showOpIdPrefix, showOpId])\n return \n }).toArray()\n }\n \n\n
\n )\n }).toArray()\n }\n\n { taggedOps.size < 1 &&

No operations defined in spec!

}\n
\n )\n }\n\n}\n\nOverview.propTypes = {\n layoutSelectors: PropTypes.object.isRequired,\n specSelectors: PropTypes.object.isRequired,\n layoutActions: PropTypes.object.isRequired,\n getComponent: PropTypes.func.isRequired\n}\n\nexport class OperationLink extends React.Component {\n\n constructor(props) {\n super(props)\n this.onClick = this._onClick.bind(this)\n }\n\n _onClick() {\n let { showOpId, showOpIdPrefix, onClick, shown } = this.props\n onClick([showOpIdPrefix, showOpId], !shown)\n }\n\n render() {\n let { id, method, shown, href } = this.props\n\n return (\n \n
\n {method.toUpperCase()}\n {id}\n
\n \n )\n }\n\n}\n\nOperationLink.propTypes = {\n href: PropTypes.string,\n onClick: PropTypes.func,\n id: PropTypes.string.isRequired,\n method: PropTypes.string.isRequired,\n shown: PropTypes.bool.isRequired,\n showOpId: PropTypes.string.isRequired,\n showOpIdPrefix: PropTypes.string.isRequired\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/core/components/overview.jsx","import React, { PureComponent } from \"react\"\nimport PropTypes from \"prop-types\"\nimport { fromJS, List } from \"immutable\"\nimport { getSampleSchema } from \"core/utils\"\n\nconst NOOP = Function.prototype\n\nexport default class ParamBody extends PureComponent {\n\n static propTypes = {\n param: PropTypes.object,\n onChange: PropTypes.func,\n onChangeConsumes: PropTypes.func,\n consumes: PropTypes.object,\n consumesValue: PropTypes.string,\n fn: PropTypes.object.isRequired,\n getComponent: PropTypes.func.isRequired,\n isExecute: PropTypes.bool,\n specSelectors: PropTypes.object.isRequired,\n pathMethod: PropTypes.array.isRequired\n };\n\n static defaultProp = {\n consumes: fromJS([\"application/json\"]),\n param: fromJS({}),\n onChange: NOOP,\n onChangeConsumes: NOOP,\n };\n\n constructor(props, context) {\n super(props, context)\n\n this.state = {\n isEditBox: false,\n value: \"\"\n }\n\n }\n\n componentDidMount() {\n this.updateValues.call(this, this.props)\n }\n\n componentWillReceiveProps(nextProps) {\n this.updateValues.call(this, nextProps)\n }\n\n updateValues = (props) => {\n let { specSelectors, pathMethod, param, isExecute, consumesValue=\"\" } = props\n let parameter = specSelectors ? specSelectors.getParameter(pathMethod, param.get(\"name\"), param.get(\"in\")) : fromJS({})\n let isXml = /xml/i.test(consumesValue)\n let isJson = /json/i.test(consumesValue)\n let paramValue = isXml ? parameter.get(\"value_xml\") : parameter.get(\"value\")\n\n if ( paramValue !== undefined ) {\n let val = !paramValue && isJson ? \"{}\" : paramValue\n this.setState({ value: val })\n this.onChange(val, {isXml: isXml, isEditBox: isExecute})\n } else {\n if (isXml) {\n this.onChange(this.sample(\"xml\"), {isXml: isXml, isEditBox: isExecute})\n } else {\n this.onChange(this.sample(), {isEditBox: isExecute})\n }\n }\n }\n\n sample = (xml) => {\n let { param, fn:{inferSchema} } = this.props\n let schema = inferSchema(param.toJS())\n\n return getSampleSchema(schema, xml, {\n includeWriteOnly: true\n })\n }\n\n onChange = (value, { isEditBox, isXml }) => {\n this.setState({value, isEditBox})\n this._onChange(value, isXml)\n }\n\n _onChange = (val, isXml) => { (this.props.onChange || NOOP)(this.props.param, val, isXml) }\n\n handleOnChange = e => {\n const {consumesValue} = this.props\n const isJson = /json/i.test(consumesValue)\n const isXml = /xml/i.test(consumesValue)\n const inputValue = isJson ? e.target.value.trim() : e.target.value\n this.onChange(inputValue, {isXml})\n }\n\n toggleIsEditBox = () => this.setState( state => ({isEditBox: !state.isEditBox}))\n\n render() {\n let {\n onChangeConsumes,\n param,\n isExecute,\n specSelectors,\n pathMethod,\n\n getComponent,\n } = this.props\n\n const Button = getComponent(\"Button\")\n const TextArea = getComponent(\"TextArea\")\n const HighlightCode = getComponent(\"highlightCode\")\n const ContentType = getComponent(\"contentType\")\n // for domains where specSelectors not passed\n let parameter = specSelectors ? specSelectors.getParameter(pathMethod, param.get(\"name\"), param.get(\"in\")) : param\n let errors = parameter.get(\"errors\", List())\n let consumesValue = specSelectors.contentTypeValues(pathMethod).get(\"requestContentType\")\n let consumes = this.props.consumes && this.props.consumes.size ? this.props.consumes : ParamBody.defaultProp.consumes\n\n let { value, isEditBox } = this.state\n\n return (\n
\n {\n isEditBox && isExecute\n ?