diff --git a/.dockerignore b/.dockerignore index a332c2ee7..d03b3b9ab 100644 --- a/.dockerignore +++ b/.dockerignore @@ -17,3 +17,5 @@ **/htmlcov /src/.pytest_cache .idea +.venv/ +.vscode/ diff --git a/.editorconfig b/.editorconfig index 892e1dd13..125108a0c 100644 --- a/.editorconfig +++ b/.editorconfig @@ -18,14 +18,20 @@ max_line_length = off indent_size = 4 indent_style = space -[*.yml] +[*.{yml,yaml}] indent_style = space [*.rst] indent_style = space +[*.md] +indent_style = space + # Tests don't get a line width restriction. It's still a good idea to follow # the 79 character rule, but in the interests of clarity, tests often need to # violate it. [**/test_*.py] max_line_length = off + +[Dockerfile] +indent_style = space diff --git a/.env b/.env index f196b0b5b..46f557886 100644 --- a/.env +++ b/.env @@ -1,2 +1,2 @@ COMPOSE_PROJECT_NAME=paperless -export PROMPT="(pipenv-projectname)$P$G" \ No newline at end of file +export PROMPT="(pipenv-projectname)$P$G" diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 7b8e87fde..c8ef97a32 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -8,7 +8,7 @@ updates: target-branch: "dev" # Look for `package.json` and `lock` files in the `root` directory directory: "/src-ui" - # Check the npm registry for updates every week + # Check the npm registry for updates every month schedule: interval: "monthly" # Add reviewers @@ -23,6 +23,19 @@ updates: # Check for updates once a week schedule: interval: "weekly" + labels: + - "backend" + - "dependencies" + + # Enable updates for Github Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + # Check for updates to GitHub Actions every month + interval: "monthly" + labels: + - "ci-cd" + - "dependencies" # Add reviewers reviewers: - "paperless-ngx/backend" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3ddbb9b41..0daf605c4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,90 +13,100 @@ on: jobs: documentation: + name: "Build Documentation" runs-on: ubuntu-20.04 steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 + - + name: Install pipenv + run: pipx install pipenv - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v3 with: python-version: 3.9 - - - name: Get pip cache dir - id: pip-cache - run: | - echo "::set-output name=dir::$(pip cache dir)" - - - name: Persistent Github pip cache - uses: actions/cache@v2 - with: - path: ${{ steps.pip-cache.outputs.dir }} - key: ${{ runner.os }}-pip3.8} + cache: "pipenv" + cache-dependency-path: 'Pipfile.lock' - name: Install dependencies run: | - pip install --upgrade pipenv - pipenv install --system --dev --ignore-pipfile + pipenv sync --dev - name: Make documentation run: | cd docs/ - make html + pipenv run make html - name: Upload artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: documentation path: docs/_build/html/ - codestyle: + code-checks-backend: + name: "Backend Code Checks" runs-on: ubuntu-20.04 steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: 3.9 - - - name: Get pip cache dir - id: pip-cache + name: Install checkers run: | - echo "::set-output name=dir::$(pip cache dir)" + pipx install reorder-python-imports + pipx install yesqa + pipx install add-trailing-comma + pipx install flake8 - - name: Persistent Github pip cache - uses: actions/cache@v2 - with: - path: ${{ steps.pip-cache.outputs.dir }} - key: ${{ runner.os }}-pip${{ matrix.python-version }} - - - name: Install dependencies + name: Run reorder-python-imports run: | - pip install --upgrade pipenv - pipenv install --system --dev --ignore-pipfile + find src/ -type f -name '*.py' ! -path "*/migrations/*" | xargs reorder-python-imports - - name: Codestyle + name: Run yesqa run: | - cd src/ - pycodestyle --max-line-length=88 --ignore=E121,E123,E126,E226,E24,E704,W503,W504,E203 - codeformatting: - runs-on: ubuntu-20.04 - steps: + find src/ -type f -name '*.py' ! -path "*/migrations/*" | xargs yesqa - - name: Checkout - uses: actions/checkout@v2 + name: Run add-trailing-comma + run: | + find src/ -type f -name '*.py' ! -path "*/migrations/*" | xargs add-trailing-comma + # black is placed after add-trailing-comma because it may format differently + # if a trailing comma is added - name: Run black uses: psf/black@stable with: options: "--check --diff" version: "22.3.0" + - + name: Run flake8 checks + run: | + cd src/ + flake8 --max-line-length=88 --ignore=E203,W503 - tests: + code-checks-frontend: + name: "Frontend Code Checks" + runs-on: ubuntu-20.04 + steps: + - + name: Checkout + uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: '16' + - + name: Install prettier + run: | + npm install prettier + - + name: Run prettier + run: + npx prettier --check --ignore-path Pipfile.lock **/*.js **/*.ts *.md **/*.md + + tests-backend: + needs: [code-checks-backend] + name: "Backend Tests (${{ matrix.python-version }})" runs-on: ubuntu-20.04 strategy: matrix: @@ -105,73 +115,94 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 + with: + fetch-depth: 2 + - + name: Install pipenv + run: pipx install pipenv - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v3 with: python-version: "${{ matrix.python-version }}" + cache: "pipenv" + cache-dependency-path: 'Pipfile.lock' - - name: Get pip cache dir - id: pip-cache - run: | - echo "::set-output name=dir::$(pip cache dir)" - - - name: Persistent Github pip cache - uses: actions/cache@v2 - with: - path: ${{ steps.pip-cache.outputs.dir }} - key: ${{ runner.os }}-pip${{ matrix.python-version }} - - - name: Install dependencies + name: Install system dependencies run: | sudo apt-get update -qq - sudo apt-get install -qq --no-install-recommends unpaper tesseract-ocr imagemagick ghostscript optipng - pip install --upgrade pipenv - pipenv install --system --dev --ignore-pipfile + sudo apt-get install -qq --no-install-recommends unpaper tesseract-ocr imagemagick ghostscript optipng libzbar0 poppler-utils + - + name: Install Python dependencies + run: | + pipenv sync --dev - name: Tests run: | cd src/ - pytest + pipenv run pytest + - + name: Get changed files + id: changed-files-specific + uses: tj-actions/changed-files@v18.1 + with: + files: | + src/** + - + name: List all changed files + run: | + for file in ${{ steps.changed-files-specific.outputs.all_changed_files }}; do + echo "${file} was changed" + done - name: Publish coverage results - if: matrix.python-version == '3.9' + if: matrix.python-version == '3.9' && steps.changed-files-specific.outputs.any_changed == 'true' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # https://github.com/coveralls-clients/coveralls-python/issues/251 run: | cd src/ - coveralls --service=github + pipenv run coveralls --service=github + + tests-frontend: + needs: [code-checks-frontend] + name: "Frontend Tests" + runs-on: ubuntu-20.04 + strategy: + matrix: + node-version: [16.x] + steps: + - uses: actions/checkout@v3 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + - run: cd src-ui && npm ci + - run: cd src-ui && npm run test + - run: cd src-ui && npm run e2e:ci # build and push image to docker hub. build-docker-image: if: github.event_name == 'push' && (startsWith(github.ref, 'refs/heads/feature-') || github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/beta' || startsWith(github.ref, 'refs/tags/ngx-') || startsWith(github.ref, 'refs/tags/beta-')) - runs-on: ubuntu-latest - needs: [tests, codeformatting, codestyle] + concurrency: + group: ${{ github.workflow }}-build-docker-image-${{ github.ref }} + cancel-in-progress: true + runs-on: ubuntu-20.04 + needs: [tests-backend, tests-frontend] steps: - - name: Prepare - id: prepare - run: | - IMAGE_NAME=ghcr.io/${{ github.repository }} - if [[ $GITHUB_REF == refs/tags/ngx-* ]]; then - TAGS=${IMAGE_NAME}:${GITHUB_REF#refs/tags/ngx-},${IMAGE_NAME}:latest - INSPECT_TAG=${IMAGE_NAME}:latest - elif [[ $GITHUB_REF == refs/tags/beta-* ]]; then - TAGS=${IMAGE_NAME}:beta - INSPECT_TAG=${TAGS} - elif [[ $GITHUB_REF == refs/heads/* ]]; then - TAGS=${IMAGE_NAME}:${GITHUB_REF#refs/heads/} - INSPECT_TAG=${TAGS} - else - exit 1 - fi - echo ::set-output name=tags::${TAGS} - echo ::set-output name=inspect_tag::${INSPECT_TAG} + name: Gather Docker metadata + id: docker-meta + uses: docker/metadata-action@v3 + with: + images: ghcr.io/${{ github.repository }} + tags: | + type=ref,event=branch + type=ref,event=tag - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 @@ -192,36 +223,37 @@ jobs: context: . file: ./Dockerfile platforms: linux/amd64,linux/arm/v7,linux/arm64 - push: true - tags: ${{ steps.prepare.outputs.tags }} + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.docker-meta.outputs.tags }} + labels: ${{ steps.docker-meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max - name: Inspect image run: | - docker buildx imagetools inspect ${{ steps.prepare.outputs.inspect_tag }} + docker buildx imagetools inspect ${{ fromJSON(steps.docker-meta.outputs.json).tags[0] }} - name: Export frontend artifact from docker run: | - docker run -d --name frontend-extract ${{ steps.prepare.outputs.inspect_tag }} + docker create --name frontend-extract ${{ fromJSON(steps.docker-meta.outputs.json).tags[0] }} docker cp frontend-extract:/usr/src/paperless/src/documents/static/frontend src/documents/static/frontend/ - name: Upload frontend artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: frontend-compiled path: src/documents/static/frontend/ build-release: - needs: [build-docker-image, documentation, tests, codeformatting, codestyle] + needs: [build-docker-image, documentation] runs-on: ubuntu-20.04 steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v3 with: python-version: 3.9 - @@ -233,13 +265,13 @@ jobs: pip3 install -r requirements.txt - name: Download frontend artifact - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: name: frontend-compiled path: src/documents/static/frontend/ - name: Download documentation artifact - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: name: documentation path: docs/_build/html/ @@ -274,19 +306,19 @@ jobs: tar -cJf paperless-ngx.tar.xz paperless-ngx/ - name: Upload release artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: release path: dist/paperless-ngx.tar.xz publish-release: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 needs: build-release if: contains(github.ref, 'refs/tags/ngx-') || contains(github.ref, 'refs/tags/beta-') steps: - name: Download release artifact - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: name: release path: ./ @@ -297,24 +329,22 @@ jobs: if [[ $GITHUB_REF == refs/tags/ngx-* ]]; then echo ::set-output name=version::${GITHUB_REF#refs/tags/ngx-} echo ::set-output name=prerelease::false - echo ::set-output name=body::"For a complete list of changes, see the changelog at https://paperless-ngx.readthedocs.io/en/latest/changelog.html" elif [[ $GITHUB_REF == refs/tags/beta-* ]]; then echo ::set-output name=version::${GITHUB_REF#refs/tags/beta-} echo ::set-output name=prerelease::true - echo ::set-output name=body::"For a complete list of changes, see the changelog at https://github.com/paperless-ngx/paperless-ngx/blob/beta/docs/changelog.rst" fi - - name: Create release - id: create_release - uses: actions/create-release@v1 + name: Create Release and Changelog + id: create-release + uses: release-drafter/release-drafter@v5 + with: + name: Paperless-ngx ${{ steps.get_version.outputs.version }} + tag: ngx-${{ steps.get_version.outputs.version }} + version: ${{ steps.get_version.outputs.version }} + prerelease: ${{ steps.get_version.outputs.prerelease }} + publish: true # ensures release is not marked as draft env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ngx-${{ steps.get_version.outputs.version }} - release_name: Paperless-ngx ${{ steps.get_version.outputs.version }} - draft: false - prerelease: ${{ steps.get_version.outputs.prerelease }} - body: ${{ steps.get_version.outputs.body }} - name: Upload release archive id: upload-release-asset @@ -322,7 +352,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + upload_url: ${{ steps.create-release.outputs.upload_url }} asset_path: ./paperless-ngx.tar.xz asset_name: paperless-ngx-${{ steps.get_version.outputs.version }}.tar.xz asset_content_type: application/x-xz diff --git a/.gitignore b/.gitignore index b427d5c5c..c21ad4de0 100644 --- a/.gitignore +++ b/.gitignore @@ -61,6 +61,9 @@ target/ # PyCharm .idea +# VS Code +.vscode + # Other stuff that doesn't belong .virtualenv virtualenv diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..5d710584d --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +# https://prettier.io/docs/en/options.html#semicolons +semi: false +# https://prettier.io/docs/en/options.html#quotes +singleQuote: true diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 000000000..294abd1ff --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,10 @@ +/.github/workflows/ @paperless-ngx/ci-cd +/docker/ @paperless-ngx/ci-cd +/scripts/ @paperless-ngx/ci-cd + +/src-ui/ @paperless-ngx/frontend + +/src/ @paperless-ngx/backend +Pipfile* @paperless-ngx/backend +*.py @paperless-ngx/backend +requirements.txt @paperless-ngx/backend diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 0bb900f82..a0c3bb8ee 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -17,23 +17,23 @@ diverse, inclusive, and healthy community. Examples of behavior that contributes to a positive environment for our community include: -* Demonstrating empathy and kindness toward other people -* Being respectful of differing opinions, viewpoints, and experiences -* Giving and gracefully accepting constructive feedback -* Accepting responsibility and apologizing to those affected by our mistakes, +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience -* Focusing on what is best not just for us as individuals, but for the +- Focusing on what is best not just for us as individuals, but for the overall community Examples of unacceptable behavior include: -* The use of sexualized language or imagery, and sexual attention or +- The use of sexualized language or imagery, and sexual attention or advances of any kind -* Trolling, insulting or derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or email +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email address, without their explicit permission -* Other conduct which could reasonably be considered inappropriate in a +- Other conduct which could reasonably be considered inappropriate in a professional setting ## Enforcement Responsibilities @@ -106,7 +106,7 @@ Violating these terms may lead to a permanent ban. ### 4. Permanent Ban **Community Impact**: Demonstrating a pattern of violation of community -standards, including sustained inappropriate behavior, harassment of an +standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. **Consequence**: A permanent ban from any sort of public interaction within diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0d5467751..68fc44b84 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,10 +4,10 @@ If you feel like contributing to the project, please do! Bug fixes and improveme If you want to implement something big: -* Please start a discussion about that in the issues! Maybe something similar is already in development and we can make it happen together. -* When making additions to the project, consider if the majority of users will benefit from your change. If not, you're probably better of forking the project. -* Also consider if your change will get in the way of other users. A good change is a change that enhances the experience of some users who want that change and does not affect users who do not care about the change. -* Please see the [paperless-ngx merge process](#merging-prs) below. +- Please start a discussion about that in the issues! Maybe something similar is already in development and we can make it happen together. +- When making additions to the project, consider if the majority of users will benefit from your change. If not, you're probably better of forking the project. +- Also consider if your change will get in the way of other users. A good change is a change that enhances the experience of some users who want that change and does not affect users who do not care about the change. +- Please see the [paperless-ngx merge process](#merging-prs) below. ## Python @@ -27,6 +27,8 @@ Please format and test your code! I know it's a hassle, but it makes sure that y To test your code, execute `pytest` in the src/ directory. This also generates a html coverage report, which you can use to see if you missed anything important during testing. +Before you can run `pytest`, ensure to [properly set up your local environment](https://paperless-ngx.readthedocs.io/en/latest/extending.html#initial-setup-and-first-start). + ## More info: ... is available in the documentation. https://paperless-ngx.readthedocs.io/en/latest/extending.html @@ -41,9 +43,9 @@ PRs deemed `non-trivial` will go through a stricter review process before being Examples of `non-trivial` PRs might include: -* Additional features -* Large changes to many distinct files -* Breaking or depreciation of existing features +- Additional features +- Large changes to many distinct files +- Breaking or depreciation of existing features Our community review process for `non-trivial` PRs is the following: @@ -75,18 +77,18 @@ If a language has already been added, and you would like to contribute new trans If you would like the project to be translated to another language, first head over to https://crwd.in/paperless-ngx to check if that language has already been enabled for translation. If not, please request the language to be added by creating an issue on GitHub. The issue should contain: -* English name of the language (the localized name can be added on Crowdin). -* ISO language code. A list of those can be found here: https://support.crowdin.com/enterprise/language-codes/ -* Date format commonly used for the language, e.g. dd/mm/yyyy, mm/dd/yyyy, etc. +- English name of the language (the localized name can be added on Crowdin). +- ISO language code. A list of those can be found here: https://support.crowdin.com/enterprise/language-codes/ +- Date format commonly used for the language, e.g. dd/mm/yyyy, mm/dd/yyyy, etc. After the language has been added and some translations have been made on Crowdin, the language needs to be enabled in the code. Note that there is no need to manually add a .po of .xlf file as those will be automatically generated and imported from Crowdin. The following files need to be changed: -* src-ui/angular.json (under the _projects/paperless-ui/i18n/locales_ JSON key) -* src/paperless/settings.py (in the _LANGUAGES_ array) -* src-ui/src/app/services/settings.service.ts (inside the _getLanguageOptions_ method) -* src-ui/src/app/app.module.ts (import locale from _angular/common/locales_ and call _registerLocaleData_) +- src-ui/angular.json (under the _projects/paperless-ui/i18n/locales_ JSON key) +- src/paperless/settings.py (in the _LANGUAGES_ array) +- src-ui/src/app/services/settings.service.ts (inside the _getLanguageOptions_ method) +- src-ui/src/app/app.module.ts (import locale from _angular/common/locales_ and call _registerLocaleData_) Please add the language in the correct order, alphabetically by locale. Note that _en-us_ needs to stay on top of the list, as it is the default project language @@ -102,26 +104,26 @@ Paperless-ngx is a community project. We do our best to delegate permission and As of writing, there are 21 members in paperless-ngx. 4 of these people have complete administrative privileges to the repo: -* [@shamoon](https://github.com/shamoon) -* [@bauerj](https://github.com/bauerj) -* [@qcasey](https://github.com/qcasey) -* [@FrankStrieter](https://github.com/FrankStrieter) +- [@shamoon](https://github.com/shamoon) +- [@bauerj](https://github.com/bauerj) +- [@qcasey](https://github.com/qcasey) +- [@FrankStrieter](https://github.com/FrankStrieter) There are 5 teams collaborating on specific tasks within paperless-ngx: -* @paperless-ngx/backend (Python / django) -* @paperless-ngx/frontend (JavaScript / Typescript) -* @paperless-ngx/ci-cd (GitHub Actions / Deployment) -* @paperless-ngx/issues (Issue triage) -* @paperless-ngx/test (General testing for larger PRs) +- @paperless-ngx/backend (Python / django) +- @paperless-ngx/frontend (JavaScript / Typescript) +- @paperless-ngx/ci-cd (GitHub Actions / Deployment) +- @paperless-ngx/issues (Issue triage) +- @paperless-ngx/test (General testing for larger PRs) ## Permissions All team members are notified when mentioned or assigned to a relevant issue or pull request. Additionally, each team has slightly different access to paperless-ngx: -* The **test** team has no special permissions. -* The **issues** team has `triage` access. This means they can organize issues and pull requests. -* The **backend**, **frontend**, and **ci-cd** teams have `write` access. This means they can approve PRs and push code, containers, releases, and more. +- The **test** team has no special permissions. +- The **issues** team has `triage` access. This means they can organize issues and pull requests. +- The **backend**, **frontend**, and **ci-cd** teams have `write` access. This means they can approve PRs and push code, containers, releases, and more. ## Joining diff --git a/Dockerfile b/Dockerfile index afde7dcc8..8b46d072b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,64 +3,16 @@ FROM node:16 AS compile-frontend COPY . /src WORKDIR /src/src-ui -RUN npm update npm -g && npm install +RUN npm update npm -g && npm ci --no-optional RUN ./node_modules/.bin/ng build --configuration production +FROM ghcr.io/paperless-ngx/builder/ngx-base:1.7.0 as main-app -FROM ubuntu:20.04 AS jbig2enc - -WORKDIR /usr/src/jbig2enc - -RUN apt-get update && apt-get install -y --no-install-recommends build-essential automake libtool libleptonica-dev zlib1g-dev git ca-certificates - -RUN git clone https://github.com/agl/jbig2enc . -RUN ./autogen.sh -RUN ./configure && make - - -FROM python:3.9-slim-bullseye - -# Binary dependencies -RUN apt-get update \ - && apt-get -y --no-install-recommends install \ - # Basic dependencies - curl \ - gnupg \ - imagemagick \ - gettext \ - tzdata \ - gosu \ - # fonts for text file thumbnail generation - fonts-liberation \ - # for Numpy - libatlas-base-dev \ - libxslt1-dev \ - # thumbnail size reduction - optipng \ - libxml2 \ - pngquant \ - unpaper \ - zlib1g \ - ghostscript \ - icc-profiles-free \ - # Mime type detection - file \ - libmagic-dev \ - media-types \ - # OCRmyPDF dependencies - liblept5 \ - tesseract-ocr \ - tesseract-ocr-eng \ - tesseract-ocr-deu \ - tesseract-ocr-fra \ - tesseract-ocr-ita \ - tesseract-ocr-spa \ - && rm -rf /var/lib/apt/lists/* - -# copy jbig2enc -COPY --from=jbig2enc /usr/src/jbig2enc/src/.libs/libjbig2enc* /usr/local/lib/ -COPY --from=jbig2enc /usr/src/jbig2enc/src/jbig2 /usr/local/bin/ -COPY --from=jbig2enc /usr/src/jbig2enc/src/*.h /usr/local/include/ +LABEL org.opencontainers.image.authors="paperless-ngx team " +LABEL org.opencontainers.image.documentation="https://paperless-ngx.readthedocs.io/en/latest/" +LABEL org.opencontainers.image.source="https://github.com/paperless-ngx/paperless-ngx" +LABEL org.opencontainers.image.url="https://github.com/paperless-ngx/paperless-ngx" +LABEL org.opencontainers.image.licenses="GPL-3.0-only" WORKDIR /usr/src/paperless/src/ @@ -68,47 +20,31 @@ COPY requirements.txt ../ # Python dependencies RUN apt-get update \ + # python-Levenshtein still needs to be compiled here && apt-get -y --no-install-recommends install \ - build-essential \ - libpq-dev \ - git \ - zlib1g-dev \ - libjpeg62-turbo-dev \ - && if [ "$(uname -m)" = "armv7l" ] || [ "$(uname -m)" = "aarch64" ]; \ - then echo "Building qpdf" \ - && mkdir -p /usr/src/qpdf \ - && cd /usr/src/qpdf \ - && git clone https://github.com/qpdf/qpdf.git . \ - && git checkout --quiet release-qpdf-10.6.2 \ - && ./configure \ - && make \ - && make install \ - && cd /usr/src/paperless/src/ \ - && rm -rf /usr/src/qpdf; \ - else \ - echo "Skipping qpdf build because pikepdf binary wheels are available."; \ - fi \ - && python3 -m pip install --upgrade pip wheel \ - && python3 -m pip install --default-timeout=1000 --upgrade --no-cache-dir supervisor \ - && python3 -m pip install --default-timeout=1000 --no-cache-dir -r ../requirements.txt \ - && apt-get -y purge build-essential git zlib1g-dev libjpeg62-turbo-dev \ - && apt-get -y autoremove --purge \ - && rm -rf /var/lib/apt/lists/* + build-essential \ + && python3 -m pip install --upgrade --no-cache-dir pip wheel \ + && python3 -m pip install --default-timeout=1000 --upgrade --no-cache-dir supervisor \ + && python3 -m pip install --default-timeout=1000 --no-cache-dir -r ../requirements.txt \ + && apt-get -y purge build-essential \ + && apt-get -y autoremove --purge \ + && rm -rf /var/lib/apt/lists/* # setup docker-specific things COPY docker/ ./docker/ RUN cd docker \ - && cp imagemagick-policy.xml /etc/ImageMagick-6/policy.xml \ - && mkdir /var/log/supervisord /var/run/supervisord \ - && cp supervisord.conf /etc/supervisord.conf \ - && cp docker-entrypoint.sh /sbin/docker-entrypoint.sh \ - && cp docker-prepare.sh /sbin/docker-prepare.sh \ - && chmod 755 /sbin/docker-entrypoint.sh \ - && chmod +x install_management_commands.sh \ - && ./install_management_commands.sh \ - && cd .. \ - && rm docker -rf + && cp imagemagick-policy.xml /etc/ImageMagick-6/policy.xml \ + && mkdir /var/log/supervisord /var/run/supervisord \ + && cp supervisord.conf /etc/supervisord.conf \ + && cp docker-entrypoint.sh /sbin/docker-entrypoint.sh \ + && chmod 755 /sbin/docker-entrypoint.sh \ + && cp docker-prepare.sh /sbin/docker-prepare.sh \ + && chmod 755 /sbin/docker-prepare.sh \ + && chmod +x install_management_commands.sh \ + && ./install_management_commands.sh \ + && cd .. \ + && rm -rf docker/ COPY gunicorn.conf.py ../ @@ -117,18 +53,18 @@ COPY --from=compile-frontend /src/src/ ./ # add users, setup scripts RUN addgroup --gid 1000 paperless \ - && useradd --uid 1000 --gid paperless --home-dir /usr/src/paperless paperless \ - && chown -R paperless:paperless ../ \ - && gosu paperless python3 manage.py collectstatic --clear --no-input \ - && gosu paperless python3 manage.py compilemessages + && useradd --uid 1000 --gid paperless --home-dir /usr/src/paperless paperless \ + && chown -R paperless:paperless ../ \ + && gosu paperless python3 manage.py collectstatic --clear --no-input \ + && gosu paperless python3 manage.py compilemessages + +VOLUME ["/usr/src/paperless/data", \ + "/usr/src/paperless/media", \ + "/usr/src/paperless/consume", \ + "/usr/src/paperless/export"] -VOLUME ["/usr/src/paperless/data", "/usr/src/paperless/media", "/usr/src/paperless/consume", "/usr/src/paperless/export"] ENTRYPOINT ["/sbin/docker-entrypoint.sh"] -EXPOSE 8000 -CMD ["/usr/local/bin/supervisord", "-c", "/etc/supervisord.conf"] -LABEL org.opencontainers.image.authors="paperless-ngx team " -LABEL org.opencontainers.image.documentation="https://paperless-ngx.readthedocs.io/en/latest/" -LABEL org.opencontainers.image.source="https://github.com/paperless-ngx/paperless-ngx" -LABEL org.opencontainers.image.url="https://github.com/paperless-ngx/paperless-ngx" -LABEL org.opencontainers.image.licenses="GPL-3.0-only" +EXPOSE 8000 + +CMD ["/usr/local/bin/supervisord", "-c", "/etc/supervisord.conf"] diff --git a/Pipfile b/Pipfile index 3db77772a..0ab6775e6 100644 --- a/Pipfile +++ b/Pipfile @@ -9,35 +9,36 @@ verify_ssl = true name = "piwheels" [packages] -dateparser = "~=1.1.0" -django = "~=3.2" +dateparser = "~=1.1" +django = "~=4.0" django-cors-headers = "*" django-extensions = "*" django-filter = "~=21.1" -django-q = "~=1.3.4" -djangorestframework = "~=3.13.1" +django-q = "~=1.3" +djangorestframework = "~=3.13" filelock = "*" fuzzywuzzy = {extras = ["speedup"], version = "*"} gunicorn = "*" imap-tools = "*" langdetect = "*" -numpy = "~=1.22.0" pathvalidate = "*" -pillow = "~=9.0" -pikepdf = "~=5.0" +pillow = "~=9.1" +# Any version update to pikepdf requires a base image update +pikepdf = "~=5.1" python-gnupg = "*" python-dotenv = "*" python-dateutil = "*" python-magic = "*" -psycopg2-binary = "*" +# Any version update to psycopg2 requires a base image update +psycopg2 = "*" redis = "*" # Pinned because aarch64 wheels and updates cause warnings when loading the classifier model. -scikit-learn="==0.24.0" +scikit-learn="==1.0.2" whitenoise = "~=6.0.0" watchdog = "~=2.1.0" whoosh="~=2.7.4" -inotifyrecursive = "~=0.3.4" -ocrmypdf = "~=13.4.0" +inotifyrecursive = "~=0.3" +ocrmypdf = "~=13.4" tqdm = "*" tika = "*" # TODO: This will sadly also install daphne+dependencies, @@ -46,11 +47,12 @@ channels = "~=3.0" channels-redis = "*" uvicorn = {extras = ["standard"], version = "*"} concurrent-log-handler = "*" -# uvloop 0.15+ incompatible with python 3.6 -uvloop = "~=0.16" -cryptography = "~=36.0.1" "pdfminer.six" = "*" -"backports.zoneinfo" = "*" +"backports.zoneinfo" = {version = "*", markers = "python_version < '3.9'"} +"importlib-resources" = {version = "*", markers = "python_version < '3.9'"} +zipp = {version = "*", markers = "python_version < '3.9'"} +pyzbar = "*" +pdf2image = "*" [dev-packages] coveralls = "*" @@ -62,7 +64,8 @@ pytest-django = "*" pytest-env = "*" pytest-sugar = "*" pytest-xdist = "*" -sphinx = "~=3.4.2" +sphinx = "~=4.5.0" sphinx_rtd_theme = "*" tox = "*" black = "*" +pre-commit = "*" diff --git a/Pipfile.lock b/Pipfile.lock index 54429cdd3..20f28d068 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "70cb2ee8b32d5595c1f0a175f0ee0dfb35221fdc5c76cf90a9c1eedf02b52d46" + "sha256": "9573af313c811561d467d814c52c6bd1439bc48e3b31d7f56afed5f0ebe4b648" }, "pipfile-spec": 6, "requires": {}, @@ -26,6 +26,14 @@ ], "version": "==1.3.1" }, + "anyio": { + "hashes": [ + "sha256:a0aeffe2fb1fdf374a8e4b471444f0f3ac4fb9f5a5b542b48824475e0042a5a6", + "sha256:b5fa16c5ff93fa1046f2eeb5bbff2dad4d3514d6cda61d02816dba34fa8c3c2e" + ], + "markers": "python_full_version >= '3.6.2'", + "version": "==3.5.0" + }, "arrow": { "hashes": [ "sha256:05caf1fd3d9a11a1135b2b6f09887421153b94558e5ef4d090b567b47173ac2b", @@ -60,16 +68,15 @@ }, "autobahn": { "hashes": [ - "sha256:60e1f4c602aacd052ffe3d46ae40b6b75f8286b3c46922c213b523162e58c17e" + "sha256:58a887c7a196bb08d8b6624cb3695f493a9e5c9f00fd350d8d6f829b47ff9036" ], "markers": "python_version >= '3.7'", - "version": "==22.2.2" + "version": "==22.3.2" }, "automat": { "hashes": [ "sha256:7979803c74610e11ef0c0d68a2942b152df52da55336e0c9d58daf1831cbdf33", - "sha256:b6feb6455337df834f6c9962d6ccf771515b7d939bca142b29c20c2376bc6111", - "sha256:d6d976cf8da698fc85fa7def46e2544493f78cb7ee72d2f4acd1a5c759a3060e" + "sha256:b6feb6455337df834f6c9962d6ccf771515b7d939bca142b29c20c2376bc6111" ], "version": "==20.2.0" }, @@ -86,15 +93,13 @@ "sha256:89a48c0d158a3cc3f654da4c2de1ceba85263fafb861b98b59040a5086259722", "sha256:a76b38c52400b762e48131494ba26be363491ac4f9a04c1b7e92483d169f6582", "sha256:da6013fd84a690242c310d77ddb8441a559e9cb3d3d59ebac9aca1a57b2e18bc", - "sha256:dff179a489c57d2c9ccd60720f1ec13173bc1aa1c15c2714649581b32eab56ca", - "sha256:e34cdbc646438368c17100e3dafeb88626d3b5467b89681d20ef6731a29e2895", "sha256:e55b384612d93be96506932a786bbcde5a2db7a9e6a4bb4bffe8b733f5b9036b", "sha256:e81b76cace8eda1fca50e345242ba977f9be6ae3945af8d46326d776b4cf78d1", "sha256:e8236383a20872c0cdf5a62b554b27538db7fa1bbec52429d8d106effbaeca08", "sha256:f04e857b59d9d1ccc39ce2da1021d196e47234873820cbeaad210724b1ee28ac", "sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2" ], - "index": "pypi", + "markers": "python_version < '3.9'", "version": "==0.2.1" }, "blessed": { @@ -177,11 +182,11 @@ }, "channels-redis": { "hashes": [ - "sha256:899dc6433f5416cf8ad74505baaf2acb5461efac3cad40751a41119e3f68421b", - "sha256:fbb24a7a57a6cc0ebe5aa121cdf841eabf845cf47dd5c1059224ef4d64aeaeac" + "sha256:5dffd4cc16174125bd4043fc8fe7462ca7403cf801d59a9fa7410ed101fa6a57", + "sha256:6e4565b7c11c6bcde5d48556cb83bd043779697ff03811867d2f895aa6170d56" ], "index": "pypi", - "version": "==3.3.1" + "version": "==3.4.0" }, "chardet": { "hashes": [ @@ -201,11 +206,11 @@ }, "click": { "hashes": [ - "sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1", - "sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb" + "sha256:24e1a4a9ec5bf6299411369b208c1df2188d9eb8d916302fe6bf03faed227f1e", + "sha256:479707fe14d9ec9a0757618b7a100a0ae4c4e236fac5b7f80ca68028141a1a72" ], - "markers": "python_version >= '3.6'", - "version": "==8.0.4" + "markers": "python_version >= '3.7'", + "version": "==8.1.2" }, "coloredlogs": { "hashes": [ @@ -232,29 +237,29 @@ }, "cryptography": { "hashes": [ - "sha256:0a817b961b46894c5ca8a66b599c745b9a3d9f822725221f0e0fe49dc043a3a3", - "sha256:2d87cdcb378d3cfed944dac30596da1968f88fb96d7fc34fdae30a99054b2e31", - "sha256:30ee1eb3ebe1644d1c3f183d115a8c04e4e603ed6ce8e394ed39eea4a98469ac", - "sha256:391432971a66cfaf94b21c24ab465a4cc3e8bf4a939c1ca5c3e3a6e0abebdbcf", - "sha256:39bdf8e70eee6b1c7b289ec6e5d84d49a6bfa11f8b8646b5b3dfe41219153316", - "sha256:4caa4b893d8fad33cf1964d3e51842cd78ba87401ab1d2e44556826df849a8ca", - "sha256:53e5c1dc3d7a953de055d77bef2ff607ceef7a2aac0353b5d630ab67f7423638", - "sha256:596f3cd67e1b950bc372c33f1a28a0692080625592ea6392987dba7f09f17a94", - "sha256:5d59a9d55027a8b88fd9fd2826c4392bd487d74bf628bb9d39beecc62a644c12", - "sha256:6c0c021f35b421ebf5976abf2daacc47e235f8b6082d3396a2fe3ccd537ab173", - "sha256:73bc2d3f2444bcfeac67dd130ff2ea598ea5f20b40e36d19821b4df8c9c5037b", - "sha256:74d6c7e80609c0f4c2434b97b80c7f8fdfaa072ca4baab7e239a15d6d70ed73a", - "sha256:7be0eec337359c155df191d6ae00a5e8bbb63933883f4f5dffc439dac5348c3f", - "sha256:94ae132f0e40fe48f310bba63f477f14a43116f05ddb69d6fa31e93f05848ae2", - "sha256:bb5829d027ff82aa872d76158919045a7c1e91fbf241aec32cb07956e9ebd3c9", - "sha256:ca238ceb7ba0bdf6ce88c1b74a87bffcee5afbfa1e41e173b1ceb095b39add46", - "sha256:ca28641954f767f9822c24e927ad894d45d5a1e501767599647259cbf030b903", - "sha256:e0344c14c9cb89e76eb6a060e67980c9e35b3f36691e15e1b7a9e58a0a6c6dc3", - "sha256:ebc15b1c22e55c4d5566e3ca4db8689470a0ca2babef8e3a9ee057a8b82ce4b1", - "sha256:ec63da4e7e4a5f924b90af42eddf20b698a70e58d86a72d943857c4c6045b3ee" + "sha256:0a3bf09bb0b7a2c93ce7b98cb107e9170a90c51a0162a20af1c61c765b90e60b", + "sha256:1f64a62b3b75e4005df19d3b5235abd43fa6358d5516cfc43d87aeba8d08dd51", + "sha256:32db5cc49c73f39aac27574522cecd0a4bb7384e71198bc65a0d23f901e89bb7", + "sha256:4881d09298cd0b669bb15b9cfe6166f16fc1277b4ed0d04a22f3d6430cb30f1d", + "sha256:4e2dddd38a5ba733be6a025a1475a9f45e4e41139d1321f412c6b360b19070b6", + "sha256:53e0285b49fd0ab6e604f4c5d9c5ddd98de77018542e88366923f152dbeb3c29", + "sha256:70f8f4f7bb2ac9f340655cbac89d68c527af5bb4387522a8413e841e3e6628c9", + "sha256:7b2d54e787a884ffc6e187262823b6feb06c338084bbe80d45166a1cb1c6c5bf", + "sha256:7be666cc4599b415f320839e36367b273db8501127b38316f3b9f22f17a0b815", + "sha256:8241cac0aae90b82d6b5c443b853723bcc66963970c67e56e71a2609dc4b5eaf", + "sha256:82740818f2f240a5da8dfb8943b360e4f24022b093207160c77cadade47d7c85", + "sha256:8897b7b7ec077c819187a123174b645eb680c13df68354ed99f9b40a50898f77", + "sha256:c2c5250ff0d36fd58550252f54915776940e4e866f38f3a7866d92b32a654b86", + "sha256:ca9f686517ec2c4a4ce930207f75c00bf03d94e5063cbc00a1dc42531511b7eb", + "sha256:d2b3d199647468d410994dbeb8cec5816fb74feb9368aedf300af709ef507e3e", + "sha256:da73d095f8590ad437cd5e9faf6628a218aa7c387e1fdf67b888b47ba56a17f0", + "sha256:e167b6b710c7f7bc54e67ef593f8731e1f45aa35f8a8a7b72d6e42ec76afd4b3", + "sha256:ea634401ca02367c1567f012317502ef3437522e2fc44a3ea1844de028fa4b84", + "sha256:ec6597aa85ce03f3e507566b8bcdf9da2227ec86c4266bd5e6ab4d9e0cc8dab2", + "sha256:f64b232348ee82f13aac22856515ce0195837f6968aeaa94a3d0353ea2ec06a6" ], - "index": "pypi", - "version": "==36.0.1" + "markers": "python_version >= '3.6'", + "version": "==36.0.2" }, "daphne": { "hashes": [ @@ -266,19 +271,19 @@ }, "dateparser": { "hashes": [ - "sha256:faa2b97f51f3b5ff1ba2f17be90de2b733fb6191f89b4058787473e8202f3044", - "sha256:fec344db1f73d005182e214c0ff27313c748bbe0c1638ce9d48a809ddfdab2a0" + "sha256:038196b1f12c7397e38aad3d61588833257f6f552baa63a1499e6987fa8d42d9", + "sha256:9600874312ff28a41f96ec7ccdc73be1d1c44435719da47fea3339d55ff5a628" ], "index": "pypi", - "version": "==1.1.0" + "version": "==1.1.1" }, "django": { "hashes": [ - "sha256:9772e6935703e59e993960832d66a614cf0233a1c5123bc6224ecc6ad69e41e2", - "sha256:9b06c289f9ba3a8abea16c9c9505f25107809fb933676f6c891ded270039d965" + "sha256:07c8638e7a7f548dc0acaaa7825d84b7bd42b10e8d22268b3d572946f1e9b687", + "sha256:4e8177858524417563cc0430f29ea249946d831eacb0068a1455686587df40b5" ], "index": "pypi", - "version": "==3.2.12" + "version": "==4.0.4" }, "django-cors-headers": { "hashes": [ @@ -349,7 +354,6 @@ }, "gunicorn": { "hashes": [ - "sha256:8d737657cdd62f483d482ee65cf9cc6a64d5b2199674f8b174803be9065e5d60", "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e", "sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8" ], @@ -404,9 +408,7 @@ "sha256:c39c46d9e44447181cd502a35aad2bb178dbf1b1f86cf4db639d7b9614f837c6", "sha256:cb2126603091902767d96bcb74093bd8b14982f41809f85c9b96e519c7e1dc41", "sha256:dcef843f8de4e2ff5e35e96ec2a4abbdf403bd0f732ead127bd27e51f38ac298", - "sha256:de22905c5920f6a2af2fccc54a7897cf52f1d0a4b9de87f546c6fb70d13e4e0b", "sha256:e3447d9e074abf0e3cd85aef8131e01ab93f9f0e86654db7ac8a3f73c63706ce", - "sha256:f299820a91e907fcfb92ca45923bfc0653c7314c05f0dfef226c76c608a95f4a", "sha256:f52010e0a44e3d8530437e7da38d11fb822acfb0d5b12e9cd5ba655509937ca0", "sha256:f8196f739092a78e4f6b1b2172679ed3343c39c61a3e9d722ce6fcf1dac2824a" ], @@ -415,32 +417,42 @@ }, "httptools": { "hashes": [ - "sha256:04114db99605c9b56ea22a8ec4d7b1485b908128ed4f4a8f6438489c428da794", - "sha256:074afd8afdeec0fa6786cd4a1676e0c0be23dc9a017a86647efa6b695168104f", - "sha256:113816f9af7dcfc4aa71ebb5354d77365f666ecf96ac7ff2aa1d24b6bca44165", - "sha256:1a8f26327023fa1a947d36e60a0582149e182fbbc949c8a65ec8665754dbbe69", - "sha256:2119fa619a4c53311f594f25c0205d619350fcb32140ec5057f861952e9b2b4f", - "sha256:21e948034f70e47c8abfa2d5e6f1a5661f87a2cddc7bcc70f61579cc87897c70", - "sha256:32a10a5903b5bc0eb647d01cd1e95bec3bb614a9bf53f0af1e01360b2debdf81", - "sha256:3787c1f46e9722ef7f07ea5c76b0103037483d1b12e34a02c53ceca5afa4e09a", - "sha256:3f82eb106e1474c63dba36a176067e65b48385f4cecddf3616411aa5d1fbdfec", - "sha256:3f9b4856d46ba1f0c850f4e84b264a9a8b4460acb20e865ec00978ad9fbaa4cf", - "sha256:4137137de8976511a392e27bfdcf231bd926ac13d375e0414e927b08217d779e", - "sha256:4687dfc116a9f1eb22a7d797f0dc6f6e17190d406ca4e729634b38aa98044b17", - "sha256:47dba2345aaa01b87e4981e8756af441349340708d5b60712c98c55a4d28f4af", - "sha256:5a836bd85ae1fb4304f674808488dae403e136d274aa5bafd0e6ee456f11c371", - "sha256:6e676bc3bb911b11f3d7e2144b9a53600bf6b9b21e0e4437aa308e1eef094d97", - "sha256:72ee0e3fb9c6437ab3ae34e9abee67fcee6876f4f58504e3f613dd5882aafdb7", - "sha256:79717080dc3f8b1eeb7f820b9b81528acbc04be6041f323fdd97550da2062575", - "sha256:8ac842df4fc3952efa7820b277961ea55e068bbc54cb59a0820400de7ae358d8", - "sha256:9f475b642c48b1b78584bdd12a5143e2c512485664331eade9c29ef769a17598", - "sha256:b8ac7dee63af4346e02b1e6d32202e3b5b3706a9928bec6da6d7a5b066217422", - "sha256:c0ac2e0ce6733c55858932e7d37fcc7b67ba6bb23e9648593c55f663de031b93", - "sha256:c14576b737d9e6e4f2a86af04918dbe9b62f57ce8102a8695c9a382dbe405c7f", - "sha256:cdc3975db86c29817e6d13df14e037c931fc893a710fb71097777a4147090068", - "sha256:eda95634027200f4b2a6d499e7c2e7fa9b8ee57e045dfda26958ea0af27c070b" + "sha256:1a99346ebcb801b213c591540837340bdf6fd060a8687518d01c607d338b7424", + "sha256:1ee0b459257e222b878a6c09ccf233957d3a4dcb883b0847640af98d2d9aac23", + "sha256:20a45bcf22452a10fa8d58b7dbdb474381f6946bf5b8933e3662d572bc61bae4", + "sha256:29bf97a5c532da9c7a04de2c7a9c31d1d54f3abd65a464119b680206bbbb1055", + "sha256:2c9a930c378b3d15d6b695fb95ebcff81a7395b4f9775c4f10a076beb0b2c1ff", + "sha256:2db44a0b294d317199e9f80123e72c6b005c55b625b57fae36de68670090fa48", + "sha256:3194f6d6443befa8d4db16c1946b2fc428a3ceb8ab32eb6f09a59f86104dc1a0", + "sha256:34d2903dd2a3dd85d33705b6fde40bf91fc44411661283763fd0746723963c83", + "sha256:48e48530d9b995a84d1d89ae6b3ec4e59ea7d494b150ac3bbc5e2ac4acce92cd", + "sha256:54bbd295f031b866b9799dd39cb45deee81aca036c9bff9f58ca06726f6494f1", + "sha256:5d1fe6b6661022fd6cac541f54a4237496b246e6f1c0a6b41998ee08a1135afe", + "sha256:645373c070080e632480a3d251d892cb795be3d3a15f86975d0f1aca56fd230d", + "sha256:6a1a7dfc1f9c78a833e2c4904757a0f47ce25d08634dd2a52af394eefe5f9777", + "sha256:701e66b59dd21a32a274771238025d58db7e2b6ecebbab64ceff51b8e31527ae", + "sha256:72aa3fbe636b16d22e04b5a9d24711b043495e0ecfe58080addf23a1a37f3409", + "sha256:7af6bdbd21a2a25d6784f6d67f44f5df33ef39b6159543b9f9064d365c01f919", + "sha256:7ee9f226acab9085037582c059d66769862706e8e8cd2340470ceb8b3850873d", + "sha256:7f7bfb74718f52d5ed47d608d507bf66d3bc01d4a8b3e6dd7134daaae129357b", + "sha256:8e2eb957787cbb614a0f006bfc5798ff1d90ac7c4dd24854c84edbdc8c02369e", + "sha256:903f739c9fb78dab8970b0f3ea51f21955b24b45afa77b22ff0e172fc11ef111", + "sha256:98993805f1e3cdb53de4eed02b55dcc953cdf017ba7bbb2fd89226c086a6d855", + "sha256:9967d9758df505975913304c434cb9ab21e2c609ad859eb921f2f615a038c8de", + "sha256:a113789e53ac1fa26edf99856a61e4c493868e125ae0dd6354cf518948fbbd5c", + "sha256:a522d12e2ddbc2e91842ffb454a1aeb0d47607972c7d8fc88bd0838d97fb8a2a", + "sha256:abe829275cdd4174b4c4e65ad718715d449e308d59793bf3a931ee1bf7e7b86c", + "sha256:c286985b5e194ca0ebb2908d71464b9be8f17cc66d6d3e330e8d5407248f56ad", + "sha256:cd1295f52971097f757edfbfce827b6dbbfb0f7a74901ee7d4933dff5ad4c9af", + "sha256:ceafd5e960b39c7e0d160a1936b68eb87c5e79b3979d66e774f0c77d4d8faaed", + "sha256:d1f27bb0f75bef722d6e22dc609612bfa2f994541621cd2163f8c943b6463dfe", + "sha256:d3a4e165ca6204f34856b765d515d558dc84f1352033b8721e8d06c3e44930c3", + "sha256:d9b90bf58f3ba04e60321a23a8723a1ff2a9377502535e70495e5ada8e6e6722", + "sha256:f72b5d24d6730035128b238decdc4c0f2104b7056a7ca55cf047c106842ec890", + "sha256:fcddfe70553be717d9745990dfdb194e22ee0f60eb8f48c0794e7bfeda30d2d5", + "sha256:fdb9f9ed79bc6f46b021b3319184699ba1a22410a82204e6e89c774530069683" ], - "version": "==0.3.0" + "version": "==0.4.0" }, "humanfriendly": { "hashes": [ @@ -467,25 +479,25 @@ }, "imap-tools": { "hashes": [ - "sha256:2217173e2da081dd70d1be5213d635b6c19af4714c89bdd21facbcec152d8c08", - "sha256:e7ab95381244ca24257e0387a8d8193c0f18a6b6cb721adea622b7bce4920783" + "sha256:119f1a60ea4048a4c5d72d9e9fa47c295685e340c730cb0b71fdf0ad3b7e53f8", + "sha256:3648bac835657b1c56ba856452c8a28bdbe3689d3730f95a4ad20d4c39f1c2d0" ], "index": "pypi", - "version": "==0.51.1" + "version": "==0.53.0" }, "img2pdf": { "hashes": [ - "sha256:8e51c5043efa95d751481b516071a006f87c2a4059961a9ac43ec238915de09f" + "sha256:8ec898a9646523fd3862b154f3f47cd52609c24cc3e2dc1fb5f0168f0cbe793c" ], - "version": "==0.4.3" + "version": "==0.4.4" }, "importlib-resources": { "hashes": [ - "sha256:33a95faed5fc19b4bc16b29a6eeae248a3fe69dd55d4d229d2b480e23eeaad45", - "sha256:d756e2f85dd4de2ba89be0b21dba2a3bbec2e871a42a3a16719258a11f87506b" + "sha256:1b93238cbf23b4cde34240dd8321d99e9bf2eb4bc91c0c99b2886283e7baad85", + "sha256:a9dd72f6cc106aeb50f6e66b86b69b454766dd6e39b69ac68450253058706bcc" ], "markers": "python_version < '3.9'", - "version": "==5.4.0" + "version": "==5.6.0" }, "incremental": { "hashes": [ @@ -496,8 +508,7 @@ }, "inotify-simple": { "hashes": [ - "sha256:8440ffe49c4ae81a8df57c1ae1eb4b6bfa7acb830099bfb3e305b383005cc128", - "sha256:854f9ac752cc1fcff6ca34e9d3d875c9a94c9b7d6eb377f63be2d481a566c6ee" + "sha256:8440ffe49c4ae81a8df57c1ae1eb4b6bfa7acb830099bfb3e305b383005cc128" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.3.5" @@ -521,7 +532,6 @@ "langdetect": { "hashes": [ "sha256:7cbc0746252f19e76f77c0b1690aadf01963be835ef0cd4b56dddf2a8f1dfc2a", - "sha256:87963db181db734abf00b1c463df5cadb3f9edad8efb334d3e52d5ad008d9cc7", "sha256:cbc1fef89f8d062739774bd51eda3da3274006b3661d199c2655f6b3f6d605a0" ], "index": "pypi", @@ -635,36 +645,37 @@ }, "numpy": { "hashes": [ - "sha256:03ae5850619abb34a879d5f2d4bb4dcd025d6d8fb72f5e461dae84edccfe129f", - "sha256:076aee5a3763d41da6bef9565fdf3cb987606f567cd8b104aded2b38b7b47abf", - "sha256:0b536b6840e84c1c6a410f3a5aa727821e6108f3454d81a5cd5900999ef04f89", - "sha256:15efb7b93806d438e3bc590ca8ef2f953b0ce4f86f337ef4559d31ec6cf9d7dd", - "sha256:168259b1b184aa83a514f307352c25c56af111c269ffc109d9704e81f72e764b", - "sha256:2638389562bda1635b564490d76713695ff497242a83d9b684d27bb4a6cc9d7a", - "sha256:3556c5550de40027d3121ebbb170f61bbe19eb639c7ad0c7b482cd9b560cd23b", - "sha256:4a176959b6e7e00b5a0d6f549a479f869829bfd8150282c590deee6d099bbb6e", - "sha256:515a8b6edbb904594685da6e176ac9fbea8f73a5ebae947281de6613e27f1956", - "sha256:55535c7c2f61e2b2fc817c5cbe1af7cb907c7f011e46ae0a52caa4be1f19afe2", - "sha256:59153979d60f5bfe9e4c00e401e24dfe0469ef8da6d68247439d3278f30a180f", - "sha256:60cb8e5933193a3cc2912ee29ca331e9c15b2da034f76159b7abc520b3d1233a", - "sha256:6767ad399e9327bfdbaa40871be4254d1995f4a3ca3806127f10cec778bd9896", - "sha256:76a4f9bce0278becc2da7da3b8ef854bed41a991f4226911a24a9711baad672c", - "sha256:8cf33634b60c9cef346663a222d9841d3bbbc0a2f00221d6bcfd0d993d5543f6", - "sha256:94dd11d9f13ea1be17bac39c1942f527cbf7065f94953cf62dfe805653da2f8f", - "sha256:aafa46b5a39a27aca566198d3312fb3bde95ce9677085efd02c86f7ef6be4ec7", - "sha256:badca914580eb46385e7f7e4e426fea6de0a37b9e06bec252e481ae7ec287082", - "sha256:d76a26c5118c4d96e264acc9e3242d72e1a2b92e739807b3b69d8d47684b6677" + "sha256:07a8c89a04997625236c5ecb7afe35a02af3896c8aa01890a849913a2309c676", + "sha256:08d9b008d0156c70dc392bb3ab3abb6e7a711383c3247b410b39962263576cd4", + "sha256:201b4d0552831f7250a08d3b38de0d989d6f6e4658b709a02a73c524ccc6ffce", + "sha256:2c10a93606e0b4b95c9b04b77dc349b398fdfbda382d2a39ba5a822f669a0123", + "sha256:3ca688e1b9b95d80250bca34b11a05e389b1420d00e87a0d12dc45f131f704a1", + "sha256:48a3aecd3b997bf452a2dedb11f4e79bc5bfd21a1d4cc760e703c31d57c84b3e", + "sha256:568dfd16224abddafb1cbcce2ff14f522abe037268514dd7e42c6776a1c3f8e5", + "sha256:5bfb1bb598e8229c2d5d48db1860bcf4311337864ea3efdbe1171fb0c5da515d", + "sha256:639b54cdf6aa4f82fe37ebf70401bbb74b8508fddcf4797f9fe59615b8c5813a", + "sha256:8251ed96f38b47b4295b1ae51631de7ffa8260b5b087808ef09a39a9d66c97ab", + "sha256:92bfa69cfbdf7dfc3040978ad09a48091143cffb778ec3b03fa170c494118d75", + "sha256:97098b95aa4e418529099c26558eeb8486e66bd1e53a6b606d684d0c3616b168", + "sha256:a3bae1a2ed00e90b3ba5f7bd0a7c7999b55d609e0c54ceb2b076a25e345fa9f4", + "sha256:c34ea7e9d13a70bf2ab64a2532fe149a9aced424cd05a2c4ba662fd989e3e45f", + "sha256:dbc7601a3b7472d559dc7b933b18b4b66f9aa7452c120e87dfb33d02008c8a18", + "sha256:e7927a589df200c5e23c57970bafbd0cd322459aa7b1ff73b7c2e84d6e3eae62", + "sha256:f8c1f39caad2c896bc0018f699882b345b2a63708008be29b1f355ebf6f933fe", + "sha256:f950f8845b480cffe522913d35567e29dd381b0dc7e4ce6a4a9f9156417d2430", + "sha256:fade0d4f4d292b6f39951b6836d7a3c7ef5b2347f3c420cd9820a1d90d794802", + "sha256:fdf3c08bce27132395d3c3ba1503cac12e17282358cb4bddc25cc46b0aca07aa" ], - "index": "pypi", - "version": "==1.22.2" + "markers": "python_version >= '3.8'", + "version": "==1.22.3" }, "ocrmypdf": { "hashes": [ - "sha256:bb770ef09439112c4fd84b7cca7f53da88f10927eda8c24ab0e9ae1c1626d018", - "sha256:e5a882afe9e1eb5382c916f13649dcab03035546f34d4bf1487d561081cb662c" + "sha256:7f0a6165b80ba1b37ce5943cf5b4faf93bf98c04c8f5157ef83c5f292491485f", + "sha256:d52410bc38cf5b66da27668e38c66ac41fd3136457c1ec388b311f0a78ee213c" ], "index": "pypi", - "version": "==13.4.0" + "version": "==13.4.2" }, "packaging": { "hashes": [ @@ -682,87 +693,98 @@ "index": "pypi", "version": "==2.5.0" }, - "pdfminer.six": { + "pdf2image": { "hashes": [ - "sha256:0351f17d362ee2d48b158be52bcde6576d96460efd038a3e89a043fba6d634d7", - "sha256:d3efb75c0249b51c1bf795e3a8bddf1726b276c77bf75fb136adea471ee2825b" + "sha256:84f79f2b8fad943e36323ea4e937fcb05f26ded0caa0a01181df66049e42fb65", + "sha256:d58ed94d978a70c73c2bb7fdf8acbaf2a7089c29ff8141be5f45433c0c4293bb" ], "index": "pypi", - "version": "==20211012" + "version": "==1.16.0" + }, + "pdfminer.six": { + "hashes": [ + "sha256:af0630f98a292bad4170f54e80f82ca81b916dd0b2c996437ec45c02f11d8762", + "sha256:eff2ce0abeaa4df94dc3461f70eab104487c7b4a2b3c7e9fd0aeec6c5f44d6a6" + ], + "index": "pypi", + "version": "==20220319" }, "pikepdf": { "hashes": [ - "sha256:14cd4bbbc699377d264549c07b0f6faa3ad79bba73ee1f0331e7c52d06a0e1ef", - "sha256:1d84f75196b37d61ea9d9b0fc2dafb37af6f34a37f07cbd69a1280e7a862176c", - "sha256:23c01f191d675525481c6ec2e1556ae5d8e8cdefe726677d90ff93350dac2cba", - "sha256:26b084188e65444236e8f760c97e6abc8eb9b4d0db9c78d34133a55bf66fb354", - "sha256:3988dde776155cb5616bc19ee4b50b5d3f26da6289fcec450e5927c72ca8ccd6", - "sha256:3c7bbcb67fa63003903f2d903046e31e85d17466325a03ff2bf0c96862f5d2fd", - "sha256:4f589b1856650defacaad0c516b1dc434986601e734abae5b7dcd4b0f0efeac7", - "sha256:5654f63b352def2c2ac835e911d7c9197b8c20a673f541747984c6b7dfa0f9f7", - "sha256:58d992a2c927c0db10a3380e55337525fefc84e6849c5889078de72e25259f3c", - "sha256:5f99cd81e9735e88bfa227d6cb97f9d64f79eda0d58bd3eeec53172bf6514f3a", - "sha256:5fae9eeb7a0120d466fb219aea643a94a1423d68ee9171639a44cf0329ebe7aa", - "sha256:6945fe8d62983f18393969c59098428aaf3d36e6726a2a91431bb38c7977ee06", - "sha256:6d120d972e18b4693aa52b6ad18e359bea2aef4ffc49c2cde922eba3860e9003", - "sha256:6ed285cf894d26a89d705c6f6a6301d8e29d2f7109cc7e40625db1981dddc678", - "sha256:745d0a0a38702e9bc8e4a9e3e6f26da59cab3e4a3d5180c360da8f42973bc1c0", - "sha256:77031dada8172c97760f51724176413d4a05e019ed5b14d16c65517c6eddd061", - "sha256:8573dd1023109cf9b58f15e3400402d6652ac35691267db3bc4493807099b4d0", - "sha256:8d2281fde206e68d38519ec495b7515c599194cb5fb4b486099b43c8055b15e3", - "sha256:8f5c949ce6edb8b51a7bfe843d5fd39077ef8a55491c56e2027a47228119f47a", - "sha256:a0147dd6f8bcfa7b887b61288b9a84b0907fcb8b898c6710c4ca615c77b8269d", - "sha256:a17187746419810ae587eebdd82ef90d286c8bb5377c384abe335b1ef289e32e", - "sha256:a59414a3c13c31dc9e5fe9d27c8081281d20f6eb3e056a0bc56a92a2b71f58e3", - "sha256:ad51e987b40996c8b54aae9fa73860433a48691913b467d56921f67e6e553ded", - "sha256:b67254b1c1d04584232ab7347447f56d3bc44c937832fe432bcbd44b46d6ecab", - "sha256:dbc7dee78f87c485e3bd5cfd9cc9c34e963d2765dff1a04d1a123814cdef28ab", - "sha256:e2be38b7fb16bdeb92a67ccfb4a4383f7d055470ab72e3516b60241e77c3f27a", - "sha256:fa60fd5f9217ab8188a0cfd92ac40d327785fe9183a8071d27bc228c7a5d7434" + "sha256:01be838a44430c4be84b748a33950fed09892472934a8041596c11189f365f7f", + "sha256:0cc95ef470169dfa5acc9196299bdba236716234a0d8b2746e2a563bc6f1f456", + "sha256:13e72d0aeeb3fc452569a3f7994acdd007de9aad804ced734d57cec269261b8b", + "sha256:2873503522ef26a09a6020c29c2efd221fa2ddc31e83bd902be27d317144cf63", + "sha256:2d5d6d3248b33ca5961d84bc3121a299cd27237fad56868d815e381c9a98d3d1", + "sha256:2f62e6c7bcf5d631e6ea74cf861f3e816f587c6ccb4ecbf6ac862e088ba2e4ac", + "sha256:51694d3d2f90510da6a8d7a4d07313ca868b373fffec6de270d9bbff1ce37180", + "sha256:5c23cbd7ae71f08fb5b5d9660eb0bc61abf345ada01bea6e1b6884c4261e17d6", + "sha256:6371bf02a436be2b7c63322b83a8e47523f2cd16438b2e93d546c7caf9ae308d", + "sha256:657293b74af8c7cf03f9905218a7935b26a4f3006803016b40b3db78e04cb35c", + "sha256:680d47377bb9fd6a36b6a81464ee269b4b29cbf29a84ae4f2ab8f6ea3665bf69", + "sha256:710535c679ab0d7b8249f72247832773e7a9a121dfbe9cad7f6465bd9bb45fae", + "sha256:7b4d7c09036d863915cb01007ca183d6fe64e2d57c0472453097bc9e029a58fb", + "sha256:978b6388ae99a024bdcae5a322c68e90c187cb568d09d43e6586b3479267121d", + "sha256:9917a03d500aab72715a9236136af7a5c8c7b26c034bf71ebdf028e177f0d25f", + "sha256:996faa6b119488f96d7271672a22af86e56e5544ec6b8eae6cd7d4432c70ae2d", + "sha256:9bac9e9d6b28dc0cc5a554051f183fbd070d0f9fe63c4e9aca939b8c44a5bb4d", + "sha256:aac14061de06843759ea6f5777fd8d7b71af808ed9264f57483a3311a09788ab", + "sha256:ad5361c3669fc0c8dbaf8fa0a590bddf59fad256bb2c527d5ce5cf991743a240", + "sha256:bc40b30c37f8f7c5bef873eca1f04e91ce34b6b74507d8d0019238a17d281fdc", + "sha256:bd9faae19787a5d05b9fcbe84d7cfe4d44e318068e06eca18906b9dba45425b6", + "sha256:c64e7905ec438b7a6c12626f2859df87f471892fab75b65b1441d9e1b38b4dde", + "sha256:d4db409b21a8ec0d3a79d2bbd894b997b13223c9ccf341cdc31b64360f1ee4c7", + "sha256:e0b635d6d9faefb4d0d32722279b8eb4e4d5d7b596c426f3433343de65e0c772", + "sha256:e62e9e8afe77fe2f06715faf10f38a4810d282d66f1e9e05208bb8d9723e6acf", + "sha256:f85d309bcfeeb3e2d344346a5050bfc41e332f19d390f79c20e4fc7de4b10a17", + "sha256:fe3fc2efe498aba6204b85c17c6a5d54ab7303354ecc5c3da624a6b6af0b3406" ], "index": "pypi", - "version": "==5.0.1" + "version": "==5.1.1" }, "pillow": { "hashes": [ - "sha256:011233e0c42a4a7836498e98c1acf5e744c96a67dd5032a6f666cc1fb97eab97", - "sha256:0f29d831e2151e0b7b39981756d201f7108d3d215896212ffe2e992d06bfe049", - "sha256:12875d118f21cf35604176872447cdb57b07126750a33748bac15e77f90f1f9c", - "sha256:14d4b1341ac07ae07eb2cc682f459bec932a380c3b122f5540432d8977e64eae", - "sha256:1c3c33ac69cf059bbb9d1a71eeaba76781b450bc307e2291f8a4764d779a6b28", - "sha256:1d19397351f73a88904ad1aee421e800fe4bbcd1aeee6435fb62d0a05ccd1030", - "sha256:253e8a302a96df6927310a9d44e6103055e8fb96a6822f8b7f514bb7ef77de56", - "sha256:2632d0f846b7c7600edf53c48f8f9f1e13e62f66a6dbc15191029d950bfed976", - "sha256:335ace1a22325395c4ea88e00ba3dc89ca029bd66bd5a3c382d53e44f0ccd77e", - "sha256:413ce0bbf9fc6278b2d63309dfeefe452835e1c78398efb431bab0672fe9274e", - "sha256:5100b45a4638e3c00e4d2320d3193bdabb2d75e79793af7c3eb139e4f569f16f", - "sha256:514ceac913076feefbeaf89771fd6febde78b0c4c1b23aaeab082c41c694e81b", - "sha256:528a2a692c65dd5cafc130de286030af251d2ee0483a5bf50c9348aefe834e8a", - "sha256:6295f6763749b89c994fcb6d8a7f7ce03c3992e695f89f00b741b4580b199b7e", - "sha256:6c8bc8238a7dfdaf7a75f5ec5a663f4173f8c367e5a39f87e720495e1eed75fa", - "sha256:718856856ba31f14f13ba885ff13874be7fefc53984d2832458f12c38205f7f7", - "sha256:7f7609a718b177bf171ac93cea9fd2ddc0e03e84d8fa4e887bdfc39671d46b00", - "sha256:80ca33961ced9c63358056bd08403ff866512038883e74f3a4bf88ad3eb66838", - "sha256:80fe64a6deb6fcfdf7b8386f2cf216d329be6f2781f7d90304351811fb591360", - "sha256:81c4b81611e3a3cb30e59b0cf05b888c675f97e3adb2c8672c3154047980726b", - "sha256:855c583f268edde09474b081e3ddcd5cf3b20c12f26e0d434e1386cc5d318e7a", - "sha256:9bfdb82cdfeccec50aad441afc332faf8606dfa5e8efd18a6692b5d6e79f00fd", - "sha256:a5d24e1d674dd9d72c66ad3ea9131322819ff86250b30dc5821cbafcfa0b96b4", - "sha256:a9f44cd7e162ac6191491d7249cceb02b8116b0f7e847ee33f739d7cb1ea1f70", - "sha256:b5b3f092fe345c03bca1e0b687dfbb39364b21ebb8ba90e3fa707374b7915204", - "sha256:b9618823bd237c0d2575283f2939655f54d51b4527ec3972907a927acbcc5bfc", - "sha256:cef9c85ccbe9bee00909758936ea841ef12035296c748aaceee535969e27d31b", - "sha256:d21237d0cd37acded35154e29aec853e945950321dd2ffd1a7d86fe686814669", - "sha256:d3c5c79ab7dfce6d88f1ba639b77e77a17ea33a01b07b99840d6ed08031cb2a7", - "sha256:d9d7942b624b04b895cb95af03a23407f17646815495ce4547f0e60e0b06f58e", - "sha256:db6d9fac65bd08cea7f3540b899977c6dee9edad959fa4eaf305940d9cbd861c", - "sha256:ede5af4a2702444a832a800b8eb7f0a7a1c0eed55b644642e049c98d589e5092", - "sha256:effb7749713d5317478bb3acb3f81d9d7c7f86726d41c1facca068a04cf5bb4c", - "sha256:f154d173286a5d1863637a7dcd8c3437bb557520b01bddb0be0258dcb72696b5", - "sha256:f25ed6e28ddf50de7e7ea99d7a976d6a9c415f03adcaac9c41ff6ff41b6d86ac" + "sha256:01ce45deec9df310cbbee11104bae1a2a43308dd9c317f99235b6d3080ddd66e", + "sha256:0c51cb9edac8a5abd069fd0758ac0a8bfe52c261ee0e330f363548aca6893595", + "sha256:17869489de2fce6c36690a0c721bd3db176194af5f39249c1ac56d0bb0fcc512", + "sha256:21dee8466b42912335151d24c1665fcf44dc2ee47e021d233a40c3ca5adae59c", + "sha256:25023a6209a4d7c42154073144608c9a71d3512b648a2f5d4465182cb93d3477", + "sha256:255c9d69754a4c90b0ee484967fc8818c7ff8311c6dddcc43a4340e10cd1636a", + "sha256:35be4a9f65441d9982240e6966c1eaa1c654c4e5e931eaf580130409e31804d4", + "sha256:3f42364485bfdab19c1373b5cd62f7c5ab7cc052e19644862ec8f15bb8af289e", + "sha256:3fddcdb619ba04491e8f771636583a7cc5a5051cd193ff1aa1ee8616d2a692c5", + "sha256:463acf531f5d0925ca55904fa668bb3461c3ef6bc779e1d6d8a488092bdee378", + "sha256:4fe29a070de394e449fd88ebe1624d1e2d7ddeed4c12e0b31624561b58948d9a", + "sha256:55dd1cf09a1fd7c7b78425967aacae9b0d70125f7d3ab973fadc7b5abc3de652", + "sha256:5a3ecc026ea0e14d0ad7cd990ea7f48bfcb3eb4271034657dc9d06933c6629a7", + "sha256:5cfca31ab4c13552a0f354c87fbd7f162a4fafd25e6b521bba93a57fe6a3700a", + "sha256:66822d01e82506a19407d1afc104c3fcea3b81d5eb11485e593ad6b8492f995a", + "sha256:69e5ddc609230d4408277af135c5b5c8fe7a54b2bdb8ad7c5100b86b3aab04c6", + "sha256:6b6d4050b208c8ff886fd3db6690bf04f9a48749d78b41b7a5bf24c236ab0165", + "sha256:7a053bd4d65a3294b153bdd7724dce864a1d548416a5ef61f6d03bf149205160", + "sha256:82283af99c1c3a5ba1da44c67296d5aad19f11c535b551a5ae55328a317ce331", + "sha256:8782189c796eff29dbb37dd87afa4ad4d40fc90b2742704f94812851b725964b", + "sha256:8d79c6f468215d1a8415aa53d9868a6b40c4682165b8cb62a221b1baa47db458", + "sha256:97bda660702a856c2c9e12ec26fc6d187631ddfd896ff685814ab21ef0597033", + "sha256:a325ac71914c5c043fa50441b36606e64a10cd262de12f7a179620f579752ff8", + "sha256:a336a4f74baf67e26f3acc4d61c913e378e931817cd1e2ef4dfb79d3e051b481", + "sha256:a598d8830f6ef5501002ae85c7dbfcd9c27cc4efc02a1989369303ba85573e58", + "sha256:a5eaf3b42df2bcda61c53a742ee2c6e63f777d0e085bbc6b2ab7ed57deb13db7", + "sha256:aea7ce61328e15943d7b9eaca87e81f7c62ff90f669116f857262e9da4057ba3", + "sha256:af79d3fde1fc2e33561166d62e3b63f0cc3e47b5a3a2e5fea40d4917754734ea", + "sha256:c24f718f9dd73bb2b31a6201e6db5ea4a61fdd1d1c200f43ee585fc6dcd21b34", + "sha256:c5b0ff59785d93b3437c3703e3c64c178aabada51dea2a7f2c5eccf1bcf565a3", + "sha256:c7110ec1701b0bf8df569a7592a196c9d07c764a0a74f65471ea56816f10e2c8", + "sha256:c870193cce4b76713a2b29be5d8327c8ccbe0d4a49bc22968aa1e680930f5581", + "sha256:c9efef876c21788366ea1f50ecb39d5d6f65febe25ad1d4c0b8dff98843ac244", + "sha256:de344bcf6e2463bb25179d74d6e7989e375f906bcec8cb86edb8b12acbc7dfef", + "sha256:eb1b89b11256b5b6cad5e7593f9061ac4624f7651f7a8eb4dfa37caa1dfaa4d0", + "sha256:ed742214068efa95e9844c2d9129e209ed63f61baa4d54dbf4cf8b5e2d30ccf2", + "sha256:f401ed2bbb155e1ade150ccc63db1a4f6c1909d3d378f7d1235a44e90d75fb97", + "sha256:fb89397013cf302f282f0fc998bb7abf11d49dcff72c8ecb320f76ea6e2c5717" ], "index": "pypi", - "version": "==9.0.1" + "version": "==9.1.0" }, "pluggy": { "hashes": [ @@ -780,64 +802,19 @@ "markers": "python_version >= '3'", "version": "==2.4.0" }, - "psycopg2-binary": { + "psycopg2": { "hashes": [ - "sha256:01310cf4cf26db9aea5158c217caa92d291f0500051a6469ac52166e1a16f5b7", - "sha256:083a55275f09a62b8ca4902dd11f4b33075b743cf0d360419e2051a8a5d5ff76", - "sha256:090f3348c0ab2cceb6dfbe6bf721ef61262ddf518cd6cc6ecc7d334996d64efa", - "sha256:0a29729145aaaf1ad8bafe663131890e2111f13416b60e460dae0a96af5905c9", - "sha256:0c9d5450c566c80c396b7402895c4369a410cab5a82707b11aee1e624da7d004", - "sha256:10bb90fb4d523a2aa67773d4ff2b833ec00857f5912bafcfd5f5414e45280fb1", - "sha256:12b11322ea00ad8db8c46f18b7dfc47ae215e4df55b46c67a94b4effbaec7094", - "sha256:152f09f57417b831418304c7f30d727dc83a12761627bb826951692cc6491e57", - "sha256:15803fa813ea05bef089fa78835118b5434204f3a17cb9f1e5dbfd0b9deea5af", - "sha256:15c4e4cfa45f5a60599d9cec5f46cd7b1b29d86a6390ec23e8eebaae84e64554", - "sha256:183a517a3a63503f70f808b58bfbf962f23d73b6dccddae5aa56152ef2bcb232", - "sha256:1f14c8b0942714eb3c74e1e71700cbbcb415acbc311c730370e70c578a44a25c", - "sha256:1f6b813106a3abdf7b03640d36e24669234120c72e91d5cbaeb87c5f7c36c65b", - "sha256:280b0bb5cbfe8039205c7981cceb006156a675362a00fe29b16fbc264e242834", - "sha256:2d872e3c9d5d075a2e104540965a1cf898b52274a5923936e5bfddb58c59c7c2", - "sha256:2f9ffd643bc7349eeb664eba8864d9e01f057880f510e4681ba40a6532f93c71", - "sha256:3303f8807f342641851578ee7ed1f3efc9802d00a6f83c101d21c608cb864460", - "sha256:35168209c9d51b145e459e05c31a9eaeffa9a6b0fd61689b48e07464ffd1a83e", - "sha256:3a79d622f5206d695d7824cbf609a4f5b88ea6d6dab5f7c147fc6d333a8787e4", - "sha256:404224e5fef3b193f892abdbf8961ce20e0b6642886cfe1fe1923f41aaa75c9d", - "sha256:46f0e0a6b5fa5851bbd9ab1bc805eef362d3a230fbdfbc209f4a236d0a7a990d", - "sha256:47133f3f872faf28c1e87d4357220e809dfd3fa7c64295a4a148bcd1e6e34ec9", - "sha256:526ea0378246d9b080148f2d6681229f4b5964543c170dd10bf4faaab6e0d27f", - "sha256:53293533fcbb94c202b7c800a12c873cfe24599656b341f56e71dd2b557be063", - "sha256:539b28661b71da7c0e428692438efbcd048ca21ea81af618d845e06ebfd29478", - "sha256:57804fc02ca3ce0dbfbef35c4b3a4a774da66d66ea20f4bda601294ad2ea6092", - "sha256:63638d875be8c2784cfc952c9ac34e2b50e43f9f0a0660b65e2a87d656b3116c", - "sha256:6472a178e291b59e7f16ab49ec8b4f3bdada0a879c68d3817ff0963e722a82ce", - "sha256:68641a34023d306be959101b345732360fc2ea4938982309b786f7be1b43a4a1", - "sha256:6e82d38390a03da28c7985b394ec3f56873174e2c88130e6966cb1c946508e65", - "sha256:761df5313dc15da1502b21453642d7599d26be88bff659382f8f9747c7ebea4e", - "sha256:7af0dd86ddb2f8af5da57a976d27cd2cd15510518d582b478fbb2292428710b4", - "sha256:7b1e9b80afca7b7a386ef087db614faebbf8839b7f4db5eb107d0f1a53225029", - "sha256:874a52ecab70af13e899f7847b3e074eeb16ebac5615665db33bce8a1009cf33", - "sha256:887dd9aac71765ac0d0bac1d0d4b4f2c99d5f5c1382d8b770404f0f3d0ce8a39", - "sha256:8b344adbb9a862de0c635f4f0425b7958bf5a4b927c8594e6e8d261775796d53", - "sha256:8fc53f9af09426a61db9ba357865c77f26076d48669f2e1bb24d85a22fb52307", - "sha256:91920527dea30175cc02a1099f331aa8c1ba39bf8b7762b7b56cbf54bc5cce42", - "sha256:93cd1967a18aa0edd4b95b1dfd554cf15af657cb606280996d393dadc88c3c35", - "sha256:99485cab9ba0fa9b84f1f9e1fef106f44a46ef6afdeec8885e0b88d0772b49e8", - "sha256:9d29409b625a143649d03d0fd7b57e4b92e0ecad9726ba682244b73be91d2fdb", - "sha256:a29b3ca4ec9defec6d42bf5feb36bb5817ba3c0230dd83b4edf4bf02684cd0ae", - "sha256:a9e1f75f96ea388fbcef36c70640c4efbe4650658f3d6a2967b4cc70e907352e", - "sha256:accfe7e982411da3178ec690baaceaad3c278652998b2c45828aaac66cd8285f", - "sha256:adf20d9a67e0b6393eac162eb81fb10bc9130a80540f4df7e7355c2dd4af9fba", - "sha256:af9813db73395fb1fc211bac696faea4ca9ef53f32dc0cfa27e4e7cf766dcf24", - "sha256:b1c8068513f5b158cf7e29c43a77eb34b407db29aca749d3eb9293ee0d3103ca", - "sha256:bda845b664bb6c91446ca9609fc69f7db6c334ec5e4adc87571c34e4f47b7ddb", - "sha256:c381bda330ddf2fccbafab789d83ebc6c53db126e4383e73794c74eedce855ef", - "sha256:c3ae8e75eb7160851e59adc77b3a19a976e50622e44fd4fd47b8b18208189d42", - "sha256:d1c1b569ecafe3a69380a94e6ae09a4789bbb23666f3d3a08d06bbd2451f5ef1", - "sha256:def68d7c21984b0f8218e8a15d514f714d96904265164f75f8d3a70f9c295667", - "sha256:dffc08ca91c9ac09008870c9eb77b00a46b3378719584059c034b8945e26b272", - "sha256:e3699852e22aa68c10de06524a3721ade969abf382da95884e6a10ff798f9281", - "sha256:e847774f8ffd5b398a75bc1c18fbb56564cda3d629fe68fd81971fece2d3c67e", - "sha256:ffb7a888a047696e7f8240d649b43fb3644f14f0ee229077e7f6b9f9081635bd" + "sha256:06f32425949bd5fe8f625c49f17ebb9784e1e4fe928b7cce72edc36fb68e4c0c", + "sha256:0762c27d018edbcb2d34d51596e4346c983bd27c330218c56c4dc25ef7e819bf", + "sha256:083707a696e5e1c330af2508d8fab36f9700b26621ccbcb538abe22e15485362", + "sha256:34b33e0162cfcaad151f249c2649fd1030010c16f4bbc40a604c1cb77173dcf7", + "sha256:4295093a6ae3434d33ec6baab4ca5512a5082cc43c0505293087b8a46d108461", + "sha256:8cf3878353cc04b053822896bc4922b194792df9df2f1ad8da01fb3043602126", + "sha256:8e841d1bf3434da985cc5ef13e6f75c8981ced601fd70cc6bf33351b91562981", + "sha256:9572e08b50aed176ef6d66f15a21d823bb6f6d23152d35e8451d7d2d18fdac56", + "sha256:a81e3866f99382dfe8c15a151f1ca5fde5815fde879348fe5a9884a7c092a305", + "sha256:cb10d44e6694d763fa1078a26f7f6137d69f555a78ec85dc2ef716c37447e4b2", + "sha256:d3ca6421b942f60c008f81a3541e8faf6865a28d5a9b48544b0ee4f40cac7fca" ], "index": "pypi", "version": "==2.9.3" @@ -883,7 +860,6 @@ "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9", "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.21" }, "pyopenssl": { @@ -891,16 +867,15 @@ "sha256:660b1b1425aac4a1bea1d94168a85d99f0b3144c869dd4390d27629d0087f1bf", "sha256:ea252b38c87425b64116f808355e8da644ef9b07e429398bfece610f893ee2e0" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==22.0.0" }, "pyparsing": { "hashes": [ - "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea", - "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484" + "sha256:7bf433498c016c4314268d95df76c81b842a4cb2b276fa3312cfb1e1d85f6954", + "sha256:ef7b523f6356f763771559412c0d7134753f037822dad1b16945b7b846f7ad06" ], - "markers": "python_version >= '3.6'", - "version": "==3.0.7" + "markers": "python_full_version >= '3.6.8'", + "version": "==3.0.8" }, "python-dateutil": { "hashes": [ @@ -912,11 +887,11 @@ }, "python-dotenv": { "hashes": [ - "sha256:32b2bdc1873fd3a3c346da1c6db83d0053c3c62f28f1f38516070c4c8971b1d3", - "sha256:a5de49a31e953b45ff2d2fd434bbc2670e8db5273606c1e737cc6b93eff3655f" + "sha256:b7e3b04a59693c42c36f9ab1cc2acc46fa5df8c78e178fc33a8d4cd05c8d498f", + "sha256:d92a187be61fe482e4fd675b6d52200e7be63a12b724abbf931a40ce4fa92938" ], "index": "pypi", - "version": "==0.19.2" + "version": "==0.20.0" }, "python-gnupg": { "hashes": [ @@ -928,9 +903,6 @@ }, "python-levenshtein": { "hashes": [ - "sha256:212db61934fcb819f5cb2fcb5ad5c0e2e43f3161f524eef4a135f7285dfb308a", - "sha256:a31d3065bf4e8fc6721038c783df132650ad24711e986b25ae0c37e140a99da3", - "sha256:d92fe5c3b10c8ad8f2d880499f5e96ed24dbc7cd0414a665c2e2505feaf4ec58", "sha256:dc2395fbd148a1ab31090dd113c366695934b9e85fe5a4b2a032745efd0346f6" ], "version": "==0.12.2" @@ -945,10 +917,10 @@ }, "pytz": { "hashes": [ - "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c", - "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326" + "sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7", + "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c" ], - "version": "==2021.3" + "version": "==2022.1" }, "pytz-deprecation-shim": { "hashes": [ @@ -996,10 +968,18 @@ ], "version": "==6.0" }, + "pyzbar": { + "hashes": [ + "sha256:13e3ee5a2f3a545204a285f41814d5c0db571967e8d4af8699a03afc55182a9c", + "sha256:4559628b8192feb25766d954b36a3753baaf5c97c03135aec7e4a026036b475d", + "sha256:8f4c5264c9c7c6b9f20d01efc52a4eba1ded47d9ba857a94130afe33703eb518" + ], + "index": "pypi", + "version": "==0.1.9" + }, "redis": { "hashes": [ "sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2", - "sha256:3f1c7f166fa6c803613eec222224848a80f5e5b9c6af3aa82461506643034a7a", "sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24" ], "index": "pypi", @@ -1007,124 +987,125 @@ }, "regex": { "hashes": [ - "sha256:04611cc0f627fc4a50bc4a9a2e6178a974c6a6a4aa9c1cca921635d2c47b9c87", - "sha256:0b5d6f9aed3153487252d00a18e53f19b7f52a1651bc1d0c4b5844bc286dfa52", - "sha256:0d2f5c3f7057530afd7b739ed42eb04f1011203bc5e4663e1e1d01bb50f813e3", - "sha256:11772be1eb1748e0e197a40ffb82fb8fd0d6914cd147d841d9703e2bef24d288", - "sha256:1333b3ce73269f986b1fa4d5d395643810074dc2de5b9d262eb258daf37dc98f", - "sha256:16f81025bb3556eccb0681d7946e2b35ff254f9f888cff7d2120e8826330315c", - "sha256:1a171eaac36a08964d023eeff740b18a415f79aeb212169080c170ec42dd5184", - "sha256:1d6301f5288e9bdca65fab3de6b7de17362c5016d6bf8ee4ba4cbe833b2eda0f", - "sha256:1e031899cb2bc92c0cf4d45389eff5b078d1936860a1be3aa8c94fa25fb46ed8", - "sha256:1f8c0ae0a0de4e19fddaaff036f508db175f6f03db318c80bbc239a1def62d02", - "sha256:2245441445099411b528379dee83e56eadf449db924648e5feb9b747473f42e3", - "sha256:22709d701e7037e64dae2a04855021b62efd64a66c3ceed99dfd684bfef09e38", - "sha256:24c89346734a4e4d60ecf9b27cac4c1fee3431a413f7aa00be7c4d7bbacc2c4d", - "sha256:25716aa70a0d153cd844fe861d4f3315a6ccafce22b39d8aadbf7fcadff2b633", - "sha256:2dacb3dae6b8cc579637a7b72f008bff50a94cde5e36e432352f4ca57b9e54c4", - "sha256:34316bf693b1d2d29c087ee7e4bb10cdfa39da5f9c50fa15b07489b4ab93a1b5", - "sha256:36b2d700a27e168fa96272b42d28c7ac3ff72030c67b32f37c05616ebd22a202", - "sha256:37978254d9d00cda01acc1997513f786b6b971e57b778fbe7c20e30ae81a97f3", - "sha256:38289f1690a7e27aacd049e420769b996826f3728756859420eeee21cc857118", - "sha256:385ccf6d011b97768a640e9d4de25412204fbe8d6b9ae39ff115d4ff03f6fe5d", - "sha256:3c7ea86b9ca83e30fa4d4cd0eaf01db3ebcc7b2726a25990966627e39577d729", - "sha256:49810f907dfe6de8da5da7d2b238d343e6add62f01a15d03e2195afc180059ed", - "sha256:519c0b3a6fbb68afaa0febf0d28f6c4b0a1074aefc484802ecb9709faf181607", - "sha256:51f02ca184518702975b56affde6c573ebad4e411599005ce4468b1014b4786c", - "sha256:552a39987ac6655dad4bf6f17dd2b55c7b0c6e949d933b8846d2e312ee80005a", - "sha256:596f5ae2eeddb79b595583c2e0285312b2783b0ec759930c272dbf02f851ff75", - "sha256:6014038f52b4b2ac1fa41a58d439a8a00f015b5c0735a0cd4b09afe344c94899", - "sha256:61ebbcd208d78658b09e19c78920f1ad38936a0aa0f9c459c46c197d11c580a0", - "sha256:6213713ac743b190ecbf3f316d6e41d099e774812d470422b3a0f137ea635832", - "sha256:637e27ea1ebe4a561db75a880ac659ff439dec7f55588212e71700bb1ddd5af9", - "sha256:6aa427c55a0abec450bca10b64446331b5ca8f79b648531138f357569705bc4a", - "sha256:6ca45359d7a21644793de0e29de497ef7f1ae7268e346c4faf87b421fea364e6", - "sha256:6db1b52c6f2c04fafc8da17ea506608e6be7086715dab498570c3e55e4f8fbd1", - "sha256:752e7ddfb743344d447367baa85bccd3629c2c3940f70506eb5f01abce98ee68", - "sha256:760c54ad1b8a9b81951030a7e8e7c3ec0964c1cb9fee585a03ff53d9e531bb8e", - "sha256:768632fd8172ae03852e3245f11c8a425d95f65ff444ce46b3e673ae5b057b74", - "sha256:7a0b9f6a1a15d494b35f25ed07abda03209fa76c33564c09c9e81d34f4b919d7", - "sha256:7e070d3aef50ac3856f2ef5ec7214798453da878bb5e5a16c16a61edf1817cc3", - "sha256:7e12949e5071c20ec49ef00c75121ed2b076972132fc1913ddf5f76cae8d10b4", - "sha256:7e26eac9e52e8ce86f915fd33380f1b6896a2b51994e40bb094841e5003429b4", - "sha256:85ffd6b1cb0dfb037ede50ff3bef80d9bf7fa60515d192403af6745524524f3b", - "sha256:8618d9213a863c468a865e9d2ec50221015f7abf52221bc927152ef26c484b4c", - "sha256:8acef4d8a4353f6678fd1035422a937c2170de58a2b29f7da045d5249e934101", - "sha256:8d2f355a951f60f0843f2368b39970e4667517e54e86b1508e76f92b44811a8a", - "sha256:90b6840b6448203228a9d8464a7a0d99aa8fa9f027ef95fe230579abaf8a6ee1", - "sha256:9187500d83fd0cef4669385cbb0961e227a41c0c9bc39219044e35810793edf7", - "sha256:93c20777a72cae8620203ac11c4010365706062aa13aaedd1a21bb07adbb9d5d", - "sha256:93cce7d422a0093cfb3606beae38a8e47a25232eea0f292c878af580a9dc7605", - "sha256:94c623c331a48a5ccc7d25271399aff29729fa202c737ae3b4b28b89d2b0976d", - "sha256:97f32dc03a8054a4c4a5ab5d761ed4861e828b2c200febd4e46857069a483916", - "sha256:9a2bf98ac92f58777c0fafc772bf0493e67fcf677302e0c0a630ee517a43b949", - "sha256:a602bdc8607c99eb5b391592d58c92618dcd1537fdd87df1813f03fed49957a6", - "sha256:a9d24b03daf7415f78abc2d25a208f234e2c585e5e6f92f0204d2ab7b9ab48e3", - "sha256:abfcb0ef78df0ee9df4ea81f03beea41849340ce33a4c4bd4dbb99e23ec781b6", - "sha256:b013f759cd69cb0a62de954d6d2096d648bc210034b79b1881406b07ed0a83f9", - "sha256:b02e3e72665cd02afafb933453b0c9f6c59ff6e3708bd28d0d8580450e7e88af", - "sha256:b52cc45e71657bc4743a5606d9023459de929b2a198d545868e11898ba1c3f59", - "sha256:ba37f11e1d020969e8a779c06b4af866ffb6b854d7229db63c5fdddfceaa917f", - "sha256:bb804c7d0bfbd7e3f33924ff49757de9106c44e27979e2492819c16972ec0da2", - "sha256:bf594cc7cc9d528338d66674c10a5b25e3cde7dd75c3e96784df8f371d77a298", - "sha256:c38baee6bdb7fe1b110b6b3aaa555e6e872d322206b7245aa39572d3fc991ee4", - "sha256:c73d2166e4b210b73d1429c4f1ca97cea9cc090e5302df2a7a0a96ce55373f1c", - "sha256:c9099bf89078675c372339011ccfc9ec310310bf6c292b413c013eb90ffdcafc", - "sha256:cf0db26a1f76aa6b3aa314a74b8facd586b7a5457d05b64f8082a62c9c49582a", - "sha256:d19a34f8a3429bd536996ad53597b805c10352a8561d8382e05830df389d2b43", - "sha256:da80047524eac2acf7c04c18ac7a7da05a9136241f642dd2ed94269ef0d0a45a", - "sha256:de2923886b5d3214be951bc2ce3f6b8ac0d6dfd4a0d0e2a4d2e5523d8046fdfb", - "sha256:defa0652696ff0ba48c8aff5a1fac1eef1ca6ac9c660b047fc8e7623c4eb5093", - "sha256:e54a1eb9fd38f2779e973d2f8958fd575b532fe26013405d1afb9ee2374e7ab8", - "sha256:e5c31d70a478b0ca22a9d2d76d520ae996214019d39ed7dd93af872c7f301e52", - "sha256:ebaeb93f90c0903233b11ce913a7cb8f6ee069158406e056f884854c737d2442", - "sha256:ecfe51abf7f045e0b9cdde71ca9e153d11238679ef7b5da6c82093874adf3338", - "sha256:f99112aed4fb7cee00c7f77e8b964a9b10f69488cdff626ffd797d02e2e4484f", - "sha256:fd914db437ec25bfa410f8aa0aa2f3ba87cdfc04d9919d608d02330947afaeab" + "sha256:0008650041531d0eadecc96a73d37c2dc4821cf51b0766e374cb4f1ddc4e1c14", + "sha256:03299b0bcaa7824eb7c0ebd7ef1e3663302d1b533653bfe9dc7e595d453e2ae9", + "sha256:06b1df01cf2aef3a9790858af524ae2588762c8a90e784ba00d003f045306204", + "sha256:09b4b6ccc61d4119342b26246ddd5a04accdeebe36bdfe865ad87a0784efd77f", + "sha256:0be0c34a39e5d04a62fd5342f0886d0e57592a4f4993b3f9d257c1f688b19737", + "sha256:0d96eec8550fd2fd26f8e675f6d8b61b159482ad8ffa26991b894ed5ee19038b", + "sha256:0eb0e2845e81bdea92b8281a3969632686502565abf4a0b9e4ab1471c863d8f3", + "sha256:13bbf0c9453c6d16e5867bda7f6c0c7cff1decf96c5498318bb87f8136d2abd4", + "sha256:17e51ad1e6131c496b58d317bc9abec71f44eb1957d32629d06013a21bc99cac", + "sha256:1977bb64264815d3ef016625adc9df90e6d0e27e76260280c63eca993e3f455f", + "sha256:1e30762ddddb22f7f14c4f59c34d3addabc789216d813b0f3e2788d7bcf0cf29", + "sha256:1e73652057473ad3e6934944af090852a02590c349357b79182c1b681da2c772", + "sha256:20e6a27959f162f979165e496add0d7d56d7038237092d1aba20b46de79158f1", + "sha256:286ff9ec2709d56ae7517040be0d6c502642517ce9937ab6d89b1e7d0904f863", + "sha256:297c42ede2c81f0cb6f34ea60b5cf6dc965d97fa6936c11fc3286019231f0d66", + "sha256:320c2f4106962ecea0f33d8d31b985d3c185757c49c1fb735501515f963715ed", + "sha256:35ed2f3c918a00b109157428abfc4e8d1ffabc37c8f9abc5939ebd1e95dabc47", + "sha256:3d146e5591cb67c5e836229a04723a30af795ef9b70a0bbd913572e14b7b940f", + "sha256:42bb37e2b2d25d958c25903f6125a41aaaa1ed49ca62c103331f24b8a459142f", + "sha256:42d6007722d46bd2c95cce700181570b56edc0dcbadbfe7855ec26c3f2d7e008", + "sha256:43eba5c46208deedec833663201752e865feddc840433285fbadee07b84b464d", + "sha256:452519bc4c973e961b1620c815ea6dd8944a12d68e71002be5a7aff0a8361571", + "sha256:4b9c16a807b17b17c4fa3a1d8c242467237be67ba92ad24ff51425329e7ae3d0", + "sha256:5510932596a0f33399b7fff1bd61c59c977f2b8ee987b36539ba97eb3513584a", + "sha256:55820bc631684172b9b56a991d217ec7c2e580d956591dc2144985113980f5a3", + "sha256:57484d39447f94967e83e56db1b1108c68918c44ab519b8ecfc34b790ca52bf7", + "sha256:58ba41e462653eaf68fc4a84ec4d350b26a98d030be1ab24aba1adcc78ffe447", + "sha256:5bc5f921be39ccb65fdda741e04b2555917a4bced24b4df14eddc7569be3b493", + "sha256:5dcc4168536c8f68654f014a3db49b6b4a26b226f735708be2054314ed4964f4", + "sha256:5f92a7cdc6a0ae2abd184e8dfd6ef2279989d24c85d2c85d0423206284103ede", + "sha256:67250b36edfa714ba62dc62d3f238e86db1065fccb538278804790f578253640", + "sha256:6df070a986fc064d865c381aecf0aaff914178fdf6874da2f2387e82d93cc5bd", + "sha256:729aa8ca624c42f309397c5fc9e21db90bf7e2fdd872461aabdbada33de9063c", + "sha256:72bc3a5effa5974be6d965ed8301ac1e869bc18425c8a8fac179fbe7876e3aee", + "sha256:74d86e8924835f863c34e646392ef39039405f6ce52956d8af16497af4064a30", + "sha256:79e5af1ff258bc0fe0bdd6f69bc4ae33935a898e3cbefbbccf22e88a27fa053b", + "sha256:7b103dffb9f6a47ed7ffdf352b78cfe058b1777617371226c1894e1be443afec", + "sha256:83f03f0bd88c12e63ca2d024adeee75234d69808b341e88343b0232329e1f1a1", + "sha256:86d7a68fa53688e1f612c3246044157117403c7ce19ebab7d02daf45bd63913e", + "sha256:878c626cbca3b649e14e972c14539a01191d79e58934e3f3ef4a9e17f90277f8", + "sha256:878f5d649ba1db9f52cc4ef491f7dba2d061cdc48dd444c54260eebc0b1729b9", + "sha256:87bc01226cd288f0bd9a4f9f07bf6827134dc97a96c22e2d28628e824c8de231", + "sha256:8babb2b5751105dc0aef2a2e539f4ba391e738c62038d8cb331c710f6b0f3da7", + "sha256:91e0f7e7be77250b808a5f46d90bf0032527d3c032b2131b63dee54753a4d729", + "sha256:9557545c10d52c845f270b665b52a6a972884725aa5cf12777374e18f2ea8960", + "sha256:9ccb0a4ab926016867260c24c192d9df9586e834f5db83dfa2c8fffb3a6e5056", + "sha256:9d828c5987d543d052b53c579a01a52d96b86f937b1777bbfe11ef2728929357", + "sha256:9efa41d1527b366c88f265a227b20bcec65bda879962e3fc8a2aee11e81266d7", + "sha256:aaf5317c961d93c1a200b9370fb1c6b6836cc7144fef3e5a951326912bf1f5a3", + "sha256:ab69b4fe09e296261377d209068d52402fb85ef89dc78a9ac4a29a895f4e24a7", + "sha256:ad397bc7d51d69cb07ef89e44243f971a04ce1dca9bf24c992c362406c0c6573", + "sha256:ae17fc8103f3b63345709d3e9654a274eee1c6072592aec32b026efd401931d0", + "sha256:af4d8cc28e4c7a2f6a9fed544228c567340f8258b6d7ea815b62a72817bbd178", + "sha256:b22ff939a8856a44f4822da38ef4868bd3a9ade22bb6d9062b36957c850e404f", + "sha256:b549d851f91a4efb3e65498bd4249b1447ab6035a9972f7fc215eb1f59328834", + "sha256:be319f4eb400ee567b722e9ea63d5b2bb31464e3cf1b016502e3ee2de4f86f5c", + "sha256:c0446b2871335d5a5e9fcf1462f954586b09a845832263db95059dcd01442015", + "sha256:c68d2c04f7701a418ec2e5631b7f3552efc32f6bcc1739369c6eeb1af55f62e0", + "sha256:c87ac58b9baaf50b6c1b81a18d20eda7e2883aa9a4fb4f1ca70f2e443bfcdc57", + "sha256:caa2734ada16a44ae57b229d45091f06e30a9a52ace76d7574546ab23008c635", + "sha256:cb34c2d66355fb70ae47b5595aafd7218e59bb9c00ad8cc3abd1406ca5874f07", + "sha256:cb3652bbe6720786b9137862205986f3ae54a09dec8499a995ed58292bdf77c2", + "sha256:cf668f26604e9f7aee9f8eaae4ca07a948168af90b96be97a4b7fa902a6d2ac1", + "sha256:d326ff80ed531bf2507cba93011c30fff2dd51454c85f55df0f59f2030b1687b", + "sha256:d6c2441538e4fadd4291c8420853431a229fcbefc1bf521810fbc2629d8ae8c2", + "sha256:d6ecfd1970b3380a569d7b3ecc5dd70dba295897418ed9e31ec3c16a5ab099a5", + "sha256:e5602a9b5074dcacc113bba4d2f011d2748f50e3201c8139ac5b68cf2a76bd8b", + "sha256:ef806f684f17dbd6263d72a54ad4073af42b42effa3eb42b877e750c24c76f86", + "sha256:f3356afbb301ec34a500b8ba8b47cba0b44ed4641c306e1dd981a08b416170b5", + "sha256:f6f7ee2289176cb1d2c59a24f50900f8b9580259fa9f1a739432242e7d254f93", + "sha256:f7e8f1ee28e0a05831c92dc1c0c1c94af5289963b7cf09eca5b5e3ce4f8c91b0", + "sha256:f8169ec628880bdbca67082a9196e2106060a4a5cbd486ac51881a4df805a36f", + "sha256:fbc88d3ba402b5d041d204ec2449c4078898f89c4a6e6f0ed1c1a510ef1e221d", + "sha256:fbd3fe37353c62fd0eb19fb76f78aa693716262bcd5f9c14bb9e5aca4b3f0dc4" ], - "version": "==2022.1.18" + "markers": "python_version >= '3.6'", + "version": "==2022.3.2" }, "reportlab": { "hashes": [ - "sha256:06c8dbaa26c2bf63e7fcddb86f232ddaf7c57141072407d22b4e8cbfcc5348e4", - "sha256:0e308e91d995beb35f0cef8c7c16d6c10c22ae937929c345f745caa6d371b7a9", - "sha256:1e28735a9a01124637d637a8513ffec74a34e5fdd3c3af595eb3e0217525e8e0", - "sha256:232ff75d29a1a5b3e8aa321eaec8e541afaf9704fd2e059127b816df3f2296f4", - "sha256:27088f0f10639f8ca27222264910c816aa3b089d590b4a1c01e9d1b0935835df", - "sha256:2b1360785b73a52613712df48600d62788e0fb3ebd6e47fa52fb0dd498430893", - "sha256:3bda030877d3b683e4fb72fd114a6dad1e5b1ba83928ae914af5e0171d5bcff9", - "sha256:3d402cd8cdd1b9b8631b6d7811c6bb788aa3caa3f38b300e9d4a5e12276d8863", - "sha256:401b72f70fcac83c52853d17b0c1f1f9d93c6ceaafdd94b3c0e7b0bdfecca182", - "sha256:439f3b2eca084aad48f6231253a33469c8eac9fcd924d80b157cbe6b77699931", - "sha256:4432abb4c61d914cbac22baa9172efe8036074cea539a12f3b37134055d38ccb", - "sha256:449a03741f10454d64afc55180eeac91bb22f3560332c7e25df3dc7e884cbf22", - "sha256:47fa377b24044514807d539780c58bc5cec91fa4ea8700f3c150c61de358d91a", - "sha256:5013b0468712dc9fbd9ace297821d27677abf427ac32fe2b537d8876bfb41c65", - "sha256:51b222f2315d34a7201b1ea5d843715a2625107838de52979406d4dd5ab2f7f6", - "sha256:51c0c5c0611c9b6b3d1aae0037efb303c57da6d1349830b83915a92bd0f5f246", - "sha256:6bb42e672c1866a52412888cc07a91589a28a922100770c1f53569d3e7e3ad8f", - "sha256:80c9cdfed6b4bcca9dfd904d1d139b98975cd9ccb2558588307a0d53b5b6c8b4", - "sha256:891b2ad614b43d911f70bcdefe2366db8ca7e85e952ffa96255975c1636d46e4", - "sha256:a137df1507414115e3f0c8821514f450d9f9c973f2821dfa112ed797464fc93d", - "sha256:a13824c9363393ead2ed72907ecc40250c6d3489963627bd34e437e5accea2a1", - "sha256:b6d72e9f2d5cf20378b1c6a8ea3589728496744677332f0688dc415a8a5c91b7", - "sha256:b7e5b0372f15331d806dd5847c4ec1f737b02438579a7e2dd798e9bf8c27c83e", - "sha256:b8faa40a3f74bbf932bcda30ea8258511a3b6194460202a4720c1e4b64acb338", - "sha256:b91d2952ca4264c145927303ec3c03cdf6b0b035688077b514ba37e8683c21ec", - "sha256:bf2e6e5b4d58ad1220228f5620064e13a53148775c28dcbe1c552f3f7e359389", - "sha256:d035054724278129aba2a55c3edd6111b07e625ad1ff845e3ba2a5e4e203bbc8", - "sha256:d1890f197f12f3c734bafc21cbf9ebe18164e780164997a0d717187db2a46adc", - "sha256:d5f5ab22f71433a665f50b24cced62298626753536a50db0c769c2fee07038e6", - "sha256:db9462b443d9f0834d997039fc2648336ada3141dc96b146bcde85c81a6b3224", - "sha256:dd4d53e5d09f9912df86746330148d739ad837424383ea0b99486ac38e5edaa2", - "sha256:e703d862c1c85b5e377e3cf2b33763303deb80e799ad301e99d09ec81feecdb1", - "sha256:ea5ca026695210cc3364328a9490b2f29ce97b99614950df8fb11b2680641008", - "sha256:ec67e5bdf6cb0f3b410b1bfb75a41aeb39f89ffedd1fd5165fa87833ecbb48dd", - "sha256:fd5bc5d0b56df4cafb70b5ba8ec0bb19921574d2f99fbf623c3a215fcaa79aba", - "sha256:fe319e0891e20fb04f038926ace02cf87f34fd223c478437572b5ed2b821f8af" + "sha256:09b2ca175129a34292399fc4c6a8b1739f6c5946368fcaa6f931d69385b2f720", + "sha256:0a7f2b7232c3ffb451b649d55c51a6dd0c8104ad7bbcfe355addf7619705e7fa", + "sha256:0e767cf4507ca8eed7dde8511f0889b0f19f160a2bdf9ef07742b2aaeceed9f2", + "sha256:10681d89a0ca37bb4036283fb8c0efac9ac1b22265dbdf350bda0448be33e00c", + "sha256:15294435f786968bcdf1a7a67bcc23a136470b6ea26919497f5c76ff0f653041", + "sha256:193671445b4885128d8800d3e416eb2fa4fd89bafae08cc9889c0752fe5ad8c2", + "sha256:1967dbc9930917d75c39784712a137d432dbc2e5ca9e132a2453319c2619ccff", + "sha256:1ec84055cf2c83783958b74eadf0e577eb0cd9088c8b5d536e9ddc0f4a9f8c70", + "sha256:23f5aed2d212096f2fe95d56f868d63f839a08bf7e389237e644d93981274222", + "sha256:32a5c5cd9625a40feec956f460355b4813bc3187c4f8dc9efd9f1a7f8f854e34", + "sha256:37dda88dbe16dd3f4f9039464637cce66e462c0b95e5763dbd45ac5799136d3a", + "sha256:496f42840604255ce06777bc129048b3bab966213bbac4f07fbe4ceb6a2e0482", + "sha256:4ba8eebfa4383e4680d6e7e6dba9c45c1fe19bbc0a754db4d84823f1a9511e56", + "sha256:4fbe23ac870adf90544d2014c572dba6ec4d772afad6505bb91f171ddad12839", + "sha256:50f8e30f5410efc69b0217261b1f21912888da392a4549e79c7aaaac85f01bfa", + "sha256:5d0cc3682456ad213150f6dbffe7d47eab737d809e517c316103376be548fb84", + "sha256:6a114761ad3ba6e0cdfacf14a8fb2cb8f5713b115ca1f0c17f3cd638d0a5b4bd", + "sha256:713574da534b6ce73d884f1574c35a565e438af4888fcc75e752f1de02e356a7", + "sha256:8cb82b6d14ad4bd915acacc8f114c6a7bab8b9b1503cabb930e433ebd320f90c", + "sha256:90f74627cafecf3924741ab8b0690a19df4214eb56b1cfce2dc74a15c9744034", + "sha256:92a6613af9877e3ad2a1c5a16a122514a4f9f8d9b91b1f22e7fa0fa796617b36", + "sha256:a441afdfe31870b964bccde042d7172ed3c0077f519bbf3ed7d9d34c406b6b91", + "sha256:ab1ffe4ec7be99ad348791116d436610afdc7a9a02a968997f31eaa62eaadad8", + "sha256:b2c2fd861f10b2cd49ccf29a31da9ad5c3b95aa437804e4fd0351ed4eb695f74", + "sha256:bbaab798991863952c593c0459dcb82e0aade837675593310e13cba2ce7fb45a", + "sha256:c9a5f63bc381c0f945402ef4c1bccc74a8eed28f6be6596704b1db7d82ec89fe", + "sha256:cb21666fc9edec9716553bfcfe0c30d1bbbe2731910a96f07ec65652974e5f83", + "sha256:ce3a3aad287c8532f62223f5720b5504e31abe3dce52a27bd2a25f508c0d846e", + "sha256:cebd0b28a0e875a9ce789514700f80659269ecf2a8fcef0aa10b8ae52b40474a", + "sha256:d1bf9455aff37beb421a4447d89d6dd77bb46f677c0bab4eb0272cdb79faad2f", + "sha256:d927bf802bf53c1b5a3878a22e9be310900877984e7c436a3a99bdd19cfec4c3", + "sha256:de724c78f4eb1363b1195dce85a2a8806e7509b69ac5c842a714d942ea534d63", + "sha256:e1fc1b1f5d9d1c2e18b5e60602dfa7854b2330ba0efc312ef605abf588abea9c", + "sha256:e492e87886423192af1fafde23907bcd9d2fdccfc22f67e18aa5c73db3a380a3", + "sha256:e9b5e9115363545a727d8ebe7e4b94f7cf6f26113261a269d50d88b8db4eb726", + "sha256:ff0e014a3a3fe286c642ef51213c41684a156b9ed293ef205e8890bc1dbbfdc7" ], - "markers": "python_version >= '3.6' and python_version < '4'", - "version": "==3.6.7" + "markers": "python_version >= '3.7' and python_version < '4'", + "version": "==3.6.9" }, "requests": { "hashes": [ @@ -1136,36 +1117,41 @@ }, "scikit-learn": { "hashes": [ - "sha256:076369634ee72b5a5941440661e2f306ff4ac30903802dc52031c7e9199ac640", - "sha256:18f7131e62265bf2691ed1d0303c640313894ccfe4278427478c6b2f45094b53", - "sha256:26f66b3726b54dfb76ea51c5d9c2431ed17ebc066cb4527662b9e851a3e7ba61", - "sha256:2951f87d35e72f007701c6e028aa230f6df6212a3194677c0c950486066a454d", - "sha256:2a5348585aa793bc8cc5a72f8e9067c9380834b0aadbd55f924843b071f13282", - "sha256:3eeff086f7329521d27249a082ea3c48c085cedb110db5f65968ab55c3ba2e09", - "sha256:4395e91b3548005f4a645018435b5a94f8cce232b5b70753020e606c6a750656", - "sha256:44e452ea8491225c5783d49577aad0f36202dfd52aec7f82c0fdfe5fbd5f7400", - "sha256:490436b44b3a1957cb625e871764b0aa330b34cc416aea4abc6c38ca63d0d682", - "sha256:5e6e3c042cea83f2e20a45e563b8eabc1f8f72446251fe23ebefdf111a173a33", - "sha256:66f27bf21202a850bcd7b6303916e4907f6e22ec59a14974ede4955aed5c7ed0", - "sha256:743b6edd98c98991be46c08e6b21df3861d5ae915f91d59f988384d93f7263e7", - "sha256:758619e49cd7c17282e6cc60d5cc73c02c072b47c9a10010bb3bb47e0d976e50", - "sha256:7f654befc5ad413690cc58f3f34a3e906caf825195ce0fda00a8e9565e1403e6", - "sha256:800aaf63f8838c00e85db2267dd226f89858594843fd03932a9eda95746d2c40", - "sha256:80ca024154b84b6ac4cfc86930ba13fdc348a209753bf2c16129db6f9eb8a80b", - "sha256:890d7d588f65acb0c4f6c083347c9076916bda5e6bd8400f06244b1afc1009af", - "sha256:905d8934d1e27a686698864a5863ff2c0e13a2ae1adb78a8a848aacc8a49927d", - "sha256:a83fcd9d59c42a2f66b307e3b0b0f08aa8e6e45be33da055697ea499f0e4f7c2", - "sha256:afeb06dc69847927634e58579b9cdc72e1390b79497336b2324b1b173f33bd47", - "sha256:b0d13fd56d26cf3de0314a4fd48037108c638fe126d813f5c1222bb0f08b6a76", - "sha256:c08b27cb78ee8d2dc781a7affed09859441f5b624f9f92da59ac0791c8774dfc", - "sha256:c912247e42114f389858ae05d63f4359d4e667ea72aaabee191aee9ad3f9774a", - "sha256:c9ee65e3e0179951f8c196db0de7f243564c631ec671d1e5ca87f6846029bbab", - "sha256:d7fe05fcb44eadd6d6c874c768f085f5de1239db3a3b7be4d3d23d12e4120589", - "sha256:d819d625832fb2969911a243e009cfa135cb8ef1e150866e417d6e9d75290087", - "sha256:e534f5f3796db6781c87e9835dcd51b7854c8c5a379c9210b93605965c1941fd" + "sha256:08ef968f6b72033c16c479c966bf37ccd49b06ea91b765e1cc27afefe723920b", + "sha256:158faf30684c92a78e12da19c73feff9641a928a8024b4fa5ec11d583f3d8a87", + "sha256:16455ace947d8d9e5391435c2977178d0ff03a261571e67f627c8fee0f9d431a", + "sha256:245c9b5a67445f6f044411e16a93a554edc1efdcce94d3fc0bc6a4b9ac30b752", + "sha256:285db0352e635b9e3392b0b426bc48c3b485512d3b4ac3c7a44ec2a2ba061e66", + "sha256:2f3b453e0b149898577e301d27e098dfe1a36943f7bb0ad704d1e548efc3b448", + "sha256:46f431ec59dead665e1370314dbebc99ead05e1c0a9df42f22d6a0e00044820f", + "sha256:55f2f3a8414e14fbee03782f9fe16cca0f141d639d2b1c1a36779fa069e1db57", + "sha256:5cb33fe1dc6f73dc19e67b264dbb5dde2a0539b986435fdd78ed978c14654830", + "sha256:75307d9ea39236cad7eea87143155eea24d48f93f3a2f9389c817f7019f00705", + "sha256:7626a34eabbf370a638f32d1a3ad50526844ba58d63e3ab81ba91e2a7c6d037e", + "sha256:7a93c1292799620df90348800d5ac06f3794c1316ca247525fa31169f6d25855", + "sha256:7d6b2475f1c23a698b48515217eb26b45a6598c7b1840ba23b3c5acece658dbb", + "sha256:80095a1e4b93bd33261ef03b9bc86d6db649f988ea4dbcf7110d0cded8d7213d", + "sha256:85260fb430b795d806251dd3bb05e6f48cdc777ac31f2bcf2bc8bbed3270a8f5", + "sha256:9369b030e155f8188743eb4893ac17a27f81d28a884af460870c7c072f114243", + "sha256:a053a6a527c87c5c4fa7bf1ab2556fa16d8345cf99b6c5a19030a4a7cd8fd2c0", + "sha256:a90b60048f9ffdd962d2ad2fb16367a87ac34d76e02550968719eb7b5716fd10", + "sha256:a999c9f02ff9570c783069f1074f06fe7386ec65b84c983db5aeb8144356a355", + "sha256:b1391d1a6e2268485a63c3073111fe3ba6ec5145fc957481cfd0652be571226d", + "sha256:b54a62c6e318ddbfa7d22c383466d38d2ee770ebdb5ddb668d56a099f6eaf75f", + "sha256:b5870959a5484b614f26d31ca4c17524b1b0317522199dc985c3b4256e030767", + "sha256:bc3744dabc56b50bec73624aeca02e0def06b03cb287de26836e730659c5d29c", + "sha256:d93d4c28370aea8a7cbf6015e8a669cd5d69f856cc2aa44e7a590fb805bb5583", + "sha256:d9aac97e57c196206179f674f09bc6bffcd0284e2ba95b7fe0b402ac3f986023", + "sha256:da3c84694ff693b5b3194d8752ccf935a665b8b5edc33a283122f4273ca3e687", + "sha256:e174242caecb11e4abf169342641778f68e1bfaba80cd18acd6bc84286b9a534", + "sha256:eabceab574f471de0b0eb3f2ecf2eee9f10b3106570481d007ed1c84ebf6d6a1", + "sha256:f14517e174bd7332f1cca2c959e704696a5e0ba246eb8763e6c24876d8710049", + "sha256:fa38a1b9b38ae1fad2863eff5e0d69608567453fdfc850c992e6e47eb764e846", + "sha256:ff3fa8ea0e09e38677762afc6e14cad77b5e125b0ea70c9bba1992f02c93b028", + "sha256:ff746a69ff2ef25f62b36338c615dd15954ddc3ab8e73530237dd73235e76d62" ], "index": "pypi", - "version": "==0.24.0" + "version": "==1.0.2" }, "scipy": { "hashes": [ @@ -1205,11 +1191,11 @@ }, "setuptools": { "hashes": [ - "sha256:2347b2b432c891a863acadca2da9ac101eae6169b1d3dfee2ec605ecd50dbfe5", - "sha256:e4f30b9f84e5ab3decf945113119649fec09c1fc3507c6ebffec75646c56e62b" + "sha256:26ead7d1f93efc0f8c804d9fafafbe4a44b179580a7105754b245155f9af05a8", + "sha256:47c7b0c0f8fc10eec4cf1e71c6fdadf8decaa74ffa087e68cd1c20db7ad6a592" ], "markers": "python_version >= '3.7'", - "version": "==60.9.3" + "version": "==62.1.0" }, "six": { "hashes": [ @@ -1219,6 +1205,14 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.16.0" }, + "sniffio": { + "hashes": [ + "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663", + "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de" + ], + "markers": "python_version >= '3.5'", + "version": "==1.2.0" + }, "sqlparse": { "hashes": [ "sha256:0c00730c74263a94e5a9919ade150dfc3b19c574389985446148402998287dae", @@ -1237,30 +1231,29 @@ }, "tika": { "hashes": [ - "sha256:c2c50f405622f74531841104f9e85c17511aede11de8e5385eab1a29a31f191b", - "sha256:d1f2eddb93caa9a2857569486aa2bc0320d0bf1796cdbe03066954cbc4b4bf62" + "sha256:c2c50f405622f74531841104f9e85c17511aede11de8e5385eab1a29a31f191b" ], "index": "pypi", "version": "==1.24" }, "tqdm": { "hashes": [ - "sha256:8dd278a422499cd6b727e6ae4061c40b48fce8b76d1ccbf5d34fca9b7f925b0c", - "sha256:d359de7217506c9851b7869f3708d8ee53ed70a1b8edbba4dbcb47442592920d" + "sha256:40be55d30e200777a307a7585aee69e4eabb46b4ec6a4b4a5f2d9f11e7d5408d", + "sha256:74a2cdefe14d11442cedf3ba4e21a3b84ff9a2dbdc6cfae2c34addb2a14a5ea6" ], "index": "pypi", - "version": "==4.62.3" + "version": "==4.64.0" }, "twisted": { "extras": [ "tls" ], "hashes": [ - "sha256:b7971ec9805b0f80e1dcb1a3721d7bfad636d5f909de687430ce373979d67b61", - "sha256:ccd638110d9ccfdc003042aa3e1b6d6af272eaca45d36e083359560549e3e848" + "sha256:a047990f57dfae1e0bd2b7df2526d4f16dcdc843774dc108b78c52f2a5f13680", + "sha256:f9f7a91f94932477a9fc3b169d57f54f96c6e74a23d78d9ce54039a7f48928a2" ], "markers": "python_full_version >= '3.6.7'", - "version": "==22.1.0" + "version": "==22.4.0" }, "txaio": { "hashes": [ @@ -1280,38 +1273,38 @@ }, "tzdata": { "hashes": [ - "sha256:3eee491e22ebfe1e5cfcc97a4137cd70f092ce59144d81f8924a844de05ba8f5", - "sha256:68dbe41afd01b867894bbdfd54fa03f468cfa4f0086bfb4adcd8de8f24f3ee21" + "sha256:238e70234214138ed7b4e8a0fab0e5e13872edab3be586ab8198c407620e2ab9", + "sha256:8b536a8ec63dc0751342b3984193a3118f8fca2afe25752bb9b7fffd398552d3" ], "markers": "python_version >= '3.6'", - "version": "==2021.5" + "version": "==2022.1" }, "tzlocal": { "hashes": [ - "sha256:0f28015ac68a5c067210400a9197fc5d36ba9bc3f8eaf1da3cbd59acdfed9e09", - "sha256:28ba8d9fcb6c9a782d6e0078b4f6627af1ea26aeaa32b4eab5324abc7df4149f" + "sha256:89885494684c929d9191c57aa27502afc87a579be5cdd3225c77c463ea043745", + "sha256:ee5842fa3a795f023514ac2d801c4a81d1743bbe642e3940143326b3a00addd7" ], "markers": "python_version >= '3.6'", - "version": "==4.1" + "version": "==4.2" }, "urllib3": { "hashes": [ - "sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed", - "sha256:0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c" + "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14", + "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", - "version": "==1.26.8" + "version": "==1.26.9" }, "uvicorn": { "extras": [ "standard" ], "hashes": [ - "sha256:8adddf629b79857b48b999ae1b14d6c92c95d4d7840bd86461f09bee75f1653e", - "sha256:c04a9c069111489c324f427501b3840d306c6b91a77b00affc136a840a3f45f1" + "sha256:19e2a0e96c9ac5581c01eb1a79a7d2f72bb479691acd2b8921fce48ed5b961a6", + "sha256:5180f9d059611747d841a4a4c4ab675edf54c8489e97f96d0583ee90ac3bfc23" ], "index": "pypi", - "version": "==0.17.5" + "version": "==0.17.6" }, "uvloop": { "hashes": [ @@ -1320,58 +1313,56 @@ "sha256:1e5f2e2ff51aefe6c19ee98af12b4ae61f5be456cd24396953244a30880ad861", "sha256:30ba9dcbd0965f5c812b7c2112a1ddf60cf904c1c160f398e7eed3a6b82dcd9c", "sha256:3a19828c4f15687675ea912cc28bbcb48e9bb907c801873bd1519b96b04fb805", - "sha256:54dbcb085c076f8749954d1497ecabdb227a94114dac2e7296bc0df26b240c3e", "sha256:6224f1401025b748ffecb7a6e2652b17768f30b1a6a3f7b44660e5b5b690b12d", "sha256:647e481940379eebd314c00440314c81ea547aa636056f554d491e40503c8464", "sha256:6ccd57ae8db17d677e9e06192e9c9ec4bd2066b77790f9aa7dede2cc4008ee8f", "sha256:772206116b9b57cd625c8a88f2413df2fcfd0b496eb188b82a43bed7af2c2ec9", "sha256:8e0d26fa5875d43ddbb0d9d79a447d2ace4180d9e3239788208527c4784f7cab", "sha256:98d117332cc9e5ea8dfdc2b28b0a23f60370d02e1395f88f40d1effd2cb86c4f", - "sha256:b3b768c390952983694e5465382e3769f21a88003f608a4f9ca4a44700d95eaf", "sha256:b572256409f194521a9895aef274cea88731d14732343da3ecdb175228881638", "sha256:bd53f7f5db562f37cd64a3af5012df8cac2c464c97e732ed556800129505bd64", "sha256:bd8f42ea1ea8f4e84d265769089964ddda95eb2bb38b5cbe26712b0616c3edee", "sha256:e814ac2c6f9daf4c36eb8e85266859f42174a4ff0d71b99405ed559257750382", "sha256:f74bc20c7b67d1c27c72601c78cf95be99d5c2cdd4514502b4f3eb0933ff1228" ], - "index": "pypi", "version": "==0.16.0" }, "watchdog": { "hashes": [ - "sha256:25fb5240b195d17de949588628fdf93032ebf163524ef08933db0ea1f99bd685", - "sha256:3386b367e950a11b0568062b70cc026c6f645428a698d33d39e013aaeda4cc04", - "sha256:3becdb380d8916c873ad512f1701f8a92ce79ec6978ffde92919fd18d41da7fb", - "sha256:4ae38bf8ba6f39d5b83f78661273216e7db5b00f08be7592062cb1fc8b8ba542", - "sha256:8047da932432aa32c515ec1447ea79ce578d0559362ca3605f8e9568f844e3c6", - "sha256:8f1c00aa35f504197561060ca4c21d3cc079ba29cf6dd2fe61024c70160c990b", - "sha256:922a69fa533cb0c793b483becaaa0845f655151e7256ec73630a1b2e9ebcb660", - "sha256:9693f35162dc6208d10b10ddf0458cc09ad70c30ba689d9206e02cd836ce28a3", - "sha256:a0f1c7edf116a12f7245be06120b1852275f9506a7d90227648b250755a03923", - "sha256:a36e75df6c767cbf46f61a91c70b3ba71811dfa0aca4a324d9407a06a8b7a2e7", - "sha256:aba5c812f8ee8a3ff3be51887ca2d55fb8e268439ed44110d3846e4229eb0e8b", - "sha256:ad6f1796e37db2223d2a3f302f586f74c72c630b48a9872c1e7ae8e92e0ab669", - "sha256:ae67501c95606072aafa865b6ed47343ac6484472a2f95490ba151f6347acfc2", - "sha256:b2fcf9402fde2672545b139694284dc3b665fd1be660d73eca6805197ef776a3", - "sha256:b52b88021b9541a60531142b0a451baca08d28b74a723d0c99b13c8c8d48d604", - "sha256:b7d336912853d7b77f9b2c24eeed6a5065d0a0cc0d3b6a5a45ad6d1d05fb8cd8", - "sha256:bd9ba4f332cf57b2c1f698be0728c020399ef3040577cde2939f2e045b39c1e5", - "sha256:be9be735f827820a06340dff2ddea1fb7234561fa5e6300a62fe7f54d40546a0", - "sha256:cca7741c0fcc765568350cb139e92b7f9f3c9a08c4f32591d18ab0a6ac9e71b6", - "sha256:d0d19fb2441947b58fbf91336638c2b9f4cc98e05e1045404d7a4cb7cddc7a65", - "sha256:e02794ac791662a5eafc6ffeaf9bcc149035a0e48eb0a9d40a8feb4622605a3d", - "sha256:e0f30db709c939cabf64a6dc5babb276e6d823fd84464ab916f9b9ba5623ca15", - "sha256:e92c2d33858c8f560671b448205a268096e17870dcf60a9bb3ac7bfbafb7f5f9" + "sha256:03b43d583df0f18782a0431b6e9e9965c5b3f7cf8ec36a00b930def67942c385", + "sha256:0908bb50f6f7de54d5d31ec3da1654cb7287c6b87bce371954561e6de379d690", + "sha256:0b4a1fe6201c6e5a1926f5767b8664b45f0fcb429b62564a41f490ff1ce1dc7a", + "sha256:177bae28ca723bc00846466016d34f8c1d6a621383b6caca86745918d55c7383", + "sha256:19b36d436578eb437e029c6b838e732ed08054956366f6dd11875434a62d2b99", + "sha256:1d1cf7dfd747dec519486a98ef16097e6c480934ef115b16f18adb341df747a4", + "sha256:1e877c70245424b06c41ac258023ea4bd0c8e4ff15d7c1368f17cd0ae6e351dd", + "sha256:340b875aecf4b0e6672076a6f05cfce6686935559bb6d34cebedee04126a9566", + "sha256:351e09b6d9374d5bcb947e6ac47a608ec25b9d70583e9db00b2fcdb97b00b572", + "sha256:3fd47815353be9c44eebc94cc28fe26b2b0c5bd889dafc4a5a7cbdf924143480", + "sha256:49639865e3db4be032a96695c98ac09eed39bbb43fe876bb217da8f8101689a6", + "sha256:4d0e98ac2e8dd803a56f4e10438b33a2d40390a72750cff4939b4b274e7906fa", + "sha256:6e6ae29b72977f2e1ee3d0b760d7ee47896cb53e831cbeede3e64485e5633cc8", + "sha256:7f14ce6adea2af1bba495acdde0e510aecaeb13b33f7bd2f6324e551b26688ca", + "sha256:81982c7884aac75017a6ecc72f1a4fedbae04181a8665a34afce9539fc1b3fab", + "sha256:81a5861d0158a7e55fe149335fb2bbfa6f48cbcbd149b52dbe2cd9a544034bbd", + "sha256:ae934e34c11aa8296c18f70bf66ed60e9870fcdb4cc19129a04ca83ab23e7055", + "sha256:b26e13e8008dcaea6a909e91d39b629a39635d1a8a7239dd35327c74f4388601", + "sha256:b3750ee5399e6e9c69eae8b125092b871ee9e2fcbd657a92747aea28f9056a5c", + "sha256:b61acffaf5cd5d664af555c0850f9747cc5f2baf71e54bbac164c58398d6ca7b", + "sha256:b9777664848160449e5b4260e0b7bc1ae0f6f4992a8b285db4ec1ef119ffa0e2", + "sha256:bdcbf75580bf4b960fb659bbccd00123d83119619195f42d721e002c1621602f", + "sha256:d802d65262a560278cf1a65ef7cae4e2bc7ecfe19e5451349e4c67e23c9dc420", + "sha256:ed6d9aad09a2a948572224663ab00f8975fae242aa540509737bb4507133fa2d" ], "index": "pypi", - "version": "==2.1.6" + "version": "==2.1.7" }, "watchgod": { "hashes": [ - "sha256:48140d62b0ebe9dd9cf8381337f06351e1f2e70b2203fa9c6eff4e572ca84f29", - "sha256:d6c1ea21df37847ac0537ca0d6c2f4cdf513562e95f77bb93abbcf05573407b7" + "sha256:2f3e8137d98f493ff58af54ea00f4d1433a6afe2ed08ab331a657df468c6bfce", + "sha256:cb11ff66657befba94d828e3b622d5fb76f22fbda1376f355f3e6e51e97d9450" ], - "version": "==0.7" + "version": "==0.8.2" }, "wcwidth": { "hashes": [ @@ -1452,11 +1443,11 @@ }, "zipp": { "hashes": [ - "sha256:9f50f446828eb9d45b267433fd3e9da8d801f614129124863f9c51ebceafb87d", - "sha256:b47250dd24f92b7dd6a0a8fc5244da14608f3ca90a5efcd37a3b1642fac9a375" + "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad", + "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099" ], - "markers": "python_version < '3.10'", - "version": "==3.7.0" + "markers": "python_version < '3.9'", + "version": "==3.8.0" }, "zope.interface": { "hashes": [ @@ -1489,7 +1480,6 @@ "sha256:5dd9ca406499444f4c8299f803d4a14edf7890ecc595c8b1c7115c2342cadc5f", "sha256:5f931a1c21dfa7a9c573ec1f50a31135ccce84e32507c54e1ea404894c5eb96f", "sha256:63b82bb63de7c821428d513607e84c6d97d58afd1fe2eb645030bdc185440120", - "sha256:6508154df547b9d8651fa21e944c5946436614093d5a58d662a28448ed80df78", "sha256:66c0061c91b3b9cf542131148ef7ecbecb2690d48d1612ec386de9d36766058f", "sha256:6f0c02cbb9691b7c91d5009108f975f8ffeab5dff8f26d62e21c493060eff2a1", "sha256:71aace0c42d53abe6fc7f726c5d3b60d90f3c5c055a447950ad6ea9cec2e37d9", @@ -1510,7 +1500,6 @@ "sha256:d4d9d6c1a455d4babd320203b918ccc7fcbefe308615c521062bc2ba1aa4d26e", "sha256:db1fa631737dab9fa0b37f3979d8d2631e348c3b4e8325d6873c2541d0ae5a48", "sha256:dd93ea5c0c7f3e25335ab7d22a507b1dc43976e1345508f845efc573d3d779d8", - "sha256:e0653479008a6118d2deec9ea3461d79331c65973ab4b25434ddc1018a982188", "sha256:f44e517131a98f7a76696a7b21b164bcb85291cee106a23beccce454e1f433a4", "sha256:f7ee479e96f7ee350db1cf24afa5685a5899e2b34992fb99e1f7c1b0b758d263" ], @@ -1542,6 +1531,35 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.9.1" }, + "black": { + "hashes": [ + "sha256:06f9d8846f2340dfac80ceb20200ea5d1b3f181dd0556b47af4e8e0b24fa0a6b", + "sha256:10dbe6e6d2988049b4655b2b739f98785a884d4d6b85bc35133a8fb9a2233176", + "sha256:2497f9c2386572e28921fa8bec7be3e51de6801f7459dffd6e62492531c47e09", + "sha256:30d78ba6bf080eeaf0b7b875d924b15cd46fec5fd044ddfbad38c8ea9171043a", + "sha256:328efc0cc70ccb23429d6be184a15ce613f676bdfc85e5fe8ea2a9354b4e9015", + "sha256:35020b8886c022ced9282b51b5a875b6d1ab0c387b31a065b84db7c33085ca79", + "sha256:5795a0375eb87bfe902e80e0c8cfaedf8af4d49694d69161e5bd3206c18618bb", + "sha256:5891ef8abc06576985de8fa88e95ab70641de6c1fca97e2a15820a9b69e51b20", + "sha256:637a4014c63fbf42a692d22b55d8ad6968a946b4a6ebc385c5505d9625b6a464", + "sha256:67c8301ec94e3bcc8906740fe071391bce40a862b7be0b86fb5382beefecd968", + "sha256:6d2fc92002d44746d3e7db7cf9313cf4452f43e9ea77a2c939defce3b10b5c82", + "sha256:6ee227b696ca60dd1c507be80a6bc849a5a6ab57ac7352aad1ffec9e8b805f21", + "sha256:863714200ada56cbc366dc9ae5291ceb936573155f8bf8e9de92aef51f3ad0f0", + "sha256:9b542ced1ec0ceeff5b37d69838106a6348e60db7b8fdd245294dc1d26136265", + "sha256:a6342964b43a99dbc72f72812bf88cad8f0217ae9acb47c0d4f141a6416d2d7b", + "sha256:ad4efa5fad66b903b4a5f96d91461d90b9507a812b3c5de657d544215bb7877a", + "sha256:bc58025940a896d7e5356952228b68f793cf5fcb342be703c3a2669a1488cb72", + "sha256:cc1e1de68c8e5444e8f94c3670bb48a2beef0e91dddfd4fcc29595ebd90bb9ce", + "sha256:cee3e11161dde1b2a33a904b850b0899e0424cc331b7295f2a9698e79f9a69a0", + "sha256:e3556168e2e5c49629f7b0f377070240bd5511e45e25a4497bb0073d9dda776a", + "sha256:e8477ec6bbfe0312c128e74644ac8a02ca06bcdb8982d4ee06f209be28cdf163", + "sha256:ee8f1f7228cce7dffc2b464f07ce769f478968bfb3dd1254a4c2eeed84928aad", + "sha256:fd57160949179ec517d32ac2ac898b5f20d68ed1a9c977346efbac9c2f1e779d" + ], + "index": "pypi", + "version": "==22.3.0" + }, "certifi": { "hashes": [ "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872", @@ -1549,6 +1567,14 @@ ], "version": "==2021.10.8" }, + "cfgv": { + "hashes": [ + "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426", + "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736" + ], + "markers": "python_full_version >= '3.6.1'", + "version": "==3.3.1" + }, "charset-normalizer": { "hashes": [ "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597", @@ -1557,7 +1583,18 @@ "markers": "python_version >= '3'", "version": "==2.0.12" }, + "click": { + "hashes": [ + "sha256:24e1a4a9ec5bf6299411369b208c1df2188d9eb8d916302fe6bf03faed227f1e", + "sha256:479707fe14d9ec9a0757618b7a100a0ae4c4e236fac5b7f80ca68028141a1a72" + ], + "markers": "python_version >= '3.7'", + "version": "==8.1.2" + }, "coverage": { + "extras": [ + + ], "hashes": [ "sha256:03e2a7826086b91ef345ff18742ee9fc47a6839ccd517061ef8fa1976e652ce9", "sha256:07e6db90cd9686c767dcc593dff16c8c09f9814f5e9c51034066cad3373b914d", @@ -1621,7 +1658,6 @@ }, "docopt": { "hashes": [ - "sha256:15fde8252aa9f2804171014d50d069ffbf42c7a50b7d74bcbb82bfd5700fcfc2", "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491" ], "version": "==0.6.2" @@ -1652,11 +1688,11 @@ }, "faker": { "hashes": [ - "sha256:206050b40d6dfb6efe8ccfbbb9866c56477c53edfdab83f80de3b59f38a88ce0", - "sha256:edb62f9511a0977abcea6a78e43b99d1f26c915d2142bbf4c6bf02a9bb597c7f" + "sha256:188961065fb5c78ea639f42176f55100f72c90c3a3179ac6c955c4bd712b0511", + "sha256:7758ece2593ce603db117db3d27393c31f4af03f783e176f3f0e14839a4f3426" ], "markers": "python_version >= '3.6'", - "version": "==13.2.0" + "version": "==13.3.4" }, "filelock": { "hashes": [ @@ -1666,6 +1702,14 @@ "index": "pypi", "version": "==3.6.0" }, + "identify": { + "hashes": [ + "sha256:3f3244a559290e7d3deb9e9adc7b33594c1bc85a9dd82e0f1be519bf12a1ec17", + "sha256:5f06b14366bd1facb88b00540a1de05b69b310cbc2654db3c7e07fa3a4339323" + ], + "markers": "python_version >= '3.7'", + "version": "==2.4.12" + }, "idna": { "hashes": [ "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", @@ -1685,64 +1729,77 @@ "iniconfig": { "hashes": [ "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3", - "sha256:8647b85c03813b8680f4ae9c9db2fd7293f8591ea536a10d73d90f6eb4b10aac", "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32" ], "version": "==1.1.1" }, "jinja2": { "hashes": [ - "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8", - "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7" + "sha256:539835f51a74a69f41b848a9645dbdc35b4f20a3b601e2d9a7e22947b15ff119", + "sha256:640bed4bb501cbd17194b3cace1dc2126f5b619cf068a726b98192a0fde74ae9" ], - "markers": "python_version >= '3.6'", - "version": "==3.0.3" + "markers": "python_version >= '3.7'", + "version": "==3.1.1" }, "markupsafe": { "hashes": [ - "sha256:023af8c54fe63530545f70dd2a2a7eed18d07a9a77b94e8bf1e2ff7f252db9a3", - "sha256:09c86c9643cceb1d87ca08cdc30160d1b7ab49a8a21564868921959bd16441b8", - "sha256:142119fb14a1ef6d758912b25c4e803c3ff66920635c44078666fe7cc3f8f759", - "sha256:1d1fb9b2eec3c9714dd936860850300b51dbaa37404209c8d4cb66547884b7ed", - "sha256:204730fd5fe2fe3b1e9ccadb2bd18ba8712b111dcabce185af0b3b5285a7c989", - "sha256:24c3be29abb6b34052fd26fc7a8e0a49b1ee9d282e3665e8ad09a0a68faee5b3", - "sha256:290b02bab3c9e216da57c1d11d2ba73a9f73a614bbdcc027d299a60cdfabb11a", - "sha256:3028252424c72b2602a323f70fbf50aa80a5d3aa616ea6add4ba21ae9cc9da4c", - "sha256:30c653fde75a6e5eb814d2a0a89378f83d1d3f502ab710904ee585c38888816c", - "sha256:3cace1837bc84e63b3fd2dfce37f08f8c18aeb81ef5cf6bb9b51f625cb4e6cd8", - "sha256:4056f752015dfa9828dce3140dbadd543b555afb3252507348c493def166d454", - "sha256:454ffc1cbb75227d15667c09f164a0099159da0c1f3d2636aa648f12675491ad", - "sha256:598b65d74615c021423bd45c2bc5e9b59539c875a9bdb7e5f2a6b92dfcfc268d", - "sha256:599941da468f2cf22bf90a84f6e2a65524e87be2fce844f96f2dd9a6c9d1e635", - "sha256:5ddea4c352a488b5e1069069f2f501006b1a4362cb906bee9a193ef1245a7a61", - "sha256:62c0285e91414f5c8f621a17b69fc0088394ccdaa961ef469e833dbff64bd5ea", - "sha256:679cbb78914ab212c49c67ba2c7396dc599a8479de51b9a87b174700abd9ea49", - "sha256:6e104c0c2b4cd765b4e83909cde7ec61a1e313f8a75775897db321450e928cce", - "sha256:736895a020e31b428b3382a7887bfea96102c529530299f426bf2e636aacec9e", - "sha256:75bb36f134883fdbe13d8e63b8675f5f12b80bb6627f7714c7d6c5becf22719f", - "sha256:7d2f5d97fcbd004c03df8d8fe2b973fe2b14e7bfeb2cfa012eaa8759ce9a762f", - "sha256:80beaf63ddfbc64a0452b841d8036ca0611e049650e20afcb882f5d3c266d65f", - "sha256:84ad5e29bf8bab3ad70fd707d3c05524862bddc54dc040982b0dbcff36481de7", - "sha256:8da5924cb1f9064589767b0f3fc39d03e3d0fb5aa29e0cb21d43106519bd624a", - "sha256:961eb86e5be7d0973789f30ebcf6caab60b844203f4396ece27310295a6082c7", - "sha256:96de1932237abe0a13ba68b63e94113678c379dca45afa040a17b6e1ad7ed076", - "sha256:a0a0abef2ca47b33fb615b491ce31b055ef2430de52c5b3fb19a4042dbc5cadb", - "sha256:b2a5a856019d2833c56a3dcac1b80fe795c95f401818ea963594b345929dffa7", - "sha256:b8811d48078d1cf2a6863dafb896e68406c5f513048451cd2ded0473133473c7", - "sha256:c532d5ab79be0199fa2658e24a02fce8542df196e60665dd322409a03db6a52c", - "sha256:d3b64c65328cb4cd252c94f83e66e3d7acf8891e60ebf588d7b493a55a1dbf26", - "sha256:d4e702eea4a2903441f2735799d217f4ac1b55f7d8ad96ab7d4e25417cb0827c", - "sha256:d5653619b3eb5cbd35bfba3c12d575db2a74d15e0e1c08bf1db788069d410ce8", - "sha256:d66624f04de4af8bbf1c7f21cc06649c1c69a7f84109179add573ce35e46d448", - "sha256:e67ec74fada3841b8c5f4c4f197bea916025cb9aa3fe5abf7d52b655d042f956", - "sha256:e6f7f3f41faffaea6596da86ecc2389672fa949bd035251eab26dc6697451d05", - "sha256:f02cf7221d5cd915d7fa58ab64f7ee6dd0f6cddbb48683debf5d04ae9b1c2cc1", - "sha256:f0eddfcabd6936558ec020130f932d479930581171368fd728efcfb6ef0dd357", - "sha256:fabbe18087c3d33c5824cb145ffca52eccd053061df1d79d4b66dafa5ad2a5ea", - "sha256:fc3150f85e2dbcf99e65238c842d1cfe69d3e7649b19864c1cc043213d9cd730" + "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003", + "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88", + "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5", + "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7", + "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a", + "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603", + "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1", + "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135", + "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247", + "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6", + "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601", + "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77", + "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02", + "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e", + "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63", + "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f", + "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980", + "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b", + "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812", + "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff", + "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96", + "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1", + "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925", + "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a", + "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6", + "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e", + "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f", + "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4", + "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f", + "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3", + "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c", + "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a", + "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417", + "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a", + "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a", + "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37", + "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452", + "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933", + "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a", + "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7" ], "markers": "python_version >= '3.7'", - "version": "==2.1.0" + "version": "==2.1.1" + }, + "mypy-extensions": { + "hashes": [ + "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d", + "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8" + ], + "version": "==0.4.3" + }, + "nodeenv": { + "hashes": [ + "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b", + "sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7" + ], + "version": "==1.6.0" }, "packaging": { "hashes": [ @@ -1752,6 +1809,13 @@ "markers": "python_version >= '3.6'", "version": "==21.3" }, + "pathspec": { + "hashes": [ + "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a", + "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1" + ], + "version": "==0.9.0" + }, "platformdirs": { "hashes": [ "sha256:7535e70dfa32e84d4b34996ea99c5e432fa29a708d0f4e394bbcb2a8faa4f16d", @@ -1768,6 +1832,14 @@ "markers": "python_version >= '3.6'", "version": "==1.0.0" }, + "pre-commit": { + "hashes": [ + "sha256:02226e69564ebca1a070bd1f046af866aa1c318dbc430027c50ab832ed2b73f2", + "sha256:5d445ee1fa8738d506881c5d84f83c62bb5be6b2838e32207433647e8e5ebe10" + ], + "index": "pypi", + "version": "==2.18.1" + }, "py": { "hashes": [ "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719", @@ -1794,19 +1866,19 @@ }, "pyparsing": { "hashes": [ - "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea", - "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484" + "sha256:7bf433498c016c4314268d95df76c81b842a4cb2b276fa3312cfb1e1d85f6954", + "sha256:ef7b523f6356f763771559412c0d7134753f037822dad1b16945b7b846f7ad06" ], - "markers": "python_version >= '3.6'", - "version": "==3.0.7" + "markers": "python_full_version >= '3.6.8'", + "version": "==3.0.8" }, "pytest": { "hashes": [ - "sha256:9ce3ff477af913ecf6321fe337b93a2c0dcf2a0a1439c43f5452112c1e4280db", - "sha256:e30905a0c131d3d94b89624a1cc5afec3e0ba2fbdb151867d8e0ebd49850f171" + "sha256:841132caef6b1ad17a9afde46dc4f6cfa59a05f9555aae5151f73bdf2820ca63", + "sha256:92f723789a8fdd7180b6b06483874feca4c48a5c76968e03bb3e7f806a1869ea" ], "index": "pypi", - "version": "==7.0.1" + "version": "==7.1.1" }, "pytest-cov": { "hashes": [ @@ -1826,7 +1898,6 @@ }, "pytest-env": { "hashes": [ - "sha256:33b4030383a021924fe3f3ba5ca4311990d8b1d02ca77389c2be020c4500f96a", "sha256:7e94956aef7f2764f3c147d216ce066bf6c42948bb9e293169b1b1c880a580c2" ], "index": "pypi", @@ -1842,7 +1913,6 @@ }, "pytest-sugar": { "hashes": [ - "sha256:67a55a83c7b2717ad607704d3fe9004bb6543b54017ef82f9c6590acc38c1aec", "sha256:b1b2186b0a72aada6859bea2a5764145e3aaa2c1cfbb23c3a19b5f7b697563d3" ], "index": "pypi", @@ -1866,10 +1936,48 @@ }, "pytz": { "hashes": [ - "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c", - "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326" + "sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7", + "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c" ], - "version": "==2021.3" + "version": "==2022.1" + }, + "pyyaml": { + "hashes": [ + "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293", + "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b", + "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57", + "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b", + "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4", + "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07", + "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba", + "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9", + "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287", + "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513", + "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0", + "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0", + "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92", + "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f", + "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2", + "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc", + "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c", + "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86", + "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4", + "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c", + "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34", + "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b", + "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c", + "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb", + "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737", + "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3", + "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d", + "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53", + "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78", + "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803", + "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a", + "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174", + "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5" + ], + "version": "==6.0" }, "requests": { "hashes": [ @@ -1879,14 +1987,6 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", "version": "==2.27.1" }, - "setuptools": { - "hashes": [ - "sha256:2347b2b432c891a863acadca2da9ac101eae6169b1d3dfee2ec605ecd50dbfe5", - "sha256:e4f30b9f84e5ab3decf945113119649fec09c1fc3507c6ebffec75646c56e62b" - ], - "markers": "python_version >= '3.7'", - "version": "==60.9.3" - }, "six": { "hashes": [ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", @@ -1904,11 +2004,11 @@ }, "sphinx": { "hashes": [ - "sha256:41cad293f954f7d37f803d97eb184158cfd90f51195131e94875bc07cd08b93c", - "sha256:c314c857e7cd47c856d2c5adff514ac2e6495f8b8e0f886a8a37e9305dfea0d8" + "sha256:7bf8ca9637a4ee15af412d1a1d9689fec70523a68ca9bb9127c2f3eeb344e2e6", + "sha256:ebf612653238bcc8f4359627a9b7ce44ede6fdd75d9d30f68255c7383d3a6226" ], "index": "pypi", - "version": "==3.4.3" + "version": "==4.5.0" }, "sphinx-rtd-theme": { "hashes": [ @@ -1968,7 +2068,6 @@ }, "termcolor": { "hashes": [ - "sha256:19b1225d03bfb56571484caaa8521d8ec6e2473ae1640c9f48a48dda49417706", "sha256:1d6d69ce66211143803fbc56652b41d73b4a400a2891d7bf7a1cdf4c02de613b" ], "version": "==1.1.0" @@ -1999,19 +2098,19 @@ }, "urllib3": { "hashes": [ - "sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed", - "sha256:0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c" + "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14", + "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", - "version": "==1.26.8" + "version": "==1.26.9" }, "virtualenv": { "hashes": [ - "sha256:01f5f80744d24a3743ce61858123488e91cb2dd1d3bdf92adaf1bba39ffdedf0", - "sha256:e7b34c9474e6476ee208c43a4d9ac1510b041c68347eabfe9a9ea0c86aa0a46b" + "sha256:e617f16e25b42eb4f6e74096b9c9e37713cf10bf30168fb4a739f3fa8f898a3a", + "sha256:ef589a79795589aada0c1c5b319486797c03b67ac3984c48c669c0e4f50df3a5" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==20.13.2" + "version": "==20.14.1" } } } diff --git a/README.md b/README.md index c3d5d435c..3395d8e3c 100644 --- a/README.md +++ b/README.md @@ -10,23 +10,23 @@

+ # Paperless-ngx -Paperless-ngx is a document management system that transforms your physical documents into a searchable online archive so you can keep, well, *less paper*. +Paperless-ngx is a document management system that transforms your physical documents into a searchable online archive so you can keep, well, _less paper_. Paperless-ngx forked from [paperless-ng](https://github.com/jonaswinkler/paperless-ng) to continue the great work and distribute responsibility of supporting and advancing the project among a team of people. [Consider joining us!](#community-support) Discussion of this transition can be found in issues [#1599](https://github.com/jonaswinkler/paperless-ng/issues/1599) and [#1632](https://github.com/jonaswinkler/paperless-ng/issues/1632). -A demo is available at [demo.paperless-ngx.com](https://demo.paperless-ngx.com) using login `demo` / `demo`. *Note: demo content is reset frequently and confidential information should not be uploaded.* - +A demo is available at [demo.paperless-ngx.com](https://demo.paperless-ngx.com) using login `demo` / `demo`. _Note: demo content is reset frequently and confidential information should not be uploaded._ - [Features](#features) - [Getting started](#getting-started) - [Contributing](#contributing) - - [Community Support](#community-support) - - [Translation](#translation) - - [Feature Requests](#feature-requests) - - [Bugs](#bugs) + - [Community Support](#community-support) + - [Translation](#translation) + - [Feature Requests](#feature-requests) + - [Bugs](#bugs) - [Affiliated Projects](#affiliated-projects) - [Important Note](#important-note) @@ -35,28 +35,28 @@ A demo is available at [demo.paperless-ngx.com](https://demo.paperless-ngx.com) ![Dashboard](https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/docs/_static/screenshots/documents-wchrome.png#gh-light-mode-only) ![Dashboard](https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/docs/_static/screenshots/documents-wchrome-dark.png#gh-dark-mode-only) -* Organize and index your scanned documents with tags, correspondents, types, and more. -* Performs OCR on your documents, adds selectable text to image only documents and adds tags, correspondents and document types to your documents. -* Supports PDF documents, images, plain text files, and Office documents (Word, Excel, Powerpoint, and LibreOffice equivalents). - * Office document support is optional and provided by Apache Tika (see [configuration](https://paperless-ngx.readthedocs.io/en/latest/configuration.html#tika-settings)) -* Paperless stores your documents plain on disk. Filenames and folders are managed by paperless and their format can be configured freely. -* Single page application front end. - * Includes a dashboard that shows basic statistics and has document upload. - * Filtering by tags, correspondents, types, and more. - * Customizable views can be saved and displayed on the dashboard. -* Full text search helps you find what you need. - * Auto completion suggests relevant words from your documents. - * Results are sorted by relevance to your search query. - * Highlighting shows you which parts of the document matched the query. - * Searching for similar documents ("More like this") -* Email processing: Paperless adds documents from your email accounts. - * Configure multiple accounts and filters for each account. - * When adding documents from mail, paperless can move these mail to a new folder, mark them as read, flag them as important or delete them. -* Machine learning powered document matching. - * Paperless-ngx learns from your documents and will be able to automatically assign tags, correspondents and types to documents once you've stored a few documents in paperless. -* Optimized for multi core systems: Paperless-ngx consumes multiple documents in parallel. -* The integrated sanity checker makes sure that your document archive is in good health. -* [More screenshots are available in the documentation](https://paperless-ngx.readthedocs.io/en/latest/screenshots.html). +- Organize and index your scanned documents with tags, correspondents, types, and more. +- Performs OCR on your documents, adds selectable text to image only documents and adds tags, correspondents and document types to your documents. +- Supports PDF documents, images, plain text files, and Office documents (Word, Excel, Powerpoint, and LibreOffice equivalents). + - Office document support is optional and provided by Apache Tika (see [configuration](https://paperless-ngx.readthedocs.io/en/latest/configuration.html#tika-settings)) +- Paperless stores your documents plain on disk. Filenames and folders are managed by paperless and their format can be configured freely. +- Single page application front end. + - Includes a dashboard that shows basic statistics and has document upload. + - Filtering by tags, correspondents, types, and more. + - Customizable views can be saved and displayed on the dashboard. +- Full text search helps you find what you need. + - Auto completion suggests relevant words from your documents. + - Results are sorted by relevance to your search query. + - Highlighting shows you which parts of the document matched the query. + - Searching for similar documents ("More like this") +- Email processing: Paperless adds documents from your email accounts. + - Configure multiple accounts and filters for each account. + - When adding documents from mail, paperless can move these mail to a new folder, mark them as read, flag them as important or delete them. +- Machine learning powered document matching. + - Paperless-ngx learns from your documents and will be able to automatically assign tags, correspondents and types to documents once you've stored a few documents in paperless. +- Optimized for multi core systems: Paperless-ngx consumes multiple documents in parallel. +- The integrated sanity checker makes sure that your document archive is in good health. +- [More screenshots are available in the documentation](https://paperless-ngx.readthedocs.io/en/latest/screenshots.html). # Getting started @@ -65,7 +65,7 @@ The easiest way to deploy paperless is docker-compose. The files in the [`/docke If you'd like to jump right in, you can configure a docker-compose environment with our install script: ```bash -bash -c "$(curl -L https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/master/install-paperless-ngx.sh)" +bash -c "$(curl -L https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/install-paperless-ngx.sh)" ``` Alternatively, you can install the dependencies and setup apache and a database server yourself. The [documentation](https://paperless-ngx.readthedocs.io/en/latest/setup.html#installation) has a step by step guide on how to do it. @@ -73,6 +73,7 @@ Alternatively, you can install the dependencies and setup apache and a database Migrating from Paperless-ng is easy, just drop in the new docker image! See the [documentation on migrating](https://paperless-ngx.readthedocs.io/en/latest/setup.html#migrating-from-paperless-ng) for more details. + ### Documentation The documentation for Paperless-ngx is available on [ReadTheDocs](https://paperless-ngx.readthedocs.io/). @@ -101,18 +102,18 @@ For bugs please [open an issue](https://github.com/paperless-ngx/paperless-ngx/i Paperless has been around a while now, and people are starting to build stuff on top of it. If you're one of those people, we can add your project to this list: -* [Paperless App](https://github.com/bauerj/paperless_app): An Android/iOS app for Paperless-ngx. Also works with the original Paperless and Paperless-ng. -* [Paperless Share](https://github.com/qcasey/paperless_share). Share any files from your Android application with paperless. Very simple, but works with all of the mobile scanning apps out there that allow you to share scanned documents. -* [Scan to Paperless](https://github.com/sbrunner/scan-to-paperless): Scan and prepare (crop, deskew, OCR, ...) your documents for Paperless. +- [Paperless App](https://github.com/bauerj/paperless_app): An Android/iOS app for Paperless-ngx. Also works with the original Paperless and Paperless-ngx. +- [Paperless Share](https://github.com/qcasey/paperless_share). Share any files from your Android application with paperless. Very simple, but works with all of the mobile scanning apps out there that allow you to share scanned documents. +- [Scan to Paperless](https://github.com/sbrunner/scan-to-paperless): Scan and prepare (crop, deskew, OCR, ...) your documents for Paperless. These projects also exist, but their status and compatibility with paperless-ngx is unknown. -* [paperless-cli](https://github.com/stgarf/paperless-cli): A golang command line binary to interact with a Paperless instance. +- [paperless-cli](https://github.com/stgarf/paperless-cli): A golang command line binary to interact with a Paperless instance. This project also exists, but needs updates to be compatible with paperless-ngx. -* [Paperless Desktop](https://github.com/thomasbrueggemann/paperless-desktop): A desktop UI for your Paperless installation. Runs on Mac, Linux, and Windows. - Known issues on Mac: (Could not load reminders and documents) +- [Paperless Desktop](https://github.com/thomasbrueggemann/paperless-desktop): A desktop UI for your Paperless installation. Runs on Mac, Linux, and Windows. + Known issues on Mac: (Could not load reminders and documents) # Important Note diff --git a/docker/compose/docker-compose.env b/docker/compose/docker-compose.env index e9e8ecb06..34e694b92 100644 --- a/docker/compose/docker-compose.env +++ b/docker/compose/docker-compose.env @@ -22,6 +22,10 @@ # Docker setup does not use the configuration file. # A few commonly adjusted settings are provided below. +# This is required if you will be exposing Paperless-ngx on a public domain +# (if doing so please consider security measures such as reverse proxy) +#PAPERLESS_URL=https://paperless.example.com + # Adjust this key if you plan to make paperless available publicly. It should # be a very long sequence of random characters. You don't need to remember it. #PAPERLESS_SECRET_KEY=change-me diff --git a/docker/compose/docker-compose.postgres-tika.yml b/docker/compose/docker-compose.postgres-tika.yml index 78dfc9df5..c6a72e903 100644 --- a/docker/compose/docker-compose.postgres-tika.yml +++ b/docker/compose/docker-compose.postgres-tika.yml @@ -1,6 +1,7 @@ -# docker-compose file for running paperless from the Docker Hub. +# docker-compose file for running paperless from the docker container registry. # This file contains everything paperless needs to run. -# Paperless supports amd64, arm and arm64 hardware. +# Paperless supports amd64, arm and arm64 hardware. The apache/tika image +# does not support arm or arm64, however. # # All compose files of paperless configure paperless in the following way: # @@ -79,8 +80,9 @@ services: gotenberg: image: gotenberg/gotenberg:7 restart: unless-stopped - environment: - CHROMIUM_DISABLE_ROUTES: 1 + command: + - "gotenberg" + - "--chromium-disable-routes=true" tika: image: apache/tika diff --git a/docker/compose/docker-compose.sqlite-tika.arm.yml b/docker/compose/docker-compose.sqlite-tika.arm.yml new file mode 100644 index 000000000..16633fd1d --- /dev/null +++ b/docker/compose/docker-compose.sqlite-tika.arm.yml @@ -0,0 +1,85 @@ +# docker-compose file for running paperless from the docker container registry. +# This file contains everything paperless needs to run. +# Paperless supports amd64, arm and arm64 hardware. +# +# All compose files of paperless configure paperless in the following way: +# +# - Paperless is (re)started on system boot, if it was running before shutdown. +# - Docker volumes for storing data are managed by Docker. +# - Folders for importing and exporting files are created in the same directory +# as this file and mounted to the correct folders inside the container. +# - Paperless listens on port 8000. +# +# SQLite is used as the database. The SQLite file is stored in the data volume. +# +# iwishiwasaneagle/apache-tika-arm docker image is used to enable arm64 arch +# which apache/tika does not currently support. +# +# In addition to that, this docker-compose file adds the following optional +# configurations: +# +# - Apache Tika and Gotenberg servers are started with paperless and paperless +# is configured to use these services. These provide support for consuming +# Office documents (Word, Excel, Power Point and their LibreOffice counter- +# parts. +# +# To install and update paperless with this file, do the following: +# +# - Copy this file as 'docker-compose.yml' and the files 'docker-compose.env' +# and '.env' into a folder. +# - Run 'docker-compose pull'. +# - Run 'docker-compose run --rm webserver createsuperuser' to create a user. +# - Run 'docker-compose up -d'. +# +# For more extensive installation and update instructions, refer to the +# documentation. + +version: "3.4" +services: + broker: + image: redis:6.0 + restart: unless-stopped + volumes: + - redisdata:/data + + webserver: + image: ghcr.io/paperless-ngx/paperless-ngx:latest + restart: unless-stopped + depends_on: + - broker + - gotenberg + - tika + ports: + - 8000:8000 + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8000"] + interval: 30s + timeout: 10s + retries: 5 + volumes: + - data:/usr/src/paperless/data + - media:/usr/src/paperless/media + - ./export:/usr/src/paperless/export + - ./consume:/usr/src/paperless/consume + env_file: docker-compose.env + environment: + PAPERLESS_REDIS: redis://broker:6379 + PAPERLESS_TIKA_ENABLED: 1 + PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://gotenberg:3000 + PAPERLESS_TIKA_ENDPOINT: http://tika:9998 + + gotenberg: + image: gotenberg/gotenberg:7 + restart: unless-stopped + command: + - "gotenberg" + - "--chromium-disable-routes=true" + + tika: + image: iwishiwasaneagle/apache-tika-arm@sha256:a78c25ffe57ecb1a194b2859d42a61af46e9e845191512b8f1a4bf90578ffdfd + restart: unless-stopped + +volumes: + data: + media: + redisdata: diff --git a/docker/compose/docker-compose.sqlite-tika.yml b/docker/compose/docker-compose.sqlite-tika.yml index 1aaaf2e1b..d9327533e 100644 --- a/docker/compose/docker-compose.sqlite-tika.yml +++ b/docker/compose/docker-compose.sqlite-tika.yml @@ -1,6 +1,7 @@ -# docker-compose file for running paperless from the Docker Hub. +# docker-compose file for running paperless from the docker container registry. # This file contains everything paperless needs to run. -# Paperless supports amd64, arm and arm64 hardware. +# Paperless supports amd64, arm and arm64 hardware. The apache/tika image +# does not support arm or arm64, however. # # All compose files of paperless configure paperless in the following way: # @@ -68,8 +69,9 @@ services: gotenberg: image: gotenberg/gotenberg:7 restart: unless-stopped - environment: - CHROMIUM_DISABLE_ROUTES: 1 + command: + - "gotenberg" + - "--chromium-disable-routes=true" tika: image: apache/tika diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh index e1bca5e4e..6079d03df 100755 --- a/docker/docker-entrypoint.sh +++ b/docker/docker-entrypoint.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -e @@ -10,7 +10,7 @@ map_uidgid() { USERMAP_NEW_GID=${USERMAP_GID:-${USERMAP_ORIG_GID:-$USERMAP_NEW_UID}} if [[ ${USERMAP_NEW_UID} != "${USERMAP_ORIG_UID}" || ${USERMAP_NEW_GID} != "${USERMAP_ORIG_GID}" ]]; then echo "Mapping UID and GID for paperless:paperless to $USERMAP_NEW_UID:$USERMAP_NEW_GID" - usermod -u "${USERMAP_NEW_UID}" paperless + usermod -o -u "${USERMAP_NEW_UID}" paperless groupmod -o -g "${USERMAP_NEW_GID}" paperless fi } @@ -56,12 +56,12 @@ install_languages() { # continue #fi - if dpkg -s $pkg &>/dev/null; then + if dpkg -s "$pkg" &>/dev/null; then echo "Package $pkg already installed!" continue fi - if ! apt-cache show $pkg &>/dev/null; then + if ! apt-cache show "$pkg" &>/dev/null; then echo "Package $pkg not found! :(" continue fi @@ -77,7 +77,7 @@ install_languages() { echo "Paperless-ngx docker container starting..." # Install additional languages if specified -if [[ ! -z "$PAPERLESS_OCR_LANGUAGES" ]]; then +if [[ -n "$PAPERLESS_OCR_LANGUAGES" ]]; then install_languages "$PAPERLESS_OCR_LANGUAGES" fi diff --git a/docker/docker-prepare.sh b/docker/docker-prepare.sh index 28ddda55a..681ccf5a0 100755 --- a/docker/docker-prepare.sh +++ b/docker/docker-prepare.sh @@ -6,14 +6,11 @@ wait_for_postgres() { echo "Waiting for PostgreSQL to start..." - host="${PAPERLESS_DBHOST}" - port="${PAPERLESS_DBPORT}" + host="${PAPERLESS_DBHOST:=localhost}" + port="${PAPERLESS_DBPORT:=5342}" - if [[ -z $port ]]; then - port="5432" - fi - while ! # Install Sphinx and Pygments RUN pip install Sphinx Pygments diff --git a/docs/administration.rst b/docs/administration.rst index 75c5b57d0..85f573460 100644 --- a/docs/administration.rst +++ b/docs/administration.rst @@ -379,7 +379,7 @@ the naming scheme. The command takes no arguments and processes all your documents at once. -Learn how to use :ref:`Management Utilities`. +Learn how to use :ref:`Management Utilities`. .. _utilities-sanity-checker: diff --git a/docs/advanced_usage.rst b/docs/advanced_usage.rst index a04d8c3b1..4dbb32f36 100644 --- a/docs/advanced_usage.rst +++ b/docs/advanced_usage.rst @@ -179,13 +179,14 @@ Assumed you have ``/home/foo/paperless-ngx/scripts/post-consumption-example.sh`` You can pass that script into the consumer container via a host mount in your ``docker-compose.yml``. .. code:: bash - ... - consumer: - ... - volumes: - ... - - /home/paperless-ngx/scripts:/path/in/container/scripts/ - ... + + ... + consumer: + ... + volumes: + ... + - /home/paperless-ngx/scripts:/path/in/container/scripts/ + ... Example (docker-compose.yml): ``- /home/foo/paperless-ngx/scripts:/usr/src/paperless/scripts`` diff --git a/docs/changelog.rst b/docs/changelog.rst index aa26f56c9..984c86075 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -5,6 +5,87 @@ Changelog ********* +paperless-ngx 1.7.0 +################### + +Breaking Changes + +* ``PAPERLESS_URL`` is now required when using a reverse proxy. See `#674`_. + +Features + +* Allow setting more than one tag in mail rules `@jonasc`_ (#270) +* global drag'n'drop `@shamoon`_ (#283). +* Fix: download buttons should disable while waiting `@shamoon`_ (#630). +* Update checker `@shamoon`_ (#591). +* Show prompt on password-protected pdfs `@shamoon`_ (#564). +* Filtering query params aka browser navigation for filtering `@shamoon`_ (#540). +* Clickable tags in dashboard widgets `@shamoon`_ (#515). +* Add bottom pagination `@shamoon`_ (#372). +* Feature barcode splitter `@gador`_ (#532). +* App loading screen `@shamoon`_ (#298). +* Use progress bar for delayed buttons `@shamoon`_ (#415). +* Add minimum length for documents text filter `@shamoon`_ (#401). +* Added nav buttons in the document detail view `@GruberViktor`_ (#273). +* Improve date keyboard input `@shamoon`_ (#253). +* Color theming `@shamoon`_ (#243). +* Parse dates when entered without separators `@GruberViktor`_ (#250). + +Bug Fixes + +* add "localhost" to ALLOWED_HOSTS `@gador`_ (#700). +* Fix: scanners table `@qcasey`_ (#690). +* Adds wait for file before consuming `@stumpylog`_ (#483). +* Fix: frontend document editing erases time data `@shamoon`_ (#654). +* Increase length of SavedViewFilterRule `@stumpylog`_ (#612). +* Fixes attachment filename matching during mail fetching `@stumpylog`_ (#680). +* Add ``PAPERLESS_URL`` env variable & CSRF var `@shamoon`_ (#674). +* Fix: download buttons should disable while waiting `@shamoon`_ (#630). +* Fixes downloaded filename, add more consumer ignore settings `@stumpylog`_ (#599). +* FIX BUG: case-sensitive matching was not possible `@danielBreitlauch`_ (#594). +* uses shutil.move instead of rename `@gador`_ (#617). +* Fix npm deps 01.02.22 2 `@shamoon`_ (#610). +* Fix npm dependencies 01.02.22 `@shamoon`_ (#600). +* fix issue 416: implement PAPERLESS_OCR_MAX_IMAGE_PIXELS `@hacker-h`_ (#441). +* fix: exclude cypress from build in Dockerfile `@FrankStrieter`_ (#526). +* Corrections to pass pre-commit hooks `@schnuffle`_ (#454). +* Fix 311 unable to click checkboxes in document list `@shamoon`_ (#313). +* Fix imap tools bug `@stumpylog`_ (#393). +* Fix filterable dropdown buttons arent translated `@shamoon`_ (#366). +* Fix 224: "Auto-detected date is day before receipt date" `@a17t`_ (#246). +* Fix minor sphinx errors `@shamoon`_ (#322). +* Fix page links hidden `@shamoon`_ (#314). +* Fix: Include excluded items in dropdown count `@shamoon`_ (#263). + +Translation + +* `@miku323`_ contributed to Slovenian translation. +* `@FaintGhost`_ contributed to Chinese Simplified translation. +* `@DarkoBG79`_ contributed to Serbian translation. +* `Kemal Secer`_ contributed to Turkish translation. +* `@Prominence`_ contributed to Belarusian translation. + +Documentation + +* Fix: scanners table `@qcasey`_ (#690). +* Add `PAPERLESS_URL` env variable & CSRF var `@shamoon`_ (#674). +* Fixes downloaded filename, add more consumer ignore settings `@stumpylog`_ (#599). +* fix issue 416: implement ``PAPERLESS_OCR_MAX_IMAGE_PIXELS`` `@hacker-h`_ (#441). +* Fix minor sphinx errors `@shamoon`_ (#322). + +Maintenance + +* Add ``PAPERLESS_URL`` env variable & CSRF var `@shamoon`_ (#674). +* Chore: Implement release-drafter action for Changelogs `@qcasey`_ (#669). +* Chore: Add CODEOWNERS `@qcasey`_ (#667). +* Support docker-compose v2 in install `@stumpylog`_ (#611). +* Add Belarusian localization `@shamoon`_ (#588). +* Add Turkish localization `@shamoon`_ (#536). +* Add Serbian localization `@shamoon`_ (#504). +* Create PULL_REQUEST_TEMPLATE.md `@shamoon`_ (#304). +* Add Chinese localization `@shamoon`_ (#247). +* Add Slovenian language for frontend `@shamoon`_ (#315). + paperless-ngx 1.6.0 ################### @@ -144,7 +225,7 @@ paperless-ng 1.4.0 * New URL pattern for accessing documents by ASN directly (http:///asn/123) - * Added logging when executing pre- and post-consume scripts. + * Added logging when executing pre* and post-consume scripts. * Better error logging during document consumption. @@ -1580,6 +1661,16 @@ bulk of the work on this big change. .. _@azapater: https://github.com/azapater .. _@tim-vogel: https://github.com/tim-vogel .. _@jschpp: https://github.com/jschpp +.. _@schnuffle: https://github.com/schnuffle +.. _@GruberViktor: https://github.com/gruberviktor +.. _@hacker-h: https://github.com/hacker-h +.. _@danielBreitlauch: https://github.com/danielbreitlauch +.. _@miku323: https://github.com/miku323 +.. _@FaintGhost: https://github.com/FaintGhost +.. _@DarkoBG79: https://github.com/DarkoBG79 +.. _Kemal Secer: https://crowdin.com/profile/kemal.secer +.. _@Prominence: https://github.com/Prominence +.. _@jonasc: https://github.com/jonasc .. _#20: https://github.com/the-paperless-project/paperless/issues/20 .. _#44: https://github.com/the-paperless-project/paperless/issues/44 @@ -1688,6 +1779,7 @@ bulk of the work on this big change. .. _#488: https://github.com/the-paperless-project/paperless/pull/488 .. _#489: https://github.com/the-paperless-project/paperless/pull/489 .. _#492: https://github.com/the-paperless-project/paperless/pull/492 +.. _#674: https://github.com/paperless-ngx/paperless-ngx/pull/674 .. _a new home on Docker Hub: https://hub.docker.com/r/danielquinn/paperless/ .. _optipng: http://optipng.sourceforge.net/ diff --git a/docs/configuration.rst b/docs/configuration.rst index ae789f616..42935dab8 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -130,6 +130,8 @@ PAPERLESS_LOGROTATE_MAX_BACKUPS= Defaults to 20. +.. _hosting-and-security: + Hosting & Security ################## @@ -142,7 +144,24 @@ PAPERLESS_SECRET_KEY= Default is listed in the file ``src/paperless/settings.py``. -PAPERLESS_ALLOWED_HOSTS +PAPERLESS_URL= + This setting can be used to set the three options below (ALLOWED_HOSTS, + CORS_ALLOWED_HOSTS and CSRF_TRUSTED_ORIGINS). If the other options are + set the values will be combined with this one. Do not include a trailing + slash. E.g. https://paperless.domain.com + + Defaults to empty string, leaving the other settings unaffected. + +PAPERLESS_CSRF_TRUSTED_ORIGINS= + A list of trusted origins for unsafe requests (e.g. POST). As of Django 4.0 + this is required to access the Django admin via the web. + See https://docs.djangoproject.com/en/4.0/ref/settings/#csrf-trusted-origins + + Can also be set using PAPERLESS_URL (see above). + + Defaults to empty string, which does not add any origins to the trusted list. + +PAPERLESS_ALLOWED_HOSTS= If you're planning on putting Paperless on the open internet, then you really should set this value to the domain name you're using. Failing to do so leaves you open to HTTP host header attacks: @@ -151,12 +170,19 @@ PAPERLESS_ALLOWED_HOSTS Just remember that this is a comma-separated list, so "example.com" is fine, as is "example.com,www.example.com", but NOT " example.com" or "example.com," + Can also be set using PAPERLESS_URL (see above). + + If manually set, please remember to include "localhost". Otherwise docker + healthcheck will fail. + Defaults to "*", which is all hosts. -PAPERLESS_CORS_ALLOWED_HOSTS +PAPERLESS_CORS_ALLOWED_HOSTS= You need to add your servers to the list of allowed hosts that can do CORS calls. Set this to your public domain name. + Can also be set using PAPERLESS_URL (see above). + Defaults to "http://localhost:8000". PAPERLESS_FORCE_SCRIPT_NAME= @@ -389,6 +415,15 @@ PAPERLESS_OCR_IMAGE_DPI= Default is none, which will automatically calculate image DPI so that the produced PDF documents are A4 sized. +PAPERLESS_OCR_MAX_IMAGE_PIXELS= + Paperless will not OCR images that have more pixels than this limit. + This is intended to prevent decompression bombs from overloading paperless. + Increasing this limit is desired if you face a DecompressionBombError despite + the concerning file not being malicious; this could e.g. be caused by invalidly + recognized metadata. + If you have enough resources or if you are certain that your uploaded files + are not malicious you can increase this value to your needs. + The default value is 256000000, an image with more pixels than that would not be parsed. PAPERLESS_OCR_USER_ARGS= OCRmyPDF offers many more options. Use this parameter to specify any @@ -462,8 +497,9 @@ requires are as follows: gotenberg: image: gotenberg/gotenberg:7 restart: unless-stopped - environment: - CHROMIUM_DISABLE_ROUTES: 1 + command: + - "gotenberg" + - "--chromium-disable-routes=true" tika: image: apache/tika @@ -473,6 +509,8 @@ Add the configuration variables to the environment of the webserver (alternative put the configuration in the ``docker-compose.env`` file) and add the additional services below the webserver service. Watch out for indentation. +Make sure to use the correct format `PAPERLESS_TIKA_ENABLED = 1` so python_dotenv can parse the statement correctly. + Software tweaks ############### @@ -528,6 +566,10 @@ PAPERLESS_WORKER_TIMEOUT= large documents within the default 1800 seconds. So extending this timeout may prove to be useful on weak hardware setups. +PAPERLESS_WORKER_RETRY= + If PAPERLESS_WORKER_TIMEOUT has been configured, the retry time for a task can + also be configured. By default, this value will be set to 10s more than the + worker timeout. This value should never be set less than the worker timeout. PAPERLESS_TIME_ZONE= Set the time zone here. @@ -576,6 +618,27 @@ PAPERLESS_CONSUMER_SUBDIRS_AS_TAGS= Defaults to false. +PAPERLESS_CONSUMER_ENABLE_BARCODES= + Enables the scanning and page separation based on detected barcodes. + This allows for scanning and adding multiple documents per uploaded + file, which are separated by one or multiple barcode pages. + + For ease of use, it is suggested to use a standardized separation page, + e.g. `here `_. + + If no barcodes are detected in the uploaded file, no page separation + will happen. + + Defaults to false. + + +PAPERLESS_CONSUMER_BARCODE_STRING=PATCHT + Defines the string to be detected as a separator barcode. + If paperless is used with the PATCH-T separator pages, users + shouldn't change this. + + Defaults to "PATCHT" + PAPERLESS_CONVERT_MEMORY_LIMIT= On smaller systems, or even in the case of Very Large Documents, the consumer @@ -659,7 +722,7 @@ PAPERLESS_CONSUMER_IGNORE_PATTERNS= This can be adjusted by configuring a custom json array with patterns to exclude. - Defaults to ``[".DS_STORE/*", "._*", ".stfolder/*"]``. + Defaults to ``[".DS_STORE/*", "._*", ".stfolder/*", ".stversions/*", ".localized/*", "desktop.ini"]``. Binaries ######## @@ -752,3 +815,26 @@ PAPERLESS_OCR_LANGUAGES= PAPERLESS_OCR_LANGUAGE=tur Defaults to none, which does not install any additional languages. + + +.. _configuration-update-checking: + +Update Checking +############### + +PAPERLESS_ENABLE_UPDATE_CHECK= + Enable (or disable) the automatic check for available updates. This feature is disabled + by default but if it is not explicitly set Paperless-ngx will show a message about this. + + If enabled, the feature works by pinging the the Github API for the latest release e.g. + https://api.github.com/repos/paperless-ngx/paperless-ngx/releases/latest + to determine whether a new version is available. + + Actual updating of the app must still be performed manually. + + Note that for users of thirdy-party containers e.g. linuxserver.io this notification + may be 'ahead' of a new release from the third-party maintainers. + + In either case, no tracking data is collected by the app in any way. + + Defaults to none, which disables the feature. diff --git a/docs/extending.rst b/docs/extending.rst index 46b1e7ad7..8b276dacc 100644 --- a/docs/extending.rst +++ b/docs/extending.rst @@ -34,6 +34,8 @@ it fixed for everyone! Before contributing please review our `code of conduct`_ and other important information in the `contributing guidelines`_. +.. _code-formatting-with-pre-commit-hooks: + Code formatting with pre-commit Hooks ===================================== @@ -85,6 +87,7 @@ To do the setup you need to perform the steps from the following chapters in a c docker run -d -p 6379:6379 --restart unless-stopped redis:latest 7. Install the python dependencies by performing in the src/ directory. + .. code:: shell-session pipenv install --dev @@ -139,8 +142,9 @@ Testing and code style: * Run ``pytest`` in the src/ directory to execute all tests. This also generates a HTML coverage report. When runnings test, paperless.conf is loaded as well. However: the tests rely on the default configuration. This is not ideal. But for now, make sure no settings except for DEBUG are overridden when testing. -* Run ``black`` to format your code. -* Run ``pycodestyle`` to test your code for issues with the configured code style settings. +* Coding style is enforced by the Git pre-commit hooks. These will ensure your code is formatted and do some + linting when you do a `git commit`. +* You can also run ``black`` manually to format your code .. note:: @@ -182,6 +186,31 @@ X-Frame-Options are in place so that the front end behaves exactly as in product relies on you being logged into the back end. Without a valid session, The front end will simply not work. +Testing and code style: + +* The frontend code (.ts, .html, .scss) use ``prettier`` for code formatting via the Git + ``pre-commit`` hooks which run automatically on commit. See + :ref:`above ` for installation. You can also run this + via cli with a command such as + + .. code:: shell-session + + $ git ls-files -- '*.ts' | xargs pre-commit run prettier --files + +* Frontend testing uses jest and cypress. There is currently a need for significantly more + frontend tests. Unit tests and e2e tests, respectively, can be run non-interactively with: + + .. code:: shell-session + + $ ng test + $ npm run e2e:ci + + Cypress also includes a UI which can be run from within the ``src-ui`` directory with + + .. code:: shell-session + + $ ./node_modules/.bin/cypress open + In order to build the front end and serve it as part of django, execute .. code:: shell-session diff --git a/docs/faq.rst b/docs/faq.rst index 71a9272af..1b2892fc3 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -5,11 +5,11 @@ Frequently asked questions **Q:** *What's the general plan for Paperless-ngx?* -**A:** While Paperless-ngx is already considered largely "feature-complete" it is a community-driven +**A:** While Paperless-ngx is already considered largely "feature-complete" it is a community-driven project and development will be guided in this way. New features can be submitted via GitHub discussions and "up-voted" by the community but this is not a guarantee the feature will be implemented. This project will always be open to collaboration in the form of PRs, -ideas etc. +ideas etc. **Q:** *I'm using docker. Where are my documents?* @@ -81,11 +81,10 @@ python requirements do not have precompiled packages for ARM / ARM64. Installati of these will require additional development libraries and compilation will take a long time. -**Q:** *How do I run this on unRaid?* +**Q:** *How do I run this on Unraid?* -**A:** Head over to ``_, -`Uli Fahrer `_ created a container template for that. -I don't exactly know how to use that though, since I don't use unRaid. +**A:** Paperless-ngx is available as `community app `_ +in Unraid. `Uli Fahrer `_ created a container template for that. **Q:** *How do I run this on my toaster?* diff --git a/docs/scanners.rst b/docs/scanners.rst index 51611c9ac..cd3777ba2 100644 --- a/docs/scanners.rst +++ b/docs/scanners.rst @@ -13,43 +13,43 @@ that works right for you based on recommendations from other Paperless users. Physical scanners ================= -+---------+----------------+-----+-----+-----+------+----------+----------------+ -| Brand | Model | Supports | Recommended By | -+---------+----------------+-----+-----+-----+------+----------+----------------+ -| | | FTP | NFS | SMB | SMTP | API [1]_ | | -+=========+================+=====+=====+=====+======+==========+================+ -| Brother | `ADS-1700W`_ | yes | | yes | yes | |`holzhannes`_ | -+---------+----------------+-----+-----+-----+------+----------+----------------+ -| Brother | `ADS-1600W`_ | yes | | yes | yes | |`holzhannes`_ | -+---------+----------------+-----+-----+-----+------+----------+----------------+ -| Brother | `ADS-1500W`_ | yes | | yes | yes | |`danielquinn`_ | -+---------+----------------+-----+-----+-----+------+----------+----------------+ -| Brother | `ADS-1100W`_ | yes | | | | |`ytzelf`_ | -+---------+----------------+-----+-----+-----+------+----------+----------------+ -| Brother | `ADS-2800W`_ | yes | yes | | yes | yes |`philpagel`_ | -+---------+----------------+-----+-----+-----+------+----------+----------------+ -| Brother | `MFC-J6930DW`_ | yes | | | | |`ayounggun`_ | -+---------+----------------+-----+-----+-----+------+----------+----------------+ -| Brother | `MFC-L5850DW`_ | yes | | | yes | |`holzhannes`_ | -+---------+----------------+-----+-----+-----+------+----------+----------------+ -| Brother | `MFC-L2750DW`_ | yes | | yes | yes | |`muued`_ | -+---------+----------------+-----+-----+-----+------+----------+----------------+ -| Brother | `MFC-J5910DW`_ | yes | | | | |`bmsleight`_ | -+---------+----------------+-----+-----+-----+------+----------+----------------+ -| Brother | `MFC-8950DW`_ | yes | | | yes | yes |`philpagel`_ | -+---------+----------------+-----+-----+-----+------+----------+----------------+ -| Brother | `MFC-9142CDN`_ | yes | | yes | | |`REOLDEV`_ | -+---------+----------------+-----+-----+-----+------+----------+----------------+ -| Fujitsu | `ix500`_ | yes | | yes | | |`eonist`_ | -+---------+----------------+-----+-----+-----+------+----------+----------------+ -| Epson | `ES-580W`_ | yes | | yes | yes | |`fignew`_ | -+---------+----------------+-----+-----+-----+------+----------+----------------+ -| Epson | `WF-7710DWF`_ | yes | | yes | | |`Skylinar`_ | -+---------+----------------+-----+-----+-----+------+----------+----------------+ -| Fujitsu | `S1300i`_ | yes | | yes | | |`jonaswinkler`_ | -+---------+----------------+-----+-----+-----+------+----------+----------------+ -| Doxie | `Q2`_ | | | | | yes |`Unkn0wnCat`_ | -+---------+----------------+-----+-----+-----+------+----------+----------------+ ++---------+----------------+-----+------+-----+-----+------+----------+----------------+ +| Brand | Model | Supports | Recommended By | ++---------+----------------+-----+------+-----+-----+------+----------+----------------+ +| | | FTP | SFTP | NFS | SMB | SMTP | API [1]_ | | ++=========+================+=====+======+=====+=====+======+==========+================+ +| Brother | `ADS-1700W`_ | yes | | | yes | yes | |`holzhannes`_ | ++---------+----------------+-----+------+-----+-----+------+----------+----------------+ +| Brother | `ADS-1600W`_ | yes | | | yes | yes | |`holzhannes`_ | ++---------+----------------+-----+------+-----+-----+------+----------+----------------+ +| Brother | `ADS-1500W`_ | yes | | | yes | yes | |`danielquinn`_ | ++---------+----------------+-----+------+-----+-----+------+----------+----------------+ +| Brother | `ADS-1100W`_ | yes | | | | | |`ytzelf`_ | ++---------+----------------+-----+------+-----+-----+------+----------+----------------+ +| Brother | `ADS-2800W`_ | yes | yes | | yes | yes | |`philpagel`_ | ++---------+----------------+-----+------+-----+-----+------+----------+----------------+ +| Brother | `MFC-J6930DW`_ | yes | | | | | |`ayounggun`_ | ++---------+----------------+-----+------+-----+-----+------+----------+----------------+ +| Brother | `MFC-L5850DW`_ | yes | | | | yes | |`holzhannes`_ | ++---------+----------------+-----+------+-----+-----+------+----------+----------------+ +| Brother | `MFC-L2750DW`_ | yes | | | yes | yes | |`muued`_ | ++---------+----------------+-----+------+-----+-----+------+----------+----------------+ +| Brother | `MFC-J5910DW`_ | yes | | | | | |`bmsleight`_ | ++---------+----------------+-----+------+-----+-----+------+----------+----------------+ +| Brother | `MFC-8950DW`_ | yes | | | yes | yes | |`philpagel`_ | ++---------+----------------+-----+------+-----+-----+------+----------+----------------+ +| Brother | `MFC-9142CDN`_ | yes | | | yes | | |`REOLDEV`_ | ++---------+----------------+-----+------+-----+-----+------+----------+----------------+ +| Fujitsu | `ix500`_ | yes | | | yes | | |`eonist`_ | ++---------+----------------+-----+------+-----+-----+------+----------+----------------+ +| Epson | `ES-580W`_ | yes | | | yes | yes | |`fignew`_ | ++---------+----------------+-----+------+-----+-----+------+----------+----------------+ +| Epson | `WF-7710DWF`_ | yes | | | yes | | |`Skylinar`_ | ++---------+----------------+-----+------+-----+-----+------+----------+----------------+ +| Fujitsu | `S1300i`_ | yes | | | yes | | |`jonaswinkler`_ | ++---------+----------------+-----+------+-----+-----+------+----------+----------------+ +| Doxie | `Q2`_ | | | | | | yes |`Unkn0wnCat`_ | ++---------+----------------+-----+------+-----+-----+------+----------+----------------+ .. _MFC-L5850DW: https://www.brother-usa.com/products/mfcl5850dw .. _MFC-L2750DW: https://www.brother.de/drucker/laserdrucker/mfc-l2750dw @@ -131,4 +131,3 @@ This part assumes your Doxie is connected to WiFi and you know its IP. 6. Click *Submit* at the bottom of the page Congrats, you can now scan directly from your Doxie to your Paperless-ngx instance! - diff --git a/docs/setup.rst b/docs/setup.rst index c6e751da5..de694bda8 100644 --- a/docs/setup.rst +++ b/docs/setup.rst @@ -110,7 +110,7 @@ performs all the steps described in :ref:`setup-docker_hub` automatically. .. code:: shell-session - $ bash -c "$(curl -L https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/master/install-paperless-ngx.sh)" + $ bash -c "$(curl -L https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/install-paperless-ngx.sh)" .. _setup-docker_hub: @@ -481,7 +481,7 @@ Migrating from Paperless-ng =========================== Paperless-ngx is meant to be a drop-in replacement for Paperless-ng and thus upgrading should be -trivial for most users, especially when using docker. However, as with any major change, it is +trivial for most users, especially when using docker. However, as with any major change, it is recommended to take a full backup first. Once you are ready, simply change the docker image to point to the new source. E.g. if using Docker Compose, edit ``docker-compose.yml`` and change: @@ -494,12 +494,12 @@ to .. code:: image: ghcr.io/paperless-ngx/paperless-ngx:latest - + and then run ``docker-compose up -d`` which will pull the new image recreate the container. That's it! -Users who installed with the bare-metal route should also update their Git clone to point to -``https://github.com/paperless-ngx/paperless-ngx``, e.g. using the command +Users who installed with the bare-metal route should also update their Git clone to point to +``https://github.com/paperless-ngx/paperless-ngx``, e.g. using the command ``git remote set-url origin https://github.com/paperless-ngx/paperless-ngx`` and then pull the lastest version. @@ -728,6 +728,8 @@ configuring some options in paperless can help improve performance immensely: times. Thumbnails will be about 20% larger. * If using docker, consider setting ``PAPERLESS_WEBSERVER_WORKERS`` to 1. This will save some memory. +* Use the arm compatible docker-compose if you're wanting to use Tika on something like + a raspberry pi. The official apache/tika image does not support the arm architecture. For details, refer to :ref:`configuration`. @@ -786,4 +788,6 @@ the following configuration is required for paperless to operate: } } +The ``PAPERLESS_URL`` configuration variable is also required when using a reverse proxy. Please refer to the :ref:`hosting-and-security` docs. + Also read `this `__, towards the end of the section. diff --git a/docs/troubleshooting.rst b/docs/troubleshooting.rst index c5c669b18..3ae4909de 100644 --- a/docs/troubleshooting.rst +++ b/docs/troubleshooting.rst @@ -119,7 +119,7 @@ You may experience these errors when using the optional TIKA integration: Gotenberg is a server that converts Office documents into PDF documents and has a default timeout of 30 seconds. When conversion takes longer, Gotenberg raises this error. -You can increase the timeout by configuring an environment variable for Gotenberg (see also `here `__). +You can increase the timeout by configuring a command flag for Gotenberg (see also `here `__). If using docker-compose, this is achieved by the following configuration change in the ``docker-compose.yml`` file: .. code:: yaml @@ -127,9 +127,10 @@ If using docker-compose, this is achieved by the following configuration change gotenberg: image: gotenberg/gotenberg:7 restart: unless-stopped - environment: - CHROMIUM_DISABLE_ROUTES: 1 - API_PROCESS_TIMEOUT: 60 + command: + - "gotenberg" + - "--chromium-disable-routes=true" + - "--api-timeout=60" Permission denied errors in the consumption directory ##################################################### diff --git a/docs/usage_overview.rst b/docs/usage_overview.rst index ffaff8f3e..be6b471c1 100644 --- a/docs/usage_overview.rst +++ b/docs/usage_overview.rst @@ -180,6 +180,14 @@ These are as follows: automatically or manually and tell paperless to move them to yet another folder after consumption. It's up to you. +.. note:: + + When defining a mail rule with a folder, you may need to try different characters to + define how the sub-folders are separated. Common values include ".", "/" or "|", but + this varies by the mail server. Unfortunately, this isn't a value we can determine + automatically. Either check the documentation for your mail server, or check for + errors in the logs and try different folder separator values. + .. note:: Paperless will process the rules in the order defined in the admin page. diff --git a/install-paperless-ngx.sh b/install-paperless-ngx.sh index e8a046c40..6ffcefbb6 100755 --- a/install-paperless-ngx.sh +++ b/install-paperless-ngx.sh @@ -3,16 +3,16 @@ ask() { while true ; do if [[ -z $3 ]] ; then - read -p "$1 [$2]: " result + read -r -p "$1 [$2]: " result else - read -p "$1 ($3) [$2]: " result + read -r -p "$1 ($3) [$2]: " result fi if [[ -z $result ]]; then ask_result=$2 return fi array=$3 - if [[ -z $3 || " ${array[@]} " =~ " ${result} " ]]; then + if [[ -z $3 || " ${array[*]} " =~ ${result} ]]; then ask_result=$result return else @@ -24,7 +24,7 @@ ask() { ask_docker_folder() { while true ; do - read -p "$1 [$2]: " result + read -r -p "$1 [$2]: " result if [[ -z $result ]]; then ask_result=$2 @@ -47,25 +47,29 @@ if [[ $(id -u) == "0" ]] ; then exit 1 fi -if [[ -z $(which wget) ]] ; then +if ! command -v wget &> /dev/null ; then echo "wget executable not found. Is wget installed?" exit 1 fi -if [[ -z $(which docker) ]] ; then +if ! command -v docker &> /dev/null ; then echo "docker executable not found. Is docker installed?" exit 1 fi -if [[ -z $(which docker-compose) ]] ; then - echo "docker-compose executable not found. Is docker-compose installed?" - exit 1 +DOCKER_COMPOSE_CMD="docker-compose" +if ! command -v ${DOCKER_COMPOSE_CMD} ; then + if docker compose version &> /dev/null ; then + DOCKER_COMPOSE_CMD="docker compose" + else + echo "docker-compose executable not found. Is docker-compose installed?" + exit 1 + fi fi # Check if user has permissions to run Docker by trying to get the status of Docker (docker status). # If this fails, the user probably does not have permissions for Docker. -docker stats --no-stream 2>/dev/null 1>&2 -if [ $? -ne 0 ] ; then +if ! docker stats --no-stream &> /dev/null ; then echo "" echo "WARN: It look like the current user does not have Docker permissions." echo "WARN: Use 'sudo usermod -aG docker $USER' to assign Docker permissions to the user." @@ -88,6 +92,14 @@ echo "" echo "1. Application configuration" echo "============================" +echo "" +echo "The URL paperless will be available at. This is required if the" +echo "installation will be accessible via the web, otherwise can be left blank." +echo "" + +ask "URL" "" +URL=$ask_result + echo "" echo "The port on which the paperless webserver will listen for incoming" echo "connections." @@ -162,7 +174,7 @@ ask "Target folder" "$(pwd)/paperless-ngx" TARGET_FOLDER=$ask_result echo "" -echo "The consume folder is where paperles will search for new documents." +echo "The consume folder is where paperless will search for new documents." echo "Point this to a folder where your scanner is able to put your scanned" echo "documents." echo "" @@ -228,7 +240,7 @@ ask "Paperless username" "$(whoami)" USERNAME=$ask_result while true; do - read -sp "Paperless password: " PASSWORD + read -r -sp "Paperless password: " PASSWORD echo "" if [[ -z $PASSWORD ]] ; then @@ -236,7 +248,7 @@ while true; do continue fi - read -sp "Paperless password (again): " PASSWORD_REPEAT + read -r -sp "Paperless password (again): " PASSWORD_REPEAT echo "" if [[ ! "$PASSWORD" == "$PASSWORD_REPEAT" ]] ; then @@ -274,6 +286,7 @@ if [[ "$DATABASE_BACKEND" == "postgres" ]] ; then fi fi echo "" +echo "URL: $URL" echo "Port: $PORT" echo "Database: $DATABASE_BACKEND" echo "Tika enabled: $TIKA_ENABLED" @@ -285,7 +298,7 @@ echo "Paperless username: $USERNAME" echo "Paperless email: $EMAIL" echo "" -read -p "Press any key to install." +read -r -p "Press any key to install." echo "" echo "Installing paperless..." @@ -301,14 +314,17 @@ if [[ $TIKA_ENABLED == "yes" ]] ; then DOCKER_COMPOSE_VERSION="$DOCKER_COMPOSE_VERSION-tika" fi -wget "https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/master/docker/compose/docker-compose.$DOCKER_COMPOSE_VERSION.yml" -O docker-compose.yml -wget "https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/master/docker/compose/.env" -O .env +wget "https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/docker/compose/docker-compose.$DOCKER_COMPOSE_VERSION.yml" -O docker-compose.yml +wget "https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/docker/compose/.env" -O .env -SECRET_KEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 64 | head -n 1) +SECRET_KEY=$(tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 64 | head -n 1) DEFAULT_LANGUAGES="deu eng fra ita spa" { + if [[ ! $URL == "" ]] ; then + echo "PAPERLESS_URL=$URL" + fi if [[ ! $USERMAP_UID == "1000" ]] ; then echo "USERMAP_UID=$USERMAP_UID" fi @@ -318,7 +334,7 @@ DEFAULT_LANGUAGES="deu eng fra ita spa" echo "PAPERLESS_TIME_ZONE=$TIME_ZONE" echo "PAPERLESS_OCR_LANGUAGE=$OCR_LANGUAGE" echo "PAPERLESS_SECRET_KEY=$SECRET_KEY" - if [[ ! " ${DEFAULT_LANGUAGES[@]} " =~ " ${OCR_LANGUAGE} " ]] ; then + if [[ ! " ${DEFAULT_LANGUAGES[*]} " =~ ${OCR_LANGUAGE} ]] ; then echo "PAPERLESS_OCR_LANGUAGES=$OCR_LANGUAGE" fi } > docker-compose.env @@ -329,18 +345,31 @@ sed -i "s#- \./consume:/usr/src/paperless/consume#- $CONSUME_FOLDER:/usr/src/pap if [[ -n $MEDIA_FOLDER ]] ; then sed -i "s#- media:/usr/src/paperless/media#- $MEDIA_FOLDER:/usr/src/paperless/media#g" docker-compose.yml + sed -i "/^\s*media:/d" docker-compose.yml fi if [[ -n $DATA_FOLDER ]] ; then sed -i "s#- data:/usr/src/paperless/data#- $DATA_FOLDER:/usr/src/paperless/data#g" docker-compose.yml + sed -i "/^\s*data:/d" docker-compose.yml fi if [[ -n $POSTGRES_FOLDER ]] ; then sed -i "s#- pgdata:/var/lib/postgresql/data#- $POSTGRES_FOLDER:/var/lib/postgresql/data#g" docker-compose.yml + sed -i "/^\s*pgdata:/d" docker-compose.yml fi -docker-compose pull +# remove trailing blank lines from end of file +sed -i -e :a -e '/^\n*$/{$d;N;};/\n$/ba' docker-compose.yml +# if last line in file contains "volumes:", remove that line since no more named volumes are left +l1=$(grep -n '^volumes:' docker-compose.yml | cut -d : -f 1) # get line number containing volume: at begin of line +l2=$(wc -l < docker-compose.yml) # get total number of lines +if [ "$l1" -eq "$l2" ] ; then + sed -i "/^volumes:/d" docker-compose.yml +fi -docker-compose run --rm -e DJANGO_SUPERUSER_PASSWORD="$PASSWORD" webserver createsuperuser --noinput --username "$USERNAME" --email "$EMAIL" -docker-compose up -d +${DOCKER_COMPOSE_CMD} pull + +${DOCKER_COMPOSE_CMD} run --rm -e DJANGO_SUPERUSER_PASSWORD="$PASSWORD" webserver createsuperuser --noinput --username "$USERNAME" --email "$EMAIL" + +${DOCKER_COMPOSE_CMD} up -d diff --git a/paperless.conf.example b/paperless.conf.example index bfb4fac7e..be5071636 100644 --- a/paperless.conf.example +++ b/paperless.conf.example @@ -27,8 +27,10 @@ # Security and hosting #PAPERLESS_SECRET_KEY=change-me -#PAPERLESS_ALLOWED_HOSTS=example.com,www.example.com -#PAPERLESS_CORS_ALLOWED_HOSTS=http://example.com,http://localhost:8000 +#PAPERLESS_URL=https://example.com +#PAPERLESS_CSRF_TRUSTED_ORIGINS=https://example.com # can be set using PAPERLESS_URL +#PAPERLESS_ALLOWED_HOSTS=example.com,www.example.com # can be set using PAPERLESS_URL +#PAPERLESS_CORS_ALLOWED_HOSTS=https://localhost:8080,https://example.com # can be set using PAPERLESS_URL #PAPERLESS_FORCE_SCRIPT_NAME= #PAPERLESS_STATIC_URL=/static/ #PAPERLESS_AUTO_LOGIN_USERNAME= @@ -58,8 +60,10 @@ #PAPERLESS_CONSUMER_POLLING=10 #PAPERLESS_CONSUMER_DELETE_DUPLICATES=false #PAPERLESS_CONSUMER_RECURSIVE=false -#PAPERLESS_CONSUMER_IGNORE_PATTERNS=[".DS_STORE/*", "._*", ".stfolder/*"] +#PAPERLESS_CONSUMER_IGNORE_PATTERNS=[".DS_STORE/*", "._*", ".stfolder/*", ".stversions/*", ".localized/*", "desktop.ini"] #PAPERLESS_CONSUMER_SUBDIRS_AS_TAGS=false +#PAPERLESS_CONSUMER_ENABLE_BARCODES=false +#PAPERLESS_CONSUMER_ENABLE_BARCODES=PATCHT #PAPERLESS_OPTIMIZE_THUMBNAILS=true #PAPERLESS_PRE_CONSUME_SCRIPT=/path/to/an/arbitrary/script.sh #PAPERLESS_POST_CONSUME_SCRIPT=/path/to/an/arbitrary/script.sh @@ -67,6 +71,7 @@ #PAPERLESS_FILENAME_PARSE_TRANSFORMS=[] #PAPERLESS_THUMBNAIL_FONT_NAME= #PAPERLESS_IGNORE_DATES= +#PAPERLESS_ENABLE_UPDATE_CHECK= # Tika settings diff --git a/requirements.txt b/requirements.txt index f65cf7fc1..99856abff 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,49 +5,50 @@ # pipenv lock --requirements # --i https://pypi.python.org/simple ---extra-index-url https://www.piwheels.org/simple +-i https://pypi.python.org/simple/ +--extra-index-url https://www.piwheels.org/simple/ aioredis==1.3.1 +anyio==3.5.0; python_full_version >= '3.6.2' arrow==1.2.2; python_version >= '3.6' asgiref==3.5.0; python_version >= '3.7' async-timeout==4.0.2; python_version >= '3.6' attrs==21.4.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' -autobahn==22.2.2; python_version >= '3.7' +autobahn==22.3.2; python_version >= '3.7' automat==20.2.0 -backports.zoneinfo==0.2.1 +backports.zoneinfo==0.2.1; python_version < '3.9' blessed==1.19.1; python_version >= '2.7' certifi==2021.10.8 cffi==1.15.0 -channels-redis==3.3.1 +channels-redis==3.4.0 channels==3.0.4 chardet==4.0.0; python_version >= '3.1' charset-normalizer==2.0.12; python_version >= '3' -click==8.0.4; python_version >= '3.6' +click==8.1.2; python_version >= '3.7' coloredlogs==15.0.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' concurrent-log-handler==0.9.20 constantly==15.1.0 -cryptography==36.0.1 +cryptography==36.0.2; python_version >= '3.6' daphne==3.0.2; python_version >= '3.6' -dateparser==1.1.0 +dateparser==1.1.1 django-cors-headers==3.11.0 django-extensions==3.1.5 django-filter==21.1 django-picklefield==3.0.1; python_version >= '3' django-q==1.3.9 -django==3.2.12 +django==4.0.4 djangorestframework==3.13.1 filelock==3.6.0 fuzzywuzzy[speedup]==0.18.0 gunicorn==20.1.0 h11==0.13.0; python_version >= '3.6' hiredis==2.0.0; python_version >= '3.6' -httptools==0.3.0 +httptools==0.4.0 humanfriendly==10.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' hyperlink==21.0.0 idna==3.3; python_version >= '3.5' -imap-tools==0.51.1 -img2pdf==0.4.3 -importlib-resources==5.4.0; python_version < '3.9' +imap-tools==0.53.0 +img2pdf==0.4.4 +importlib-resources==5.6.0; python_version < '3.9' incremental==21.3.0 inotify-simple==1.3.5; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' inotifyrecursive==0.3.5 @@ -55,55 +56,58 @@ joblib==1.1.0; python_version >= '3.6' langdetect==1.0.9 lxml==4.8.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' msgpack==1.0.3 -numpy==1.22.2 -ocrmypdf==13.4.0 +numpy==1.22.3; python_version >= '3.8' +ocrmypdf==13.4.2 packaging==21.3; python_version >= '3.6' pathvalidate==2.5.0 -pdfminer.six==20211012 -pikepdf==5.0.1 -pillow==9.0.1 +pdf2image==1.16.0 +pdfminer.six==20220319 +pikepdf==5.1.1 +pillow==9.1.0 pluggy==1.0.0; python_version >= '3.6' portalocker==2.4.0; python_version >= '3' -psycopg2-binary==2.9.3 +psycopg2==2.9.3 pyasn1-modules==0.2.8 pyasn1==0.4.8 -pycparser==2.21; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' -pyopenssl==22.0.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' -pyparsing==3.0.7; python_version >= '3.6' +pycparser==2.21 +pyopenssl==22.0.0 +pyparsing==3.0.8; python_full_version >= '3.6.8' python-dateutil==2.8.2 -python-dotenv==0.19.2 +python-dotenv==0.20.0 python-gnupg==0.4.8 python-levenshtein==0.12.2 python-magic==0.4.25 pytz-deprecation-shim==0.1.0.post0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' -pytz==2021.3 +pytz==2022.1 pyyaml==6.0 +pyzbar==0.1.9 redis==3.5.3 -regex==2022.1.18 -reportlab==3.6.7; python_version >= '3.6' and python_version < '4' +regex==2022.3.2; python_version >= '3.6' +reportlab==3.6.9; python_version >= '3.7' and python_version < '4' requests==2.27.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' -scikit-learn==0.24.0 +scikit-learn==1.0.2 scipy==1.8.0; python_version < '3.11' and python_version >= '3.8' service-identity==21.1.0 -setuptools==60.9.3; python_version >= '3.7' +setuptools==62.1.0; python_version >= '3.7' six==1.16.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +sniffio==1.2.0; python_version >= '3.5' sqlparse==0.4.2; python_version >= '3.5' threadpoolctl==3.1.0; python_version >= '3.6' tika==1.24 -tqdm==4.62.3 -twisted[tls]==22.1.0; python_full_version >= '3.6.7' +tqdm==4.64.0 +twisted[tls]==22.4.0; python_full_version >= '3.6.7' txaio==22.2.1; python_version >= '3.6' typing-extensions==4.1.1; python_version >= '3.6' -tzdata==2021.5; python_version >= '3.6' -tzlocal==4.1; python_version >= '3.6' -urllib3==1.26.8; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4' -uvicorn[standard]==0.17.5 +tzdata==2022.1; python_version >= '3.6' +tzlocal==4.2; python_version >= '3.6' +urllib3==1.26.9; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4' +uvicorn[standard]==0.17.6 uvloop==0.16.0 -watchdog==2.1.6 -watchgod==0.7 +watchdog==2.1.7 +watchgod==0.8.2 wcwidth==0.2.5 websockets==10.2 whitenoise==6.0.0 whoosh==2.7.4 -zipp==3.7.0; python_version < '3.10' +zipp==3.8.0; python_version < '3.9' zope.interface==5.4.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' diff --git a/scripts/start_services.sh b/scripts/start_services.sh index ecc842715..24e3233cd 100755 --- a/scripts/start_services.sh +++ b/scripts/start_services.sh @@ -1,3 +1,5 @@ +#!/usr/bin/env bash + docker run -p 5432:5432 -e POSTGRES_PASSWORD=password -v paperless_pgdata:/var/lib/postgresql/data -d postgres:13 docker run -d -p 6379:6379 redis:latest docker run -p 3000:3000 -d gotenberg/gotenberg:7 diff --git a/src-ui/.gitignore b/src-ui/.gitignore index 53a8849ee..5f427c51c 100644 --- a/src-ui/.gitignore +++ b/src-ui/.gitignore @@ -45,3 +45,7 @@ testem.log # System Files .DS_Store Thumbs.db + +# Cypress +cypress/videos/**/* +cypress/screenshots/**/* diff --git a/src-ui/angular.json b/src-ui/angular.json index e2045737b..0bdd84de4 100644 --- a/src-ui/angular.json +++ b/src-ui/angular.json @@ -16,6 +16,7 @@ "i18n": { "sourceLocale": "en-US", "locales": { + "be-BY": "src/locale/messages.be_BY.xlf", "cs-CZ": "src/locale/messages.cs_CZ.xlf", "da-DK": "src/locale/messages.da_DK.xlf", "de-DE": "src/locale/messages.de_DE.xlf", @@ -30,8 +31,12 @@ "pt-PT": "src/locale/messages.pt_PT.xlf", "ro-RO": "src/locale/messages.ro_RO.xlf", "ru-RU": "src/locale/messages.ru_RU.xlf", - "sv-SE": "src/locale/messages.sv_SE.xlf" - } + "sl-SI": "src/locale/messages.sl_SI.xlf", + "sr-CS": "src/locale/messages.sr_CS.xlf", + "sv-SE": "src/locale/messages.sv_SE.xlf", + "tr-TR": "src/locale/messages.tr_TR.xlf", + "zh-CN": "src/locale/messages.zh_CN.xlf" + } }, "architect": { "build": { @@ -121,12 +126,9 @@ } }, "test": { - "builder": "@angular-devkit/build-angular:karma", + "builder": "@angular-builders/jest:run", "options": { - "main": "src/test.ts", - "polyfills": "src/polyfills.ts", "tsConfig": "tsconfig.spec.json", - "karmaConfig": "karma.conf.js", "assets": [ "src/favicon.ico", "src/apple-touch-icon.png", @@ -140,9 +142,21 @@ } }, "e2e": { - "builder": "@angular-devkit/build-angular:protractor", + "builder": "@cypress/schematic:cypress", + "options": { + "devServerTarget": "paperless-ui:serve", + "watch": true, + "headless": false + }, + "configurations": { + "production": { + "devServerTarget": "paperless-ui:serve:production" + } + } + }, + "cypress-run": { + "builder": "@cypress/schematic:cypress", "options": { - "protractorConfig": "e2e/protractor.conf.js", "devServerTarget": "paperless-ui:serve" }, "configurations": { @@ -150,6 +164,13 @@ "devServerTarget": "paperless-ui:serve:production" } } + }, + "cypress-open": { + "builder": "@cypress/schematic:cypress", + "options": { + "watch": true, + "headless": false + } } } } diff --git a/src-ui/cypress.json b/src-ui/cypress.json new file mode 100644 index 000000000..bd321dcbf --- /dev/null +++ b/src-ui/cypress.json @@ -0,0 +1,9 @@ +{ + "integrationFolder": "cypress/integration", + "supportFile": "cypress/support/index.ts", + "videosFolder": "cypress/videos", + "screenshotsFolder": "cypress/screenshots", + "pluginsFile": "cypress/plugins/index.ts", + "fixturesFolder": "cypress/fixtures", + "baseUrl": "http://localhost:4200" +} \ No newline at end of file diff --git a/src-ui/cypress/fixtures/correspondents/correspondents.json b/src-ui/cypress/fixtures/correspondents/correspondents.json new file mode 100644 index 000000000..fe9fa1d5f --- /dev/null +++ b/src-ui/cypress/fixtures/correspondents/correspondents.json @@ -0,0 +1 @@ +{"count":27,"next":"http://localhost:8000/api/correspondents/?page=2","previous":null,"results":[{"id":9,"slug":"abc-test-correspondent","name":"ABC Test Correspondent","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":13,"slug":"corresp-10","name":"Corresp 10","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":14,"slug":"corresp-11","name":"Corresp 11","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":15,"slug":"corresp-12","name":"Corresp 12","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":16,"slug":"corresp-13","name":"Corresp 13","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":18,"slug":"corresp-15","name":"Corresp 15","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":19,"slug":"corresp-16","name":"Corresp 16","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":20,"slug":"corresp-17","name":"Corresp 17","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":21,"slug":"corresp-18","name":"Corresp 18","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":22,"slug":"corresp-19","name":"Corresp 19","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":23,"slug":"corresp-20","name":"Corresp 20","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":24,"slug":"corresp-21","name":"Corresp 21","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":25,"slug":"corresp-22","name":"Corresp 22","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":26,"slug":"corresp-23","name":"Corresp 23","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":5,"slug":"corresp-3","name":"Corresp 3","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":6,"slug":"corresp-4","name":"Corresp 4","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":7,"slug":"corresp-5","name":"Corresp 5","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":8,"slug":"corresp-6","name":"Corresp 6","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":10,"slug":"corresp-7","name":"Corresp 7","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":11,"slug":"corresp-8","name":"Corresp 8","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":12,"slug":"corresp-9","name":"Corresp 9","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":17,"slug":"correspondent-14","name":"Correspondent 14","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0,"last_correspondence":null},{"id":2,"slug":"correspondent-2","name":"Correspondent 2","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":7,"last_correspondence":"2021-01-20T23:37:58.204614Z"},{"id":27,"slug":"michael-shamoon","name":"Michael Shamoon","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":1,"last_correspondence":"2022-03-16T03:48:50.089624Z"},{"id":4,"slug":"newest-correspondent","name":"Newest Correspondent","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":1,"last_correspondence":"2021-02-07T08:00:00Z"}]} diff --git a/src-ui/cypress/fixtures/document_types/doctypes.json b/src-ui/cypress/fixtures/document_types/doctypes.json new file mode 100644 index 000000000..36c75f2ff --- /dev/null +++ b/src-ui/cypress/fixtures/document_types/doctypes.json @@ -0,0 +1 @@ +{"count":1,"next":null,"previous":null,"results":[{"id":1,"slug":"test","name":"Test Doc Type","match":"","matching_algorithm":1,"is_insensitive":true,"document_count":0}]} diff --git a/src-ui/cypress/fixtures/documents/1/metadata.json b/src-ui/cypress/fixtures/documents/1/metadata.json new file mode 100644 index 000000000..f5bfd9531 --- /dev/null +++ b/src-ui/cypress/fixtures/documents/1/metadata.json @@ -0,0 +1 @@ +{"original_checksum":"e959bc7d593245d92685213264e962ba","original_size":963754,"original_mime_type":"application/pdf","media_filename":"2022/lorem-ipsum.pdf","has_archive_version":true,"original_metadata":[],"archive_checksum":"5a1f46a9150bcade978c764b039ce4d0","archive_media_filename":"2022/lorem-ipsum.pdf","archive_size":351160,"archive_metadata":[{"namespace":"http://ns.adobe.com/pdf/1.3/","prefix":"pdf","key":"Producer","value":"pikepdf5.0.1"},{"namespace":"http://ns.adobe.com/xap/1.0/","prefix":"xmp","key":"ModifyDate","value":"2022-03-22T04:53:18+00:00"},{"namespace":"http://ns.adobe.com/xap/1.0/","prefix":"xmp","key":"CreateDate","value":"2022-03-22T18:05:43+00:00"},{"namespace":"http://ns.adobe.com/xap/1.0/","prefix":"xmp","key":"CreatorTool","value":"ocrmypdf13.4.0/TesseractOCR-PDF4.1.1"},{"namespace":"http://ns.adobe.com/xap/1.0/mm/","prefix":"xmpMM","key":"DocumentID","value":"uuid:df27edcf-e34a-11f7-0000-8fa6067a3c04"},{"namespace":"http://purl.org/dc/elements/1.1/","prefix":"dc","key":"format","value":"application/pdf"},{"namespace":"http://purl.org/dc/elements/1.1/","prefix":"dc","key":"title","value":"ScannedDocument"},{"namespace":"http://www.aiim.org/pdfa/ns/id/","prefix":"pdfaid","key":"part","value":"2"},{"namespace":"http://www.aiim.org/pdfa/ns/id/","prefix":"pdfaid","key":"conformance","value":"B"},{"namespace":"http://purl.org/dc/elements/1.1/","prefix":"dc","key":"creator","value":"None"},{"namespace":"http://ns.adobe.com/xap/1.0/","prefix":"xmp","key":"MetadataDate","value":"2022-03-22T21:53:18.882551-07:00"}]} diff --git a/src-ui/cypress/fixtures/documents/1/suggestions.json b/src-ui/cypress/fixtures/documents/1/suggestions.json new file mode 100644 index 000000000..d9888dbf3 --- /dev/null +++ b/src-ui/cypress/fixtures/documents/1/suggestions.json @@ -0,0 +1 @@ +{"correspondents":[],"tags":[3],"document_types":[1]} diff --git a/src-ui/cypress/fixtures/documents/documents.json b/src-ui/cypress/fixtures/documents/documents.json new file mode 100644 index 000000000..618a3f07c --- /dev/null +++ b/src-ui/cypress/fixtures/documents/documents.json @@ -0,0 +1 @@ +{"count":3,"next":null,"previous":null,"results":[{"id":1,"correspondent":9,"document_type":1,"title":"lorem-ipsum","content":"Test document PDF \n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla est purus, ultrices in porttitor \nin, accumsan non quam. Nam consectetur porttitor rhoncus. Curabitur eu est et leo feugiat \nauctor vel quis lorem. Ut et ligula dolor, sit amet consequat lorem. Aliquam porta eros sed \nvelit imperdiet egestas. Maecenas tempus eros ut diam ullamcorper id dictum libero \ntempor. Donec quis augue quis magna condimentum lobortis. Quisque imperdiet ipsum vel \nmagna viverra rutrum. Cras viverra molestie urna, vitae vestibulum turpis varius id. \nVestibulum mollis, arcu iaculis bibendum varius, velit sapien blandit metus, ac posuere lorem \nnulla ac dolor. Maecenas urna elit, tincidunt in dapibus nec, vehicula eu dui. Duis lacinia \nfringilla massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur \nridiculus mus. Ut consequat ultricies est, non rhoncus mauris congue porta. Vivamus viverra \nsuscipit felis eget condimentum. Cum sociis natoque penatibus et magnis dis parturient \nmontes, nascetur ridiculus mus. Integer bibendum sagittis ligula, non faucibus nulla volutpat \nvitae. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. \nIn aliquet quam et velit bibendum accumsan. Cum sociis natoque penatibus et magnis dis \nparturient montes, nascetur ridiculus mus. Vestibulum vitae ipsum nec arcu semper \nadipiscing at ac lacus. Praesent id pellentesque orci. Morbi congue viverra nisl nec rhoncus. \nInteger mattis, ipsum a tincidunt commodo, lacus arcu elementum elit, at mollis eros ante ac \nrisus. In volutpat, ante at pretium ultricies, velit magna suscipit enim, aliquet blandit massa \norci nec lorem. Nulla facilisi. Duis eu vehicula arcu. Nulla facilisi. Maecenas pellentesque \nvolutpat felis, quis tristique ligula luctus vel. Sed nec mi eros. Integer augue enim, sollicitudin \nullamcorper mattis eget, aliquam in est. Morbi sollicitudin libero nec augue dignissim ut \nconsectetur dui volutpat. Nulla facilisi. Mauris egestas vestibulum neque cursus tincidunt. \nDonec sit amet pulvinar orci. \nQuisque volutpat pharetra tincidunt. Fusce sapien arcu, molestie eget varius egestas, \nfaucibus ac urna. Sed at nisi in velit egestas aliquam ut a felis. Aenean malesuada iaculis nisl, \nut tempor lacus egestas consequat. Nam nibh lectus, gravida sed egestas ut, feugiat quis \ndolor. Donec eu leo enim, non laoreet ante. Morbi dictum tempor vulputate. Phasellus \nultricies risus vel augue sagittis euismod. Vivamus tincidunt placerat nisi in aliquam. Cras \nquis mi ac nunc pretium aliquam. Aenean elementum erat ac metus commodo rhoncus. \nAliquam nulla augue, porta non sagittis quis, accumsan vitae sem. Phasellus id lectus tortor, \neget pulvinar augue. Etiam eget velit ac purus fringilla blandit. Donec odio odio, sagittis sed \niaculis sed, consectetur eget sem. Lorem ipsum dolor sit amet, consectetur adipiscing elit. \nMaecenas accumsan velit vel turpis rutrum in sodales diam placerat. \nQuisque luctus ullamcorper velit sit amet lobortis. Etiam ligula felis, vulputate quis rhoncus \nnec, fermentum eget odio. Vivamus vel ipsum ac augue sodales mollis euismod nec tellus. \nFusce et augue rutrum nunc semper vehicula vel semper nisl. Nam laoreet euismod quam at \nvarius. Sed aliquet auctor nibh. Curabitur malesuada fermentum lacus vel accumsan. Duis \nornare scelerisque nulla, ac pulvinar ligula tempus sit amet. In placerat nulla ac ante \nscelerisque posuere. Phasellus at ante felis. Sed hendrerit risus a metus posuere rutrum. \nPhasellus eu augue dui. Proin in vestibulum ipsum. Aenean accumsan mollis sapien, ut \neleifend sem blandit at. Vivamus luctus mi eget lorem lobortis pharetra. Phasellus at tortor \nquam, a volutpat purus. Etiam sollicitudin arcu vel elit bibendum et imperdiet risus tincidunt. \nEtiam elit velit, posuere ut pulvinar ac, condimentum eget justo. Fusce a erat velit. Vivamus \nimperdiet ultrices orci in hendrerit.","tags":[4],"created":"2022-03-22T07:24:18Z","modified":"2022-03-22T07:24:23.264859Z","added":"2022-03-22T07:24:22.922631Z","archive_serial_number":null,"original_file_name":"2022-03-22 lorem-ipsum.pdf","archived_file_name":"2022-03-22 lorem-ipsum.pdf"},{"id":2,"correspondent":null,"document_type":null,"title":"lorem-ipsum","content":"Test document PDF","tags":[],"created":"2022-03-23T07:24:18Z","modified":"2022-03-23T07:24:23.264859Z","added":"2022-03-23T07:24:22.922631Z","archive_serial_number":null,"original_file_name":"2022-03-23 lorem-ipsum.pdf","archived_file_name":"2022-03-23 lorem-ipsum.pdf"},{"id":3,"correspondent":null,"document_type":1,"title":"lorem-ipsum","content":"Test document PDF","tags":[2],"created":"2022-03-24T07:24:18Z","modified":"2022-03-24T07:24:23.264859Z","added":"2022-03-24T07:24:22.922631Z","archive_serial_number":null,"original_file_name":"2022-03-24 lorem-ipsum.pdf","archived_file_name":"2022-03-24 lorem-ipsum.pdf"}]} diff --git a/src-ui/cypress/fixtures/documents/lorem-ipsum.png b/src-ui/cypress/fixtures/documents/lorem-ipsum.png new file mode 100644 index 000000000..a74f2aee2 Binary files /dev/null and b/src-ui/cypress/fixtures/documents/lorem-ipsum.png differ diff --git a/src-ui/cypress/fixtures/saved_views/savedviews.json b/src-ui/cypress/fixtures/saved_views/savedviews.json new file mode 100644 index 000000000..003bd900a --- /dev/null +++ b/src-ui/cypress/fixtures/saved_views/savedviews.json @@ -0,0 +1 @@ +{"count":3,"next":null,"previous":null,"results":[{"id":1,"name":"Inbox","show_on_dashboard":true,"show_in_sidebar":true,"sort_field":"created","sort_reverse":true,"filter_rules":[{"rule_type":6,"value":"18"}]},{"id":2,"name":"Recently Added","show_on_dashboard":true,"show_in_sidebar":false,"sort_field":"created","sort_reverse":true,"filter_rules":[]},{"id":11,"name":"Taxes","show_on_dashboard":false,"show_in_sidebar":true,"sort_field":"created","sort_reverse":true,"filter_rules":[{"rule_type":6,"value":"39"}]}]} diff --git a/src-ui/cypress/fixtures/tags/tags.json b/src-ui/cypress/fixtures/tags/tags.json new file mode 100644 index 000000000..e48049f93 --- /dev/null +++ b/src-ui/cypress/fixtures/tags/tags.json @@ -0,0 +1 @@ +{"count":8,"next":null,"previous":null,"results":[{"id":4,"slug":"another-sample-tag","name":"Another Sample Tag","color":"#a6cee3","text_color":"#000000","match":"","matching_algorithm":6,"is_insensitive":true,"is_inbox_tag":false,"document_count":3},{"id":7,"slug":"newone","name":"NewOne","color":"#9e4ad1","text_color":"#ffffff","match":"","matching_algorithm":1,"is_insensitive":true,"is_inbox_tag":false,"document_count":2},{"id":6,"slug":"partial-tag","name":"Partial Tag","color":"#72dba7","text_color":"#000000","match":"","matching_algorithm":1,"is_insensitive":true,"is_inbox_tag":false,"document_count":1},{"id":2,"slug":"tag-2","name":"Tag 2","color":"#612db7","text_color":"#ffffff","match":"","matching_algorithm":1,"is_insensitive":true,"is_inbox_tag":false,"document_count":3},{"id":3,"slug":"tag-3","name":"Tag 3","color":"#b2df8a","text_color":"#000000","match":"","matching_algorithm":1,"is_insensitive":true,"is_inbox_tag":false,"document_count":4},{"id":5,"slug":"tagwithpartial","name":"TagWithPartial","color":"#3b2db4","text_color":"#ffffff","match":"","matching_algorithm":6,"is_insensitive":true,"is_inbox_tag":false,"document_count":2},{"id":8,"slug":"test-another","name":"Test Another","color":"#3ccea5","text_color":"#000000","match":"","matching_algorithm":4,"is_insensitive":true,"is_inbox_tag":false,"document_count":0},{"id":1,"slug":"test-tag","name":"Test Tag","color":"#fb9a99","text_color":"#000000","match":"","matching_algorithm":1,"is_insensitive":true,"is_inbox_tag":false,"document_count":4}]} diff --git a/src-ui/cypress/integration/document-detail.spec.ts b/src-ui/cypress/integration/document-detail.spec.ts new file mode 100644 index 000000000..9ff566760 --- /dev/null +++ b/src-ui/cypress/integration/document-detail.spec.ts @@ -0,0 +1,64 @@ +describe('document-detail', () => { + beforeEach(() => { + this.modifiedDocuments = [] + + cy.fixture('documents/documents.json').then((documentsJson) => { + cy.intercept('GET', 'http://localhost:8000/api/documents/1/', (req) => { + let response = { ...documentsJson } + response = response.results.find((d) => d.id == 1) + req.reply(response) + }) + }) + + cy.intercept('PUT', 'http://localhost:8000/api/documents/1/', (req) => { + this.modifiedDocuments.push(req.body) // store this for later + req.reply({ result: 'OK' }) + }).as('saveDoc') + + cy.intercept('http://localhost:8000/api/documents/1/metadata/', { + fixture: 'documents/1/metadata.json', + }) + + cy.intercept('http://localhost:8000/api/documents/1/suggestions/', { + fixture: 'documents/1/suggestions.json', + }) + + cy.intercept('http://localhost:8000/api/saved_views/*', { + fixture: 'saved_views/savedviews.json', + }) + + cy.intercept('http://localhost:8000/api/tags/*', { + fixture: 'tags/tags.json', + }) + + cy.intercept('http://localhost:8000/api/correspondents/*', { + fixture: 'correspondents/correspondents.json', + }) + + cy.intercept('http://localhost:8000/api/document_types/*', { + fixture: 'document_types/doctypes.json', + }) + + cy.viewport(1024, 1024) + cy.visit('/documents/1/') + }) + + it('should activate / deactivate save button when changes are saved', () => { + cy.contains('button', 'Save').should('be.disabled') + cy.get('app-input-text[formcontrolname="title"]') + .type(' additional') + .wait(1500) // this delay is for frontend debounce + cy.contains('button', 'Save').should('not.be.disabled') + }) + + it('should warn on unsaved changes', () => { + cy.get('app-input-text[formcontrolname="title"]') + .type(' additional') + .wait(1500) // this delay is for frontend debounce + cy.get('button[title="Close"]').click() + cy.contains('You have unsaved changes') + cy.contains('button', 'Cancel').click().wait(150) + cy.contains('button', 'Save').click().wait('@saveDoc').wait(2000) // navigates away after saving + cy.contains('You have unsaved changes').should('not.exist') + }) +}) diff --git a/src-ui/cypress/integration/documents-list.spec.ts b/src-ui/cypress/integration/documents-list.spec.ts new file mode 100644 index 000000000..5b923ed2f --- /dev/null +++ b/src-ui/cypress/integration/documents-list.spec.ts @@ -0,0 +1,143 @@ +describe('documents-list', () => { + beforeEach(() => { + this.bulkEdits = {} + + // mock API methods + cy.fixture('documents/documents.json').then((documentsJson) => { + // bulk edit + cy.intercept( + 'POST', + 'http://localhost:8000/api/documents/bulk_edit/', + (req) => { + this.bulkEdits = req.body // store this for later + req.reply({ result: 'OK' }) + } + ) + + cy.intercept('GET', 'http://localhost:8000/api/documents/*', (req) => { + let response = { ...documentsJson } + + // bulkEdits was set earlier by bulk_edit intercept + if (this.bulkEdits.hasOwnProperty('documents')) { + response.results = response.results.map((d) => { + if ((this.bulkEdits['documents'] as Array).includes(d.id)) { + switch (this.bulkEdits['method']) { + case 'modify_tags': + d.tags = (d.tags as Array).concat([ + this.bulkEdits['parameters']['add_tags'], + ]) + break + case 'set_correspondent': + d.correspondent = + this.bulkEdits['parameters']['correspondent'] + break + case 'set_document_type': + d.document_type = + this.bulkEdits['parameters']['document_type'] + break + } + } + + return d + }) + } else if (req.query.hasOwnProperty('tags__id__all')) { + // filtering e.g. http://localhost:8000/api/documents/?page=1&page_size=50&ordering=-created&tags__id__all=2 + const tag_id = +req.query['tags__id__all'] + response.results = (documentsJson.results as Array).filter((d) => + (d.tags as Array).includes(tag_id) + ) + response.count = response.results.length + } + + req.reply(response) + }) + }) + + cy.intercept('http://localhost:8000/api/documents/1/thumb/', { + fixture: 'documents/lorem-ipsum.png', + }) + + cy.intercept('http://localhost:8000/api/tags/*', { + fixture: 'tags/tags.json', + }) + + cy.intercept('http://localhost:8000/api/correspondents/*', { + fixture: 'correspondents/correspondents.json', + }) + + cy.intercept('http://localhost:8000/api/document_types/*', { + fixture: 'document_types/doctypes.json', + }) + + cy.visit('/documents') + }) + + it('should show a list of documents rendered as cards with thumbnails', () => { + cy.contains('3 documents') + cy.contains('lorem-ipsum') + cy.get('app-document-card-small:first-of-type img') + .invoke('attr', 'src') + .should('eq', 'http://localhost:8000/api/documents/1/thumb/') + }) + + it('should change to table "details" view', () => { + cy.get('div.btn-group-toggle input[value="details"]').parent().click() + cy.get('table') + }) + + it('should change to large cards view', () => { + cy.get('div.btn-group-toggle input[value="largeCards"]').parent().click() + cy.get('app-document-card-large') + }) + + it('should filter tags', () => { + cy.get('app-filter-editor app-filterable-dropdown[title="Tags"]').within( + () => { + cy.contains('button', 'Tags').click() + cy.contains('button', 'Tag 2').click() + } + ) + cy.contains('One document') + }) + + it('should apply tags', () => { + cy.get('app-document-card-small:first-of-type').click() + cy.get('app-bulk-editor app-filterable-dropdown[title="Tags"]').within( + () => { + cy.contains('button', 'Tags').click() + cy.contains('button', 'Test Tag').click() + cy.contains('button', 'Apply').click() + } + ) + cy.contains('button', 'Confirm').click() + cy.get('app-document-card-small:first-of-type').contains('Test Tag') + }) + + it('should apply correspondent', () => { + cy.get('app-document-card-small:first-of-type').click() + cy.get( + 'app-bulk-editor app-filterable-dropdown[title="Correspondent"]' + ).within(() => { + cy.contains('button', 'Correspondent').click() + cy.contains('button', 'ABC Test Correspondent').click() + cy.contains('button', 'Apply').click() + }) + cy.contains('button', 'Confirm').click() + cy.get('app-document-card-small:first-of-type').contains( + 'ABC Test Correspondent' + ) + }) + + it('should apply document type', () => { + cy.get('app-document-card-small:first-of-type').click() + cy.get( + 'app-bulk-editor app-filterable-dropdown[title="Document type"]' + ).within(() => { + cy.contains('button', 'Document type').click() + cy.contains('button', 'Test Doc Type').click() + cy.contains('button', 'Apply').click() + }) + cy.contains('button', 'Confirm').click() + cy.get('app-document-card-small:first-of-type').contains('Test Doc Type') + }) +}) diff --git a/src-ui/cypress/integration/manage.spec.ts b/src-ui/cypress/integration/manage.spec.ts new file mode 100644 index 000000000..f0703a4ed --- /dev/null +++ b/src-ui/cypress/integration/manage.spec.ts @@ -0,0 +1,32 @@ +describe('manage', () => { + beforeEach(() => { + cy.intercept('http://localhost:8000/api/correspondents/*', { + fixture: 'correspondents/correspondents.json', + }) + cy.intercept('http://localhost:8000/api/tags/*', { + fixture: 'tags/tags.json', + }) + }) + + it('should show a list of correspondents with bottom pagination as well', () => { + cy.visit('/correspondents') + cy.get('tbody').find('tr').its('length').should('eq', 25) + cy.get('ngb-pagination').its('length').should('eq', 2) + }) + + it('should show a list of tags without bottom pagination', () => { + cy.visit('/tags') + cy.get('tbody').find('tr').its('length').should('eq', 8) + cy.get('ngb-pagination').its('length').should('eq', 1) + }) + + it('should show a list of documents filtered by tag', () => { + cy.intercept('http://localhost:8000/api/documents/*', (req) => { + if (req.url.indexOf('tags__id__all=4')) + req.reply({ count: 3, next: null, previous: null, results: [] }) + }) + cy.visit('/tags') + cy.get('tbody').find('button').contains('Documents').first().click() // id = 4 + cy.contains('3 documents') + }) +}) diff --git a/src-ui/cypress/integration/settings.spec.ts b/src-ui/cypress/integration/settings.spec.ts new file mode 100644 index 000000000..72f9835f2 --- /dev/null +++ b/src-ui/cypress/integration/settings.spec.ts @@ -0,0 +1,91 @@ +describe('settings', () => { + beforeEach(() => { + this.modifiedViews = [] + + // mock API methods + cy.fixture('saved_views/savedviews.json').then((savedViewsJson) => { + // saved views PATCH + cy.intercept( + 'PATCH', + 'http://localhost:8000/api/saved_views/*', + (req) => { + this.modifiedViews.push(req.body) // store this for later + req.reply({ result: 'OK' }) + } + ) + + cy.intercept('GET', 'http://localhost:8000/api/saved_views/*', (req) => { + let response = { ...savedViewsJson } + if (this.modifiedViews.length) { + response.results = response.results.map((v) => { + if (this.modifiedViews.find((mv) => mv.id == v.id)) + v = this.modifiedViews.find((mv) => mv.id == v.id) + return v + }) + } + + req.reply(response) + }).as('savedViews') + }) + + cy.fixture('documents/documents.json').then((documentsJson) => { + cy.intercept('GET', 'http://localhost:8000/api/documents/1/', (req) => { + let response = { ...documentsJson } + response = response.results.find((d) => d.id == 1) + req.reply(response) + }) + }) + + cy.intercept('http://localhost:8000/api/documents/1/metadata/', { + fixture: 'documents/1/metadata.json', + }) + + cy.intercept('http://localhost:8000/api/documents/1/suggestions/', { + fixture: 'documents/1/suggestions.json', + }) + + cy.viewport(1024, 1024) + cy.visit('/settings') + cy.wait('@savedViews') + }) + + it('should activate / deactivate save button when settings change and are saved', () => { + cy.contains('button', 'Save').should('be.disabled') + cy.contains('Use system settings').click() + cy.contains('button', 'Save').should('not.be.disabled') + cy.contains('button', 'Save').click() + cy.contains('button', 'Save').should('be.disabled') + }) + + it('should warn on unsaved changes', () => { + cy.contains('Use system settings').click() + cy.contains('a', 'Dashboard').click() + cy.contains('You have unsaved changes') + cy.contains('button', 'Cancel').click() + cy.contains('button', 'Save').click().wait('@savedViews') + cy.contains('a', 'Dashboard').click() + cy.contains('You have unsaved changes').should('not.exist') + }) + + it('should apply appearance changes when set', () => { + cy.contains('Use system settings').click() + cy.get('body').should('not.have.class', 'color-scheme-system') + cy.contains('Enable dark mode').click() + cy.get('body').should('have.class', 'color-scheme-dark') + }) + + it('should remove saved view from sidebar when unset', () => { + cy.contains('a', 'Saved views').click() + cy.get('#show_in_sidebar_1').click() + cy.contains('button', 'Save').click().wait('@savedViews') + cy.contains('li', 'Inbox').should('not.exist') + }) + + it('should remove saved view from dashboard when unset', () => { + cy.contains('a', 'Saved views').click() + cy.get('#show_on_dashboard_1').click() + cy.contains('button', 'Save').click().wait('@savedViews') + cy.visit('/dashboard') + cy.get('app-saved-view-widget').contains('Inbox').should('not.exist') + }) +}) diff --git a/src-ui/cypress/plugins/index.ts b/src-ui/cypress/plugins/index.ts new file mode 100644 index 000000000..bfc9d3b65 --- /dev/null +++ b/src-ui/cypress/plugins/index.ts @@ -0,0 +1,3 @@ +// Plugins enable you to tap into, modify, or extend the internal behavior of Cypress +// For more info, visit https://on.cypress.io/plugins-api +module.exports = (on, config) => {} diff --git a/src-ui/cypress/support/commands.ts b/src-ui/cypress/support/commands.ts new file mode 100644 index 000000000..af1f44a0f --- /dev/null +++ b/src-ui/cypress/support/commands.ts @@ -0,0 +1,43 @@ +// *********************************************** +// This example namespace declaration will help +// with Intellisense and code completion in your +// IDE or Text Editor. +// *********************************************** +// declare namespace Cypress { +// interface Chainable { +// customCommand(param: any): typeof customCommand; +// } +// } +// +// function customCommand(param: any): void { +// console.warn(param); +// } +// +// NOTE: You can use it like so: +// Cypress.Commands.add('customCommand', customCommand); +// +// *********************************************** +// This example commands.js shows you how to +// create various custom commands and overwrite +// existing commands. +// +// For more comprehensive examples of custom +// commands please read more here: +// https://on.cypress.io/custom-commands +// *********************************************** +// +// +// -- This is a parent command -- +// Cypress.Commands.add("login", (email, password) => { ... }) +// +// +// -- This is a child command -- +// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) +// +// +// -- This is a dual command -- +// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) +// +// +// -- This will overwrite an existing command -- +// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) diff --git a/src-ui/cypress/support/index.ts b/src-ui/cypress/support/index.ts new file mode 100644 index 000000000..ac293b616 --- /dev/null +++ b/src-ui/cypress/support/index.ts @@ -0,0 +1,17 @@ +// *********************************************************** +// This example support/index.js is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +// When a command from ./commands is ready to use, import with `import './commands'` syntax +// import './commands'; diff --git a/src-ui/cypress/tsconfig.json b/src-ui/cypress/tsconfig.json new file mode 100644 index 000000000..79d78d7ec --- /dev/null +++ b/src-ui/cypress/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../tsconfig.json", + "include": ["**/*.ts"], + "compilerOptions": { + "sourceMap": false, + "types": ["cypress"] + } +} diff --git a/src-ui/e2e/protractor.conf.js b/src-ui/e2e/protractor.conf.js index 09a96840f..fc1b55c65 100644 --- a/src-ui/e2e/protractor.conf.js +++ b/src-ui/e2e/protractor.conf.js @@ -2,18 +2,16 @@ // Protractor configuration file, see link for more information // https://github.com/angular/protractor/blob/master/lib/config.ts -const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter'); +const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter') /** * @type { import("protractor").Config } */ exports.config = { allScriptsTimeout: 11000, - specs: [ - './src/**/*.e2e-spec.ts' - ], + specs: ['./src/**/*.e2e-spec.ts'], capabilities: { - browserName: 'chrome' + browserName: 'chrome', }, directConnect: true, baseUrl: 'http://localhost:4200/', @@ -21,16 +19,18 @@ exports.config = { jasmineNodeOpts: { showColors: true, defaultTimeoutInterval: 30000, - print: function() {} + print: function () {}, }, onPrepare() { require('ts-node').register({ - project: require('path').join(__dirname, './tsconfig.json') - }); - jasmine.getEnv().addReporter(new SpecReporter({ - spec: { - displayStacktrace: StacktraceOption.PRETTY - } - })); - } -}; + project: require('path').join(__dirname, './tsconfig.json'), + }) + jasmine.getEnv().addReporter( + new SpecReporter({ + spec: { + displayStacktrace: StacktraceOption.PRETTY, + }, + }) + ) + }, +} diff --git a/src-ui/e2e/src/app.e2e-spec.ts b/src-ui/e2e/src/app.e2e-spec.ts index f2348e0c4..760871864 100644 --- a/src-ui/e2e/src/app.e2e-spec.ts +++ b/src-ui/e2e/src/app.e2e-spec.ts @@ -1,23 +1,25 @@ -import { AppPage } from './app.po'; -import { browser, logging } from 'protractor'; +import { AppPage } from './app.po' +import { browser, logging } from 'protractor' describe('workspace-project App', () => { - let page: AppPage; + let page: AppPage beforeEach(() => { - page = new AppPage(); - }); + page = new AppPage() + }) it('should display welcome message', () => { - page.navigateTo(); - expect(page.getTitleText()).toEqual('paperless-ui app is running!'); - }); + page.navigateTo() + expect(page.getTitleText()).toEqual('paperless-ui app is running!') + }) afterEach(async () => { // Assert that there are no errors emitted from the browser - const logs = await browser.manage().logs().get(logging.Type.BROWSER); - expect(logs).not.toContain(jasmine.objectContaining({ - level: logging.Level.SEVERE, - } as logging.Entry)); - }); -}); + const logs = await browser.manage().logs().get(logging.Type.BROWSER) + expect(logs).not.toContain( + jasmine.objectContaining({ + level: logging.Level.SEVERE, + } as logging.Entry) + ) + }) +}) diff --git a/src-ui/e2e/src/app.po.ts b/src-ui/e2e/src/app.po.ts index b68475e0f..7a2f42e17 100644 --- a/src-ui/e2e/src/app.po.ts +++ b/src-ui/e2e/src/app.po.ts @@ -1,11 +1,13 @@ -import { browser, by, element } from 'protractor'; +import { browser, by, element } from 'protractor' export class AppPage { navigateTo(): Promise { - return browser.get(browser.baseUrl) as Promise; + return browser.get(browser.baseUrl) as Promise } getTitleText(): Promise { - return element(by.css('app-root .content span')).getText() as Promise; + return element( + by.css('app-root .content span') + ).getText() as Promise } } diff --git a/src-ui/jest.config.js b/src-ui/jest.config.js new file mode 100644 index 000000000..23de7b188 --- /dev/null +++ b/src-ui/jest.config.js @@ -0,0 +1,8 @@ +module.exports = { + moduleNameMapper: { + '@core/(.*)': '/src/app/core/$1', + }, + preset: 'jest-preset-angular', + setupFilesAfterEnv: ['/setup-jest.ts'], + testPathIgnorePatterns: ['/node_modules/', '/cypress/'], +} diff --git a/src-ui/karma.conf.js b/src-ui/karma.conf.js deleted file mode 100644 index 9fb9e914b..000000000 --- a/src-ui/karma.conf.js +++ /dev/null @@ -1,32 +0,0 @@ -// Karma configuration file, see link for more information -// https://karma-runner.github.io/1.0/config/configuration-file.html - -module.exports = function (config) { - config.set({ - basePath: '', - frameworks: ['jasmine', '@angular-devkit/build-angular'], - plugins: [ - require('karma-jasmine'), - require('karma-chrome-launcher'), - require('karma-jasmine-html-reporter'), - require('karma-coverage-istanbul-reporter'), - require('@angular-devkit/build-angular/plugins/karma') - ], - client: { - clearContext: false // leave Jasmine Spec Runner output visible in browser - }, - coverageIstanbulReporter: { - dir: require('path').join(__dirname, './coverage/paperless-ui'), - reports: ['html', 'lcovonly', 'text-summary'], - fixWebpackSourcePaths: true - }, - reporters: ['progress', 'kjhtml'], - port: 9876, - colors: true, - logLevel: config.LOG_INFO, - autoWatch: true, - browsers: ['Chrome'], - singleRun: false, - restartOnFileChange: true - }); -}; diff --git a/src-ui/package-lock.json b/src-ui/package-lock.json index 7e5cc049a..1ed0ac0a9 100644 --- a/src-ui/package-lock.json +++ b/src-ui/package-lock.json @@ -8,50 +8,47 @@ "name": "paperless-ui", "version": "0.0.0", "dependencies": { - "@angular/animations": "~13.2.4", - "@angular/common": "~13.2.5", - "@angular/compiler": "~13.2.4", - "@angular/core": "~13.2.4", - "@angular/forms": "~13.2.5", - "@angular/localize": "~13.2.4", - "@angular/platform-browser": "~13.2.5", - "@angular/platform-browser-dynamic": "~13.2.4", - "@angular/router": "~13.2.5", - "@ng-bootstrap/ng-bootstrap": "^12.0.0", + "@angular/common": "~13.3.1", + "@angular/compiler": "~13.3.1", + "@angular/core": "~13.3.1", + "@angular/forms": "~13.3.1", + "@angular/localize": "~13.3.1", + "@angular/platform-browser": "~13.3.1", + "@angular/platform-browser-dynamic": "~13.3.1", + "@angular/router": "~13.3.1", + "@ng-bootstrap/ng-bootstrap": "^12.0.1", "@ng-select/ng-select": "^8.1.1", - "@ngneat/dirty-check-forms": "^1.1.0", - "@popperjs/core": "^2.11.2", + "@ngneat/dirty-check-forms": "^3.0.2", + "@popperjs/core": "^2.11.4", "bootstrap": "^5.1.3", "file-saver": "^2.0.5", - "ng2-pdf-viewer": "^8.0.1", + "ng2-pdf-viewer": "^9.0.0", "ngx-color": "^7.3.3", "ngx-cookie-service": "^13.1.2", "ngx-file-drop": "^13.0.0", - "ngx-infinite-scroll": "^10.0.1", - "rxjs": "~6.6.7", + "rxjs": "~7.5.5", "tslib": "^2.3.1", "uuid": "^8.3.1", "zone.js": "~0.11.4" }, "devDependencies": { - "@angular-devkit/build-angular": "~13.2.5", - "@angular/cli": "~13.2.5", - "@angular/compiler-cli": "~13.2.4", - "@types/jasmine": "~3.10.3", - "@types/jasminewd2": "~2.0.10", - "@types/node": "^17.0.21", + "@angular-builders/jest": "13.0.3", + "@angular-devkit/build-angular": "~13.3.1", + "@angular/cli": "~13.3.1", + "@angular/compiler-cli": "~13.3.1", + "@types/jest": "27.4.1", + "@types/node": "^17.0.23", "codelyzer": "^6.0.2", - "jasmine-core": "~4.0.1", - "jasmine-spec-reporter": "~7.0.0", - "karma": "~6.3.16", - "karma-chrome-launcher": "~3.1.0", - "karma-coverage-istanbul-reporter": "~3.0.3", - "karma-jasmine": "~4.0.1", - "karma-jasmine-html-reporter": "^1.7.0", - "protractor": "~7.0.0", + "concurrently": "7.0.0", + "jest": "27.5.1", "ts-node": "~10.7.0", "tslint": "~6.1.3", - "typescript": "~4.5.5" + "typescript": "~4.6.3", + "wait-on": "~6.0.1" + }, + "optionalDependencies": { + "@cypress/schematic": "^1.6.0", + "cypress": "~9.5.3" } }, "node_modules/@ampproject/remapping": { @@ -67,13 +64,31 @@ "node": ">=6.0.0" } }, - "node_modules/@angular-devkit/architect": { - "version": "0.1302.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1302.5.tgz", - "integrity": "sha512-r07oo8GgUGY28SR3PCM1qNfLE6PNx6SfzBlG4p0OrQQ68ln8HipsEysDGakOWjNFK18SCGWOXAUNrUj8GnV+5g==", + "node_modules/@angular-builders/jest": { + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/@angular-builders/jest/-/jest-13.0.3.tgz", + "integrity": "sha512-HJfN8gCfbg14U/eaE5vEvt6IrecFTUWSibHLvf2gBMzgnRQzqPKNAAoHY5kZ0DL+HwsCW/KlSp2m47ukOdVcYA==", "dev": true, "dependencies": { - "@angular-devkit/core": "13.2.5", + "@angular-devkit/architect": ">=0.1300.0 < 0.1400.0", + "@angular-devkit/core": "^13.0.0", + "jest-preset-angular": "11.1.0", + "lodash": "^4.17.15" + }, + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "jest": ">=27" + } + }, + "node_modules/@angular-devkit/architect": { + "version": "0.1303.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1303.1.tgz", + "integrity": "sha512-ppaLzNZPrqrI96ddgm1RuEALVpWZsmHbIPLDd0GBwhF6aOkwF0LpZHd5XyS4ktGFZPReiFIjWSVtqV5vaBdRsw==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "13.3.1", "rxjs": "6.6.7" }, "engines": { @@ -82,16 +97,34 @@ "yarn": ">= 1.13.0" } }, + "node_modules/@angular-devkit/architect/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/@angular-devkit/architect/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, "node_modules/@angular-devkit/build-angular": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-13.2.5.tgz", - "integrity": "sha512-ny80YoLOrS6USJCzCChj1ZOEVTldcx0KWo3e86barmt5iVA2ekrnsQ02Bor5Bl5NlZFpE6Fu0FCXFAQZElFmcg==", + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-13.3.1.tgz", + "integrity": "sha512-xxBW4zZZM+lewW0nEpk9SXw6BMYhxe8WI/FjyEroOV8G2IuOrjZ4112QOpk6jCgmPHSOEldbltEdwoVLAnu09Q==", "dev": true, "dependencies": { "@ampproject/remapping": "1.1.1", - "@angular-devkit/architect": "0.1302.5", - "@angular-devkit/build-webpack": "0.1302.5", - "@angular-devkit/core": "13.2.5", + "@angular-devkit/architect": "0.1303.1", + "@angular-devkit/build-webpack": "0.1303.1", + "@angular-devkit/core": "13.3.1", "@babel/core": "7.16.12", "@babel/generator": "7.16.8", "@babel/helper-annotate-as-pure": "7.16.7", @@ -102,7 +135,7 @@ "@babel/runtime": "7.16.7", "@babel/template": "7.16.7", "@discoveryjs/json-ext": "0.5.6", - "@ngtools/webpack": "13.2.5", + "@ngtools/webpack": "13.3.1", "ansi-colors": "4.1.1", "babel-loader": "8.2.3", "babel-plugin-istanbul": "6.1.1", @@ -136,7 +169,7 @@ "regenerator-runtime": "0.13.9", "resolve-url-loader": "5.0.0", "rxjs": "6.6.7", - "sass": "1.49.0", + "sass": "1.49.9", "sass-loader": "12.4.0", "semver": "7.3.5", "source-map-loader": "3.0.1", @@ -147,7 +180,7 @@ "text-table": "0.2.0", "tree-kill": "1.2.2", "tslib": "2.3.1", - "webpack": "5.67.0", + "webpack": "5.70.0", "webpack-dev-middleware": "5.3.0", "webpack-dev-server": "4.7.3", "webpack-merge": "5.8.0", @@ -162,14 +195,14 @@ "esbuild": "0.14.22" }, "peerDependencies": { - "@angular/compiler-cli": "^13.0.0", - "@angular/localize": "^13.0.0", - "@angular/service-worker": "^13.0.0", + "@angular/compiler-cli": "^13.0.0 || ^13.3.0-rc.0", + "@angular/localize": "^13.0.0 || ^13.3.0-rc.0", + "@angular/service-worker": "^13.0.0 || ^13.3.0-rc.0", "karma": "^6.3.0", "ng-packagr": "^13.0.0", "protractor": "^7.0.0", "tailwindcss": "^2.0.0 || ^3.0.0", - "typescript": ">=4.4.3 <4.6" + "typescript": ">=4.4.3 <4.7" }, "peerDependenciesMeta": { "@angular/localize": { @@ -192,13 +225,31 @@ } } }, - "node_modules/@angular-devkit/build-webpack": { - "version": "0.1302.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1302.5.tgz", - "integrity": "sha512-hxtFDX1cQaGfpHMSWRqfMO9/hucfIz61C0Lc/QGg9spay1Dvjwe+JpEoKMv3mz1K2fwHO9Hr5ZBAYFT4C5mxZQ==", + "node_modules/@angular-devkit/build-angular/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": { - "@angular-devkit/architect": "0.1302.5", + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/rxjs/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/@angular-devkit/build-webpack": { + "version": "0.1303.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1303.1.tgz", + "integrity": "sha512-KSnR3y2q5hxh7t7ZSi0Emv/Kh9+D105JaEeyEqjqRjLdZSd2m6eAxbSUMNOAsbqnJTMCfzU5AG7jhbujuge0dQ==", + "dev": true, + "dependencies": { + "@angular-devkit/architect": "0.1303.1", "rxjs": "6.6.7" }, "engines": { @@ -211,10 +262,28 @@ "webpack-dev-server": "^4.0.0" } }, + "node_modules/@angular-devkit/build-webpack/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/@angular-devkit/build-webpack/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, "node_modules/@angular-devkit/core": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-13.2.5.tgz", - "integrity": "sha512-WuWp/1R0FtCHPBcJLF13lTLHETtDGFUX0ULfGPRaYB5OVCSQcovVp5UbZTTy/Ss3ub3EOEmJlU8kMJfBrWuq+A==", + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-13.3.1.tgz", + "integrity": "sha512-eXAcQaP1mn6rnQb+5bv5NsamY6b34UYM7G+S154Hnma6CTTSGBtcmoNAJs8cekuFqWlw7YgpB/e15jR5OLPkDA==", "dev": true, "dependencies": { "ajv": "8.9.0", @@ -238,13 +307,31 @@ } } }, - "node_modules/@angular-devkit/schematics": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-13.2.5.tgz", - "integrity": "sha512-kAye6VYiF9JQAoeO+BYhy8eT2QOmhB+WLziRjXoFCBxh5+yXTygTVfs9fD5jmIpHmeu4hd2ErSh69yT5xWcD9g==", + "node_modules/@angular-devkit/core/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": { - "@angular-devkit/core": "13.2.5", + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular-devkit/core/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/@angular-devkit/schematics": { + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-13.3.1.tgz", + "integrity": "sha512-DxXMjlq/sALcHuONZRMTBX5k30XPfN4b6Ue4k7Xl8JKZqyHhEzfXaZzgD9u2cwb7wybKEeF/BZ5eJd8JG525og==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "13.3.1", "jsonc-parser": "3.0.0", "magic-string": "0.25.7", "ora": "5.4.1", @@ -256,31 +343,35 @@ "yarn": ">= 1.13.0" } }, - "node_modules/@angular/animations": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-13.2.5.tgz", - "integrity": "sha512-1mGOePSDTiVwNIuV2g3+mUHrZJAkqJVzRKqKyNPXdwZupzVAgAfLbfUC07hhD/H53mXupIVugcUMFC3dvMu7uQ==", + "node_modules/@angular-devkit/schematics/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": "^2.3.0" + "tslib": "^1.9.0" }, "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0" - }, - "peerDependencies": { - "@angular/core": "13.2.5" + "npm": ">=2.0.0" } }, + "node_modules/@angular-devkit/schematics/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, "node_modules/@angular/cli": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-13.2.5.tgz", - "integrity": "sha512-S1uuScNCue6K7HpSG707/N+ULy+utrByeYLjx8zIwIOW1/ZjLB+1/Dxem3bu/OSLY2j2R7bX1WHw8Mnljnk4QQ==", + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-13.3.1.tgz", + "integrity": "sha512-0uwU8v3V/2s95X4cZT582J6upReT/ZNw/VAf4p4q51JN+BBvdCEb251xTF+TcOojyToFyJYvg8T28XSrsNsmTQ==", "dev": true, "hasInstallScript": true, "dependencies": { - "@angular-devkit/architect": "0.1302.5", - "@angular-devkit/core": "13.2.5", - "@angular-devkit/schematics": "13.2.5", - "@schematics/angular": "13.2.5", + "@angular-devkit/architect": "0.1303.1", + "@angular-devkit/core": "13.3.1", + "@angular-devkit/schematics": "13.3.1", + "@schematics/angular": "13.3.1", "@yarnpkg/lockfile": "1.1.0", "ansi-colors": "4.1.1", "debug": "4.3.3", @@ -307,9 +398,9 @@ } }, "node_modules/@angular/common": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-13.2.5.tgz", - "integrity": "sha512-px2qZP8Fd2qYbCVWmgLmop2OBQ/LKU2Oq8U/La2EEo8kgVuNWNTxmIh826cgZK/v9VQw8b/EoU7PeEjSWz0Zow==", + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-13.3.1.tgz", + "integrity": "sha512-Var5ChoX8kZl9cbIWbW7Reb3Xz3t1c1XHwq1k+oK2fgrPdEfypY9n/6DxyXOtSEGb9aV7ZCaxcv2c5JUKR3OPg==", "dependencies": { "tslib": "^2.3.0" }, @@ -317,14 +408,14 @@ "node": "^12.20.0 || ^14.15.0 || >=16.10.0" }, "peerDependencies": { - "@angular/core": "13.2.5", + "@angular/core": "13.3.1", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-13.2.5.tgz", - "integrity": "sha512-OF7xqs/7HPyRJXWiP8ZLwcgT+O/pyBdTjubrVNUPmzeKWPFyE9ZVKEg8MLGLbGHRtw1omhU9Mq4b12NqI1B/gA==", + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-13.3.1.tgz", + "integrity": "sha512-ppJURRRDPZB6UaZctH6yBsznZXB7wZdCpfy5yo4lFE4k8rygfV80TmnrbJBZXNNq057VK48Bap1tsehFwckjog==", "dependencies": { "tslib": "^2.3.0" }, @@ -333,16 +424,15 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-13.2.5.tgz", - "integrity": "sha512-Xd8xj2Z0ilA4TJAM/JkTtA1CAa6SuebFsEEvabHCRO5MDvtdsIUP91ADUZIqDHy7qe6Qift/rAVN2PXxT2aaNA==", - "dev": true, + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-13.3.1.tgz", + "integrity": "sha512-dImxLUITNwODlXaLcEACw10bxTiajWEQz3sLwhT/936UH+MNtM/RyLJ0M7xDvILDqq77W3psK5/M6F3M1mUpew==", "dependencies": { "@babel/core": "^7.17.2", "chokidar": "^3.0.0", "convert-source-map": "^1.5.1", "dependency-graph": "^0.11.0", - "magic-string": "^0.25.0", + "magic-string": "^0.26.0", "reflect-metadata": "^0.1.2", "semver": "^7.0.0", "sourcemap-codec": "^1.4.8", @@ -358,15 +448,14 @@ "node": "^12.20.0 || ^14.15.0 || >=16.10.0" }, "peerDependencies": { - "@angular/compiler": "13.2.5", - "typescript": ">=4.4.2 <4.6" + "@angular/compiler": "13.3.1", + "typescript": ">=4.4.2 <4.7" } }, "node_modules/@angular/compiler-cli/node_modules/@ampproject/remapping": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", - "dev": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.0" }, @@ -375,18 +464,17 @@ } }, "node_modules/@angular/compiler-cli/node_modules/@babel/core": { - "version": "7.17.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.5.tgz", - "integrity": "sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA==", - "dev": true, + "version": "7.17.8", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.8.tgz", + "integrity": "sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ==", "dependencies": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.3", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helpers": "^7.17.2", - "@babel/parser": "^7.17.3", + "@babel/generator": "^7.17.7", + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-module-transforms": "^7.17.7", + "@babel/helpers": "^7.17.8", + "@babel/parser": "^7.17.8", "@babel/template": "^7.16.7", "@babel/traverse": "^7.17.3", "@babel/types": "^7.17.0", @@ -408,16 +496,14 @@ "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/@angular/compiler-cli/node_modules/@babel/generator": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.3.tgz", - "integrity": "sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==", - "dev": true, + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.7.tgz", + "integrity": "sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==", "dependencies": { "@babel/types": "^7.17.0", "jsesc": "^2.5.1", @@ -427,19 +513,29 @@ "node": ">=6.9.0" } }, + "node_modules/@angular/compiler-cli/node_modules/magic-string": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.1.tgz", + "integrity": "sha512-ndThHmvgtieXe8J/VGPjG+Apu7v7ItcD5mhEIvOscWjPF/ccOiLxHaSuCAS2G+3x4GKsAbT8u7zdyamupui8Tg==", + "dependencies": { + "sourcemap-codec": "^1.4.8" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@angular/compiler-cli/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/@angular/core": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-13.2.5.tgz", - "integrity": "sha512-4CC69JQbgyETJR6xsQk6hOQqb6fBGZ/Qc333x0hwRDBbGnYE6hQehDibV+Apljea8YjV+NX6VmyOvPvHhtL4PQ==", + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-13.3.1.tgz", + "integrity": "sha512-ZU/B9jEiZ0jadRkRL9Sb2btzqgQ0ylx380PfRQaojVIsij/EO6+jOSHIo5upMIGu/OvkggfweShJGlylCOrOXA==", "dependencies": { "tslib": "^2.3.0" }, @@ -452,9 +548,9 @@ } }, "node_modules/@angular/forms": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-13.2.5.tgz", - "integrity": "sha512-0IOSj6OxW7fcaOLxaBydzFot3QsyQXeASXkq5xXGT10IsufVlnMS6wCULy/Ru3C1YAZZEM/z2rU+2yjjflea6A==", + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-13.3.1.tgz", + "integrity": "sha512-S6a/CEq1ht0vw2epuESiO551dsyLQTb/HuwceIBlsX2JqRRccynYlyx92gsDAo4hD2F0q+EeqZEPuq3oQIK43A==", "dependencies": { "tslib": "^2.3.0" }, @@ -462,16 +558,16 @@ "node": "^12.20.0 || ^14.15.0 || >=16.10.0" }, "peerDependencies": { - "@angular/common": "13.2.5", - "@angular/core": "13.2.5", - "@angular/platform-browser": "13.2.5", + "@angular/common": "13.3.1", + "@angular/core": "13.3.1", + "@angular/platform-browser": "13.3.1", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/localize": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-13.2.5.tgz", - "integrity": "sha512-K5uitSEPw0EJCYKpn5DkWvBqeN0uLXf3nr594hMHRfD+I7INnMZkZoqb6SuT1/VQhWbGfqb4XkTPlOBYe1Kb3w==", + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-13.3.1.tgz", + "integrity": "sha512-1s51ufL28EZuDQJ6+dHvLA9yyR8O9dpqS1PFrtNo9OcD62/JiDI8CHQlAdk2kmU5eTmulDf39sSLbOsDUGPGuQ==", "dependencies": { "@babel/core": "7.17.2", "glob": "7.2.0", @@ -486,8 +582,8 @@ "node": "^12.20.0 || ^14.15.0 || >=16.10.0" }, "peerDependencies": { - "@angular/compiler": "13.2.5", - "@angular/compiler-cli": "13.2.5" + "@angular/compiler": "13.3.1", + "@angular/compiler-cli": "13.3.1" } }, "node_modules/@angular/localize/node_modules/@ampproject/remapping": { @@ -531,9 +627,9 @@ } }, "node_modules/@angular/localize/node_modules/@babel/generator": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.3.tgz", - "integrity": "sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.7.tgz", + "integrity": "sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==", "dependencies": { "@babel/types": "^7.17.0", "jsesc": "^2.5.1", @@ -560,9 +656,9 @@ } }, "node_modules/@angular/platform-browser": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-13.2.5.tgz", - "integrity": "sha512-/M8ZpBftXC6vXDpxop1mLfbkvP2naUHBJmMRAQkJMLN4UlZKP3J+yjC8CN8uzQx0Y6Zt3G+LrGdOWYD9IRXBvw==", + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-13.3.1.tgz", + "integrity": "sha512-WtyrkK0pLYj6w7pz3xk8zlhWL1NwGCWT+k7YxEjBOONCIXlZvCqWVzWo4nNQn9Xqxd+z1FVI0dssDwZm2TD+Eg==", "dependencies": { "tslib": "^2.3.0" }, @@ -570,9 +666,9 @@ "node": "^12.20.0 || ^14.15.0 || >=16.10.0" }, "peerDependencies": { - "@angular/animations": "13.2.5", - "@angular/common": "13.2.5", - "@angular/core": "13.2.5" + "@angular/animations": "13.3.1", + "@angular/common": "13.3.1", + "@angular/core": "13.3.1" }, "peerDependenciesMeta": { "@angular/animations": { @@ -581,9 +677,9 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-13.2.5.tgz", - "integrity": "sha512-5NMlp/3DF7EOEMqtAoQ04Kuhyr9KqQmUt9skfei1AL5KyqKXnyxUVePIG+HqpwkeTV8P7XegR2+pZMfvxo/gPA==", + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-13.3.1.tgz", + "integrity": "sha512-TKV63SSyjrv5EsD03PloCbo8ZrJq5owkJ38E2FO/VvJAV3xu3Ey0SnoikNZMd8o3rh7+ocuT5K9Xcr4YuKVgEA==", "dependencies": { "tslib": "^2.3.0" }, @@ -591,16 +687,16 @@ "node": "^12.20.0 || ^14.15.0 || >=16.10.0" }, "peerDependencies": { - "@angular/common": "13.2.5", - "@angular/compiler": "13.2.5", - "@angular/core": "13.2.5", - "@angular/platform-browser": "13.2.5" + "@angular/common": "13.3.1", + "@angular/compiler": "13.3.1", + "@angular/core": "13.3.1", + "@angular/platform-browser": "13.3.1" } }, "node_modules/@angular/router": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-13.2.5.tgz", - "integrity": "sha512-R0U8/QR8YbVeDuvGHpdf61hygVVBbD8j5pIr+kD8vUmYYnn3447XdZg9zkQ9qaQUvBSV0voNIOffUfoP2HaBSw==", + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-13.3.1.tgz", + "integrity": "sha512-YpZLjI4UI9KK6x8yn41XMrBWZgVb5JyJR7KNhQXB7WiX8bVH5SZzFRkjR3qUxTGaxe6I7KFvzySwm4JTYNj+xw==", "dependencies": { "tslib": "^2.3.0" }, @@ -608,9 +704,9 @@ "node": "^12.20.0 || ^14.15.0 || >=16.10.0" }, "peerDependencies": { - "@angular/common": "13.2.5", - "@angular/core": "13.2.5", - "@angular/platform-browser": "13.2.5", + "@angular/common": "13.3.1", + "@angular/core": "13.3.1", + "@angular/platform-browser": "13.3.1", "rxjs": "^6.5.3 || ^7.4.0" } }, @@ -632,9 +728,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", - "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.7.tgz", + "integrity": "sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ==", "engines": { "node": ">=6.9.0" } @@ -643,7 +739,6 @@ "version": "7.16.12", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.12.tgz", "integrity": "sha512-dK5PtG1uiN2ikk++5OzSYsitZKny4wOCD0nrO4TqnW4BVBTQ2NGS3NgilvT/TEyxTST7LNyWV/T4tXDoD3fOgg==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.16.7", "@babel/generator": "^7.16.8", @@ -673,7 +768,6 @@ "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" } @@ -682,7 +776,6 @@ "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" } @@ -691,7 +784,6 @@ "version": "7.16.8", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.8.tgz", "integrity": "sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw==", - "dev": true, "dependencies": { "@babel/types": "^7.16.8", "jsesc": "^2.5.1", @@ -705,7 +797,6 @@ "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" } @@ -736,11 +827,11 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", - "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.7.tgz", + "integrity": "sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w==", "dependencies": { - "@babel/compat-data": "^7.16.4", + "@babel/compat-data": "^7.17.7", "@babel/helper-validator-option": "^7.16.7", "browserslist": "^4.17.5", "semver": "^6.3.0" @@ -884,12 +975,12 @@ } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", - "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz", + "integrity": "sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw==", "dev": true, "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.17.0" }, "engines": { "node": ">=6.9.0" @@ -907,13 +998,13 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.6.tgz", - "integrity": "sha512-2ULmRdqoOMpdvkbT8jONrZML/XALfzxlb052bldftkicAUy8AxSCkD5trDPQcwHNmolcl7wP6ehNqMlyUw6AaA==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz", + "integrity": "sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw==", "dependencies": { "@babel/helper-environment-visitor": "^7.16.7", "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", "@babel/helper-split-export-declaration": "^7.16.7", "@babel/helper-validator-identifier": "^7.16.7", "@babel/template": "^7.16.7", @@ -976,11 +1067,11 @@ } }, "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==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz", + "integrity": "sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA==", "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.17.0" }, "engines": { "node": ">=6.9.0" @@ -1041,12 +1132,12 @@ } }, "node_modules/@babel/helpers": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz", - "integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==", + "version": "7.17.8", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.8.tgz", + "integrity": "sha512-QcL86FGxpfSJwGtAvv4iG93UL6bmqBdmoVY0CMCU2g+oD2ezQse3PT5Pa+jiD6LJndBQi0EDlpzOWNlLuhz5gw==", "dependencies": { "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.0", + "@babel/traverse": "^7.17.3", "@babel/types": "^7.17.0" }, "engines": { @@ -1067,9 +1158,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.3.tgz", - "integrity": "sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==", + "version": "7.17.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.8.tgz", + "integrity": "sha512-BoHhDJrJXqcg+ZL16Xv39H9n+AqJ4pcDrQBGZN+wHxIysrLZ3/ECwCBUch/1zUNhnsXULcONU3Ei5Hmkfk6kiQ==", "bin": { "parser": "bin/babel-parser.js" }, @@ -1369,6 +1460,18 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-class-properties": { "version": "7.12.13", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", @@ -1420,6 +1523,18 @@ "@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", @@ -1534,6 +1649,21 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz", + "integrity": "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==", + "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-arrow-functions": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz", @@ -1634,9 +1764,9 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.3.tgz", - "integrity": "sha512-dDFzegDYKlPqa72xIlbmSkly5MluLoaC1JswABGktyt6NTXSBcUuse/kWE/wvKFWJHPETpi158qJZFS3JmykJg==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.7.tgz", + "integrity": "sha512-XVh0r5yq9sLR4vZ6eVZe8FKfIcSgaTBxVBRSYokRj2qksf6QerYnTxz9/GTuKTH/n/HwLP7t6gtlybHetJ/6hQ==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.16.7" @@ -1775,14 +1905,14 @@ } }, "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==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.7.tgz", + "integrity": "sha512-ITPmR2V7MqioMJyrxUo2onHNC3e+MvfFiFIR0RP21d3PtlVb6sfzoxNKiphSZUOM9hEIdzCcZe83ieX3yoqjUA==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-module-transforms": "^7.17.7", "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", "babel-plugin-dynamic-import-node": "^2.3.3" }, "engines": { @@ -1793,13 +1923,13 @@ } }, "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==", + "version": "7.17.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.17.8.tgz", + "integrity": "sha512-39reIkMTUVagzgA5x88zDYXPCMT6lcaRKs1+S9K6NKBPErbgO/w/kP8GlNQTC87b412ZTlmNgr3k2JrWgHH+Bw==", "dev": true, "dependencies": { "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-module-transforms": "^7.17.7", "@babel/helper-plugin-utils": "^7.16.7", "@babel/helper-validator-identifier": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" @@ -2228,9 +2358,9 @@ } }, "node_modules/@babel/traverse/node_modules/@babel/generator": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.3.tgz", - "integrity": "sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.7.tgz", + "integrity": "sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==", "dependencies": { "@babel/types": "^7.17.0", "jsesc": "^2.5.1", @@ -2260,14 +2390,11 @@ "node": ">=6.9.0" } }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "dev": true, - "engines": { - "node": ">=0.1.90" - } + "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/@cspotcode/source-map-consumer": { "version": "0.8.0", @@ -2313,6 +2440,185 @@ "node": ">=10" } }, + "node_modules/@cypress/request": { + "version": "2.88.10", + "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.10.tgz", + "integrity": "sha512-Zp7F+R93N0yZyG34GutyTNr+okam7s/Fzc1+i3kcqOP8vk6OuajuE9qZJ6Rs+10/1JFtXFYMdyarnU1rZuJesg==", + "optional": true, + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "http-signature": "~1.3.6", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@cypress/schematic": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@cypress/schematic/-/schematic-1.6.0.tgz", + "integrity": "sha512-ENHceK21AANBCthaiQ4gJGEvHsqJ9wS3b9PjnlD4MKOMzqwU/WMrJAs/Xnxa6PGh3btB2w0xNN+0beeaf0KiCA==", + "optional": true, + "dependencies": { + "@angular-devkit/architect": "^0.1202.10", + "@angular-devkit/core": "^12.2.10", + "@angular-devkit/schematics": "^12.2.10", + "@schematics/angular": "^12.2.10", + "jsonc-parser": "^3.0.0", + "rxjs": "~6.6.0" + } + }, + "node_modules/@cypress/schematic/node_modules/@angular-devkit/architect": { + "version": "0.1202.17", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1202.17.tgz", + "integrity": "sha512-uUQcHcLbPvr9adALQSLU1MTDduVUR2kZAHi2e7SmL9ioel84pPVXBoD0WpSBeUMKwPiDs3TQDaxDB49hl0nBSQ==", + "optional": true, + "dependencies": { + "@angular-devkit/core": "12.2.17", + "rxjs": "6.6.7" + }, + "engines": { + "node": "^12.14.1 || >=14.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@cypress/schematic/node_modules/@angular-devkit/core": { + "version": "12.2.17", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-12.2.17.tgz", + "integrity": "sha512-PyOY7LGUPPd6rakxUYbfQN6zAdOCMCouVp5tERY1WTdMdEiuULOtHsPee8kNbh75pD59KbJNU+fwozPRMuIm5g==", + "optional": true, + "dependencies": { + "ajv": "8.6.2", + "ajv-formats": "2.1.0", + "fast-json-stable-stringify": "2.1.0", + "magic-string": "0.25.7", + "rxjs": "6.6.7", + "source-map": "0.7.3" + }, + "engines": { + "node": "^12.14.1 || >=14.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@cypress/schematic/node_modules/@angular-devkit/schematics": { + "version": "12.2.17", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-12.2.17.tgz", + "integrity": "sha512-c0eNu/nx1Mnu7KcZgYTYHP736H4Y9pSyLBSmLAHYZv3t3m0dIPbhifRcLQX7hHQ8fGT2ZFxmOpaQG5/DcIghSw==", + "optional": true, + "dependencies": { + "@angular-devkit/core": "12.2.17", + "ora": "5.4.1", + "rxjs": "6.6.7" + }, + "engines": { + "node": "^12.14.1 || >=14.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@cypress/schematic/node_modules/@schematics/angular": { + "version": "12.2.17", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-12.2.17.tgz", + "integrity": "sha512-HM/4KkQu944KL5ebhIyy1Ot5OV6prHNW7kmGeMVeQefLSbbfMQCHLa1psB9UU9BoahwGhUBvleLylNSitOBCgg==", + "optional": true, + "dependencies": { + "@angular-devkit/core": "12.2.17", + "@angular-devkit/schematics": "12.2.17", + "jsonc-parser": "3.0.0" + }, + "engines": { + "node": "^12.14.1 || >=14.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@cypress/schematic/node_modules/ajv": { + "version": "8.6.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.2.tgz", + "integrity": "sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w==", + "optional": 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/@cypress/schematic/node_modules/ajv-formats": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.0.tgz", + "integrity": "sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q==", + "optional": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/@cypress/schematic/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "optional": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@cypress/schematic/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "optional": true + }, + "node_modules/@cypress/xvfb": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz", + "integrity": "sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==", + "optional": true, + "dependencies": { + "debug": "^3.1.0", + "lodash.once": "^4.1.1" + } + }, + "node_modules/@cypress/xvfb/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "optional": true, + "dependencies": { + "ms": "^2.1.1" + } + }, "node_modules/@discoveryjs/json-ext": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.6.tgz", @@ -2328,6 +2634,21 @@ "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", "dev": true }, + "node_modules/@hapi/hoek": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.1.tgz", + "integrity": "sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw==", + "dev": true + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, "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", @@ -2353,6 +2674,659 @@ "node": ">=8" } }, + "node_modules/@jest/console": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", + "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "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/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/@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.5.1", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", + "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", + "dev": true, + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/reporters": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^27.5.1", + "jest-config": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-resolve-dependencies": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "jest-watcher": "^27.5.1", + "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/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/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/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/@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.5.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", + "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", + "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "@sinonjs/fake-timers": "^8.0.1", + "@types/node": "*", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", + "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/types": "^27.5.1", + "expect": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", + "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.9", + "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.5.1", + "jest-resolve": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "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/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/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/@jest/reporters/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/@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.5.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", + "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9", + "source-map": "^0.6.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/source-map/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/@jest/test-result": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", + "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", + "dev": true, + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/types": "^27.5.1", + "@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-sequencer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", + "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", + "dev": true, + "dependencies": { + "@jest/test-result": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-runtime": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.5.1", + "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.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "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/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/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/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/@jest/transform/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/@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": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "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/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" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/types/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/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/resolve-uri": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", @@ -2376,9 +3350,9 @@ } }, "node_modules/@ng-bootstrap/ng-bootstrap": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-12.0.0.tgz", - "integrity": "sha512-XWf/CsP1gH0aev7Mtsldtj0DPPFdTrJpSiyjzLFS29gU1ZuDlJz6OKthgUDxZoua6uNPAzaGMc0A20T+reMfRw==", + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-12.0.1.tgz", + "integrity": "sha512-q0N1Pi032kfqHdoHEu9RqSdmN0ycSKmlg0b4YaqgOxNcOfuI9bH3oSejCttcYhe0q5SPB0IgVDJ6M0MrcKVi6Q==", "dependencies": { "tslib": "^2.3.0" }, @@ -2409,17 +3383,23 @@ } }, "node_modules/@ngneat/dirty-check-forms": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@ngneat/dirty-check-forms/-/dirty-check-forms-1.1.0.tgz", - "integrity": "sha512-Ak6SUMUV2oFlaylhUnar1yT4ahmq3Y2mHrd9uQHesE0iUZWfQTrIN07kMtwyT2JXR/x4RqdAmvp/+IJ+QlUPGg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@ngneat/dirty-check-forms/-/dirty-check-forms-3.0.2.tgz", + "integrity": "sha512-SKl3f/SqIdBMle7QorO4T90TqaWAjLe0xtJrTrzCsjC4uQlsk+old1DugUF16FJxAikPcBMoUABHa2iT3Uh75g==", + "dependencies": { + "tslib": ">=2.0.0" + }, "peerDependencies": { - "tslib": "^1.10.0" + "@angular/core": ">=13.0.0", + "@angular/forms": ">=13.0.0", + "@angular/router": ">=13.0.0", + "rxjs": ">=6.0.0" } }, "node_modules/@ngtools/webpack": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-13.2.5.tgz", - "integrity": "sha512-obiPvwPe+UJUO8cfNbBxukLKG30F+gLF5/erexwklRknJzS4KP8ciH2on6XlTuXUahpDjbO0pffugFE2I/IszQ==", + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-13.3.1.tgz", + "integrity": "sha512-40iEqAA/l882MPbGuG5EYxzsPWJ37fT4fF22SkPLX2eBgNhJ4K8XMt0gqcFhkHUsSe63frg1qjQ1Pd31msu0bQ==", "dev": true, "engines": { "node": "^12.20.0 || ^14.15.0 || >=16.10.0", @@ -2428,7 +3408,7 @@ }, "peerDependencies": { "@angular/compiler-cli": "^13.0.0", - "typescript": ">=4.4.3 <4.6", + "typescript": ">=4.4.3 <4.7", "webpack": "^5.30.0" } }, @@ -2493,21 +3473,6 @@ "which": "^2.0.2" } }, - "node_modules/@npmcli/git/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/@npmcli/installed-package-contents": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz", @@ -2565,28 +3530,22 @@ } }, "node_modules/@popperjs/core": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.2.tgz", - "integrity": "sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA==", + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.4.tgz", + "integrity": "sha512-q/ytXxO5NKvyT37pmisQAItCFqA7FD/vNb8dgaJy3/630Fsc+Mz9/9f2SziBoIZ30TJooXyTwZmhi1zjXmObYg==", "funding": { "type": "opencollective", "url": "https://opencollective.com/popperjs" } }, - "node_modules/@scarf/scarf": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.1.1.tgz", - "integrity": "sha512-VGbKDbk1RFIaSmdVb0cNjjWJoRWRI/Weo23AjRCC2nryO0iAS8pzsToJfPVPtVs74WHw4L1UTADNdIYRLkirZQ==", - "hasInstallScript": true - }, "node_modules/@schematics/angular": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-13.2.5.tgz", - "integrity": "sha512-pUaTwyMZRy7laV9RQozREomiUKi7Tn4wdyyuCUSqVvaiLI+DKvWE4vJXA2+/ketfzRjx6xIaCEexjsHJ+2FNtg==", + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-13.3.1.tgz", + "integrity": "sha512-+lrK/d1eJsAK6d6E9TDeg3Vc71bDy1KsE8M+lEINdX9Wax22mAz4pw20X9RSCw5RHgn+XcNUuMsgRJAwVhDNpg==", "dev": true, "dependencies": { - "@angular-devkit/core": "13.2.5", - "@angular-devkit/schematics": "13.2.5", + "@angular-devkit/core": "13.3.1", + "@angular-devkit/schematics": "13.3.1", "jsonc-parser": "3.0.0" }, "engines": { @@ -2595,13 +3554,43 @@ "yarn": ">= 1.13.0" } }, - "node_modules/@socket.io/base64-arraybuffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@socket.io/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", - "integrity": "sha512-dOlCBKnDw4iShaIsH/bxujKTM18+2TOAsYz+KSc11Am38H4q5Xw8Bbz97ZYdrVNM+um3p7w86Bvvmcn9q+5+eQ==", + "node_modules/@sideway/address": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", + "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", "dev": true, - "engines": { - "node": ">= 0.6.0" + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", + "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==", + "dev": true + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "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/@tootallnate/once": { @@ -2637,6 +3626,47 @@ "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", "dev": true }, + "node_modules/@types/babel__core": { + "version": "7.1.19", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", + "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", + "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", @@ -2656,12 +3686,6 @@ "@types/node": "*" } }, - "node_modules/@types/component-emitter": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.11.tgz", - "integrity": "sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ==", - "dev": true - }, "node_modules/@types/connect": { "version": "3.4.35", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", @@ -2681,18 +3705,6 @@ "@types/node": "*" } }, - "node_modules/@types/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", - "dev": true - }, - "node_modules/@types/cors": { - "version": "2.8.12", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", - "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", - "dev": true - }, "node_modules/@types/eslint": { "version": "8.4.1", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz", @@ -2714,9 +3726,9 @@ } }, "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==", + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", "dev": true }, "node_modules/@types/express": { @@ -2742,6 +3754,15 @@ "@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/http-proxy": { "version": "1.17.8", "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz", @@ -2751,25 +3772,44 @@ "@types/node": "*" } }, - "node_modules/@types/jasmine": { - "version": "3.10.3", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.10.3.tgz", - "integrity": "sha512-SWyMrjgdAUHNQmutvDcKablrJhkDLy4wunTme8oYLjKp41GnHGxMRXr2MQMvy/qy8H3LdzwQk9gH4hZ6T++H8g==", + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", "dev": true }, - "node_modules/@types/jasminewd2": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.10.tgz", - "integrity": "sha512-J7mDz7ovjwjc+Y9rR9rY53hFWKATcIkrr9DwQWmOas4/pnIPJTXawnzjwpHm3RSxz/e3ZVUvQ7cRbd5UQLo10g==", + "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/jasmine": "*" + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "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/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==", + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true }, "node_modules/@types/mime": { @@ -2779,10 +3819,10 @@ "dev": true }, "node_modules/@types/node": { - "version": "17.0.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", - "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==", - "dev": true + "version": "17.0.23", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.23.tgz", + "integrity": "sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw==", + "devOptional": true }, "node_modules/@types/parse-json": { "version": "4.0.0", @@ -2790,10 +3830,10 @@ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "dev": true }, - "node_modules/@types/q": { - "version": "0.0.32", - "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", - "integrity": "sha1-vShOV8hPEyXacCur/IKlMoGQwMU=", + "node_modules/@types/prettier": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.4.tgz", + "integrity": "sha512-ReVR2rLTV1kvtlWFyuot+d1pkpG2Fw/XKE3PDAdj57rbM97ttSp9JZ2UsP+2EHTylra9cUf6JA7tGwW1INzUrA==", "dev": true }, "node_modules/@types/qs": { @@ -2814,12 +3854,6 @@ "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==", "dev": true }, - "node_modules/@types/selenium-webdriver": { - "version": "3.0.19", - "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.19.tgz", - "integrity": "sha512-OFUilxQg+rWL2FMxtmIgCkUDlJB6pskkpvmew7yeXfzzsOBb5rc+y2+DjHm+r3r1ZPPcJefK3DveNSYWGiy68g==", - "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", @@ -2839,6 +3873,18 @@ "@types/node": "*" } }, + "node_modules/@types/sinonjs__fake-timers": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz", + "integrity": "sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==", + "optional": true + }, + "node_modules/@types/sizzle": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", + "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==", + "optional": true + }, "node_modules/@types/sockjs": { "version": "0.3.33", "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", @@ -2848,15 +3894,45 @@ "@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/ws": { - "version": "8.5.2", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.2.tgz", - "integrity": "sha512-VXI82ykONr5tacHEojnErTQk+KQSoYbW1NB6iz6wUwrNd+BqfkfggQNoNdCqhJSzbNumShPERbM+Pc5zpfhlbw==", + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", + "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", "dev": true, "dependencies": { "@types/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/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "node_modules/@types/yauzl": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.2.tgz", + "integrity": "sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA==", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", @@ -3058,6 +4134,28 @@ "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-globals/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-import-assertions": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", @@ -3068,9 +4166,9 @@ } }, "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==", + "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" @@ -3103,15 +4201,6 @@ "node": ">=8.9.0" } }, - "node_modules/adm-zip": { - "version": "0.4.16", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", - "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", - "dev": true, - "engines": { - "node": ">=0.3.0" - } - }, "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -3142,7 +4231,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, + "devOptional": true, "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" @@ -3185,19 +4274,22 @@ } }, "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==", + "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": "^6.9.1" + "ajv": "^8.8.2" } }, "node_modules/ansi-colors": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, + "devOptional": true, "engines": { "node": ">=6" } @@ -3206,7 +4298,7 @@ "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, + "devOptional": true, "dependencies": { "type-fest": "^0.21.3" }, @@ -3252,7 +4344,6 @@ "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" @@ -3276,6 +4367,26 @@ "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", "dev": true }, + "node_modules/arch": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", + "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true + }, "node_modules/are-we-there-yet": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.0.tgz", @@ -3338,29 +4449,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/asn1": { "version": "0.2.6", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, + "optional": true, "dependencies": { "safer-buffer": "~2.1.0" } @@ -3369,7 +4462,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true, + "optional": true, "engines": { "node": ">=0.8" } @@ -3380,20 +4473,35 @@ "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=", "dev": true }, - "node_modules/async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "dev": true, - "dependencies": { - "lodash": "^4.17.14" + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "optional": true, + "engines": { + "node": ">=8" } }, + "node_modules/async": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", + "optional": true + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true + "devOptional": true + }, + "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==", + "optional": true, + "engines": { + "node": ">= 4.0.0" + } }, "node_modules/atob": { "version": "2.1.2", @@ -3408,14 +4516,24 @@ } }, "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==", + "version": "10.4.4", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.4.tgz", + "integrity": "sha512-Tm8JxsB286VweiZ5F0anmbyGiNI3v3wGv3mz9W+cxEDYB/6jbnj6GM9H9mK3wIL8ftgl+C07Lcwb8PG5PCCPzA==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + } + ], "dependencies": { - "browserslist": "^4.19.1", - "caniuse-lite": "^1.0.30001297", - "fraction.js": "^4.1.2", + "browserslist": "^4.20.2", + "caniuse-lite": "^1.0.30001317", + "fraction.js": "^4.2.0", "normalize-range": "^0.1.2", "picocolors": "^1.0.0", "postcss-value-parser": "^4.2.0" @@ -3426,10 +4544,6 @@ "engines": { "node": "^10 || ^12 || >=14" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, "peerDependencies": { "postcss": "^8.1.0" } @@ -3438,7 +4552,7 @@ "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true, + "optional": true, "engines": { "node": "*" } @@ -3447,7 +4561,16 @@ "version": "1.11.0", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", - "dev": true + "optional": true + }, + "node_modules/axios": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", + "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", + "dev": true, + "dependencies": { + "follow-redirects": "^1.14.7" + } }, "node_modules/axobject-query": { "version": "2.0.2", @@ -3458,6 +4581,107 @@ "ast-types-flow": "0.0.7" } }, + "node_modules/babel-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", + "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", + "dev": true, + "dependencies": { + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "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/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/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/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/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", @@ -3528,6 +4752,21 @@ "node": ">=8" } }, + "node_modules/babel-plugin-jest-hoist": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", + "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", + "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-polyfill-corejs2": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", @@ -3576,6 +4815,45 @@ "@babel/core": "^7.0.0-0" } }, + "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.5.1", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", + "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^27.5.1", + "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/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -3585,7 +4863,7 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, + "devOptional": true, "funding": [ { "type": "github", @@ -3601,15 +4879,6 @@ } ] }, - "node_modules/base64id": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", - "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", - "dev": true, - "engines": { - "node": "^4.5.0 || >= 5.9" - } - }, "node_modules/batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", @@ -3620,7 +4889,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, + "optional": true, "dependencies": { "tweetnacl": "^0.14.3" } @@ -3638,7 +4907,6 @@ "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" } @@ -3647,27 +4915,24 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, + "devOptional": true, "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, - "node_modules/blocking-proxy": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-1.0.1.tgz", - "integrity": "sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "blocking-proxy": "built/lib/bin.js" - }, - "engines": { - "node": ">=6.9.x" - } + "node_modules/blob-util": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz", + "integrity": "sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==", + "optional": true + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "optional": true }, "node_modules/body-parser": { "version": "1.19.2", @@ -3690,6 +4955,15 @@ "node": ">= 0.8" } }, + "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", @@ -3705,6 +4979,18 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, + "node_modules/body-parser/node_modules/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==", + "dev": true, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/bonjour": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", @@ -3750,7 +5036,6 @@ "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" }, @@ -3758,13 +5043,29 @@ "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.20.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.0.tgz", - "integrity": "sha512-bnpOoa+DownbciXj0jVGENf8VYQnE2LNWomhYuCsMmmx9Jd9lwq0WXODuwpSsp8AVdKM2/HorrzxAfbKvWTByQ==", + "version": "4.20.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.2.tgz", + "integrity": "sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], "dependencies": { - "caniuse-lite": "^1.0.30001313", - "electron-to-chromium": "^1.4.76", + "caniuse-lite": "^1.0.30001317", + "electron-to-chromium": "^1.4.84", "escalade": "^3.1.1", "node-releases": "^2.0.2", "picocolors": "^1.0.0" @@ -3774,60 +5075,34 @@ }, "engines": { "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" } }, - "node_modules/browserstack": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.6.1.tgz", - "integrity": "sha512-GxtFjpIaKdbAyzHfFDKixKO8IBT7wR3NjbzrGc78nNs/Ciys9wU3/nBtsqsWv5nDSrdI5tz0peKuzCPuNXNUiw==", + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", "dev": true, "dependencies": { - "https-proxy-agent": "^2.2.1" - } - }, - "node_modules/browserstack/node_modules/agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", - "dev": true, - "dependencies": { - "es6-promisify": "^5.0.0" + "fast-json-stable-stringify": "2.x" }, "engines": { - "node": ">= 4.0.0" + "node": ">= 6" } }, - "node_modules/browserstack/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "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": { - "ms": "^2.1.1" - } - }, - "node_modules/browserstack/node_modules/https-proxy-agent": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", - "dev": true, - "dependencies": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - }, - "engines": { - "node": ">= 4.5.0" + "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, + "devOptional": true, "funding": [ { "type": "github", @@ -3847,6 +5122,15 @@ "ieee754": "^1.1.13" } }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "optional": true, + "engines": { + "node": "*" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -3875,9 +5159,9 @@ "dev": true }, "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "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" @@ -3912,6 +5196,15 @@ "node": ">= 10" } }, + "node_modules/cachedir": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", + "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", + "optional": true, + "engines": { + "node": ">=6" + } + }, "node_modules/call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -3944,19 +5237,25 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001313", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001313.tgz", - "integrity": "sha512-rI1UN0koZUiKINjysQDuRi2VeSCce3bYJNmDcj3PIKREiAmjakugBul1QSkg/fPrlULYl6oWfGg3PbgOSY9X4Q==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } + "version": "1.0.30001323", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001323.tgz", + "integrity": "sha512-e4BF2RlCVELKx8+RmklSEIVub1TWrmdhvA5kEUueummz1XyySW0DVk+3x9HyhU9MuWTa2BhqLgEuEmUwASAdCA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] }, "node_modules/caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true + "optional": true }, "node_modules/chalk": { "version": "2.4.2", @@ -3971,17 +5270,34 @@ "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-more-types": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", + "integrity": "sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA=", + "optional": true, + "engines": { + "node": ">= 0.8.0" + } + }, "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", @@ -4022,6 +5338,12 @@ "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==", + "devOptional": true + }, "node_modules/circular-dependency-plugin": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-5.2.2.tgz", @@ -4034,11 +5356,17 @@ "webpack": ">=4.0.1" } }, + "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-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, + "devOptional": true, "engines": { "node": ">=6" } @@ -4047,7 +5375,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, + "devOptional": true, "dependencies": { "restore-cursor": "^3.1.0" }, @@ -4059,7 +5387,7 @@ "version": "2.6.1", "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", - "dev": true, + "devOptional": true, "engines": { "node": ">=6" }, @@ -4067,6 +5395,37 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/cli-table3": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.1.tgz", + "integrity": "sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA==", + "optional": true, + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "colors": "1.4.0" + } + }, + "node_modules/cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "optional": true, + "dependencies": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/cli-width": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", @@ -4090,7 +5449,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", - "dev": true, + "devOptional": true, "engines": { "node": ">=0.8" } @@ -4109,6 +5468,16 @@ "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/codelyzer": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-6.0.2.tgz", @@ -4156,6 +5525,18 @@ "zone.js": "~0.10.2" } }, + "node_modules/codelyzer/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/codelyzer/node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -4177,6 +5558,12 @@ "integrity": "sha512-LXVLVEq0NNOqK/fLJo3d0kfzd4sxwn2/h67/02pjCjfKDxgx1i9QqpvtHD8CrBnSSwMw5+dy11O7FRX5mkO7Cg==", "dev": true }, + "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", @@ -4203,13 +5590,13 @@ "version": "2.0.16", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", - "dev": true + "devOptional": true }, "node_modules/colors": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true, + "optional": true, "engines": { "node": ">=0.1.90" } @@ -4218,7 +5605,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, + "devOptional": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -4232,18 +5619,21 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "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==", + "optional": 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/component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, "node_modules/compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", @@ -4274,15 +5664,6 @@ "node": ">= 0.8.0" } }, - "node_modules/compression/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/compression/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -4303,19 +5684,147 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, - "node_modules/connect": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", - "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "node_modules/concurrently": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-7.0.0.tgz", + "integrity": "sha512-WKM7PUsI8wyXpF80H+zjHP32fsgsHNQfPLw/e70Z5dYkV7hF+rf8q3D+ScWJIEr57CpkO3OWBko6hwhQLPR8Pw==", "dev": true, "dependencies": { - "debug": "2.6.9", - "finalhandler": "1.1.2", - "parseurl": "~1.3.3", - "utils-merge": "1.0.1" + "chalk": "^4.1.0", + "date-fns": "^2.16.1", + "lodash": "^4.17.21", + "rxjs": "^6.6.3", + "spawn-command": "^0.0.2-1", + "supports-color": "^8.1.0", + "tree-kill": "^1.2.2", + "yargs": "^16.2.0" + }, + "bin": { + "concurrently": "dist/bin/concurrently.js" }, "engines": { - "node": ">= 0.10.0" + "node": "^12.20.0 || ^14.13.0 || >=16.0.0" + } + }, + "node_modules/concurrently/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/concurrently/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/concurrently/node_modules/chalk/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/concurrently/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/concurrently/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/concurrently/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/concurrently/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/concurrently/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/concurrently/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/concurrently/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/connect-history-api-fallback": { @@ -4327,21 +5836,6 @@ "node": ">=0.8" } }, - "node_modules/connect/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/connect/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/console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", @@ -4448,18 +5942,6 @@ "webpack": "^5.1.0" } }, - "node_modules/copy-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/copy-webpack-plugin/node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -4529,20 +6011,7 @@ "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/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "dev": true, - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - } + "devOptional": true }, "node_modules/cosmiconfig": { "version": "7.0.1", @@ -4654,7 +6123,7 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, + "devOptional": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -4664,21 +6133,6 @@ "node": ">= 8" } }, - "node_modules/cross-spawn/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/css": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/css/-/css-3.0.0.tgz", @@ -4768,14 +6222,14 @@ } }, "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==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", "dev": true, "dependencies": { "boolbase": "^1.0.0", - "css-what": "^5.1.0", - "domhandler": "^4.3.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", "domutils": "^2.8.0", "nth-check": "^2.0.1" }, @@ -4794,9 +6248,9 @@ } }, "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==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", "dev": true, "engines": { "node": ">= 6" @@ -4841,12 +6295,187 @@ "node": ">=4" } }, - "node_modules/custom-event": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", - "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", + "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/cypress": { + "version": "9.5.3", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-9.5.3.tgz", + "integrity": "sha512-ItelIVmqMTnKYbo1JrErhsGgQGjWOxCpHT1TfMvwnIXKXN/OSlPjEK7rbCLYDZhejQL99PmUqul7XORI24Ik0A==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "@cypress/request": "^2.88.10", + "@cypress/xvfb": "^1.2.4", + "@types/node": "^14.14.31", + "@types/sinonjs__fake-timers": "8.1.1", + "@types/sizzle": "^2.3.2", + "arch": "^2.2.0", + "blob-util": "^2.0.2", + "bluebird": "^3.7.2", + "buffer": "^5.6.0", + "cachedir": "^2.3.0", + "chalk": "^4.1.0", + "check-more-types": "^2.24.0", + "cli-cursor": "^3.1.0", + "cli-table3": "~0.6.1", + "commander": "^5.1.0", + "common-tags": "^1.8.0", + "dayjs": "^1.10.4", + "debug": "^4.3.2", + "enquirer": "^2.3.6", + "eventemitter2": "^6.4.3", + "execa": "4.1.0", + "executable": "^4.1.1", + "extract-zip": "2.0.1", + "figures": "^3.2.0", + "fs-extra": "^9.1.0", + "getos": "^3.2.1", + "is-ci": "^3.0.0", + "is-installed-globally": "~0.4.0", + "lazy-ass": "^1.6.0", + "listr2": "^3.8.3", + "lodash": "^4.17.21", + "log-symbols": "^4.0.0", + "minimist": "^1.2.6", + "ospath": "^1.2.2", + "pretty-bytes": "^5.6.0", + "proxy-from-env": "1.0.0", + "request-progress": "^3.0.0", + "semver": "^7.3.2", + "supports-color": "^8.1.1", + "tmp": "~0.2.1", + "untildify": "^4.0.0", + "yauzl": "^2.10.0" + }, + "bin": { + "cypress": "bin/cypress" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/cypress/node_modules/@types/node": { + "version": "14.18.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.12.tgz", + "integrity": "sha512-q4jlIR71hUpWTnGhXWcakgkZeHa3CCjcQcnuzU8M891BAWA2jHiziiWEPEkdS5pFsz7H9HJiy8BrK7tBRNrY7A==", + "optional": true + }, + "node_modules/cypress/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==", + "optional": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cypress/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "optional": 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/cypress/node_modules/chalk/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==", + "optional": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cypress/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==", + "optional": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/cypress/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==", + "optional": true + }, + "node_modules/cypress/node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "optional": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/cypress/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==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cypress/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==", + "optional": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -4857,7 +6486,7 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, + "optional": true, "dependencies": { "assert-plus": "^1.0.0" }, @@ -4865,15 +6494,39 @@ "node": ">=0.10" } }, - "node_modules/date-format": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.4.tgz", - "integrity": "sha512-/jyf4rhB17ge328HJuJjAcmRtCsGd+NDeAtahRBTaK6vSPR6MO5HlrAit3Nn7dVjaa6sowW0WXt8yQtLyZQFRg==", + "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.28.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz", + "integrity": "sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw==", "dev": true, "engines": { - "node": ">=4.0" + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" } }, + "node_modules/dayjs": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.0.tgz", + "integrity": "sha512-JLC809s6Y948/FuCZPm5IX8rRhQwOiyMb2TfVVQEixG7P8Lm/gt5S7yoQZmC8x1UehI9Pb7sksEt4xx14m+7Ug==", + "optional": true + }, "node_modules/debug": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", @@ -4890,14 +6543,11 @@ } } }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } + "node_modules/decimal.js": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", + "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", + "dev": true }, "node_modules/decode-uri-component": { "version": "0.2.0", @@ -4908,6 +6558,12 @@ "node": ">=0.10" } }, + "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", @@ -4925,6 +6581,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.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/default-gateway": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", @@ -4937,11 +6608,55 @@ "node": ">= 10" } }, + "node_modules/default-gateway/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/default-gateway/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/default-gateway/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/defaults": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", - "dev": true, + "devOptional": true, "dependencies": { "clone": "^1.0.2" } @@ -4968,69 +6683,70 @@ } }, "node_modules/del": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", - "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz", + "integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==", "dev": true, "dependencies": { - "globby": "^5.0.0", - "is-path-cwd": "^1.0.0", - "is-path-in-cwd": "^1.0.0", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "rimraf": "^2.2.8" + "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": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/del/node_modules/array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "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, - "dependencies": { - "array-uniq": "^1.0.1" - }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/del/node_modules/globby": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", - "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "dependencies": { - "array-union": "^1.0.1", - "arrify": "^1.0.0", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "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": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/del/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "node_modules/del/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" + "engines": { + "node": ">=8" } }, "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=", - "dev": true, + "devOptional": true, "engines": { "node": ">=0.4.0" } @@ -5054,7 +6770,6 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", - "dev": true, "engines": { "node": ">= 0.6.0" } @@ -5065,18 +6780,21 @@ "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", "dev": true }, + "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/di": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", - "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", - "dev": true - }, "node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -5086,6 +6804,15 @@ "node": ">=0.3.1" } }, + "node_modules/diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "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", @@ -5123,18 +6850,6 @@ "buffer-indexof": "^1.0.0" } }, - "node_modules/dom-serialize": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", - "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", - "dev": true, - "dependencies": { - "custom-event": "~1.0.0", - "ent": "~2.2.0", - "extend": "^3.0.0", - "void-elements": "^2.0.0" - } - }, "node_modules/dom-serializer": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", @@ -5161,10 +6876,31 @@ } ] }, + "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==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "dev": true, "dependencies": { "domelementtype": "^2.2.0" @@ -5194,7 +6930,7 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, + "optional": true, "dependencies": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" @@ -5207,9 +6943,21 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.4.76", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.76.tgz", - "integrity": "sha512-3Vftv7cenJtQb+k00McEBZ2vVmZ/x+HEF7pcZONZIkOsESqAqVuACmBxMv0JhzX7u0YltU0vSqRqgBSTAhFUjA==" + "version": "1.4.103", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.103.tgz", + "integrity": "sha512-c/uKWR1Z/W30Wy/sx3dkZoj4BijbXX85QKWu9jJfjho3LBAXNEGAEW3oWiGb+dotA6C6BzCTxL2/aLes7jlUeg==" + }, + "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", @@ -5257,37 +7005,13 @@ "node": ">=0.10.0" } }, - "node_modules/engine.io": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.1.3.tgz", - "integrity": "sha512-rqs60YwkvWTLLnfazqgZqLa/aKo+9cueVfEi/dZ8PyGyaf8TLOxj++4QMIgeG3Gn0AhrWiFXvghsoY9L9h25GA==", - "dev": true, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "optional": true, "dependencies": { - "@types/cookie": "^0.4.1", - "@types/cors": "^2.8.12", - "@types/node": ">=10.0.0", - "accepts": "~1.3.4", - "base64id": "2.0.0", - "cookie": "~0.4.1", - "cors": "~2.8.5", - "debug": "~4.3.1", - "engine.io-parser": "~5.0.3", - "ws": "~8.2.3" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/engine.io-parser": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.3.tgz", - "integrity": "sha512-BtQxwF27XUNnSafQLvDi0dQ8s3i6VgzSoQMJacpIcGNrlUdfHSKbgm3jmjCVvQluGzqwujQMPAoMai3oYSTurg==", - "dev": true, - "dependencies": { - "@socket.io/base64-arraybuffer": "~1.0.2" - }, - "engines": { - "node": ">=10.0.0" + "once": "^1.4.0" } }, "node_modules/enhanced-resolve": { @@ -5303,11 +7027,17 @@ "node": ">=10.13.0" } }, - "node_modules/ent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", - "dev": true + "node_modules/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "optional": true, + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } }, "node_modules/entities": { "version": "2.2.0", @@ -5361,21 +7091,6 @@ "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", "dev": true }, - "node_modules/es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", - "dev": true - }, - "node_modules/es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", - "dev": true, - "dependencies": { - "es6-promise": "^4.0.3" - } - }, "node_modules/esbuild": { "version": "0.14.22", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.22.tgz", @@ -5749,6 +7464,38 @@ "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/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -5762,6 +7509,15 @@ "node": ">=8.0.0" } }, + "node_modules/eslint-scope/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -5787,7 +7543,7 @@ "node": ">=4.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { + "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", @@ -5796,15 +7552,6 @@ "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/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -5829,6 +7576,12 @@ "integrity": "sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==", "dev": true }, + "node_modules/eventemitter2": { + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.5.tgz", + "integrity": "sha512-bXE7Dyc1i6oQElDG0jMRZJrRAn9QR2xyyFGmBdZleNmyQX0FqGYmhZIrIrpPfm/w//LTo4tVQGOGQcGCb5q9uw==", + "optional": true + }, "node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", @@ -5845,19 +7598,19 @@ } }, "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "optional": true, "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", "strip-final-newline": "^2.0.0" }, "engines": { @@ -5867,6 +7620,18 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/executable": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", + "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", + "optional": true, + "dependencies": { + "pify": "^2.2.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", @@ -5876,6 +7641,21 @@ "node": ">= 0.8.0" } }, + "node_modules/expect": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, "node_modules/express": { "version": "4.17.3", "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", @@ -5938,6 +7718,18 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, + "node_modules/express/node_modules/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==", + "dev": true, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/express/node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -5962,7 +7754,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true + "optional": true }, "node_modules/external-editor": { "version": "3.1.0", @@ -5978,20 +7770,52 @@ "node": ">=4" } }, + "node_modules/external-editor/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/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "optional": true, + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, "node_modules/extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true, "engines": [ "node >=0.6.0" - ] + ], + "optional": true }, "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 + "devOptional": true }, "node_modules/fast-glob": { "version": "3.2.11", @@ -6013,6 +7837,12 @@ "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==", + "devOptional": 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/fastparse": { @@ -6042,11 +7872,29 @@ "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/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "optional": true, + "dependencies": { + "pend": "~1.2.0" + } + }, "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, + "devOptional": true, "dependencies": { "escape-string-regexp": "^1.0.5" }, @@ -6066,7 +7914,6 @@ "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" }, @@ -6137,12 +7984,6 @@ "node": ">=8" } }, - "node_modules/flatted": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", - "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", - "dev": true - }, "node_modules/follow-redirects": { "version": "1.14.9", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", @@ -6167,7 +8008,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true, + "optional": true, "engines": { "node": "*" } @@ -6176,7 +8017,7 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, + "optional": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", @@ -6218,17 +8059,18 @@ } }, "node_modules/fs-extra": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", - "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", - "dev": true, + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "optional": true, "dependencies": { + "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" }, "engines": { - "node": ">=12" + "node": ">=10" } }, "node_modules/fs-minipass": { @@ -6258,7 +8100,6 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -6275,12 +8116,11 @@ "dev": true }, "node_modules/gauge": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.2.tgz", - "integrity": "sha512-aSPRm2CvA9R8QyU5eXMFPd+cYkyxLsXHd2l5/FOH2V/eml//M04G6KZOmTap07O1PvEwNcl2NndyLfK8g3QrKA==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.1", "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.3", "console-control-strings": "^1.1.0", @@ -6291,7 +8131,7 @@ "wide-align": "^1.1.5" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, "node_modules/gensync": { @@ -6334,22 +8174,34 @@ } }, "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, + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "optional": true, + "dependencies": { + "pump": "^3.0.0" + }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/getos": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz", + "integrity": "sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==", + "optional": true, + "dependencies": { + "async": "^3.2.0" + } + }, "node_modules/getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, + "optional": true, "dependencies": { "assert-plus": "^1.0.0" } @@ -6377,7 +8229,6 @@ "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" }, @@ -6391,6 +8242,21 @@ "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", "dev": true }, + "node_modules/global-dirs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", + "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", + "optional": true, + "dependencies": { + "ini": "2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -6423,7 +8289,7 @@ "version": "4.2.9", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", - "dev": true + "devOptional": true }, "node_modules/handle-thing": { "version": "2.0.1", @@ -6431,51 +8297,6 @@ "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", "dev": true }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", - "dev": true, - "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/har-validator/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" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/har-validator/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/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -6488,27 +8309,6 @@ "node": ">= 0.4.0" } }, - "node_modules/has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-ansi/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -6615,10 +8415,22 @@ "safe-buffer": "~5.1.0" } }, + "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==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", + "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==", "dev": true }, "node_modules/html-escaper": { @@ -6690,9 +8502,9 @@ } }, "node_modules/http-proxy-middleware": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.3.tgz", - "integrity": "sha512-1bloEwnrHMnCoO/Gcwbz7eSVvW50KPES01PecpagI+YLNLci4AcuKJrujW4Mc3sBLpFxMSlsLNHS5Nl/lvrTPA==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.4.tgz", + "integrity": "sha512-m/4FxX17SUvz4lJ5WPXOHDUuCwIqXLfLHs1s0uZ3oYjhoXlx9csYxaOa0ElDEJ+h8Q4iJ1s+lTMbiCa4EXIJqg==", "dev": true, "dependencies": { "@types/http-proxy": "^1.17.8", @@ -6714,18 +8526,17 @@ } }, "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", + "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", + "optional": true, "dependencies": { "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "jsprim": "^2.0.2", + "sshpk": "^1.14.1" }, "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" + "node": ">=0.10" } }, "node_modules/https-proxy-agent": { @@ -6742,12 +8553,12 @@ } }, "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, + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "optional": true, "engines": { - "node": ">=10.17.0" + "node": ">=8.12.0" } }, "node_modules/humanize-ms": { @@ -6787,7 +8598,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, + "devOptional": true, "funding": [ { "type": "github", @@ -6837,12 +8648,6 @@ "node": ">=0.10.0" } }, - "node_modules/immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=", - "dev": true - }, "node_modules/immutable": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz", @@ -6874,6 +8679,25 @@ "node": ">=4" } }, + "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/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -6887,7 +8711,7 @@ "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, + "devOptional": true, "engines": { "node": ">=8" } @@ -6916,7 +8740,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "dev": true, + "devOptional": true, "engines": { "node": ">=10" } @@ -7004,15 +8828,6 @@ "node": ">=8" } }, - "node_modules/inquirer/node_modules/rxjs": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.4.tgz", - "integrity": "sha512-h5M3Hk78r6wAheJF0a5YahB1yRQKCsZ4MsGdZ5O9ETbVtjPcScGfrMmoOq7EBsCRzd4BDkvDJ7ogP8Sz5tTFiQ==", - "dev": true, - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/inquirer/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -7066,7 +8881,6 @@ "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" }, @@ -7074,6 +8888,18 @@ "node": ">=8" } }, + "node_modules/is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "optional": true, + "dependencies": { + "ci-info": "^3.2.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, "node_modules/is-core-module": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", @@ -7120,7 +8946,6 @@ "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" } @@ -7133,11 +8958,19 @@ "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" }, @@ -7145,11 +8978,27 @@ "node": ">=0.10.0" } }, + "node_modules/is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "optional": true, + "dependencies": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "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, + "devOptional": true, "engines": { "node": ">=8" } @@ -7164,42 +9013,26 @@ "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-path-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "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": ">=0.10.0" - } - }, - "node_modules/is-path-in-cwd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", - "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", - "dev": true, - "dependencies": { - "is-path-inside": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, "node_modules/is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", - "dev": true, - "dependencies": { - "path-is-inside": "^1.0.1" - }, + "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==", + "devOptional": true, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/is-plain-obj": { @@ -7226,6 +9059,12 @@ "node": ">=0.10.0" } }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -7246,7 +9085,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, + "devOptional": true, "engines": { "node": ">=8" }, @@ -7258,13 +9097,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true + "devOptional": 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, + "devOptional": true, "engines": { "node": ">=10" }, @@ -7296,23 +9135,11 @@ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, - "node_modules/isbinaryfile": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.8.tgz", - "integrity": "sha512-53h6XFniq77YdW+spoRrebh0mnmTxRPTlcuIArO57lmMdq4uBKFKaeTjnb92oYWrSn/LVL+LT+Hap2tFQj8V+w==", - "dev": true, - "engines": { - "node": ">= 8.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/gjtorikian/" - } - }, "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 + "devOptional": true }, "node_modules/isobject": { "version": "3.0.1", @@ -7327,7 +9154,7 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true + "optional": true }, "node_modules/istanbul-lib-coverage": { "version": "3.2.0", @@ -7399,71 +9226,17 @@ } }, "node_modules/istanbul-lib-source-maps": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", - "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "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": "^2.0.5", - "make-dir": "^2.1.0", - "rimraf": "^2.6.3", + "istanbul-lib-coverage": "^3.0.0", "source-map": "^0.6.1" }, "engines": { - "node": ">=6" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/istanbul-lib-coverage": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "dependencies": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/istanbul-lib-source-maps/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": ">=10" } }, "node_modules/istanbul-lib-source-maps/node_modules/source-map": { @@ -7488,48 +9261,2077 @@ "node": ">=8" } }, - "node_modules/jasmine": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz", - "integrity": "sha1-awicChFXax8W3xG4AUbZHU6Lij4=", + "node_modules/jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", + "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", "dev": true, "dependencies": { - "exit": "^0.1.2", - "glob": "^7.0.6", - "jasmine-core": "~2.8.0" + "@jest/core": "^27.5.1", + "import-local": "^3.0.2", + "jest-cli": "^27.5.1" }, "bin": { - "jasmine": "bin/jasmine.js" + "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/jasmine-core": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.0.1.tgz", - "integrity": "sha512-w+JDABxQCkxbGGxg+a2hUVZyqUS2JKngvIyLGu/xiw2ZwgsoSB0iiecLQsQORSeaKQ6iGrCyWG86RfNDuoA7Lg==", - "dev": true - }, - "node_modules/jasmine-spec-reporter": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-7.0.0.tgz", - "integrity": "sha512-OtC7JRasiTcjsaCBPtMO0Tl8glCejM4J4/dNuOJdA8lBjz4PmWjYQ6pzb0uzpBNAWJMDudYuj9OdXJWqM2QTJg==", + "node_modules/jest-changed-files": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", + "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", "dev": true, "dependencies": { - "colors": "1.4.0" + "@jest/types": "^27.5.1", + "execa": "^5.0.0", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jasmine/node_modules/jasmine-core": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", - "integrity": "sha1-vMl5rh+f0FcB5F5S5l06XWPxok4=", - "dev": true + "node_modules/jest-changed-files/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/jasminewd2": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.2.0.tgz", - "integrity": "sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4=", + "node_modules/jest-changed-files/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": ">= 6.9.x" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-changed-files/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/jest-circus": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", + "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "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/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/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/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.5.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", + "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", + "dev": true, + "dependencies": { + "@jest/core": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "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/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/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/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/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/jest-config": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", + "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.8.0", + "@jest/test-sequencer": "^27.5.1", + "@jest/types": "^27.5.1", + "babel-jest": "^27.5.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.9", + "jest-circus": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-jasmine2": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "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/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/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/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/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/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.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "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/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.5.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", + "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", + "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.5.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", + "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "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/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.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", + "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1", + "jsdom": "^16.6.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", + "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "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-jasmine2": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", + "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "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/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.5.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", + "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", + "dev": true, + "dependencies": { + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "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/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.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "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/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/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/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.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "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-preset-angular": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/jest-preset-angular/-/jest-preset-angular-11.1.0.tgz", + "integrity": "sha512-R4ePMBiQub95ESJlN7TozIpRIyMU7buvIdjm8KXqxZK/w8MYwLOSszVStsoZycDmWq5ifZI1eRvhOCUFktFotw==", + "dev": true, + "dependencies": { + "bs-logger": "^0.2.6", + "esbuild-wasm": "0.14.2", + "jest-environment-jsdom": "^27.0.0", + "pretty-format": "^27.0.0", + "ts-jest": "^27.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.15.0 || >=16.10.0" + }, + "optionalDependencies": { + "esbuild": "0.14.2" + }, + "peerDependencies": { + "@angular-devkit/build-angular": ">=0.1002.4", + "@angular/compiler-cli": ">=10.0.0", + "@angular/core": ">=10.0.0", + "@angular/platform-browser-dynamic": ">=10.0.0" + } + }, + "node_modules/jest-preset-angular/node_modules/esbuild": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.2.tgz", + "integrity": "sha512-l076A6o/PIgcyM24s0dWmDI/b8RQf41uWoJu9I0M71CtW/YSw5T5NUeXxs5lo2tFQD+O4CW4nBHJXx3OY5NpXg==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "optionalDependencies": { + "esbuild-android-arm64": "0.14.2", + "esbuild-darwin-64": "0.14.2", + "esbuild-darwin-arm64": "0.14.2", + "esbuild-freebsd-64": "0.14.2", + "esbuild-freebsd-arm64": "0.14.2", + "esbuild-linux-32": "0.14.2", + "esbuild-linux-64": "0.14.2", + "esbuild-linux-arm": "0.14.2", + "esbuild-linux-arm64": "0.14.2", + "esbuild-linux-mips64le": "0.14.2", + "esbuild-linux-ppc64le": "0.14.2", + "esbuild-netbsd-64": "0.14.2", + "esbuild-openbsd-64": "0.14.2", + "esbuild-sunos-64": "0.14.2", + "esbuild-windows-32": "0.14.2", + "esbuild-windows-64": "0.14.2", + "esbuild-windows-arm64": "0.14.2" + } + }, + "node_modules/jest-preset-angular/node_modules/esbuild-android-arm64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.2.tgz", + "integrity": "sha512-hEixaKMN3XXCkoe+0WcexO4CcBVU5DCSUT+7P8JZiWZCbAjSkc9b6Yz2X5DSfQmRCtI/cQRU6TfMYrMQ5NBfdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/jest-preset-angular/node_modules/esbuild-darwin-64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.2.tgz", + "integrity": "sha512-Uq8t0cbJQkxkQdbUfOl2wZqZ/AtLZjvJulR1HHnc96UgyzG9YlCLSDMiqjM+NANEy7/zzvwKJsy3iNC9wwqLJA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/jest-preset-angular/node_modules/esbuild-darwin-arm64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.2.tgz", + "integrity": "sha512-619MSa17sr7YCIrUj88KzQu2ESA4jKYtIYfLU/smX6qNgxQt3Y/gzM4s6sgJ4fPQzirvmXgcHv1ZNQAs/Xh48A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/jest-preset-angular/node_modules/esbuild-freebsd-64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.2.tgz", + "integrity": "sha512-aP6FE/ZsChZpUV6F3HE3x1Pz0paoYXycJ7oLt06g0G9dhJKknPawXCqQg/WMyD+ldCEZfo7F1kavenPdIT/SGQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/jest-preset-angular/node_modules/esbuild-freebsd-arm64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.2.tgz", + "integrity": "sha512-LSm98WTb1QIhyS83+Po0KTpZNdd2XpVpI9ua5rLWqKWbKeNRFwOsjeiuwBaRNc+O32s9oC2ZMefETxHBV6VNkQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/jest-preset-angular/node_modules/esbuild-linux-32": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.2.tgz", + "integrity": "sha512-8VxnNEyeUbiGflTKcuVc5JEPTqXfsx2O6ABwUbfS1Hp26lYPRPC7pKQK5Dxa0MBejGc50jy7YZae3EGQUQ8EkQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/jest-preset-angular/node_modules/esbuild-linux-64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.2.tgz", + "integrity": "sha512-4bzMS2dNxOJoFIiHId4w+tqQzdnsch71JJV1qZnbnErSFWcR9lRgpSqWnTTFtv6XM+MvltRzSXC5wQ7AEBY6Hg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/jest-preset-angular/node_modules/esbuild-linux-arm": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.2.tgz", + "integrity": "sha512-PaylahvMHhH8YMfJPMKEqi64qA0Su+d4FNfHKvlKes/2dUe4QxgbwXT9oLVgy8iJdcFMrO7By4R8fS8S0p8aVQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/jest-preset-angular/node_modules/esbuild-linux-arm64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.2.tgz", + "integrity": "sha512-RlIVp0RwJrdtasDF1vTFueLYZ8WuFzxoQ1OoRFZOTyJHCGCNgh7xJIC34gd7B7+RT0CzLBB4LcM5n0LS+hIoww==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/jest-preset-angular/node_modules/esbuild-linux-mips64le": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.2.tgz", + "integrity": "sha512-Fdwrq2roFnO5oetIiUQQueZ3+5soCxBSJswg3MvYaXDomj47BN6oAWMZgLrFh1oVrtWrxSDLCJBenYdbm2s+qQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/jest-preset-angular/node_modules/esbuild-linux-ppc64le": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.2.tgz", + "integrity": "sha512-vxptskw8JfCDD9QqpRO0XnsM1osuWeRjPaXX1TwdveLogYsbdFtcuiuK/4FxGiNMUr1ojtnCS2rMPbY8puc5NA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/jest-preset-angular/node_modules/esbuild-netbsd-64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.2.tgz", + "integrity": "sha512-I8+LzYK5iSNpspS9eCV9sW67Rj8FgMHimGri4mKiGAmN0pNfx+hFX146rYtzGtewuxKtTsPywWteHx+hPRLDsw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ] + }, + "node_modules/jest-preset-angular/node_modules/esbuild-openbsd-64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.2.tgz", + "integrity": "sha512-120HgMe9elidWUvM2E6mMf0csrGwx8sYDqUIJugyMy1oHm+/nT08bTAVXuwYG/rkMIqsEO9AlMxuYnwR6En/3Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/jest-preset-angular/node_modules/esbuild-sunos-64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.2.tgz", + "integrity": "sha512-Q3xcf9Uyfra9UuCFxoLixVvdigo0daZaKJ97TL2KNA4bxRUPK18wwGUk3AxvgDQZpRmg82w9PnkaNYo7a+24ow==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ] + }, + "node_modules/jest-preset-angular/node_modules/esbuild-wasm": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.14.2.tgz", + "integrity": "sha512-Rs8NjWoo1UdsVjhxT2o6kLCX9Sh65pyd3/h4XeJ3jjQNM6NgL+/CSowuJgvOIjDAXMLXpc6fdGnyZQDil9IUJA==", + "dev": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-preset-angular/node_modules/esbuild-windows-32": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.2.tgz", + "integrity": "sha512-TW7O49tPsrq+N1sW8mb3m24j/iDGa4xzAZH4wHWwoIzgtZAYPKC0hpIhufRRG/LA30bdMChO9pjJZ5mtcybtBQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/jest-preset-angular/node_modules/esbuild-windows-64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.2.tgz", + "integrity": "sha512-Rym6ViMNmi1E2QuQMWy0AFAfdY0wGwZD73BnzlsQBX5hZBuy/L+Speh7ucUZ16gwsrMM9v86icZUDrSN/lNBKg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/jest-preset-angular/node_modules/esbuild-windows-arm64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.2.tgz", + "integrity": "sha512-ZrLbhr0vX5Em/P1faMnHucjVVWPS+m3tktAtz93WkMZLmbRJevhiW1y4CbulBd2z0MEdXZ6emDa1zFHq5O5bSA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", + "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "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.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", + "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-snapshot": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "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/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/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/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.5.1", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", + "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", + "dev": true, + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-leak-detector": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "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/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.5.1", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", + "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/globals": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "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.9", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "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/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/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/jest-runtime/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/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/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/jest-runtime/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/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.5.1", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", + "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", + "dev": true, + "dependencies": { + "@types/node": "*", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", + "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", + "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.5.1", + "@jest/types": "^27.5.1", + "@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.5.1", + "graceful-fs": "^4.2.9", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^27.5.1", + "semver": "^7.3.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "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/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.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "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": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", + "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "leven": "^3.1.0", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "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" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-validate/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-validate/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-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-watcher": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", + "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", + "dev": true, + "dependencies": { + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^27.5.1", + "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/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-worker": { @@ -7570,6 +11372,19 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/joi": { + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.6.0.tgz", + "integrity": "sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0", + "@sideway/address": "^4.1.3", + "@sideway/formula": "^3.0.0", + "@sideway/pinpoint": "^2.0.0" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -7592,7 +11407,90 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true + "optional": true + }, + "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/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/jsdom/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/jsdom/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/jsesc": { "version": "2.5.2", @@ -7621,27 +11519,24 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true + "optional": true }, "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 + "devOptional": true }, "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true + "optional": true }, "node_modules/json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dependencies": { - "minimist": "^1.2.5" - }, + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", "bin": { "json5": "lib/cli.js" }, @@ -7653,13 +11548,13 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", - "dev": true + "devOptional": true }, "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, + "optional": true, "dependencies": { "universalify": "^2.0.0" }, @@ -7677,151 +11572,20 @@ ] }, "node_modules/jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "dev": true, + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", + "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", + "engines": [ + "node >=0.6.0" + ], + "optional": true, "dependencies": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", "json-schema": "0.4.0", "verror": "1.10.0" - }, - "engines": { - "node": ">=0.6.0" } }, - "node_modules/jszip": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.7.1.tgz", - "integrity": "sha512-ghL0tz1XG9ZEmRMcEN2vt7xabrDdqHHeykgARpmZ0BiIctWxM47Vt63ZO2dnp4QYt/xJVLLy5Zv1l/xRdh2byg==", - "dev": true, - "dependencies": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "set-immediate-shim": "~1.0.1" - } - }, - "node_modules/jszip/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/jszip/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/karma": { - "version": "6.3.17", - "resolved": "https://registry.npmjs.org/karma/-/karma-6.3.17.tgz", - "integrity": "sha512-2TfjHwrRExC8yHoWlPBULyaLwAFmXmxQrcuFImt/JsAsSZu1uOWTZ1ZsWjqQtWpHLiatJOHL5jFjXSJIgCd01g==", - "dev": true, - "dependencies": { - "@colors/colors": "1.5.0", - "body-parser": "^1.19.0", - "braces": "^3.0.2", - "chokidar": "^3.5.1", - "connect": "^3.7.0", - "di": "^0.0.1", - "dom-serialize": "^2.2.1", - "glob": "^7.1.7", - "graceful-fs": "^4.2.6", - "http-proxy": "^1.18.1", - "isbinaryfile": "^4.0.8", - "lodash": "^4.17.21", - "log4js": "^6.4.1", - "mime": "^2.5.2", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.5", - "qjobs": "^1.2.0", - "range-parser": "^1.2.1", - "rimraf": "^3.0.2", - "socket.io": "^4.2.0", - "source-map": "^0.6.1", - "tmp": "^0.2.1", - "ua-parser-js": "^0.7.30", - "yargs": "^16.1.1" - }, - "bin": { - "karma": "bin/karma" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/karma-chrome-launcher": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.0.tgz", - "integrity": "sha512-3dPs/n7vgz1rxxtynpzZTvb9y/GIaW8xjAwcIGttLbycqoFtI7yo1NGnQi6oFTherRE+GIhCAHZC4vEqWGhNvg==", - "dev": true, - "dependencies": { - "which": "^1.2.1" - } - }, - "node_modules/karma-coverage-istanbul-reporter": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-3.0.3.tgz", - "integrity": "sha512-wE4VFhG/QZv2Y4CdAYWDbMmcAHeS926ZIji4z+FkB2aF/EposRb6DP6G5ncT/wXhqUfAb/d7kZrNKPonbvsATw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^3.0.6", - "istanbul-reports": "^3.0.2", - "minimatch": "^3.0.4" - }, - "funding": { - "url": "https://github.com/sponsors/mattlewis92" - } - }, - "node_modules/karma-jasmine": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-4.0.1.tgz", - "integrity": "sha512-h8XDAhTiZjJKzfkoO1laMH+zfNlra+dEQHUAjpn5JV1zCPtOIVWGQjLBrqhnzQa/hrU2XrZwSyBa6XjEBzfXzw==", - "dev": true, - "dependencies": { - "jasmine-core": "^3.6.0" - }, - "engines": { - "node": ">= 10" - }, - "peerDependencies": { - "karma": "*" - } - }, - "node_modules/karma-jasmine-html-reporter": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.7.0.tgz", - "integrity": "sha512-pzum1TL7j90DTE86eFt48/s12hqwQuiD+e5aXx2Dc9wDEn2LfGq6RoAxEZZjFiN0RDSCOnosEKRZWxbQ+iMpQQ==", - "dev": true, - "peerDependencies": { - "jasmine-core": ">=3.8", - "karma": ">=0.9", - "karma-jasmine": ">=1.1" - } - }, - "node_modules/karma-jasmine/node_modules/jasmine-core": { - "version": "3.99.1", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.99.1.tgz", - "integrity": "sha512-Hu1dmuoGcZ7AfyynN3LsfruwMbxMALMka+YtZeGoLuDEySVmVAPaonkNoBRIw/ectu8b9tVQCJNgp4a4knp+tg==", - "dev": true - }, "node_modules/karma-source-map-support": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", @@ -7831,66 +11595,6 @@ "source-map-support": "^0.5.5" } }, - "node_modules/karma/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/karma/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/karma/node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "dev": true, - "dependencies": { - "rimraf": "^3.0.0" - }, - "engines": { - "node": ">=8.17.0" - } - }, - "node_modules/karma/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/karma/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/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -7900,6 +11604,15 @@ "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", @@ -7909,6 +11622,15 @@ "node": ">= 8" } }, + "node_modules/lazy-ass": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", + "integrity": "sha1-eZllXoZGwX8In90YfRUNMyTVRRM=", + "optional": true, + "engines": { + "node": "> 0.8" + } + }, "node_modules/less": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/less/-/less-4.1.2.tgz", @@ -7969,19 +11691,6 @@ "node": ">=6" } }, - "node_modules/less/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, - "optional": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/less/node_modules/pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", @@ -8012,6 +11721,28 @@ "node": ">=0.10.0" } }, + "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.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/license-webpack-plugin": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", @@ -8029,21 +11760,39 @@ } } }, - "node_modules/lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "dev": true, - "dependencies": { - "immediate": "~3.0.5" - } - }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, + "node_modules/listr2": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", + "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==", + "optional": true, + "dependencies": { + "cli-truncate": "^2.1.0", + "colorette": "^2.0.16", + "log-update": "^4.0.0", + "p-map": "^4.0.0", + "rfdc": "^1.3.0", + "rxjs": "^7.5.1", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "enquirer": ">= 2.3.0 < 3" + }, + "peerDependenciesMeta": { + "enquirer": { + "optional": true + } + } + }, "node_modules/loader-runner": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", @@ -8078,7 +11827,7 @@ "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "devOptional": true }, "node_modules/lodash.debounce": { "version": "4.0.8", @@ -8086,11 +11835,23 @@ "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", "dev": true }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=", + "optional": 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, + "devOptional": true, "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" @@ -8106,7 +11867,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, + "devOptional": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -8121,7 +11882,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, + "devOptional": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -8137,7 +11898,7 @@ "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, + "devOptional": true, "dependencies": { "color-name": "~1.1.4" }, @@ -8149,13 +11910,13 @@ "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 + "devOptional": 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, + "devOptional": true, "engines": { "node": ">=8" } @@ -8164,7 +11925,7 @@ "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, + "devOptional": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -8172,27 +11933,92 @@ "node": ">=8" } }, - "node_modules/log4js": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.4.2.tgz", - "integrity": "sha512-k80cggS2sZQLBwllpT1p06GtfvzMmSdUCkW96f0Hj83rKGJDAu2vZjt9B9ag2vx8Zz1IXzxoLgqvRJCdMKybGg==", - "dev": true, + "node_modules/log-update": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", + "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "optional": true, "dependencies": { - "date-format": "^4.0.4", - "debug": "^4.3.3", - "flatted": "^3.2.5", - "rfdc": "^1.3.0", - "streamroller": "^3.0.4" + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.2.0" }, "engines": { - "node": ">=8.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "optional": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "optional": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-update/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "optional": true + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "optional": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "optional": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" } }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -8204,7 +12030,7 @@ "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, + "devOptional": true, "dependencies": { "sourcemap-codec": "^1.4.4" } @@ -8266,6 +12092,15 @@ "node": ">= 10" } }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, "node_modules/material-colors": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz", @@ -8302,7 +12137,7 @@ "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 + "devOptional": true }, "node_modules/merge2": { "version": "1.4.1", @@ -8323,46 +12158,46 @@ } }, "node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "braces": "^3.0.2", + "picomatch": "^2.3.1" }, "engines": { "node": ">=8.6" } }, "node_modules/mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "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.0.0" + "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==", - "dev": true, + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "devOptional": true, "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==", - "dev": true, + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "devOptional": true, "dependencies": { - "mime-db": "1.51.0" + "mime-db": "1.52.0" }, "engines": { "node": ">= 0.6" @@ -8372,7 +12207,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, + "devOptional": true, "engines": { "node": ">=6" } @@ -8396,18 +12231,6 @@ "webpack": "^5.0.0" } }, - "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/schema-utils": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", @@ -8445,9 +12268,10 @@ } }, "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "devOptional": true }, "node_modules/minipass": { "version": "3.1.6", @@ -8592,9 +12416,9 @@ "dev": true }, "node_modules/nanoid": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", - "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.2.tgz", + "integrity": "sha512-CuHBogktKwpm5g2sRgv83jEy2ijFzBwMoYA60orPDR7ynsLijJDqgsi4RDGj3OJpy3Ieb+LYwiRmIOGyytgITA==", "dev": true, "bin": { "nanoid": "bin/nanoid.cjs" @@ -8603,6 +12427,12 @@ "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/needle": { "version": "2.9.1", "resolved": "https://registry.npmjs.org/needle/-/needle-2.9.1.tgz", @@ -8647,15 +12477,15 @@ "dev": true }, "node_modules/ng2-pdf-viewer": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/ng2-pdf-viewer/-/ng2-pdf-viewer-8.0.1.tgz", - "integrity": "sha512-uJNHo0VanlK0VZUryzO66xzskg3ounD2Uz9OOtpCjGKjlJjnoKToxa2QJlJiLmmyErEWd4KI6dSeHvAaiTZ+SA==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/ng2-pdf-viewer/-/ng2-pdf-viewer-9.0.0.tgz", + "integrity": "sha512-MaPCQJMeSRV7kzVTRskygdf1YrCCfmHqKPGrhQjdkBPj5HDFX02SOxVTlnJrl2KLO6nUyJ8xAdf4Pojf85gKaw==", "dependencies": { - "pdfjs-dist": "~2.11.338", + "pdfjs-dist": "~2.13.216", "tslib": "^2.3.1" }, "peerDependencies": { - "pdfjs-dist": "~2.11.338" + "pdfjs-dist": "~2.13.216" } }, "node_modules/ngx-color": { @@ -8700,16 +12530,6 @@ "@angular/core": ">=13.0.0" } }, - "node_modules/ngx-infinite-scroll": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/ngx-infinite-scroll/-/ngx-infinite-scroll-10.0.1.tgz", - "integrity": "sha512-7is0eJZ9kJPsaHohRmMhJ/QFHAW9jp9twO5HcHRvFM/Yl/R8QCiokgjwmH0/CR3MuxUanxfHZMfO3PbYTwlBEg==", - "hasInstallScript": true, - "dependencies": { - "@scarf/scarf": "^1.1.0", - "opencollective-postinstall": "^2.0.2" - } - }, "node_modules/nice-napi": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", @@ -8733,9 +12553,9 @@ "optional": true }, "node_modules/node-forge": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.2.1.tgz", - "integrity": "sha512-Fcvtbb+zBcZXbTTVwqGA5W+MKBj56UjVRevvchv5XrcyXbmNdesfZL37nlcWOfpgHhgmxApw3tQbTr4CqNmX4w==", + "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" @@ -8766,9 +12586,9 @@ } }, "node_modules/node-gyp-build": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", - "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.4.0.tgz", + "integrity": "sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ==", "dev": true, "optional": true, "bin": { @@ -8777,20 +12597,11 @@ "node-gyp-build-test": "build-test.js" } }, - "node_modules/node-gyp/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/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.2", @@ -8816,7 +12627,6 @@ "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" } @@ -8918,6 +12728,19 @@ "node": "^12.13.0 || ^14.15.0 || >=16" } }, + "node_modules/npm-registry-fetch/node_modules/@npmcli/fs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.0.tgz", + "integrity": "sha512-DmfBvNXGaetMxj9LTp8NAN9vEidXURrf5ZTslQzEAi/6GbW+4yjaLFQc6Tue5cpZ9Frlk4OBo/Snf1Bh/S7qTQ==", + "dev": true, + "dependencies": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, "node_modules/npm-registry-fetch/node_modules/@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", @@ -8927,6 +12750,35 @@ "node": ">= 10" } }, + "node_modules/npm-registry-fetch/node_modules/cacache": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.0.3.tgz", + "integrity": "sha512-eC7wYodNCVb97kuHGk5P+xZsvUJHkhSEOyNwkenqQPAsOtrTjvWOE5vSPNBpz9d8X3acIf6w2Ub5s4rvOCTs4g==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^1.1.2", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^7.2.0", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.1.11", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, "node_modules/npm-registry-fetch/node_modules/http-proxy-agent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", @@ -8942,30 +12794,30 @@ } }, "node_modules/npm-registry-fetch/node_modules/lru-cache": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.4.1.tgz", - "integrity": "sha512-NCD7/WRlFmADccuHjsRUYqdluYBr//n/O0fesCb/n52FoGcgKh8o4Dpm7YIbZwVcDs8rPBQbCZLmWWsp6m+xGQ==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.3.tgz", + "integrity": "sha512-WY9wjJNQt9+PZilnLbuFKM+SwDull9+6IAguOrarOMoOHTcJ9GnXSO11+Gw6c7xtDkBkthR57OZMtZKYr+1CEw==", "dev": true, "engines": { "node": ">=12" } }, "node_modules/npm-registry-fetch/node_modules/make-fetch-happen": { - "version": "10.0.4", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.0.4.tgz", - "integrity": "sha512-CiReW6usy3UXby5N46XjWfLPFPq1glugCszh18I0NYJCwr129ZAx9j3Dlv+cRsK0q3VjlVysEzhdtdw2+NhdYA==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.1.1.tgz", + "integrity": "sha512-3/mCljDQNjmrP7kl0vhS5WVlV+TvSKoZaFhdiYV7MOijEnrhrjaVnqbp/EY/7S+fhUB2KpH7j8c1iRsIOs+kjw==", "dev": true, "dependencies": { "agentkeepalive": "^4.2.1", - "cacache": "^15.3.0", + "cacache": "^16.0.2", "http-cache-semantics": "^4.1.0", "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0", "is-lambda": "^1.0.1", - "lru-cache": "^7.4.0", + "lru-cache": "^7.7.1", "minipass": "^3.1.6", "minipass-collect": "^1.0.2", - "minipass-fetch": "^2.0.1", + "minipass-fetch": "^2.0.3", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^0.6.3", @@ -8974,13 +12826,13 @@ "ssri": "^8.0.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, "node_modules/npm-registry-fetch/node_modules/make-fetch-happen/node_modules/minipass-fetch": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.0.2.tgz", - "integrity": "sha512-M63u5yWX0yxY1C3DcLVY1xWai0pNM3qa1xCMXFgdejY5F/NTmyzNVHGcBxKerX51lssqxwWWTjpg/ZPuD39gOQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.0.tgz", + "integrity": "sha512-H9U4UVBGXEyyWJnqYDCLp1PwD8XIkJ4akNHp1aGVI+2Ym7wQMlxDKi4IB4JbmyU+pl9pEs/cVrK6cOuvmbK4Sg==", "dev": true, "dependencies": { "minipass": "^3.1.6", @@ -8988,7 +12840,7 @@ "minizlib": "^2.1.2" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" }, "optionalDependencies": { "encoding": "^0.1.13" @@ -8998,7 +12850,7 @@ "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, + "devOptional": true, "dependencies": { "path-key": "^3.0.0" }, @@ -9033,23 +12885,11 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } + "node_modules/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-is": { "version": "1.1.5", @@ -9133,7 +12973,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, + "devOptional": true, "dependencies": { "mimic-fn": "^2.1.0" }, @@ -9161,19 +13001,28 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/opencollective-postinstall": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz", - "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==", - "bin": { - "opencollective-postinstall": "index.js" + "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/ora": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "dev": true, + "devOptional": true, "dependencies": { "bl": "^4.1.0", "chalk": "^4.1.0", @@ -9196,7 +13045,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, + "devOptional": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -9211,7 +13060,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, + "devOptional": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -9227,7 +13076,7 @@ "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, + "devOptional": true, "dependencies": { "color-name": "~1.1.4" }, @@ -9239,13 +13088,13 @@ "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 + "devOptional": 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, + "devOptional": true, "engines": { "node": ">=8" } @@ -9254,7 +13103,7 @@ "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, + "devOptional": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -9271,6 +13120,12 @@ "node": ">=0.10.0" } }, + "node_modules/ospath": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", + "integrity": "sha1-EnZjl3Sj+O8lcvf+QoDg6kVQwHs=", + "optional": true + }, "node_modules/p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -9302,7 +13157,7 @@ "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, + "devOptional": true, "dependencies": { "aggregate-error": "^3.0.0" }, @@ -9482,17 +13337,11 @@ "node": ">=0.10.0" } }, - "node_modules/path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, "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, + "devOptional": true, "engines": { "node": ">=8" } @@ -9519,9 +13368,12 @@ } }, "node_modules/pdfjs-dist": { - "version": "2.11.338", - "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-2.11.338.tgz", - "integrity": "sha512-Ti5VTB0VvSdtTtc7TG71ghMx0SEuNcEs4ghVuZxW0p6OqLjMc0xekZV1B+MmlxEG2Du2e5jgazucWIG/SXTcdA==", + "version": "2.13.216", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-2.13.216.tgz", + "integrity": "sha512-qn/9a/3IHIKZarTK6ajeeFXBkG15Lg1Fx99PxU09PAU2i874X8mTcHJYyDJxu7WDfNhV6hM7bRQBZU384anoqQ==", + "dependencies": { + "web-streams-polyfill": "^3.2.0" + }, "peerDependencies": { "worker-loader": "^3.0.8" }, @@ -9531,11 +13383,17 @@ } } }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "optional": true + }, "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 + "optional": true }, "node_modules/picocolors": { "version": "1.0.0", @@ -9546,7 +13404,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, "engines": { "node": ">=8.6" }, @@ -9558,30 +13415,18 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true, + "devOptional": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "node_modules/pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", "dev": true, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, - "dependencies": { - "pinkie": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" + "node": ">= 6" } }, "node_modules/piscina": { @@ -9624,6 +13469,15 @@ "node": ">= 0.12.0" } }, + "node_modules/portfinder/node_modules/async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "dependencies": { + "lodash": "^4.17.14" + } + }, "node_modules/portfinder/node_modules/debug": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", @@ -9634,12 +13488,12 @@ } }, "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==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "dependencies": { - "minimist": "^1.2.5" + "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" @@ -9733,9 +13587,9 @@ } }, "node_modules/postcss-custom-properties": { - "version": "12.1.4", - "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.4.tgz", - "integrity": "sha512-i6AytuTCoDLJkWN/MtAIGriJz3j7UX6bV7Z5t+KgFz+dwZS15/mlTJY1S0kRizlk6ba0V8u8hN50Fz5Nm7tdZw==", + "version": "12.1.5", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.5.tgz", + "integrity": "sha512-FHbbB/hRo/7cxLGkc2NS7cDRIDN1oFqQnUKBiyh4b/gwk8DD8udvmRDpUhEK836kB8ggUCieHVOvZDnF9XhI3g==", "dev": true, "dependencies": { "postcss-value-parser": "^4.2.0" @@ -9794,9 +13648,9 @@ } }, "node_modules/postcss-env-function": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-4.0.5.tgz", - "integrity": "sha512-gPUJc71ji9XKyl0WSzAalBeEA/89kU+XpffpPxSaaaZ1c48OL36r1Ep5R6+9XAPkIiDlSvVAwP4io12q/vTcvA==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-4.0.6.tgz", + "integrity": "sha512-kpA6FsLra+NqcFnL81TnsU+Z7orGtDTxcOhl6pwXeEq1yFPpRMkCDpHhrz8CFQDr/Wfm0jLiNQ1OsGGPjlqPwA==", "dev": true, "dependencies": { "postcss-value-parser": "^4.2.0" @@ -9901,9 +13755,9 @@ } }, "node_modules/postcss-lab-function": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-4.1.1.tgz", - "integrity": "sha512-j3Z0WQCimY2tMle++YcmygnnVbt6XdnrCV1FO2IpzaCSmtTF2oO8h4ZYUA1Q+QHYroIiaWPvNHt9uBR4riCksQ==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-4.1.2.tgz", + "integrity": "sha512-isudf5ldhg4fk16M8viAwAbg6Gv14lVO35N3Z/49NhbwPQ2xbiEoHgrRgpgQojosF4vF7jY653ktB6dDrUOR8Q==", "dev": true, "dependencies": { "@csstools/postcss-progressive-custom-properties": "^1.1.0", @@ -10156,9 +14010,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.0.9", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz", - "integrity": "sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==", + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", "dev": true, "dependencies": { "cssesc": "^3.0.0", @@ -10174,11 +14028,20 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true }, + "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/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, + "devOptional": true, "engines": { "node": ">=6" }, @@ -10186,6 +14049,32 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "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/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -10211,248 +14100,17 @@ "node": ">=10" } }, - "node_modules/protractor": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/protractor/-/protractor-7.0.0.tgz", - "integrity": "sha512-UqkFjivi4GcvUQYzqGYNe0mLzfn5jiLmO8w9nMhQoJRLhy2grJonpga2IWhI6yJO30LibWXJJtA4MOIZD2GgZw==", + "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": { - "@types/q": "^0.0.32", - "@types/selenium-webdriver": "^3.0.0", - "blocking-proxy": "^1.0.0", - "browserstack": "^1.5.1", - "chalk": "^1.1.3", - "glob": "^7.0.3", - "jasmine": "2.8.0", - "jasminewd2": "^2.1.0", - "q": "1.4.1", - "saucelabs": "^1.5.0", - "selenium-webdriver": "3.6.0", - "source-map-support": "~0.4.0", - "webdriver-js-extender": "2.1.0", - "webdriver-manager": "^12.1.7", - "yargs": "^15.3.1" - }, - "bin": { - "protractor": "bin/protractor", - "webdriver-manager": "bin/webdriver-manager" + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" }, "engines": { - "node": ">=10.13.x" - } - }, - "node_modules/protractor/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/protractor/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/protractor/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/protractor/node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/protractor/node_modules/cliui/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/protractor/node_modules/cliui/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/protractor/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/protractor/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/protractor/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/protractor/node_modules/source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "dev": true, - "dependencies": { - "source-map": "^0.5.6" - } - }, - "node_modules/protractor/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/protractor/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/protractor/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/protractor/node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/protractor/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/protractor/node_modules/wrap-ansi/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/protractor/node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, - "node_modules/protractor/node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/protractor/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" + "node": ">= 6" } }, "node_modules/proxy-addr": { @@ -10477,6 +14135,12 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", + "integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=", + "optional": true + }, "node_modules/prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -10488,46 +14152,34 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true + "devOptional": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "optional": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } }, "node_modules/punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, + "devOptional": true, "engines": { "node": ">=6" } }, - "node_modules/q": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", - "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=", - "dev": true, - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, - "node_modules/qjobs": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", - "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", - "dev": true, - "engines": { - "node": ">=0.9" - } - }, "node_modules/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==", - "dev": true, + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "optional": true, "engines": { "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, "node_modules/queue-microtask": { @@ -10583,6 +14235,21 @@ "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-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/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -10609,7 +14276,7 @@ "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, + "devOptional": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -10623,7 +14290,6 @@ "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" }, @@ -10634,8 +14300,7 @@ "node_modules/reflect-metadata": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", - "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", - "dev": true + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" }, "node_modules/regenerate": { "version": "1.4.2", @@ -10736,55 +14401,13 @@ "jsesc": "bin/jsesc" } }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", - "dev": true, + "node_modules/request-progress": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", + "integrity": "sha1-TKdUCBx/7GP1BeT6qCWqBs1mnb4=", + "optional": true, "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/request/node_modules/qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/request/node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "dev": true, - "bin": { - "uuid": "bin/uuid" + "throttleit": "^1.0.0" } }, "node_modules/require-directory": { @@ -10799,17 +14422,11 @@ "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, + "devOptional": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", @@ -10833,6 +14450,18 @@ "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-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -10881,11 +14510,20 @@ "node": ">=0.10.0" } }, + "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, + "devOptional": true, "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" @@ -10917,13 +14555,13 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", - "dev": true + "optional": true }, "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, + "devOptional": true, "dependencies": { "glob": "^7.1.3" }, @@ -10967,21 +14605,13 @@ } }, "node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", + "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" + "tslib": "^2.1.0" } }, - "node_modules/rxjs/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -10991,12 +14621,12 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "devOptional": true }, "node_modules/sass": { - "version": "1.49.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.49.0.tgz", - "integrity": "sha512-TVwVdNDj6p6b4QymJtNtRS2YtLJ/CqZriGg0eIAbAKMlN8Xy6kbv33FsEZSF7FufFFM705SQviHjjThfaQ4VNw==", + "version": "1.49.9", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.49.9.tgz", + "integrity": "sha512-YlYWkkHP9fbwaFRZQRXgDi3mXZShslVmmo+FVK3kHLUELHHEYrCmL1x6IUjC7wLS6VuJSAFXRQS/DxdsC4xL1A==", "dev": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", @@ -11007,7 +14637,7 @@ "sass": "sass.js" }, "engines": { - "node": ">=8.9.0" + "node": ">=12.0.0" } }, "node_modules/sass-loader": { @@ -11044,58 +14674,24 @@ } } }, - "node_modules/saucelabs": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.5.0.tgz", - "integrity": "sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ==", - "dev": true, - "dependencies": { - "https-proxy-agent": "^2.2.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/saucelabs/node_modules/agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", - "dev": true, - "dependencies": { - "es6-promisify": "^5.0.0" - }, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/saucelabs/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/saucelabs/node_modules/https-proxy-agent": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", - "dev": true, - "dependencies": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - }, - "engines": { - "node": ">= 4.5.0" - } - }, "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/schema-utils": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", @@ -11130,6 +14726,15 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/schema-utils/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/schema-utils/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -11142,52 +14747,13 @@ "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", "dev": true }, - "node_modules/selenium-webdriver": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", - "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==", - "dev": true, - "dependencies": { - "jszip": "^3.1.3", - "rimraf": "^2.5.4", - "tmp": "0.0.30", - "xml2js": "^0.4.17" - }, - "engines": { - "node": ">= 6.9.0" - } - }, - "node_modules/selenium-webdriver/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/selenium-webdriver/node_modules/tmp": { - "version": "0.0.30", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", - "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=", - "dev": true, - "dependencies": { - "os-tmpdir": "~1.0.1" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/selfsigned": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.0.0.tgz", - "integrity": "sha512-cUdFiCbKoa1mZ6osuJs2uDHrs0k0oprsKveFiiaBKCNq3SYyb5gs2HxhQyDNLCmL51ZZThqi4YNDpCK6GOP1iQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.0.1.tgz", + "integrity": "sha512-LmME957M1zOsUhG+67rAjKfiWFox3SBxE/yymatMZsAx+oMrJ0YQ8AToOnyCm7xbeg2ep37IHLxdu0o2MavQOQ==", "dev": true, "dependencies": { - "node-forge": "^1.2.0" + "node-forge": "^1" }, "engines": { "node": ">=10" @@ -11197,7 +14763,6 @@ "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" }, @@ -11265,18 +14830,6 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, - "node_modules/send/node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -11373,15 +14926,6 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, - "node_modules/set-immediate-shim": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", - "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -11404,7 +14948,7 @@ "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, + "devOptional": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -11416,7 +14960,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, + "devOptional": true, "engines": { "node": ">=8" } @@ -11425,6 +14969,12 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "devOptional": 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": { @@ -11439,6 +14989,53 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "optional": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "optional": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "optional": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/slice-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "optional": true + }, "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", @@ -11449,43 +15046,6 @@ "npm": ">= 3.0.0" } }, - "node_modules/socket.io": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.4.1.tgz", - "integrity": "sha512-s04vrBswdQBUmuWJuuNTmXUVJhP0cVky8bBDhdkf8y0Ptsu7fKU2LuLbts9g+pdmAdyMMn8F/9Mf1/wbtUN0fg==", - "dev": true, - "dependencies": { - "accepts": "~1.3.4", - "base64id": "~2.0.0", - "debug": "~4.3.2", - "engine.io": "~6.1.0", - "socket.io-adapter": "~2.3.3", - "socket.io-parser": "~4.0.4" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/socket.io-adapter": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.3.3.tgz", - "integrity": "sha512-Qd/iwn3VskrpNO60BeRyCyr8ZWw9CPZyitW4AQwmRZ8zCiyDiL+znRnWX6tDHXnWn1sJrM1+b6Mn6wEDJJ4aYQ==", - "dev": true - }, - "node_modules/socket.io-parser": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.4.tgz", - "integrity": "sha512-t+b0SS+IxG7Rxzda2EVvyBZbvFPBCjJoyHuE0P//7OAsN23GItzDRdWa6ALxZI/8R5ygK7jAR6t028/z+7295g==", - "dev": true, - "dependencies": { - "@types/component-emitter": "^1.2.10", - "component-emitter": "~1.3.0", - "debug": "~4.3.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -11529,7 +15089,7 @@ "version": "0.7.3", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true, + "devOptional": true, "engines": { "node": ">= 8" } @@ -11609,7 +15169,12 @@ "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==", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" + }, + "node_modules/spawn-command": { + "version": "0.0.2-1", + "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", + "integrity": "sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A=", "dev": true }, "node_modules/spdy": { @@ -11652,7 +15217,7 @@ "version": "1.17.0", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", - "dev": true, + "optional": true, "dependencies": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -11685,6 +15250,27 @@ "node": ">= 8" } }, + "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/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -11694,25 +15280,11 @@ "node": ">= 0.6" } }, - "node_modules/streamroller": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.0.4.tgz", - "integrity": "sha512-GI9NzeD+D88UFuIlJkKNDH/IsuR+qIN7Qh8EsmhoRZr9bQoehTraRgwtLUkZbpcAw+hLPfHOypmppz8YyGK68w==", - "dev": true, - "dependencies": { - "date-format": "^4.0.4", - "debug": "^4.3.3", - "fs-extra": "^10.0.1" - }, - "engines": { - "node": ">=8.0" - } - }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, + "devOptional": true, "dependencies": { "safe-buffer": "~5.2.0" } @@ -11721,7 +15293,7 @@ "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, + "devOptional": true, "funding": [ { "type": "github", @@ -11737,6 +15309,19 @@ } ] }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -11761,15 +15346,36 @@ "node": ">=8" } }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, + "devOptional": true, "engines": { "node": ">=6" } }, + "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/stylus": { "version": "0.56.0", "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.56.0.tgz", @@ -11823,6 +15429,40 @@ "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", @@ -11844,6 +15484,12 @@ "node": ">=0.10" } }, + "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/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -11870,6 +15516,22 @@ "node": ">= 10" } }, + "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.11.0", "resolved": "https://registry.npmjs.org/terser/-/terser-5.11.0.tgz", @@ -11938,6 +15600,15 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/terser-webpack-plugin/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/terser-webpack-plugin/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -11991,11 +15662,23 @@ "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/throttleit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", + "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=", + "optional": 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 + "devOptional": true }, "node_modules/thunky": { "version": "1.1.0", @@ -12004,17 +15687,23 @@ "dev": true }, "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "optional": true, "dependencies": { - "os-tmpdir": "~1.0.2" + "rimraf": "^3.0.0" }, "engines": { - "node": ">=0.6.0" + "node": ">=8.17.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", @@ -12027,7 +15716,6 @@ "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" }, @@ -12048,7 +15736,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, + "optional": true, "dependencies": { "psl": "^1.1.28", "punycode": "^2.1.1" @@ -12057,6 +15745,18 @@ "node": ">=0.8" } }, + "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/tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", @@ -12066,6 +15766,49 @@ "tree-kill": "cli.js" } }, + "node_modules/ts-jest": { + "version": "27.1.4", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.4.tgz", + "integrity": "sha512-qjkZlVPWVctAezwsOD1OPzbZ+k7zA5z3oxII4dGdZo5ggX/PL7kvwTM0pXTr10fAtbiVpJaL3bWd502zAhpgSQ==", + "dev": true, + "dependencies": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^27.0.0", + "json5": "2.x", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "7.x", + "yargs-parser": "20.x" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@types/jest": "^27.0.0", + "babel-jest": ">=27.0.0 <28", + "jest": "^27.0.0", + "typescript": ">=3.8 <5.0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@types/jest": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, "node_modules/ts-node": { "version": "10.7.0", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz", @@ -12109,6 +15852,15 @@ } } }, + "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/tslib": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", @@ -12146,12 +15898,12 @@ } }, "node_modules/tslint/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==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "dependencies": { - "minimist": "^1.2.5" + "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" @@ -12194,7 +15946,7 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, + "optional": true, "dependencies": { "safe-buffer": "^5.0.1" }, @@ -12206,13 +15958,34 @@ "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true + "optional": true + }, + "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/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, + "devOptional": true, "engines": { "node": ">=10" }, @@ -12239,11 +16012,19 @@ "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", "dev": true }, - "node_modules/typescript": { - "version": "4.5.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", - "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", + "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.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz", + "integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -12252,25 +16033,6 @@ "node": ">=4.2.0" } }, - "node_modules/ua-parser-js": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz", - "integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/ua-parser-js" - }, - { - "type": "paypal", - "url": "https://paypal.me/faisalman" - } - ], - "engines": { - "node": "*" - } - }, "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", @@ -12333,7 +16095,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, + "optional": true, "engines": { "node": ">= 10.0.0" } @@ -12347,11 +16109,20 @@ "node": ">= 0.8" } }, + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "optional": true, + "engines": { + "node": ">=8" + } + }, "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, + "devOptional": true, "dependencies": { "punycode": "^2.1.0" } @@ -12360,7 +16131,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true + "devOptional": true }, "node_modules/utils-merge": { "version": "1.0.1", @@ -12385,6 +16156,20 @@ "integrity": "sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA==", "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/validate-npm-package-name": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", @@ -12407,23 +16192,63 @@ "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, "engines": [ "node >=0.6.0" ], + "optional": true, "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" } }, - "node_modules/void-elements": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", - "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", + "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-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": ">=0.10.0" + "node": ">=10" + } + }, + "node_modules/wait-on": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-6.0.1.tgz", + "integrity": "sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==", + "dev": true, + "dependencies": { + "axios": "^0.25.0", + "joi": "^17.6.0", + "lodash": "^4.17.21", + "minimist": "^1.2.5", + "rxjs": "^7.5.4" + }, + "bin": { + "wait-on": "bin/wait-on" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "dependencies": { + "makeerror": "1.0.12" } }, "node_modules/watchpack": { @@ -12452,139 +16277,36 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", - "dev": true, + "devOptional": true, "dependencies": { "defaults": "^1.0.3" } }, - "node_modules/webdriver-js-extender": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz", - "integrity": "sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ==", - "dev": true, - "dependencies": { - "@types/selenium-webdriver": "^3.0.0", - "selenium-webdriver": "^3.0.1" - }, + "node_modules/web-streams-polyfill": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.0.tgz", + "integrity": "sha512-EqPmREeOzttaLRm5HS7io98goBgZ7IVz79aDvqjD0kYXLtFZTc0T/U6wHTPKyIjb+MdN7DFIIX6hgdBEpWmfPA==", "engines": { - "node": ">=6.9.x" + "node": ">= 8" } }, - "node_modules/webdriver-manager": { - "version": "12.1.8", - "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.1.8.tgz", - "integrity": "sha512-qJR36SXG2VwKugPcdwhaqcLQOD7r8P2Xiv9sfNbfZrKBnX243iAkOueX1yAmeNgIKhJ3YAT/F2gq6IiEZzahsg==", - "dev": true, - "dependencies": { - "adm-zip": "^0.4.9", - "chalk": "^1.1.1", - "del": "^2.2.0", - "glob": "^7.0.3", - "ini": "^1.3.4", - "minimist": "^1.2.0", - "q": "^1.4.1", - "request": "^2.87.0", - "rimraf": "^2.5.2", - "semver": "^5.3.0", - "xml2js": "^0.4.17" - }, - "bin": { - "webdriver-manager": "bin/webdriver-manager" - }, - "engines": { - "node": ">=6.9.x" - } - }, - "node_modules/webdriver-manager/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "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": ">=0.10.0" - } - }, - "node_modules/webdriver-manager/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webdriver-manager/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webdriver-manager/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/webdriver-manager/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/webdriver-manager/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/webdriver-manager/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webdriver-manager/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true, - "engines": { - "node": ">=0.8.0" + "node": ">=10.4" } }, "node_modules/webpack": { - "version": "5.67.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.67.0.tgz", - "integrity": "sha512-LjFbfMh89xBDpUMgA1W9Ur6Rn/gnr2Cq1jjHFPo4v6a79/ypznSYbAyPgGhwsxBtMIaEmDD1oJoA7BEYw/Fbrw==", + "version": "5.70.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.70.0.tgz", + "integrity": "sha512-ZMWWy8CeuTTjCxbeaQI21xSswseF2oNOwc70QSKNePvmxE7XW36i7vpBMYZFAUHPwQiEbNGCEYIOOlyRbdGmxw==", "dev": true, "dependencies": { - "@types/eslint-scope": "^3.7.0", - "@types/estree": "^0.0.50", + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/wasm-edit": "1.11.1", "@webassemblyjs/wasm-parser": "1.11.1", @@ -12592,7 +16314,7 @@ "acorn-import-assertions": "^1.7.6", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.8.3", + "enhanced-resolve": "^5.9.2", "es-module-lexer": "^0.9.0", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -12647,18 +16369,6 @@ "webpack": "^4.0.0 || ^5.0.0" } }, - "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/schema-utils": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", @@ -12729,18 +16439,6 @@ } } }, - "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/ansi-regex": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", @@ -12753,75 +16451,6 @@ "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/webpack-dev-server/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/webpack-dev-server/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/webpack-dev-server/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/webpack-dev-server/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/webpack-dev-server/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/webpack-dev-server/node_modules/schema-utils": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", @@ -12841,15 +16470,6 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/webpack-dev-server/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/webpack-dev-server/node_modules/strip-ansi": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", @@ -12865,6 +16485,27 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", + "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "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-merge": { "version": "5.8.0", "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", @@ -12924,6 +16565,15 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/webpack/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/webpack/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -12971,24 +16621,50 @@ "node": ">=0.8.0" } }, - "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "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-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==", + "devOptional": true, "dependencies": { "isexe": "^2.0.0" }, "bin": { - "which": "bin/which" + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" } }, - "node_modules/which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, "node_modules/wide-align": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", @@ -13004,6 +16680,15 @@ "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", "dev": true }, + "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/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -13055,13 +16740,25 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, "node_modules/ws": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", - "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", + "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", "dev": true, "engines": { - "node": ">=10.0.0" + "node": ">=8.3.0" }, "peerDependencies": { "bufferutil": "^4.0.1", @@ -13076,27 +16773,17 @@ } } }, - "node_modules/xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "dev": true, - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } + "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/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "dev": true, - "engines": { - "node": ">=4.0" - } + "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/y18n": { "version": "5.0.8", @@ -13109,8 +16796,7 @@ "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 + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yaml": { "version": "1.10.2", @@ -13122,9 +16808,9 @@ } }, "node_modules/yargs": { - "version": "17.3.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz", - "integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==", + "version": "17.4.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.4.0.tgz", + "integrity": "sha512-WJudfrk81yWFSOkZYpAZx4Nt7V4xp7S/uJkX0CnxovMCt1wCE8LNftPpNuF9X/u9gN5nsD7ycYtRcDf2pL3UiA==", "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", @@ -13139,6 +16825,15 @@ } }, "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/yargs/node_modules/yargs-parser": { "version": "21.0.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", @@ -13146,6 +16841,16 @@ "node": ">=12" } }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "optional": true, + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", @@ -13175,26 +16880,55 @@ "sourcemap-codec": "1.4.8" } }, - "@angular-devkit/architect": { - "version": "0.1302.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1302.5.tgz", - "integrity": "sha512-r07oo8GgUGY28SR3PCM1qNfLE6PNx6SfzBlG4p0OrQQ68ln8HipsEysDGakOWjNFK18SCGWOXAUNrUj8GnV+5g==", + "@angular-builders/jest": { + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/@angular-builders/jest/-/jest-13.0.3.tgz", + "integrity": "sha512-HJfN8gCfbg14U/eaE5vEvt6IrecFTUWSibHLvf2gBMzgnRQzqPKNAAoHY5kZ0DL+HwsCW/KlSp2m47ukOdVcYA==", "dev": true, "requires": { - "@angular-devkit/core": "13.2.5", + "@angular-devkit/architect": ">=0.1300.0 < 0.1400.0", + "@angular-devkit/core": "^13.0.0", + "jest-preset-angular": "11.1.0", + "lodash": "^4.17.15" + } + }, + "@angular-devkit/architect": { + "version": "0.1303.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1303.1.tgz", + "integrity": "sha512-ppaLzNZPrqrI96ddgm1RuEALVpWZsmHbIPLDd0GBwhF6aOkwF0LpZHd5XyS4ktGFZPReiFIjWSVtqV5vaBdRsw==", + "dev": true, + "requires": { + "@angular-devkit/core": "13.3.1", "rxjs": "6.6.7" + }, + "dependencies": { + "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" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } } }, "@angular-devkit/build-angular": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-13.2.5.tgz", - "integrity": "sha512-ny80YoLOrS6USJCzCChj1ZOEVTldcx0KWo3e86barmt5iVA2ekrnsQ02Bor5Bl5NlZFpE6Fu0FCXFAQZElFmcg==", + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-13.3.1.tgz", + "integrity": "sha512-xxBW4zZZM+lewW0nEpk9SXw6BMYhxe8WI/FjyEroOV8G2IuOrjZ4112QOpk6jCgmPHSOEldbltEdwoVLAnu09Q==", "dev": true, "requires": { "@ampproject/remapping": "1.1.1", - "@angular-devkit/architect": "0.1302.5", - "@angular-devkit/build-webpack": "0.1302.5", - "@angular-devkit/core": "13.2.5", + "@angular-devkit/architect": "0.1303.1", + "@angular-devkit/build-webpack": "0.1303.1", + "@angular-devkit/core": "13.3.1", "@babel/core": "7.16.12", "@babel/generator": "7.16.8", "@babel/helper-annotate-as-pure": "7.16.7", @@ -13205,7 +16939,7 @@ "@babel/runtime": "7.16.7", "@babel/template": "7.16.7", "@discoveryjs/json-ext": "0.5.6", - "@ngtools/webpack": "13.2.5", + "@ngtools/webpack": "13.3.1", "ansi-colors": "4.1.1", "babel-loader": "8.2.3", "babel-plugin-istanbul": "6.1.1", @@ -13240,7 +16974,7 @@ "regenerator-runtime": "0.13.9", "resolve-url-loader": "5.0.0", "rxjs": "6.6.7", - "sass": "1.49.0", + "sass": "1.49.9", "sass-loader": "12.4.0", "semver": "7.3.5", "source-map-loader": "3.0.1", @@ -13251,27 +16985,63 @@ "text-table": "0.2.0", "tree-kill": "1.2.2", "tslib": "2.3.1", - "webpack": "5.67.0", + "webpack": "5.70.0", "webpack-dev-middleware": "5.3.0", "webpack-dev-server": "4.7.3", "webpack-merge": "5.8.0", "webpack-subresource-integrity": "5.1.0" + }, + "dependencies": { + "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" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + } } }, "@angular-devkit/build-webpack": { - "version": "0.1302.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1302.5.tgz", - "integrity": "sha512-hxtFDX1cQaGfpHMSWRqfMO9/hucfIz61C0Lc/QGg9spay1Dvjwe+JpEoKMv3mz1K2fwHO9Hr5ZBAYFT4C5mxZQ==", + "version": "0.1303.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1303.1.tgz", + "integrity": "sha512-KSnR3y2q5hxh7t7ZSi0Emv/Kh9+D105JaEeyEqjqRjLdZSd2m6eAxbSUMNOAsbqnJTMCfzU5AG7jhbujuge0dQ==", "dev": true, "requires": { - "@angular-devkit/architect": "0.1302.5", + "@angular-devkit/architect": "0.1303.1", "rxjs": "6.6.7" + }, + "dependencies": { + "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" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } } }, "@angular-devkit/core": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-13.2.5.tgz", - "integrity": "sha512-WuWp/1R0FtCHPBcJLF13lTLHETtDGFUX0ULfGPRaYB5OVCSQcovVp5UbZTTy/Ss3ub3EOEmJlU8kMJfBrWuq+A==", + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-13.3.1.tgz", + "integrity": "sha512-eXAcQaP1mn6rnQb+5bv5NsamY6b34UYM7G+S154Hnma6CTTSGBtcmoNAJs8cekuFqWlw7YgpB/e15jR5OLPkDA==", "dev": true, "requires": { "ajv": "8.9.0", @@ -13280,39 +17050,65 @@ "magic-string": "0.25.7", "rxjs": "6.6.7", "source-map": "0.7.3" + }, + "dependencies": { + "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" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } } }, "@angular-devkit/schematics": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-13.2.5.tgz", - "integrity": "sha512-kAye6VYiF9JQAoeO+BYhy8eT2QOmhB+WLziRjXoFCBxh5+yXTygTVfs9fD5jmIpHmeu4hd2ErSh69yT5xWcD9g==", + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-13.3.1.tgz", + "integrity": "sha512-DxXMjlq/sALcHuONZRMTBX5k30XPfN4b6Ue4k7Xl8JKZqyHhEzfXaZzgD9u2cwb7wybKEeF/BZ5eJd8JG525og==", "dev": true, "requires": { - "@angular-devkit/core": "13.2.5", + "@angular-devkit/core": "13.3.1", "jsonc-parser": "3.0.0", "magic-string": "0.25.7", "ora": "5.4.1", "rxjs": "6.6.7" - } - }, - "@angular/animations": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-13.2.5.tgz", - "integrity": "sha512-1mGOePSDTiVwNIuV2g3+mUHrZJAkqJVzRKqKyNPXdwZupzVAgAfLbfUC07hhD/H53mXupIVugcUMFC3dvMu7uQ==", - "requires": { - "tslib": "^2.3.0" + }, + "dependencies": { + "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" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } } }, "@angular/cli": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-13.2.5.tgz", - "integrity": "sha512-S1uuScNCue6K7HpSG707/N+ULy+utrByeYLjx8zIwIOW1/ZjLB+1/Dxem3bu/OSLY2j2R7bX1WHw8Mnljnk4QQ==", + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-13.3.1.tgz", + "integrity": "sha512-0uwU8v3V/2s95X4cZT582J6upReT/ZNw/VAf4p4q51JN+BBvdCEb251xTF+TcOojyToFyJYvg8T28XSrsNsmTQ==", "dev": true, "requires": { - "@angular-devkit/architect": "0.1302.5", - "@angular-devkit/core": "13.2.5", - "@angular-devkit/schematics": "13.2.5", - "@schematics/angular": "13.2.5", + "@angular-devkit/architect": "0.1303.1", + "@angular-devkit/core": "13.3.1", + "@angular-devkit/schematics": "13.3.1", + "@schematics/angular": "13.3.1", "@yarnpkg/lockfile": "1.1.0", "ansi-colors": "4.1.1", "debug": "4.3.3", @@ -13331,32 +17127,31 @@ } }, "@angular/common": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-13.2.5.tgz", - "integrity": "sha512-px2qZP8Fd2qYbCVWmgLmop2OBQ/LKU2Oq8U/La2EEo8kgVuNWNTxmIh826cgZK/v9VQw8b/EoU7PeEjSWz0Zow==", + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-13.3.1.tgz", + "integrity": "sha512-Var5ChoX8kZl9cbIWbW7Reb3Xz3t1c1XHwq1k+oK2fgrPdEfypY9n/6DxyXOtSEGb9aV7ZCaxcv2c5JUKR3OPg==", "requires": { "tslib": "^2.3.0" } }, "@angular/compiler": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-13.2.5.tgz", - "integrity": "sha512-OF7xqs/7HPyRJXWiP8ZLwcgT+O/pyBdTjubrVNUPmzeKWPFyE9ZVKEg8MLGLbGHRtw1omhU9Mq4b12NqI1B/gA==", + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-13.3.1.tgz", + "integrity": "sha512-ppJURRRDPZB6UaZctH6yBsznZXB7wZdCpfy5yo4lFE4k8rygfV80TmnrbJBZXNNq057VK48Bap1tsehFwckjog==", "requires": { "tslib": "^2.3.0" } }, "@angular/compiler-cli": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-13.2.5.tgz", - "integrity": "sha512-Xd8xj2Z0ilA4TJAM/JkTtA1CAa6SuebFsEEvabHCRO5MDvtdsIUP91ADUZIqDHy7qe6Qift/rAVN2PXxT2aaNA==", - "dev": true, + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-13.3.1.tgz", + "integrity": "sha512-dImxLUITNwODlXaLcEACw10bxTiajWEQz3sLwhT/936UH+MNtM/RyLJ0M7xDvILDqq77W3psK5/M6F3M1mUpew==", "requires": { "@babel/core": "^7.17.2", "chokidar": "^3.0.0", "convert-source-map": "^1.5.1", "dependency-graph": "^0.11.0", - "magic-string": "^0.25.0", + "magic-string": "^0.26.0", "reflect-metadata": "^0.1.2", "semver": "^7.0.0", "sourcemap-codec": "^1.4.8", @@ -13368,24 +17163,22 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", - "dev": true, "requires": { "@jridgewell/trace-mapping": "^0.3.0" } }, "@babel/core": { - "version": "7.17.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.5.tgz", - "integrity": "sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA==", - "dev": true, + "version": "7.17.8", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.8.tgz", + "integrity": "sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ==", "requires": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.3", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helpers": "^7.17.2", - "@babel/parser": "^7.17.3", + "@babel/generator": "^7.17.7", + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-module-transforms": "^7.17.7", + "@babel/helpers": "^7.17.8", + "@babel/parser": "^7.17.8", "@babel/template": "^7.16.7", "@babel/traverse": "^7.17.3", "@babel/types": "^7.17.0", @@ -13399,50 +17192,55 @@ "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" } } }, "@babel/generator": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.3.tgz", - "integrity": "sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==", - "dev": true, + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.7.tgz", + "integrity": "sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==", "requires": { "@babel/types": "^7.17.0", "jsesc": "^2.5.1", "source-map": "^0.5.0" } }, + "magic-string": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.1.tgz", + "integrity": "sha512-ndThHmvgtieXe8J/VGPjG+Apu7v7ItcD5mhEIvOscWjPF/ccOiLxHaSuCAS2G+3x4GKsAbT8u7zdyamupui8Tg==", + "requires": { + "sourcemap-codec": "^1.4.8" + } + }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" } } }, "@angular/core": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-13.2.5.tgz", - "integrity": "sha512-4CC69JQbgyETJR6xsQk6hOQqb6fBGZ/Qc333x0hwRDBbGnYE6hQehDibV+Apljea8YjV+NX6VmyOvPvHhtL4PQ==", + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-13.3.1.tgz", + "integrity": "sha512-ZU/B9jEiZ0jadRkRL9Sb2btzqgQ0ylx380PfRQaojVIsij/EO6+jOSHIo5upMIGu/OvkggfweShJGlylCOrOXA==", "requires": { "tslib": "^2.3.0" } }, "@angular/forms": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-13.2.5.tgz", - "integrity": "sha512-0IOSj6OxW7fcaOLxaBydzFot3QsyQXeASXkq5xXGT10IsufVlnMS6wCULy/Ru3C1YAZZEM/z2rU+2yjjflea6A==", + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-13.3.1.tgz", + "integrity": "sha512-S6a/CEq1ht0vw2epuESiO551dsyLQTb/HuwceIBlsX2JqRRccynYlyx92gsDAo4hD2F0q+EeqZEPuq3oQIK43A==", "requires": { "tslib": "^2.3.0" } }, "@angular/localize": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-13.2.5.tgz", - "integrity": "sha512-K5uitSEPw0EJCYKpn5DkWvBqeN0uLXf3nr594hMHRfD+I7INnMZkZoqb6SuT1/VQhWbGfqb4XkTPlOBYe1Kb3w==", + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-13.3.1.tgz", + "integrity": "sha512-1s51ufL28EZuDQJ6+dHvLA9yyR8O9dpqS1PFrtNo9OcD62/JiDI8CHQlAdk2kmU5eTmulDf39sSLbOsDUGPGuQ==", "requires": { "@babel/core": "7.17.2", "glob": "7.2.0", @@ -13480,9 +17278,9 @@ } }, "@babel/generator": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.3.tgz", - "integrity": "sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.7.tgz", + "integrity": "sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==", "requires": { "@babel/types": "^7.17.0", "jsesc": "^2.5.1", @@ -13502,25 +17300,25 @@ } }, "@angular/platform-browser": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-13.2.5.tgz", - "integrity": "sha512-/M8ZpBftXC6vXDpxop1mLfbkvP2naUHBJmMRAQkJMLN4UlZKP3J+yjC8CN8uzQx0Y6Zt3G+LrGdOWYD9IRXBvw==", + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-13.3.1.tgz", + "integrity": "sha512-WtyrkK0pLYj6w7pz3xk8zlhWL1NwGCWT+k7YxEjBOONCIXlZvCqWVzWo4nNQn9Xqxd+z1FVI0dssDwZm2TD+Eg==", "requires": { "tslib": "^2.3.0" } }, "@angular/platform-browser-dynamic": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-13.2.5.tgz", - "integrity": "sha512-5NMlp/3DF7EOEMqtAoQ04Kuhyr9KqQmUt9skfei1AL5KyqKXnyxUVePIG+HqpwkeTV8P7XegR2+pZMfvxo/gPA==", + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-13.3.1.tgz", + "integrity": "sha512-TKV63SSyjrv5EsD03PloCbo8ZrJq5owkJ38E2FO/VvJAV3xu3Ey0SnoikNZMd8o3rh7+ocuT5K9Xcr4YuKVgEA==", "requires": { "tslib": "^2.3.0" } }, "@angular/router": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-13.2.5.tgz", - "integrity": "sha512-R0U8/QR8YbVeDuvGHpdf61hygVVBbD8j5pIr+kD8vUmYYnn3447XdZg9zkQ9qaQUvBSV0voNIOffUfoP2HaBSw==", + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-13.3.1.tgz", + "integrity": "sha512-YpZLjI4UI9KK6x8yn41XMrBWZgVb5JyJR7KNhQXB7WiX8bVH5SZzFRkjR3qUxTGaxe6I7KFvzySwm4JTYNj+xw==", "requires": { "tslib": "^2.3.0" } @@ -13540,15 +17338,14 @@ } }, "@babel/compat-data": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", - "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==" + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.7.tgz", + "integrity": "sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ==" }, "@babel/core": { "version": "7.16.12", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.12.tgz", "integrity": "sha512-dK5PtG1uiN2ikk++5OzSYsitZKny4wOCD0nrO4TqnW4BVBTQ2NGS3NgilvT/TEyxTST7LNyWV/T4tXDoD3fOgg==", - "dev": true, "requires": { "@babel/code-frame": "^7.16.7", "@babel/generator": "^7.16.8", @@ -13570,14 +17367,12 @@ "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" } } }, @@ -13585,7 +17380,6 @@ "version": "7.16.8", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.8.tgz", "integrity": "sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw==", - "dev": true, "requires": { "@babel/types": "^7.16.8", "jsesc": "^2.5.1", @@ -13595,8 +17389,7 @@ "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" } } }, @@ -13620,11 +17413,11 @@ } }, "@babel/helper-compilation-targets": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", - "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.7.tgz", + "integrity": "sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w==", "requires": { - "@babel/compat-data": "^7.16.4", + "@babel/compat-data": "^7.17.7", "@babel/helper-validator-option": "^7.16.7", "browserslist": "^4.17.5", "semver": "^6.3.0" @@ -13730,12 +17523,12 @@ } }, "@babel/helper-member-expression-to-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", - "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz", + "integrity": "sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw==", "dev": true, "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.17.0" } }, "@babel/helper-module-imports": { @@ -13747,13 +17540,13 @@ } }, "@babel/helper-module-transforms": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.6.tgz", - "integrity": "sha512-2ULmRdqoOMpdvkbT8jONrZML/XALfzxlb052bldftkicAUy8AxSCkD5trDPQcwHNmolcl7wP6ehNqMlyUw6AaA==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz", + "integrity": "sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw==", "requires": { "@babel/helper-environment-visitor": "^7.16.7", "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", "@babel/helper-split-export-declaration": "^7.16.7", "@babel/helper-validator-identifier": "^7.16.7", "@babel/template": "^7.16.7", @@ -13801,11 +17594,11 @@ } }, "@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==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz", + "integrity": "sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA==", "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.17.0" } }, "@babel/helper-skip-transparent-expression-wrappers": { @@ -13848,12 +17641,12 @@ } }, "@babel/helpers": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz", - "integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==", + "version": "7.17.8", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.8.tgz", + "integrity": "sha512-QcL86FGxpfSJwGtAvv4iG93UL6bmqBdmoVY0CMCU2g+oD2ezQse3PT5Pa+jiD6LJndBQi0EDlpzOWNlLuhz5gw==", "requires": { "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.0", + "@babel/traverse": "^7.17.3", "@babel/types": "^7.17.0" } }, @@ -13868,9 +17661,9 @@ } }, "@babel/parser": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.3.tgz", - "integrity": "sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==" + "version": "7.17.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.8.tgz", + "integrity": "sha512-BoHhDJrJXqcg+ZL16Xv39H9n+AqJ4pcDrQBGZN+wHxIysrLZ3/ECwCBUch/1zUNhnsXULcONU3Ei5Hmkfk6kiQ==" }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.16.7", @@ -14059,6 +17852,15 @@ "@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", @@ -14095,6 +17897,15 @@ "@babel/helper-plugin-utils": "^7.8.3" } }, + "@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", @@ -14176,6 +17987,15 @@ "@babel/helper-plugin-utils": "^7.14.5" } }, + "@babel/plugin-syntax-typescript": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz", + "integrity": "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7" + } + }, "@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", @@ -14240,9 +18060,9 @@ } }, "@babel/plugin-transform-destructuring": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.3.tgz", - "integrity": "sha512-dDFzegDYKlPqa72xIlbmSkly5MluLoaC1JswABGktyt6NTXSBcUuse/kWE/wvKFWJHPETpi158qJZFS3JmykJg==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.7.tgz", + "integrity": "sha512-XVh0r5yq9sLR4vZ6eVZe8FKfIcSgaTBxVBRSYokRj2qksf6QerYnTxz9/GTuKTH/n/HwLP7t6gtlybHetJ/6hQ==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.16.7" @@ -14327,25 +18147,25 @@ } }, "@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==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.7.tgz", + "integrity": "sha512-ITPmR2V7MqioMJyrxUo2onHNC3e+MvfFiFIR0RP21d3PtlVb6sfzoxNKiphSZUOM9hEIdzCcZe83ieX3yoqjUA==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-module-transforms": "^7.17.7", "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-simple-access": "^7.17.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==", + "version": "7.17.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.17.8.tgz", + "integrity": "sha512-39reIkMTUVagzgA5x88zDYXPCMT6lcaRKs1+S9K6NKBPErbgO/w/kP8GlNQTC87b412ZTlmNgr3k2JrWgHH+Bw==", "dev": true, "requires": { "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-module-transforms": "^7.17.7", "@babel/helper-plugin-utils": "^7.16.7", "@babel/helper-validator-identifier": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" @@ -14652,9 +18472,9 @@ }, "dependencies": { "@babel/generator": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.3.tgz", - "integrity": "sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.7.tgz", + "integrity": "sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==", "requires": { "@babel/types": "^7.17.0", "jsesc": "^2.5.1", @@ -14677,10 +18497,10 @@ "to-fast-properties": "^2.0.0" } }, - "@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "@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 }, "@cspotcode/source-map-consumer": { @@ -14712,6 +18532,151 @@ "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.4.0.tgz", "integrity": "sha512-JZButFdZ1+/xAfpguQHoabIXkcqRRKpMrWKBkpEZZyxfY9C1DpADFB8PEqGSTeFr135SaTRfKqGKx5xSCLI7ZQ==" }, + "@cypress/request": { + "version": "2.88.10", + "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.10.tgz", + "integrity": "sha512-Zp7F+R93N0yZyG34GutyTNr+okam7s/Fzc1+i3kcqOP8vk6OuajuE9qZJ6Rs+10/1JFtXFYMdyarnU1rZuJesg==", + "optional": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "http-signature": "~1.3.6", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^8.3.2" + } + }, + "@cypress/schematic": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@cypress/schematic/-/schematic-1.6.0.tgz", + "integrity": "sha512-ENHceK21AANBCthaiQ4gJGEvHsqJ9wS3b9PjnlD4MKOMzqwU/WMrJAs/Xnxa6PGh3btB2w0xNN+0beeaf0KiCA==", + "optional": true, + "requires": { + "@angular-devkit/architect": "^0.1202.10", + "@angular-devkit/core": "^12.2.10", + "@angular-devkit/schematics": "^12.2.10", + "@schematics/angular": "^12.2.10", + "jsonc-parser": "^3.0.0", + "rxjs": "~6.6.0" + }, + "dependencies": { + "@angular-devkit/architect": { + "version": "0.1202.17", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1202.17.tgz", + "integrity": "sha512-uUQcHcLbPvr9adALQSLU1MTDduVUR2kZAHi2e7SmL9ioel84pPVXBoD0WpSBeUMKwPiDs3TQDaxDB49hl0nBSQ==", + "optional": true, + "requires": { + "@angular-devkit/core": "12.2.17", + "rxjs": "6.6.7" + } + }, + "@angular-devkit/core": { + "version": "12.2.17", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-12.2.17.tgz", + "integrity": "sha512-PyOY7LGUPPd6rakxUYbfQN6zAdOCMCouVp5tERY1WTdMdEiuULOtHsPee8kNbh75pD59KbJNU+fwozPRMuIm5g==", + "optional": true, + "requires": { + "ajv": "8.6.2", + "ajv-formats": "2.1.0", + "fast-json-stable-stringify": "2.1.0", + "magic-string": "0.25.7", + "rxjs": "6.6.7", + "source-map": "0.7.3" + } + }, + "@angular-devkit/schematics": { + "version": "12.2.17", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-12.2.17.tgz", + "integrity": "sha512-c0eNu/nx1Mnu7KcZgYTYHP736H4Y9pSyLBSmLAHYZv3t3m0dIPbhifRcLQX7hHQ8fGT2ZFxmOpaQG5/DcIghSw==", + "optional": true, + "requires": { + "@angular-devkit/core": "12.2.17", + "ora": "5.4.1", + "rxjs": "6.6.7" + } + }, + "@schematics/angular": { + "version": "12.2.17", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-12.2.17.tgz", + "integrity": "sha512-HM/4KkQu944KL5ebhIyy1Ot5OV6prHNW7kmGeMVeQefLSbbfMQCHLa1psB9UU9BoahwGhUBvleLylNSitOBCgg==", + "optional": true, + "requires": { + "@angular-devkit/core": "12.2.17", + "@angular-devkit/schematics": "12.2.17", + "jsonc-parser": "3.0.0" + } + }, + "ajv": { + "version": "8.6.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.2.tgz", + "integrity": "sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w==", + "optional": 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-formats": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.0.tgz", + "integrity": "sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q==", + "optional": true, + "requires": { + "ajv": "^8.0.0" + } + }, + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "optional": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "optional": true + } + } + }, + "@cypress/xvfb": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz", + "integrity": "sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==", + "optional": true, + "requires": { + "debug": "^3.1.0", + "lodash.once": "^4.1.1" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "optional": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, "@discoveryjs/json-ext": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.6.tgz", @@ -14724,6 +18689,21 @@ "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", "dev": true }, + "@hapi/hoek": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.1.tgz", + "integrity": "sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw==", + "dev": true + }, + "@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "dev": true, + "requires": { + "@hapi/hoek": "^9.0.0" + } + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -14743,6 +18723,496 @@ "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true }, + "@jest/console": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", + "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^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" + } + }, + "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 + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "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.5.1", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", + "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", + "dev": true, + "requires": { + "@jest/console": "^27.5.1", + "@jest/reporters": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^27.5.1", + "jest-config": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-resolve-dependencies": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "jest-watcher": "^27.5.1", + "micromatch": "^4.0.4", + "rimraf": "^3.0.0", + "slash": "^3.0.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" + } + }, + "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 + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "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.5.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", + "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", + "dev": true, + "requires": { + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1" + } + }, + "@jest/fake-timers": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", + "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "@sinonjs/fake-timers": "^8.0.1", + "@types/node": "*", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + } + }, + "@jest/globals": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", + "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", + "dev": true, + "requires": { + "@jest/environment": "^27.5.1", + "@jest/types": "^27.5.1", + "expect": "^27.5.1" + } + }, + "@jest/reporters": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", + "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", + "dev": true, + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.9", + "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.5.1", + "jest-resolve": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "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": { + "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 + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "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 + }, + "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.5.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", + "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", + "dev": true, + "requires": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "@jest/test-result": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", + "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", + "dev": true, + "requires": { + "@jest/console": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + } + }, + "@jest/test-sequencer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", + "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", + "dev": true, + "requires": { + "@jest/test-result": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-runtime": "^27.5.1" + } + }, + "@jest/transform": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.5.1", + "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.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^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" + } + }, + "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 + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "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 + }, + "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": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "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" + }, + "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 + }, + "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/resolve-uri": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", @@ -14763,9 +19233,9 @@ } }, "@ng-bootstrap/ng-bootstrap": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-12.0.0.tgz", - "integrity": "sha512-XWf/CsP1gH0aev7Mtsldtj0DPPFdTrJpSiyjzLFS29gU1ZuDlJz6OKthgUDxZoua6uNPAzaGMc0A20T+reMfRw==", + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-12.0.1.tgz", + "integrity": "sha512-q0N1Pi032kfqHdoHEu9RqSdmN0ycSKmlg0b4YaqgOxNcOfuI9bH3oSejCttcYhe0q5SPB0IgVDJ6M0MrcKVi6Q==", "requires": { "tslib": "^2.3.0" } @@ -14779,15 +19249,19 @@ } }, "@ngneat/dirty-check-forms": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@ngneat/dirty-check-forms/-/dirty-check-forms-1.1.0.tgz", - "integrity": "sha512-Ak6SUMUV2oFlaylhUnar1yT4ahmq3Y2mHrd9uQHesE0iUZWfQTrIN07kMtwyT2JXR/x4RqdAmvp/+IJ+QlUPGg==" + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@ngneat/dirty-check-forms/-/dirty-check-forms-3.0.2.tgz", + "integrity": "sha512-SKl3f/SqIdBMle7QorO4T90TqaWAjLe0xtJrTrzCsjC4uQlsk+old1DugUF16FJxAikPcBMoUABHa2iT3Uh75g==", + "requires": { + "tslib": ">=2.0.0" + } }, "@ngtools/webpack": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-13.2.5.tgz", - "integrity": "sha512-obiPvwPe+UJUO8cfNbBxukLKG30F+gLF5/erexwklRknJzS4KP8ciH2on6XlTuXUahpDjbO0pffugFE2I/IszQ==", - "dev": true + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-13.3.1.tgz", + "integrity": "sha512-40iEqAA/l882MPbGuG5EYxzsPWJ37fT4fF22SkPLX2eBgNhJ4K8XMt0gqcFhkHUsSe63frg1qjQ1Pd31msu0bQ==", + "dev": true, + "requires": {} }, "@nodelib/fs.scandir": { "version": "2.1.5", @@ -14839,17 +19313,6 @@ "promise-retry": "^2.0.1", "semver": "^7.3.5", "which": "^2.0.2" - }, - "dependencies": { - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } } }, "@npmcli/installed-package-contents": { @@ -14900,32 +19363,60 @@ } }, "@popperjs/core": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.2.tgz", - "integrity": "sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA==" - }, - "@scarf/scarf": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.1.1.tgz", - "integrity": "sha512-VGbKDbk1RFIaSmdVb0cNjjWJoRWRI/Weo23AjRCC2nryO0iAS8pzsToJfPVPtVs74WHw4L1UTADNdIYRLkirZQ==" + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.4.tgz", + "integrity": "sha512-q/ytXxO5NKvyT37pmisQAItCFqA7FD/vNb8dgaJy3/630Fsc+Mz9/9f2SziBoIZ30TJooXyTwZmhi1zjXmObYg==" }, "@schematics/angular": { - "version": "13.2.5", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-13.2.5.tgz", - "integrity": "sha512-pUaTwyMZRy7laV9RQozREomiUKi7Tn4wdyyuCUSqVvaiLI+DKvWE4vJXA2+/ketfzRjx6xIaCEexjsHJ+2FNtg==", + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-13.3.1.tgz", + "integrity": "sha512-+lrK/d1eJsAK6d6E9TDeg3Vc71bDy1KsE8M+lEINdX9Wax22mAz4pw20X9RSCw5RHgn+XcNUuMsgRJAwVhDNpg==", "dev": true, "requires": { - "@angular-devkit/core": "13.2.5", - "@angular-devkit/schematics": "13.2.5", + "@angular-devkit/core": "13.3.1", + "@angular-devkit/schematics": "13.3.1", "jsonc-parser": "3.0.0" } }, - "@socket.io/base64-arraybuffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@socket.io/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", - "integrity": "sha512-dOlCBKnDw4iShaIsH/bxujKTM18+2TOAsYz+KSc11Am38H4q5Xw8Bbz97ZYdrVNM+um3p7w86Bvvmcn9q+5+eQ==", + "@sideway/address": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", + "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", + "dev": true, + "requires": { + "@hapi/hoek": "^9.0.0" + } + }, + "@sideway/formula": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", + "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==", "dev": true }, + "@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "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" + } + }, "@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", @@ -14956,6 +19447,47 @@ "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", "dev": true }, + "@types/babel__core": { + "version": "7.1.19", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", + "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", + "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", @@ -14975,12 +19507,6 @@ "@types/node": "*" } }, - "@types/component-emitter": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.11.tgz", - "integrity": "sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ==", - "dev": true - }, "@types/connect": { "version": "3.4.35", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", @@ -15000,18 +19526,6 @@ "@types/node": "*" } }, - "@types/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", - "dev": true - }, - "@types/cors": { - "version": "2.8.12", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", - "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", - "dev": true - }, "@types/eslint": { "version": "8.4.1", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz", @@ -15033,9 +19547,9 @@ } }, "@types/estree": { - "version": "0.0.50", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz", - "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==", + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", "dev": true }, "@types/express": { @@ -15061,6 +19575,15 @@ "@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/http-proxy": { "version": "1.17.8", "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz", @@ -15070,25 +19593,44 @@ "@types/node": "*" } }, - "@types/jasmine": { - "version": "3.10.3", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.10.3.tgz", - "integrity": "sha512-SWyMrjgdAUHNQmutvDcKablrJhkDLy4wunTme8oYLjKp41GnHGxMRXr2MQMvy/qy8H3LdzwQk9gH4hZ6T++H8g==", + "@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", "dev": true }, - "@types/jasminewd2": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.10.tgz", - "integrity": "sha512-J7mDz7ovjwjc+Y9rR9rY53hFWKATcIkrr9DwQWmOas4/pnIPJTXawnzjwpHm3RSxz/e3ZVUvQ7cRbd5UQLo10g==", + "@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/jasmine": "*" + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "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" } }, "@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==", + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true }, "@types/mime": { @@ -15098,10 +19640,10 @@ "dev": true }, "@types/node": { - "version": "17.0.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", - "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==", - "dev": true + "version": "17.0.23", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.23.tgz", + "integrity": "sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw==", + "devOptional": true }, "@types/parse-json": { "version": "4.0.0", @@ -15109,10 +19651,10 @@ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "dev": true }, - "@types/q": { - "version": "0.0.32", - "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", - "integrity": "sha1-vShOV8hPEyXacCur/IKlMoGQwMU=", + "@types/prettier": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.4.tgz", + "integrity": "sha512-ReVR2rLTV1kvtlWFyuot+d1pkpG2Fw/XKE3PDAdj57rbM97ttSp9JZ2UsP+2EHTylra9cUf6JA7tGwW1INzUrA==", "dev": true }, "@types/qs": { @@ -15133,12 +19675,6 @@ "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==", "dev": true }, - "@types/selenium-webdriver": { - "version": "3.0.19", - "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.19.tgz", - "integrity": "sha512-OFUilxQg+rWL2FMxtmIgCkUDlJB6pskkpvmew7yeXfzzsOBb5rc+y2+DjHm+r3r1ZPPcJefK3DveNSYWGiy68g==", - "dev": true - }, "@types/serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", @@ -15158,6 +19694,18 @@ "@types/node": "*" } }, + "@types/sinonjs__fake-timers": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz", + "integrity": "sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==", + "optional": true + }, + "@types/sizzle": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", + "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==", + "optional": true + }, "@types/sockjs": { "version": "0.3.33", "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", @@ -15167,15 +19715,45 @@ "@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/ws": { - "version": "8.5.2", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.2.tgz", - "integrity": "sha512-VXI82ykONr5tacHEojnErTQk+KQSoYbW1NB6iz6wUwrNd+BqfkfggQNoNdCqhJSzbNumShPERbM+Pc5zpfhlbw==", + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", + "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", "dev": true, "requires": { "@types/node": "*" } }, + "@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": "*" + } + }, + "@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "@types/yauzl": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.2.tgz", + "integrity": "sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA==", + "optional": true, + "requires": { + "@types/node": "*" + } + }, "@webassemblyjs/ast": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", @@ -15368,16 +19946,35 @@ "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", "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" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "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 + "dev": true, + "requires": {} }, "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==", + "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 }, "adjust-sourcemap-loader": { @@ -15403,12 +20000,6 @@ } } }, - "adm-zip": { - "version": "0.4.16", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", - "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", - "dev": true - }, "agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -15433,7 +20024,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, + "devOptional": true, "requires": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" @@ -15461,22 +20052,25 @@ } }, "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 + "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" + } }, "ansi-colors": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true + "devOptional": 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, + "devOptional": true, "requires": { "type-fest": "^0.21.3" } @@ -15504,7 +20098,6 @@ "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" @@ -15522,6 +20115,12 @@ "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", "dev": true }, + "arch": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", + "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", + "optional": true + }, "are-we-there-yet": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.0.tgz", @@ -15577,23 +20176,11 @@ "integrity": "sha512-1OvF9IbWwaeiM9VhzYXVQacMibxpXOMYVNIvMtKRyX9SImBXpKcFr8XvFDeEslCyuH/t6KRt7HEO94AlP8Iatw==", "dev": true }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true - }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true - }, "asn1": { "version": "0.2.6", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, + "optional": true, "requires": { "safer-buffer": "~2.1.0" } @@ -15602,7 +20189,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true + "optional": true }, "ast-types-flow": { "version": "0.0.7", @@ -15610,20 +20197,29 @@ "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=", "dev": true }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "optional": true + }, "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "dev": true, - "requires": { - "lodash": "^4.17.14" - } + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", + "optional": true }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true + "devOptional": true + }, + "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==", + "optional": true }, "atob": { "version": "2.1.2", @@ -15632,14 +20228,14 @@ "dev": true }, "autoprefixer": { - "version": "10.4.2", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.2.tgz", - "integrity": "sha512-9fOPpHKuDW1w/0EKfRmVnxTDt8166MAnLI3mgZ1JCnhNtYWxcJ6Ud5CO/AVOZi/AvFa8DY9RTy3h3+tFBlrrdQ==", + "version": "10.4.4", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.4.tgz", + "integrity": "sha512-Tm8JxsB286VweiZ5F0anmbyGiNI3v3wGv3mz9W+cxEDYB/6jbnj6GM9H9mK3wIL8ftgl+C07Lcwb8PG5PCCPzA==", "dev": true, "requires": { - "browserslist": "^4.19.1", - "caniuse-lite": "^1.0.30001297", - "fraction.js": "^4.1.2", + "browserslist": "^4.20.2", + "caniuse-lite": "^1.0.30001317", + "fraction.js": "^4.2.0", "normalize-range": "^0.1.2", "picocolors": "^1.0.0", "postcss-value-parser": "^4.2.0" @@ -15649,13 +20245,22 @@ "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true + "optional": true }, "aws4": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", - "dev": true + "optional": true + }, + "axios": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", + "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", + "dev": true, + "requires": { + "follow-redirects": "^1.14.7" + } }, "axobject-query": { "version": "2.0.2", @@ -15666,6 +20271,79 @@ "ast-types-flow": "0.0.7" } }, + "babel-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", + "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", + "dev": true, + "requires": { + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^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" + } + }, + "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 + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "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" + } + } + } + }, "babel-loader": { "version": "8.2.3", "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.3.tgz", @@ -15722,6 +20400,18 @@ "test-exclude": "^6.0.0" } }, + "babel-plugin-jest-hoist": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", + "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", + "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-polyfill-corejs2": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", @@ -15760,6 +20450,36 @@ "@babel/helper-define-polyfill-provider": "^0.3.1" } }, + "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.5.1", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", + "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "^27.5.1", + "babel-preset-current-node-syntax": "^1.0.0" + } + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -15769,13 +20489,7 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true - }, - "base64id": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", - "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", - "dev": true + "devOptional": true }, "batch": { "version": "0.6.1", @@ -15787,7 +20501,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, + "optional": true, "requires": { "tweetnacl": "^0.14.3" } @@ -15801,28 +20515,30 @@ "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 + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" }, "bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, + "devOptional": true, "requires": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, - "blocking-proxy": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-1.0.1.tgz", - "integrity": "sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } + "blob-util": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz", + "integrity": "sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==", + "optional": true + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "optional": true }, "body-parser": { "version": "1.19.2", @@ -15842,6 +20558,12 @@ "type-is": "~1.6.18" }, "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", @@ -15856,6 +20578,12 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true + }, + "qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==", + "dev": true } } }, @@ -15882,7 +20610,8 @@ "bootstrap": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.1.3.tgz", - "integrity": "sha512-fcQztozJ8jToQWXxVuEyXWW+dSo8AiXWKwiSSrKWsRB/Qt+Ewwza+JWoLKiTuQLaEPhdNAJ7+Dosc9DOIqNy7Q==" + "integrity": "sha512-fcQztozJ8jToQWXxVuEyXWW+dSo8AiXWKwiSSrKWsRB/Qt+Ewwza+JWoLKiTuQLaEPhdNAJ7+Dosc9DOIqNy7Q==", + "requires": {} }, "brace-expansion": { "version": "1.1.11", @@ -15897,72 +20626,62 @@ "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.20.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.0.tgz", - "integrity": "sha512-bnpOoa+DownbciXj0jVGENf8VYQnE2LNWomhYuCsMmmx9Jd9lwq0WXODuwpSsp8AVdKM2/HorrzxAfbKvWTByQ==", + "version": "4.20.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.2.tgz", + "integrity": "sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA==", "requires": { - "caniuse-lite": "^1.0.30001313", - "electron-to-chromium": "^1.4.76", + "caniuse-lite": "^1.0.30001317", + "electron-to-chromium": "^1.4.84", "escalade": "^3.1.1", "node-releases": "^2.0.2", "picocolors": "^1.0.0" } }, - "browserstack": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.6.1.tgz", - "integrity": "sha512-GxtFjpIaKdbAyzHfFDKixKO8IBT7wR3NjbzrGc78nNs/Ciys9wU3/nBtsqsWv5nDSrdI5tz0peKuzCPuNXNUiw==", + "bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", "dev": true, "requires": { - "https-proxy-agent": "^2.2.1" - }, - "dependencies": { - "agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", - "dev": true, - "requires": { - "es6-promisify": "^5.0.0" - } - }, - "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" - } - }, - "https-proxy-agent": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", - "dev": true, - "requires": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - } - } + "fast-json-stable-stringify": "2.x" + } + }, + "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, + "devOptional": true, "requires": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "optional": true + }, "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -15988,9 +20707,9 @@ "dev": true }, "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", "dev": true }, "cacache": { @@ -16019,6 +20738,12 @@ "unique-filename": "^1.1.1" } }, + "cachedir": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", + "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", + "optional": true + }, "call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -16042,15 +20767,15 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001313", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001313.tgz", - "integrity": "sha512-rI1UN0koZUiKINjysQDuRi2VeSCce3bYJNmDcj3PIKREiAmjakugBul1QSkg/fPrlULYl6oWfGg3PbgOSY9X4Q==" + "version": "1.0.30001323", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001323.tgz", + "integrity": "sha512-e4BF2RlCVELKx8+RmklSEIVub1TWrmdhvA5kEUueummz1XyySW0DVk+3x9HyhU9MuWTa2BhqLgEuEmUwASAdCA==" }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true + "optional": true }, "chalk": { "version": "2.4.2", @@ -16062,17 +20787,28 @@ "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-more-types": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", + "integrity": "sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA=", + "optional": true + }, "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", @@ -16096,23 +20832,36 @@ "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==", + "devOptional": true + }, "circular-dependency-plugin": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-5.2.2.tgz", "integrity": "sha512-g38K9Cm5WRwlaH6g03B9OEz/0qRizI+2I7n+Gz+L5DxXJAPAiWQvwlYNm1V1jkdpUv95bOe/ASm2vfi/G560jQ==", + "dev": true, + "requires": {} + }, + "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-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 + "devOptional": 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, + "devOptional": true, "requires": { "restore-cursor": "^3.1.0" } @@ -16121,7 +20870,27 @@ "version": "2.6.1", "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", - "dev": true + "devOptional": true + }, + "cli-table3": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.1.tgz", + "integrity": "sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA==", + "optional": true, + "requires": { + "colors": "1.4.0", + "string-width": "^4.2.0" + } + }, + "cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "optional": true, + "requires": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + } }, "cli-width": { "version": "3.0.0", @@ -16143,7 +20912,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", - "dev": true + "devOptional": true }, "clone-deep": { "version": "4.0.1", @@ -16156,6 +20925,12 @@ "shallow-clone": "^3.0.0" } }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, "codelyzer": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-6.0.2.tgz", @@ -16182,13 +20957,24 @@ "version": "9.0.0", "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-9.0.0.tgz", "integrity": "sha512-ctjwuntPfZZT2mNj2NDIVu51t9cvbhl/16epc5xEwyzyDt76pX9UgwvY+MbXrf/C/FWwdtmNtfP698BKI+9leQ==", - "dev": true + "dev": true, + "requires": {} }, "@angular/core": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/@angular/core/-/core-9.0.0.tgz", "integrity": "sha512-6Pxgsrf0qF9iFFqmIcWmjJGkkCaCm6V5QNnxMy2KloO3SDq6QuMVRbN9RtC8Urmo25LP+eZ6ZgYqFYpdD8Hd9w==", - "dev": true + "dev": true, + "requires": {} + }, + "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" + } }, "source-map": { "version": "0.5.7", @@ -16210,6 +20996,12 @@ } } }, + "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", @@ -16233,19 +21025,19 @@ "version": "2.0.16", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", - "dev": true + "devOptional": true }, "colors": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true + "optional": true }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, + "devOptional": true, "requires": { "delayed-stream": "~1.0.0" } @@ -16256,18 +21048,18 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "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==", + "optional": true + }, "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, "compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", @@ -16292,12 +21084,6 @@ "vary": "~1.1.2" }, "dependencies": { - "bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", - "dev": true - }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -16320,32 +21106,111 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, - "connect": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", - "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "concurrently": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-7.0.0.tgz", + "integrity": "sha512-WKM7PUsI8wyXpF80H+zjHP32fsgsHNQfPLw/e70Z5dYkV7hF+rf8q3D+ScWJIEr57CpkO3OWBko6hwhQLPR8Pw==", "dev": true, "requires": { - "debug": "2.6.9", - "finalhandler": "1.1.2", - "parseurl": "~1.3.3", - "utils-merge": "1.0.1" + "chalk": "^4.1.0", + "date-fns": "^2.16.1", + "lodash": "^4.17.21", + "rxjs": "^6.6.3", + "spawn-command": "^0.0.2-1", + "supports-color": "^8.1.0", + "tree-kill": "^1.2.2", + "yargs": "^16.2.0" }, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "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": { - "ms": "2.0.0" + "color-convert": "^2.0.1" } }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "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" + }, + "dependencies": { + "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" + } + } + } + }, + "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 + }, + "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" + } + }, + "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" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "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" + } } } }, @@ -16427,15 +21292,6 @@ "serialize-javascript": "^6.0.0" }, "dependencies": { - "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" - } - }, "glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -16487,17 +21343,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "dev": true, - "requires": { - "object-assign": "^4", - "vary": "^1" - } + "devOptional": true }, "cosmiconfig": { "version": "7.0.1", @@ -16587,22 +21433,11 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, + "devOptional": true, "requires": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" - }, - "dependencies": { - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } } }, "css": { @@ -16662,17 +21497,18 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz", "integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==", - "dev": true + "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==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", "dev": true, "requires": { "boolbase": "^1.0.0", - "css-what": "^5.1.0", - "domhandler": "^4.3.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", "domutils": "^2.8.0", "nth-check": "^2.0.1" } @@ -16688,9 +21524,9 @@ } }, "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==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", "dev": true }, "cssauron": { @@ -16714,12 +21550,153 @@ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true }, - "custom-event": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", - "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", + "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 + } + } + }, + "cypress": { + "version": "9.5.3", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-9.5.3.tgz", + "integrity": "sha512-ItelIVmqMTnKYbo1JrErhsGgQGjWOxCpHT1TfMvwnIXKXN/OSlPjEK7rbCLYDZhejQL99PmUqul7XORI24Ik0A==", + "optional": true, + "requires": { + "@cypress/request": "^2.88.10", + "@cypress/xvfb": "^1.2.4", + "@types/node": "^14.14.31", + "@types/sinonjs__fake-timers": "8.1.1", + "@types/sizzle": "^2.3.2", + "arch": "^2.2.0", + "blob-util": "^2.0.2", + "bluebird": "^3.7.2", + "buffer": "^5.6.0", + "cachedir": "^2.3.0", + "chalk": "^4.1.0", + "check-more-types": "^2.24.0", + "cli-cursor": "^3.1.0", + "cli-table3": "~0.6.1", + "commander": "^5.1.0", + "common-tags": "^1.8.0", + "dayjs": "^1.10.4", + "debug": "^4.3.2", + "enquirer": "^2.3.6", + "eventemitter2": "^6.4.3", + "execa": "4.1.0", + "executable": "^4.1.1", + "extract-zip": "2.0.1", + "figures": "^3.2.0", + "fs-extra": "^9.1.0", + "getos": "^3.2.1", + "is-ci": "^3.0.0", + "is-installed-globally": "~0.4.0", + "lazy-ass": "^1.6.0", + "listr2": "^3.8.3", + "lodash": "^4.17.21", + "log-symbols": "^4.0.0", + "minimist": "^1.2.6", + "ospath": "^1.2.2", + "pretty-bytes": "^5.6.0", + "proxy-from-env": "1.0.0", + "request-progress": "^3.0.0", + "semver": "^7.3.2", + "supports-color": "^8.1.1", + "tmp": "~0.2.1", + "untildify": "^4.0.0", + "yauzl": "^2.10.0" + }, + "dependencies": { + "@types/node": { + "version": "14.18.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.12.tgz", + "integrity": "sha512-q4jlIR71hUpWTnGhXWcakgkZeHa3CCjcQcnuzU8M891BAWA2jHiziiWEPEkdS5pFsz7H9HJiy8BrK7tBRNrY7A==", + "optional": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "optional": 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==", + "optional": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "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==", + "optional": true, + "requires": { + "has-flag": "^4.0.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==", + "optional": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "optional": true + }, + "commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "optional": 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==", + "optional": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "optional": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -16730,17 +21707,34 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, + "optional": true, "requires": { "assert-plus": "^1.0.0" } }, - "date-format": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.4.tgz", - "integrity": "sha512-/jyf4rhB17ge328HJuJjAcmRtCsGd+NDeAtahRBTaK6vSPR6MO5HlrAit3Nn7dVjaa6sowW0WXt8yQtLyZQFRg==", + "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.28.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz", + "integrity": "sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw==", "dev": true }, + "dayjs": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.0.tgz", + "integrity": "sha512-JLC809s6Y948/FuCZPm5IX8rRhQwOiyMb2TfVVQEixG7P8Lm/gt5S7yoQZmC8x1UehI9Pb7sksEt4xx14m+7Ug==", + "optional": true + }, "debug": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", @@ -16749,10 +21743,10 @@ "ms": "2.1.2" } }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "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 }, "decode-uri-component": { @@ -16761,6 +21755,12 @@ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", "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", @@ -16775,6 +21775,18 @@ "regexp.prototype.flags": "^1.2.0" } }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "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 + }, "default-gateway": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", @@ -16782,13 +21794,44 @@ "dev": true, "requires": { "execa": "^5.0.0" + }, + "dependencies": { + "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" + } + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + } } }, "defaults": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", - "dev": true, + "devOptional": true, "requires": { "clone": "^1.0.2" } @@ -16809,51 +21852,46 @@ } }, "del": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", - "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz", + "integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==", "dev": true, "requires": { - "globby": "^5.0.0", - "is-path-cwd": "^1.0.0", - "is-path-in-cwd": "^1.0.0", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "rimraf": "^2.2.8" + "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" }, "dependencies": { "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dev": true, - "requires": { - "array-uniq": "^1.0.1" - } + "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 }, "globby": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", - "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "requires": { - "array-union": "^1.0.1", - "arrify": "^1.0.0", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "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" } }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true } } }, @@ -16861,7 +21899,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true + "devOptional": true }, "delegates": { "version": "1.0.0", @@ -16878,8 +21916,7 @@ "dependency-graph": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", - "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", - "dev": true + "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==" }, "destroy": { "version": "1.0.4", @@ -16887,24 +21924,30 @@ "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", "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 }, - "di": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", - "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", - "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-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "dev": true + }, "dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -16939,18 +21982,6 @@ "buffer-indexof": "^1.0.0" } }, - "dom-serialize": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", - "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", - "dev": true, - "requires": { - "custom-event": "~1.0.0", - "ent": "~2.2.0", - "extend": "^3.0.0", - "void-elements": "^2.0.0" - } - }, "dom-serializer": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", @@ -16968,10 +21999,27 @@ "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==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "dev": true, "requires": { "domelementtype": "^2.2.0" @@ -16992,7 +22040,7 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, + "optional": true, "requires": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" @@ -17005,9 +22053,15 @@ "dev": true }, "electron-to-chromium": { - "version": "1.4.76", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.76.tgz", - "integrity": "sha512-3Vftv7cenJtQb+k00McEBZ2vVmZ/x+HEF7pcZONZIkOsESqAqVuACmBxMv0JhzX7u0YltU0vSqRqgBSTAhFUjA==" + "version": "1.4.103", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.103.tgz", + "integrity": "sha512-c/uKWR1Z/W30Wy/sx3dkZoj4BijbXX85QKWu9jJfjho3LBAXNEGAEW3oWiGb+dotA6C6BzCTxL2/aLes7jlUeg==" + }, + "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", @@ -17048,31 +22102,13 @@ } } }, - "engine.io": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.1.3.tgz", - "integrity": "sha512-rqs60YwkvWTLLnfazqgZqLa/aKo+9cueVfEi/dZ8PyGyaf8TLOxj++4QMIgeG3Gn0AhrWiFXvghsoY9L9h25GA==", - "dev": true, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "optional": true, "requires": { - "@types/cookie": "^0.4.1", - "@types/cors": "^2.8.12", - "@types/node": ">=10.0.0", - "accepts": "~1.3.4", - "base64id": "2.0.0", - "cookie": "~0.4.1", - "cors": "~2.8.5", - "debug": "~4.3.1", - "engine.io-parser": "~5.0.3", - "ws": "~8.2.3" - } - }, - "engine.io-parser": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.3.tgz", - "integrity": "sha512-BtQxwF27XUNnSafQLvDi0dQ8s3i6VgzSoQMJacpIcGNrlUdfHSKbgm3jmjCVvQluGzqwujQMPAoMai3oYSTurg==", - "dev": true, - "requires": { - "@socket.io/base64-arraybuffer": "~1.0.2" + "once": "^1.4.0" } }, "enhanced-resolve": { @@ -17085,11 +22121,14 @@ "tapable": "^2.2.0" } }, - "ent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", - "dev": true + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "optional": true, + "requires": { + "ansi-colors": "^4.1.1" + } }, "entities": { "version": "2.2.0", @@ -17134,21 +22173,6 @@ "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", "dev": true }, - "es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", - "dev": true - }, - "es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", - "dev": true, - "requires": { - "es6-promise": "^4.0.3" - } - }, "esbuild": { "version": "0.14.22", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.22.tgz", @@ -17332,6 +22356,28 @@ "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": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + } + } + }, "eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -17340,6 +22386,14 @@ "requires": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" + }, + "dependencies": { + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } } }, "esprima": { @@ -17355,20 +22409,12 @@ "dev": true, "requires": { "estraverse": "^5.2.0" - }, - "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 - } } }, "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true }, "esutils": { @@ -17389,6 +22435,12 @@ "integrity": "sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==", "dev": true }, + "eventemitter2": { + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.5.tgz", + "integrity": "sha512-bXE7Dyc1i6oQElDG0jMRZJrRAn9QR2xyyFGmBdZleNmyQX0FqGYmhZIrIrpPfm/w//LTo4tVQGOGQcGCb5q9uw==", + "optional": true + }, "eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", @@ -17402,28 +22454,49 @@ "dev": true }, "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "optional": true, "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", "strip-final-newline": "^2.0.0" } }, + "executable": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", + "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", + "optional": true, + "requires": { + "pify": "^2.2.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.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" + } + }, "express": { "version": "4.17.3", "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", @@ -17483,6 +22556,12 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, + "qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==", + "dev": true + }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -17495,7 +22574,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true + "optional": true }, "external-editor": { "version": "3.1.0", @@ -17506,19 +22585,42 @@ "chardet": "^0.7.0", "iconv-lite": "^0.4.24", "tmp": "^0.0.33" + }, + "dependencies": { + "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" + } + } + } + }, + "extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "optional": true, + "requires": { + "@types/yauzl": "^2.9.1", + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" } }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true + "optional": true }, "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 + "devOptional": true }, "fast-glob": { "version": "3.2.11", @@ -17537,6 +22639,12 @@ "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==", + "devOptional": 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 }, "fastparse": { @@ -17563,11 +22671,29 @@ "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" + } + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "optional": true, + "requires": { + "pend": "~1.2.0" + } + }, "figures": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, + "devOptional": true, "requires": { "escape-string-regexp": "^1.0.5" } @@ -17581,7 +22707,6 @@ "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" } @@ -17639,12 +22764,6 @@ "path-exists": "^4.0.0" } }, - "flatted": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", - "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", - "dev": true - }, "follow-redirects": { "version": "1.14.9", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", @@ -17655,13 +22774,13 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true + "optional": true }, "form-data": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, + "optional": true, "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", @@ -17687,11 +22806,12 @@ "dev": true }, "fs-extra": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", - "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", - "dev": true, + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "optional": true, "requires": { + "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" @@ -17721,7 +22841,6 @@ "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": { @@ -17731,12 +22850,11 @@ "dev": true }, "gauge": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.2.tgz", - "integrity": "sha512-aSPRm2CvA9R8QyU5eXMFPd+cYkyxLsXHd2l5/FOH2V/eml//M04G6KZOmTap07O1PvEwNcl2NndyLfK8g3QrKA==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", "dev": true, "requires": { - "ansi-regex": "^5.0.1", "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.3", "console-control-strings": "^1.1.0", @@ -17775,16 +22893,28 @@ "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 + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "optional": true, + "requires": { + "pump": "^3.0.0" + } + }, + "getos": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz", + "integrity": "sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==", + "optional": true, + "requires": { + "async": "^3.2.0" + } }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, + "optional": true, "requires": { "assert-plus": "^1.0.0" } @@ -17806,7 +22936,6 @@ "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" } @@ -17817,6 +22946,15 @@ "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", "dev": true }, + "global-dirs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", + "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", + "optional": true, + "requires": { + "ini": "2.0.0" + } + }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -17840,7 +22978,7 @@ "version": "4.2.9", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", - "dev": true + "devOptional": true }, "handle-thing": { "version": "2.0.1", @@ -17848,42 +22986,6 @@ "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", "dev": true }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true - }, - "har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "dev": true, - "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "dependencies": { - "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" - } - }, - "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 - } - } - }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -17893,23 +22995,6 @@ "function-bind": "^1.1.1" } }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - } - } - }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -18000,10 +23085,19 @@ } } }, + "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==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", + "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==", "dev": true }, "html-escaper": { @@ -18066,9 +23160,9 @@ } }, "http-proxy-middleware": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.3.tgz", - "integrity": "sha512-1bloEwnrHMnCoO/Gcwbz7eSVvW50KPES01PecpagI+YLNLci4AcuKJrujW4Mc3sBLpFxMSlsLNHS5Nl/lvrTPA==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.4.tgz", + "integrity": "sha512-m/4FxX17SUvz4lJ5WPXOHDUuCwIqXLfLHs1s0uZ3oYjhoXlx9csYxaOa0ElDEJ+h8Q4iJ1s+lTMbiCa4EXIJqg==", "dev": true, "requires": { "@types/http-proxy": "^1.17.8", @@ -18079,14 +23173,14 @@ } }, "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", + "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", + "optional": true, "requires": { "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "jsprim": "^2.0.2", + "sshpk": "^1.14.1" } }, "https-proxy-agent": { @@ -18100,10 +23194,10 @@ } }, "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 + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "optional": true }, "humanize-ms": { "version": "1.2.1", @@ -18127,13 +23221,14 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "dev": true + "dev": true, + "requires": {} }, "ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true + "devOptional": true }, "ignore": { "version": "5.2.0", @@ -18157,12 +23252,6 @@ "dev": true, "optional": true }, - "immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=", - "dev": true - }, "immutable": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz", @@ -18187,6 +23276,16 @@ } } }, + "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" + } + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -18197,7 +23296,7 @@ "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 + "devOptional": true }, "infer-owner": { "version": "1.0.4", @@ -18223,7 +23322,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "dev": true + "devOptional": true }, "inquirer": { "version": "8.2.0", @@ -18287,15 +23386,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "rxjs": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.4.tgz", - "integrity": "sha512-h5M3Hk78r6wAheJF0a5YahB1yRQKCsZ4MsGdZ5O9ETbVtjPcScGfrMmoOq7EBsCRzd4BDkvDJ7ogP8Sz5tTFiQ==", - "dev": true, - "requires": { - "tslib": "^2.1.0" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -18339,11 +23429,19 @@ "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-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "optional": true, + "requires": { + "ci-info": "^3.2.0" + } + }, "is-core-module": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", @@ -18371,28 +23469,42 @@ "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 + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" }, "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==" }, + "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-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "optional": true, + "requires": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + } + }, "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 + "devOptional": true }, "is-lambda": { "version": "1.0.1", @@ -18403,32 +23515,19 @@ "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 + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, "is-path-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "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-in-cwd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", - "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", - "dev": true, - "requires": { - "is-path-inside": "^1.0.0" - } - }, "is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", - "dev": true, - "requires": { - "path-is-inside": "^1.0.1" - } + "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==", + "devOptional": true }, "is-plain-obj": { "version": "3.0.0", @@ -18445,6 +23544,12 @@ "isobject": "^3.0.1" } }, + "is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, "is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -18459,19 +23564,19 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true + "devOptional": true }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true + "devOptional": 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 + "devOptional": true }, "is-what": { "version": "3.14.1", @@ -18494,17 +23599,11 @@ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, - "isbinaryfile": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.8.tgz", - "integrity": "sha512-53h6XFniq77YdW+spoRrebh0mnmTxRPTlcuIArO57lmMdq4uBKFKaeTjnb92oYWrSn/LVL+LT+Hap2tFQj8V+w==", - "dev": true - }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true + "devOptional": true }, "isobject": { "version": "3.0.1", @@ -18516,7 +23615,7 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true + "optional": true }, "istanbul-lib-coverage": { "version": "3.2.0", @@ -18574,55 +23673,16 @@ } }, "istanbul-lib-source-maps": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", - "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "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": "^2.0.5", - "make-dir": "^2.1.0", - "rimraf": "^2.6.3", + "istanbul-lib-coverage": "^3.0.0", "source-map": "^0.6.1" }, "dependencies": { - "istanbul-lib-coverage": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", - "dev": true - }, - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - } - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -18641,67 +23701,136 @@ "istanbul-lib-report": "^3.0.0" } }, - "jasmine": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz", - "integrity": "sha1-awicChFXax8W3xG4AUbZHU6Lij4=", + "jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", + "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", "dev": true, "requires": { - "exit": "^0.1.2", - "glob": "^7.0.6", - "jasmine-core": "~2.8.0" + "@jest/core": "^27.5.1", + "import-local": "^3.0.2", + "jest-cli": "^27.5.1" + } + }, + "jest-changed-files": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", + "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "execa": "^5.0.0", + "throat": "^6.0.1" }, "dependencies": { - "jasmine-core": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", - "integrity": "sha1-vMl5rh+f0FcB5F5S5l06XWPxok4=", + "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" + } + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true } } }, - "jasmine-core": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.0.1.tgz", - "integrity": "sha512-w+JDABxQCkxbGGxg+a2hUVZyqUS2JKngvIyLGu/xiw2ZwgsoSB0iiecLQsQORSeaKQ6iGrCyWG86RfNDuoA7Lg==", - "dev": true - }, - "jasmine-spec-reporter": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-7.0.0.tgz", - "integrity": "sha512-OtC7JRasiTcjsaCBPtMO0Tl8glCejM4J4/dNuOJdA8lBjz4PmWjYQ6pzb0uzpBNAWJMDudYuj9OdXJWqM2QTJg==", - "dev": true, - "requires": { - "colors": "1.4.0" - } - }, - "jasminewd2": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.2.0.tgz", - "integrity": "sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4=", - "dev": true - }, - "jest-worker": { + "jest-circus": { "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", + "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", "dev": true, "requires": { + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.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" + } + }, + "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": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "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==", + "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" @@ -18709,196 +23838,73 @@ } } }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "jest-cli": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", + "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "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": "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 - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, - "json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "requires": { - "minimist": "^1.2.5" - } - }, - "jsonc-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", - "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", - "dev": true - }, - "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" - } - }, - "jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", - "dev": true - }, - "jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - } - }, - "jszip": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.7.1.tgz", - "integrity": "sha512-ghL0tz1XG9ZEmRMcEN2vt7xabrDdqHHeykgARpmZ0BiIctWxM47Vt63ZO2dnp4QYt/xJVLLy5Zv1l/xRdh2byg==", - "dev": true, - "requires": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "set-immediate-shim": "~1.0.1" + "@jest/core": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "prompts": "^2.0.1", + "yargs": "^16.2.0" }, "dependencies": { - "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==", + "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": { - "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" + "color-convert": "^2.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==", + "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": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "karma": { - "version": "6.3.17", - "resolved": "https://registry.npmjs.org/karma/-/karma-6.3.17.tgz", - "integrity": "sha512-2TfjHwrRExC8yHoWlPBULyaLwAFmXmxQrcuFImt/JsAsSZu1uOWTZ1ZsWjqQtWpHLiatJOHL5jFjXSJIgCd01g==", - "dev": true, - "requires": { - "@colors/colors": "1.5.0", - "body-parser": "^1.19.0", - "braces": "^3.0.2", - "chokidar": "^3.5.1", - "connect": "^3.7.0", - "di": "^0.0.1", - "dom-serialize": "^2.2.1", - "glob": "^7.1.7", - "graceful-fs": "^4.2.6", - "http-proxy": "^1.18.1", - "isbinaryfile": "^4.0.8", - "lodash": "^4.17.21", - "log4js": "^6.4.1", - "mime": "^2.5.2", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.5", - "qjobs": "^1.2.0", - "range-parser": "^1.2.1", - "rimraf": "^3.0.2", - "socket.io": "^4.2.0", - "source-map": "^0.6.1", - "tmp": "^0.2.1", - "ua-parser-js": "^0.7.30", - "yargs": "^16.1.1" - }, - "dependencies": { - "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" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "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 }, - "tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "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": { - "rimraf": "^3.0.0" + "has-flag": "^4.0.0" } }, "yargs": { @@ -18915,214 +23921,108 @@ "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 } } }, - "karma-chrome-launcher": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.0.tgz", - "integrity": "sha512-3dPs/n7vgz1rxxtynpzZTvb9y/GIaW8xjAwcIGttLbycqoFtI7yo1NGnQi6oFTherRE+GIhCAHZC4vEqWGhNvg==", + "jest-config": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", + "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", "dev": true, "requires": { - "which": "^1.2.1" - } - }, - "karma-coverage-istanbul-reporter": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-3.0.3.tgz", - "integrity": "sha512-wE4VFhG/QZv2Y4CdAYWDbMmcAHeS926ZIji4z+FkB2aF/EposRb6DP6G5ncT/wXhqUfAb/d7kZrNKPonbvsATw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^3.0.6", - "istanbul-reports": "^3.0.2", - "minimatch": "^3.0.4" - } - }, - "karma-jasmine": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-4.0.1.tgz", - "integrity": "sha512-h8XDAhTiZjJKzfkoO1laMH+zfNlra+dEQHUAjpn5JV1zCPtOIVWGQjLBrqhnzQa/hrU2XrZwSyBa6XjEBzfXzw==", - "dev": true, - "requires": { - "jasmine-core": "^3.6.0" + "@babel/core": "^7.8.0", + "@jest/test-sequencer": "^27.5.1", + "@jest/types": "^27.5.1", + "babel-jest": "^27.5.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.9", + "jest-circus": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-jasmine2": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" }, "dependencies": { - "jasmine-core": { - "version": "3.99.1", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.99.1.tgz", - "integrity": "sha512-Hu1dmuoGcZ7AfyynN3LsfruwMbxMALMka+YtZeGoLuDEySVmVAPaonkNoBRIw/ectu8b9tVQCJNgp4a4knp+tg==", - "dev": true - } - } - }, - "karma-jasmine-html-reporter": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.7.0.tgz", - "integrity": "sha512-pzum1TL7j90DTE86eFt48/s12hqwQuiD+e5aXx2Dc9wDEn2LfGq6RoAxEZZjFiN0RDSCOnosEKRZWxbQ+iMpQQ==", - "dev": true - }, - "karma-source-map-support": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", - "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", - "dev": true, - "requires": { - "source-map-support": "^0.5.5" - } - }, - "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 - }, - "klona": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", - "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==", - "dev": true - }, - "less": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/less/-/less-4.1.2.tgz", - "integrity": "sha512-EoQp/Et7OSOVu0aJknJOtlXZsnr8XE8KwuzTHOLeVSEx8pVWUICc8Q0VYRHgzyjX78nMEyC/oztWFbgyhtNfDA==", - "dev": true, - "requires": { - "copy-anything": "^2.0.1", - "errno": "^0.1.1", - "graceful-fs": "^4.1.2", - "image-size": "~0.5.0", - "make-dir": "^2.1.0", - "mime": "^1.4.1", - "needle": "^2.5.2", - "parse-node-version": "^1.0.1", - "source-map": "~0.6.0", - "tslib": "^2.3.0" - }, - "dependencies": { - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "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, - "optional": true, "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" + "color-convert": "^2.0.1" } }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "optional": true + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, - "optional": true + "requires": { + "color-name": "~1.1.4" + } }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "optional": true + "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 }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "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": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "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, - "optional": true + "requires": { + "has-flag": "^4.0.0" + } } } }, - "less-loader": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-10.2.0.tgz", - "integrity": "sha512-AV5KHWvCezW27GT90WATaDnfXBv99llDbtaj4bshq6DvAihMdNjaPDcUMa6EXKLRF+P2opFenJp89BXg91XLYg==", + "jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", "dev": true, "requires": { - "klona": "^2.0.4" - } - }, - "license-webpack-plugin": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", - "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", - "dev": true, - "requires": { - "webpack-sources": "^3.0.0" - } - }, - "lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "dev": true, - "requires": { - "immediate": "~3.0.5" - } - }, - "lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "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": "3.2.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.0.tgz", - "integrity": "sha512-HVl9ZqccQihZ7JM85dco1MvO9G+ONvxoGa9rkhzFsneGLKSUg1gJf9bWzhRhcvm2qChhWpebQhP44qxjKIUCaQ==", - "dev": true - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "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 - }, - "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" + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" }, "dependencies": { "ansi-styles": { @@ -19176,24 +24076,1635 @@ } } }, - "log4js": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.4.2.tgz", - "integrity": "sha512-k80cggS2sZQLBwllpT1p06GtfvzMmSdUCkW96f0Hj83rKGJDAu2vZjt9B9ag2vx8Zz1IXzxoLgqvRJCdMKybGg==", + "jest-docblock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", + "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", "dev": true, "requires": { - "date-format": "^4.0.4", - "debug": "^4.3.3", - "flatted": "^3.2.5", + "detect-newline": "^3.0.0" + } + }, + "jest-each": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", + "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.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" + } + }, + "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-jsdom": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", + "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", + "dev": true, + "requires": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1", + "jsdom": "^16.6.0" + } + }, + "jest-environment-node": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", + "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", + "dev": true, + "requires": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + } + }, + "jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true + }, + "jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "@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.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + } + }, + "jest-jasmine2": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", + "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", + "dev": true, + "requires": { + "@jest/environment": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "throat": "^6.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" + } + }, + "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-leak-detector": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", + "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", + "dev": true, + "requires": { + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + } + }, + "jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.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" + } + }, + "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-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^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.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 + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "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.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*" + } + }, + "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-preset-angular": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/jest-preset-angular/-/jest-preset-angular-11.1.0.tgz", + "integrity": "sha512-R4ePMBiQub95ESJlN7TozIpRIyMU7buvIdjm8KXqxZK/w8MYwLOSszVStsoZycDmWq5ifZI1eRvhOCUFktFotw==", + "dev": true, + "requires": { + "bs-logger": "^0.2.6", + "esbuild": "0.14.2", + "esbuild-wasm": "0.14.2", + "jest-environment-jsdom": "^27.0.0", + "pretty-format": "^27.0.0", + "ts-jest": "^27.0.0" + }, + "dependencies": { + "esbuild": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.2.tgz", + "integrity": "sha512-l076A6o/PIgcyM24s0dWmDI/b8RQf41uWoJu9I0M71CtW/YSw5T5NUeXxs5lo2tFQD+O4CW4nBHJXx3OY5NpXg==", + "dev": true, + "optional": true, + "requires": { + "esbuild-android-arm64": "0.14.2", + "esbuild-darwin-64": "0.14.2", + "esbuild-darwin-arm64": "0.14.2", + "esbuild-freebsd-64": "0.14.2", + "esbuild-freebsd-arm64": "0.14.2", + "esbuild-linux-32": "0.14.2", + "esbuild-linux-64": "0.14.2", + "esbuild-linux-arm": "0.14.2", + "esbuild-linux-arm64": "0.14.2", + "esbuild-linux-mips64le": "0.14.2", + "esbuild-linux-ppc64le": "0.14.2", + "esbuild-netbsd-64": "0.14.2", + "esbuild-openbsd-64": "0.14.2", + "esbuild-sunos-64": "0.14.2", + "esbuild-windows-32": "0.14.2", + "esbuild-windows-64": "0.14.2", + "esbuild-windows-arm64": "0.14.2" + } + }, + "esbuild-android-arm64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.2.tgz", + "integrity": "sha512-hEixaKMN3XXCkoe+0WcexO4CcBVU5DCSUT+7P8JZiWZCbAjSkc9b6Yz2X5DSfQmRCtI/cQRU6TfMYrMQ5NBfdw==", + "dev": true, + "optional": true + }, + "esbuild-darwin-64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.2.tgz", + "integrity": "sha512-Uq8t0cbJQkxkQdbUfOl2wZqZ/AtLZjvJulR1HHnc96UgyzG9YlCLSDMiqjM+NANEy7/zzvwKJsy3iNC9wwqLJA==", + "dev": true, + "optional": true + }, + "esbuild-darwin-arm64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.2.tgz", + "integrity": "sha512-619MSa17sr7YCIrUj88KzQu2ESA4jKYtIYfLU/smX6qNgxQt3Y/gzM4s6sgJ4fPQzirvmXgcHv1ZNQAs/Xh48A==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.2.tgz", + "integrity": "sha512-aP6FE/ZsChZpUV6F3HE3x1Pz0paoYXycJ7oLt06g0G9dhJKknPawXCqQg/WMyD+ldCEZfo7F1kavenPdIT/SGQ==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-arm64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.2.tgz", + "integrity": "sha512-LSm98WTb1QIhyS83+Po0KTpZNdd2XpVpI9ua5rLWqKWbKeNRFwOsjeiuwBaRNc+O32s9oC2ZMefETxHBV6VNkQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-32": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.2.tgz", + "integrity": "sha512-8VxnNEyeUbiGflTKcuVc5JEPTqXfsx2O6ABwUbfS1Hp26lYPRPC7pKQK5Dxa0MBejGc50jy7YZae3EGQUQ8EkQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.2.tgz", + "integrity": "sha512-4bzMS2dNxOJoFIiHId4w+tqQzdnsch71JJV1qZnbnErSFWcR9lRgpSqWnTTFtv6XM+MvltRzSXC5wQ7AEBY6Hg==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.2.tgz", + "integrity": "sha512-PaylahvMHhH8YMfJPMKEqi64qA0Su+d4FNfHKvlKes/2dUe4QxgbwXT9oLVgy8iJdcFMrO7By4R8fS8S0p8aVQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.2.tgz", + "integrity": "sha512-RlIVp0RwJrdtasDF1vTFueLYZ8WuFzxoQ1OoRFZOTyJHCGCNgh7xJIC34gd7B7+RT0CzLBB4LcM5n0LS+hIoww==", + "dev": true, + "optional": true + }, + "esbuild-linux-mips64le": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.2.tgz", + "integrity": "sha512-Fdwrq2roFnO5oetIiUQQueZ3+5soCxBSJswg3MvYaXDomj47BN6oAWMZgLrFh1oVrtWrxSDLCJBenYdbm2s+qQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-ppc64le": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.2.tgz", + "integrity": "sha512-vxptskw8JfCDD9QqpRO0XnsM1osuWeRjPaXX1TwdveLogYsbdFtcuiuK/4FxGiNMUr1ojtnCS2rMPbY8puc5NA==", + "dev": true, + "optional": true + }, + "esbuild-netbsd-64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.2.tgz", + "integrity": "sha512-I8+LzYK5iSNpspS9eCV9sW67Rj8FgMHimGri4mKiGAmN0pNfx+hFX146rYtzGtewuxKtTsPywWteHx+hPRLDsw==", + "dev": true, + "optional": true + }, + "esbuild-openbsd-64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.2.tgz", + "integrity": "sha512-120HgMe9elidWUvM2E6mMf0csrGwx8sYDqUIJugyMy1oHm+/nT08bTAVXuwYG/rkMIqsEO9AlMxuYnwR6En/3Q==", + "dev": true, + "optional": true + }, + "esbuild-sunos-64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.2.tgz", + "integrity": "sha512-Q3xcf9Uyfra9UuCFxoLixVvdigo0daZaKJ97TL2KNA4bxRUPK18wwGUk3AxvgDQZpRmg82w9PnkaNYo7a+24ow==", + "dev": true, + "optional": true + }, + "esbuild-wasm": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.14.2.tgz", + "integrity": "sha512-Rs8NjWoo1UdsVjhxT2o6kLCX9Sh65pyd3/h4XeJ3jjQNM6NgL+/CSowuJgvOIjDAXMLXpc6fdGnyZQDil9IUJA==", + "dev": true + }, + "esbuild-windows-32": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.2.tgz", + "integrity": "sha512-TW7O49tPsrq+N1sW8mb3m24j/iDGa4xzAZH4wHWwoIzgtZAYPKC0hpIhufRRG/LA30bdMChO9pjJZ5mtcybtBQ==", + "dev": true, + "optional": true + }, + "esbuild-windows-64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.2.tgz", + "integrity": "sha512-Rym6ViMNmi1E2QuQMWy0AFAfdY0wGwZD73BnzlsQBX5hZBuy/L+Speh7ucUZ16gwsrMM9v86icZUDrSN/lNBKg==", + "dev": true, + "optional": true + }, + "esbuild-windows-arm64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.2.tgz", + "integrity": "sha512-ZrLbhr0vX5Em/P1faMnHucjVVWPS+m3tktAtz93WkMZLmbRJevhiW1y4CbulBd2z0MEdXZ6emDa1zFHq5O5bSA==", + "dev": true, + "optional": true + } + } + }, + "jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "dev": true + }, + "jest-resolve": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", + "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^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" + } + }, + "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 + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "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.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", + "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-snapshot": "^27.5.1" + } + }, + "jest-runner": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", + "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", + "dev": true, + "requires": { + "@jest/console": "^27.5.1", + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-leak-detector": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "source-map-support": "^0.5.6", + "throat": "^6.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" + } + }, + "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.5.1", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", + "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", + "dev": true, + "requires": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/globals": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "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.9", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0", + "strip-bom": "^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.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 + }, + "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" + } + }, + "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 + }, + "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 + }, + "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 + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "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.5.1", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", + "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", + "dev": true, + "requires": { + "@types/node": "*", + "graceful-fs": "^4.2.9" + } + }, + "jest-snapshot": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", + "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", + "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.5.1", + "@jest/types": "^27.5.1", + "@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.5.1", + "graceful-fs": "^4.2.9", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^27.5.1", + "semver": "^7.3.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.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-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.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.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": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", + "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "leven": "^3.1.0", + "pretty-format": "^27.5.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" + } + }, + "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 + }, + "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.5.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", + "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", + "dev": true, + "requires": { + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^27.5.1", + "string-length": "^4.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" + } + }, + "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-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "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" + } + } + } + }, + "joi": { + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.6.0.tgz", + "integrity": "sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw==", + "dev": true, + "requires": { + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0", + "@sideway/address": "^4.1.3", + "@sideway/formula": "^3.0.0", + "@sideway/pinpoint": "^2.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": "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" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "optional": true + }, + "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": { + "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" + } + }, + "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" + } + }, + "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 + } + } + }, + "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==", + "optional": true + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "devOptional": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "optional": true + }, + "json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" + }, + "jsonc-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", + "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", + "devOptional": true + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "optional": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", + "dev": true + }, + "jsprim": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", + "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", + "optional": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, + "karma-source-map-support": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", + "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", + "dev": true, + "requires": { + "source-map-support": "^0.5.5" + } + }, + "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 + }, + "lazy-ass": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", + "integrity": "sha1-eZllXoZGwX8In90YfRUNMyTVRRM=", + "optional": true + }, + "less": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/less/-/less-4.1.2.tgz", + "integrity": "sha512-EoQp/Et7OSOVu0aJknJOtlXZsnr8XE8KwuzTHOLeVSEx8pVWUICc8Q0VYRHgzyjX78nMEyC/oztWFbgyhtNfDA==", + "dev": true, + "requires": { + "copy-anything": "^2.0.1", + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^2.5.2", + "parse-node-version": "^1.0.1", + "source-map": "~0.6.0", + "tslib": "^2.3.0" + }, + "dependencies": { + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "optional": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "optional": 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, + "optional": true + } + } + }, + "less-loader": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-10.2.0.tgz", + "integrity": "sha512-AV5KHWvCezW27GT90WATaDnfXBv99llDbtaj4bshq6DvAihMdNjaPDcUMa6EXKLRF+P2opFenJp89BXg91XLYg==", + "dev": true, + "requires": { + "klona": "^2.0.4" + } + }, + "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.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" + } + }, + "license-webpack-plugin": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", + "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", + "dev": true, + "requires": { + "webpack-sources": "^3.0.0" + } + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "listr2": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", + "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==", + "optional": true, + "requires": { + "cli-truncate": "^2.1.0", + "colorette": "^2.0.16", + "log-update": "^4.0.0", + "p-map": "^4.0.0", "rfdc": "^1.3.0", - "streamroller": "^3.0.4" + "rxjs": "^7.5.1", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" + } + }, + "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": "3.2.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.0.tgz", + "integrity": "sha512-HVl9ZqccQihZ7JM85dco1MvO9G+ONvxoGa9rkhzFsneGLKSUg1gJf9bWzhRhcvm2qChhWpebQhP44qxjKIUCaQ==", + "dev": true + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "devOptional": true + }, + "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.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.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=", + "optional": 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==", + "devOptional": 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==", + "devOptional": 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==", + "devOptional": 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==", + "devOptional": 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==", + "devOptional": 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==", + "devOptional": 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==", + "devOptional": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "log-update": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", + "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "optional": true, + "requires": { + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.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==", + "optional": 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==", + "optional": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "optional": true + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "optional": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "optional": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + } } }, "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" } @@ -19202,7 +25713,7 @@ "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, + "devOptional": true, "requires": { "sourcemap-codec": "^1.4.4" } @@ -19254,6 +25765,15 @@ "ssri": "^8.0.0" } }, + "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" + } + }, "material-colors": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz", @@ -19284,7 +25804,7 @@ "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 + "devOptional": true }, "merge2": { "version": "1.4.1", @@ -19299,41 +25819,41 @@ "dev": true }, "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "braces": "^3.0.2", + "picomatch": "^2.3.1" } }, "mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "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==", - "dev": true + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "devOptional": true }, "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==", - "dev": true, + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "devOptional": true, "requires": { - "mime-db": "1.51.0" + "mime-db": "1.52.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 + "devOptional": true }, "mini-css-extract-plugin": { "version": "2.5.3", @@ -19344,15 +25864,6 @@ "schema-utils": "^4.0.0" }, "dependencies": { - "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" - } - }, "schema-utils": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", @@ -19382,9 +25893,10 @@ } }, "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "devOptional": true }, "minipass": { "version": "3.1.6", @@ -19497,9 +26009,15 @@ "dev": true }, "nanoid": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", - "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.2.tgz", + "integrity": "sha512-CuHBogktKwpm5g2sRgv83jEy2ijFzBwMoYA60orPDR7ynsLijJDqgsi4RDGj3OJpy3Ieb+LYwiRmIOGyytgITA==", + "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 }, "needle": { @@ -19539,11 +26057,11 @@ "dev": true }, "ng2-pdf-viewer": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/ng2-pdf-viewer/-/ng2-pdf-viewer-8.0.1.tgz", - "integrity": "sha512-uJNHo0VanlK0VZUryzO66xzskg3ounD2Uz9OOtpCjGKjlJjnoKToxa2QJlJiLmmyErEWd4KI6dSeHvAaiTZ+SA==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/ng2-pdf-viewer/-/ng2-pdf-viewer-9.0.0.tgz", + "integrity": "sha512-MaPCQJMeSRV7kzVTRskygdf1YrCCfmHqKPGrhQjdkBPj5HDFX02SOxVTlnJrl2KLO6nUyJ8xAdf4Pojf85gKaw==", "requires": { - "pdfjs-dist": "~2.11.338", + "pdfjs-dist": "~2.13.216", "tslib": "^2.3.1" } }, @@ -19573,15 +26091,6 @@ "tslib": "^2.0.0" } }, - "ngx-infinite-scroll": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/ngx-infinite-scroll/-/ngx-infinite-scroll-10.0.1.tgz", - "integrity": "sha512-7is0eJZ9kJPsaHohRmMhJ/QFHAW9jp9twO5HcHRvFM/Yl/R8QCiokgjwmH0/CR3MuxUanxfHZMfO3PbYTwlBEg==", - "requires": { - "@scarf/scarf": "^1.1.0", - "opencollective-postinstall": "^2.0.2" - } - }, "nice-napi": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", @@ -19601,9 +26110,9 @@ "optional": true }, "node-forge": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.2.1.tgz", - "integrity": "sha512-Fcvtbb+zBcZXbTTVwqGA5W+MKBj56UjVRevvchv5XrcyXbmNdesfZL37nlcWOfpgHhgmxApw3tQbTr4CqNmX4w==", + "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-gyp": { @@ -19622,26 +26131,21 @@ "semver": "^7.3.5", "tar": "^6.1.2", "which": "^2.0.2" - }, - "dependencies": { - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } } }, "node-gyp-build": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", - "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.4.0.tgz", + "integrity": "sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ==", "dev": true, "optional": true }, + "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.2", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", @@ -19659,8 +26163,7 @@ "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 + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" }, "normalize-range": { "version": "0.1.2", @@ -19741,12 +26244,48 @@ "npm-package-arg": "^8.1.5" }, "dependencies": { + "@npmcli/fs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.0.tgz", + "integrity": "sha512-DmfBvNXGaetMxj9LTp8NAN9vEidXURrf5ZTslQzEAi/6GbW+4yjaLFQc6Tue5cpZ9Frlk4OBo/Snf1Bh/S7qTQ==", + "dev": true, + "requires": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + } + }, "@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", "dev": true }, + "cacache": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.0.3.tgz", + "integrity": "sha512-eC7wYodNCVb97kuHGk5P+xZsvUJHkhSEOyNwkenqQPAsOtrTjvWOE5vSPNBpz9d8X3acIf6w2Ub5s4rvOCTs4g==", + "dev": true, + "requires": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^1.1.2", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^7.2.0", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.1.11", + "unique-filename": "^1.1.1" + } + }, "http-proxy-agent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", @@ -19759,27 +26298,27 @@ } }, "lru-cache": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.4.1.tgz", - "integrity": "sha512-NCD7/WRlFmADccuHjsRUYqdluYBr//n/O0fesCb/n52FoGcgKh8o4Dpm7YIbZwVcDs8rPBQbCZLmWWsp6m+xGQ==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.3.tgz", + "integrity": "sha512-WY9wjJNQt9+PZilnLbuFKM+SwDull9+6IAguOrarOMoOHTcJ9GnXSO11+Gw6c7xtDkBkthR57OZMtZKYr+1CEw==", "dev": true }, "make-fetch-happen": { - "version": "10.0.4", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.0.4.tgz", - "integrity": "sha512-CiReW6usy3UXby5N46XjWfLPFPq1glugCszh18I0NYJCwr129ZAx9j3Dlv+cRsK0q3VjlVysEzhdtdw2+NhdYA==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.1.1.tgz", + "integrity": "sha512-3/mCljDQNjmrP7kl0vhS5WVlV+TvSKoZaFhdiYV7MOijEnrhrjaVnqbp/EY/7S+fhUB2KpH7j8c1iRsIOs+kjw==", "dev": true, "requires": { "agentkeepalive": "^4.2.1", - "cacache": "^15.3.0", + "cacache": "^16.0.2", "http-cache-semantics": "^4.1.0", "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0", "is-lambda": "^1.0.1", - "lru-cache": "^7.4.0", + "lru-cache": "^7.7.1", "minipass": "^3.1.6", "minipass-collect": "^1.0.2", - "minipass-fetch": "^2.0.1", + "minipass-fetch": "^2.0.3", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^0.6.3", @@ -19789,9 +26328,9 @@ }, "dependencies": { "minipass-fetch": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.0.2.tgz", - "integrity": "sha512-M63u5yWX0yxY1C3DcLVY1xWai0pNM3qa1xCMXFgdejY5F/NTmyzNVHGcBxKerX51lssqxwWWTjpg/ZPuD39gOQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.0.tgz", + "integrity": "sha512-H9U4UVBGXEyyWJnqYDCLp1PwD8XIkJ4akNHp1aGVI+2Ym7wQMlxDKi4IB4JbmyU+pl9pEs/cVrK6cOuvmbK4Sg==", "dev": true, "requires": { "encoding": "^0.1.13", @@ -19808,7 +26347,7 @@ "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, + "devOptional": true, "requires": { "path-key": "^3.0.0" } @@ -19834,16 +26373,10 @@ "boolbase": "^1.0.0" } }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "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=", + "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-is": { @@ -19907,7 +26440,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, + "devOptional": true, "requires": { "mimic-fn": "^2.1.0" } @@ -19923,16 +26456,25 @@ "is-wsl": "^2.2.0" } }, - "opencollective-postinstall": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz", - "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==" + "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" + } }, "ora": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "dev": true, + "devOptional": true, "requires": { "bl": "^4.1.0", "chalk": "^4.1.0", @@ -19949,7 +26491,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, + "devOptional": true, "requires": { "color-convert": "^2.0.1" } @@ -19958,7 +26500,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, + "devOptional": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -19968,7 +26510,7 @@ "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, + "devOptional": true, "requires": { "color-name": "~1.1.4" } @@ -19977,19 +26519,19 @@ "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 + "devOptional": 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 + "devOptional": 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, + "devOptional": true, "requires": { "has-flag": "^4.0.0" } @@ -20002,6 +26544,12 @@ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, + "ospath": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", + "integrity": "sha1-EnZjl3Sj+O8lcvf+QoDg6kVQwHs=", + "optional": true + }, "p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -20024,7 +26572,7 @@ "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, + "devOptional": true, "requires": { "aggregate-error": "^3.0.0" } @@ -20164,17 +26712,11 @@ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "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 + "devOptional": true }, "path-parse": { "version": "1.0.7", @@ -20195,15 +26737,24 @@ "dev": true }, "pdfjs-dist": { - "version": "2.11.338", - "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-2.11.338.tgz", - "integrity": "sha512-Ti5VTB0VvSdtTtc7TG71ghMx0SEuNcEs4ghVuZxW0p6OqLjMc0xekZV1B+MmlxEG2Du2e5jgazucWIG/SXTcdA==" + "version": "2.13.216", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-2.13.216.tgz", + "integrity": "sha512-qn/9a/3IHIKZarTK6ajeeFXBkG15Lg1Fx99PxU09PAU2i874X8mTcHJYyDJxu7WDfNhV6hM7bRQBZU384anoqQ==", + "requires": { + "web-streams-polyfill": "^3.2.0" + } + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "optional": 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 + "optional": true }, "picocolors": { "version": "1.0.0", @@ -20213,30 +26764,20 @@ "picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" }, "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true + "devOptional": true }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", "dev": true }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, - "requires": { - "pinkie": "^2.0.0" - } - }, "piscina": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/piscina/-/piscina-3.2.0.tgz", @@ -20269,6 +26810,15 @@ "mkdirp": "^0.5.5" }, "dependencies": { + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, "debug": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", @@ -20279,12 +26829,12 @@ } }, "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "requires": { - "minimist": "^1.2.5" + "minimist": "^1.2.6" } } } @@ -20340,12 +26890,13 @@ "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 + "dev": true, + "requires": {} }, "postcss-custom-properties": { - "version": "12.1.4", - "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.4.tgz", - "integrity": "sha512-i6AytuTCoDLJkWN/MtAIGriJz3j7UX6bV7Z5t+KgFz+dwZS15/mlTJY1S0kRizlk6ba0V8u8hN50Fz5Nm7tdZw==", + "version": "12.1.5", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.5.tgz", + "integrity": "sha512-FHbbB/hRo/7cxLGkc2NS7cDRIDN1oFqQnUKBiyh4b/gwk8DD8udvmRDpUhEK836kB8ggUCieHVOvZDnF9XhI3g==", "dev": true, "requires": { "postcss-value-parser": "^4.2.0" @@ -20380,9 +26931,9 @@ } }, "postcss-env-function": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-4.0.5.tgz", - "integrity": "sha512-gPUJc71ji9XKyl0WSzAalBeEA/89kU+XpffpPxSaaaZ1c48OL36r1Ep5R6+9XAPkIiDlSvVAwP4io12q/vTcvA==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-4.0.6.tgz", + "integrity": "sha512-kpA6FsLra+NqcFnL81TnsU+Z7orGtDTxcOhl6pwXeEq1yFPpRMkCDpHhrz8CFQDr/Wfm0jLiNQ1OsGGPjlqPwA==", "dev": true, "requires": { "postcss-value-parser": "^4.2.0" @@ -20410,13 +26961,15 @@ "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 + "dev": true, + "requires": {} }, "postcss-gap-properties": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.3.tgz", "integrity": "sha512-rPPZRLPmEKgLk/KlXMqRaNkYTUpE7YC+bOIQFN5xcu1Vp11Y4faIXv6/Jpft6FMnl6YRxZqDZG0qQOW80stzxQ==", - "dev": true + "dev": true, + "requires": {} }, "postcss-image-set-function": { "version": "4.0.6", @@ -20442,12 +26995,13 @@ "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 + "dev": true, + "requires": {} }, "postcss-lab-function": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-4.1.1.tgz", - "integrity": "sha512-j3Z0WQCimY2tMle++YcmygnnVbt6XdnrCV1FO2IpzaCSmtTF2oO8h4ZYUA1Q+QHYroIiaWPvNHt9uBR4riCksQ==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-4.1.2.tgz", + "integrity": "sha512-isudf5ldhg4fk16M8viAwAbg6Gv14lVO35N3Z/49NhbwPQ2xbiEoHgrRgpgQojosF4vF7jY653ktB6dDrUOR8Q==", "dev": true, "requires": { "@csstools/postcss-progressive-custom-properties": "^1.1.0", @@ -20469,19 +27023,22 @@ "version": "5.0.4", "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz", "integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==", - "dev": true + "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 + "dev": true, + "requires": {} }, "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 + "dev": true, + "requires": {} }, "postcss-modules-local-by-default": { "version": "4.0.0", @@ -20525,13 +27082,15 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.3.tgz", "integrity": "sha512-CxZwoWup9KXzQeeIxtgOciQ00tDtnylYIlJBBODqkgS/PU2jISuWOL/mYLHmZb9ZhZiCaNKsCRiLp22dZUtNsg==", - "dev": true + "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 + "dev": true, + "requires": {} }, "postcss-place": { "version": "7.0.4", @@ -20596,7 +27155,8 @@ "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 + "dev": true, + "requires": {} }, "postcss-selector-not": { "version": "5.0.0", @@ -20608,9 +27168,9 @@ } }, "postcss-selector-parser": { - "version": "6.0.9", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz", - "integrity": "sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==", + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", "dev": true, "requires": { "cssesc": "^3.0.0", @@ -20623,11 +27183,36 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true }, + "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 + }, "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 + "devOptional": 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 + } + } }, "process-nextick-args": { "version": "2.0.1", @@ -20651,199 +27236,14 @@ "retry": "^0.12.0" } }, - "protractor": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/protractor/-/protractor-7.0.0.tgz", - "integrity": "sha512-UqkFjivi4GcvUQYzqGYNe0mLzfn5jiLmO8w9nMhQoJRLhy2grJonpga2IWhI6yJO30LibWXJJtA4MOIZD2GgZw==", + "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": { - "@types/q": "^0.0.32", - "@types/selenium-webdriver": "^3.0.0", - "blocking-proxy": "^1.0.0", - "browserstack": "^1.5.1", - "chalk": "^1.1.3", - "glob": "^7.0.3", - "jasmine": "2.8.0", - "jasminewd2": "^2.1.0", - "q": "1.4.1", - "saucelabs": "^1.5.0", - "selenium-webdriver": "3.6.0", - "source-map-support": "~0.4.0", - "webdriver-js-extender": "2.1.0", - "webdriver-manager": "^12.1.7", - "yargs": "^15.3.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "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" - } - } - } - }, - "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 - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "dev": true, - "requires": { - "source-map": "^0.5.6" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "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" - } - }, - "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" - } - } - } - }, - "y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, - "yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - } - }, - "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" } }, "proxy-addr": { @@ -20864,6 +27264,12 @@ } } }, + "proxy-from-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", + "integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=", + "optional": true + }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -20875,31 +27281,29 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true + "devOptional": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "optional": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "q": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", - "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=", - "dev": true - }, - "qjobs": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", - "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", - "dev": true + "devOptional": true }, "qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==", - "dev": true + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "optional": true }, "queue-microtask": { "version": "1.2.3", @@ -20932,8 +27336,22 @@ "http-errors": "1.8.1", "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-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 + }, "read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -20957,7 +27375,7 @@ "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, + "devOptional": true, "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -20968,7 +27386,6 @@ "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" } @@ -20976,8 +27393,7 @@ "reflect-metadata": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", - "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", - "dev": true + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" }, "regenerate": { "version": "1.4.2", @@ -21062,46 +27478,13 @@ } } }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "dev": true, + "request-progress": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", + "integrity": "sha1-TKdUCBx/7GP1BeT6qCWqBs1mnb4=", + "optional": true, "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "dev": true - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true - } + "throttleit": "^1.0.0" } }, "require-directory": { @@ -21113,13 +27496,7 @@ "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 - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true + "devOptional": true }, "requires-port": { "version": "1.0.0", @@ -21138,6 +27515,15 @@ "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" + } + }, "resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -21176,11 +27562,17 @@ } } }, + "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, + "devOptional": true, "requires": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" @@ -21202,13 +27594,13 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", - "dev": true + "optional": 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, + "devOptional": true, "requires": { "glob": "^7.1.3" } @@ -21229,18 +27621,11 @@ } }, "rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", + "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", "requires": { - "tslib": "^1.9.0" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - } + "tslib": "^2.1.0" } }, "safe-buffer": { @@ -21252,12 +27637,12 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "devOptional": true }, "sass": { - "version": "1.49.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.49.0.tgz", - "integrity": "sha512-TVwVdNDj6p6b4QymJtNtRS2YtLJ/CqZriGg0eIAbAKMlN8Xy6kbv33FsEZSF7FufFFM705SQviHjjThfaQ4VNw==", + "version": "1.49.9", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.49.9.tgz", + "integrity": "sha512-YlYWkkHP9fbwaFRZQRXgDi3mXZShslVmmo+FVK3kHLUELHHEYrCmL1x6IUjC7wLS6VuJSAFXRQS/DxdsC4xL1A==", "dev": true, "requires": { "chokidar": ">=3.0.0 <4.0.0", @@ -21275,51 +27660,21 @@ "neo-async": "^2.6.2" } }, - "saucelabs": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.5.0.tgz", - "integrity": "sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ==", - "dev": true, - "requires": { - "https-proxy-agent": "^2.2.1" - }, - "dependencies": { - "agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", - "dev": true, - "requires": { - "es6-promisify": "^5.0.0" - } - }, - "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" - } - }, - "https-proxy-agent": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", - "dev": true, - "requires": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - } - } - } - }, "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" + } + }, "schema-utils": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", @@ -21343,6 +27698,13 @@ "uri-js": "^4.2.2" } }, + "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": {} + }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -21357,52 +27719,19 @@ "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", "dev": true }, - "selenium-webdriver": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", - "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==", - "dev": true, - "requires": { - "jszip": "^3.1.3", - "rimraf": "^2.5.4", - "tmp": "0.0.30", - "xml2js": "^0.4.17" - }, - "dependencies": { - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "tmp": { - "version": "0.0.30", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", - "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.1" - } - } - } - }, "selfsigned": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.0.0.tgz", - "integrity": "sha512-cUdFiCbKoa1mZ6osuJs2uDHrs0k0oprsKveFiiaBKCNq3SYyb5gs2HxhQyDNLCmL51ZZThqi4YNDpCK6GOP1iQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.0.1.tgz", + "integrity": "sha512-LmME957M1zOsUhG+67rAjKfiWFox3SBxE/yymatMZsAx+oMrJ0YQ8AToOnyCm7xbeg2ep37IHLxdu0o2MavQOQ==", "dev": true, "requires": { - "node-forge": "^1.2.0" + "node-forge": "^1" } }, "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" } @@ -21462,12 +27791,6 @@ } } }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true - }, "ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -21559,12 +27882,6 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, - "set-immediate-shim": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", - "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", - "dev": true - }, "setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -21584,7 +27901,7 @@ "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, + "devOptional": true, "requires": { "shebang-regex": "^3.0.0" } @@ -21593,12 +27910,18 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true + "devOptional": true }, "signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "devOptional": true + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", "dev": true }, "slash": { @@ -21607,43 +27930,49 @@ "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", "dev": true }, + "slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "optional": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "optional": 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==", + "optional": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "optional": true + } + } + }, "smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", "dev": true }, - "socket.io": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.4.1.tgz", - "integrity": "sha512-s04vrBswdQBUmuWJuuNTmXUVJhP0cVky8bBDhdkf8y0Ptsu7fKU2LuLbts9g+pdmAdyMMn8F/9Mf1/wbtUN0fg==", - "dev": true, - "requires": { - "accepts": "~1.3.4", - "base64id": "~2.0.0", - "debug": "~4.3.2", - "engine.io": "~6.1.0", - "socket.io-adapter": "~2.3.3", - "socket.io-parser": "~4.0.4" - } - }, - "socket.io-adapter": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.3.3.tgz", - "integrity": "sha512-Qd/iwn3VskrpNO60BeRyCyr8ZWw9CPZyitW4AQwmRZ8zCiyDiL+znRnWX6tDHXnWn1sJrM1+b6Mn6wEDJJ4aYQ==", - "dev": true - }, - "socket.io-parser": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.4.tgz", - "integrity": "sha512-t+b0SS+IxG7Rxzda2EVvyBZbvFPBCjJoyHuE0P//7OAsN23GItzDRdWa6ALxZI/8R5ygK7jAR6t028/z+7295g==", - "dev": true, - "requires": { - "@types/component-emitter": "^1.2.10", - "component-emitter": "~1.3.0", - "debug": "~4.3.1" - } - }, "sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -21680,7 +28009,7 @@ "version": "0.7.3", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true + "devOptional": true }, "source-map-js": { "version": "1.0.2", @@ -21741,7 +28070,12 @@ "sourcemap-codec": { "version": "1.4.8", "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" + }, + "spawn-command": { + "version": "0.0.2-1", + "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", + "integrity": "sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A=", "dev": true }, "spdy": { @@ -21781,7 +28115,7 @@ "version": "1.17.0", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", - "dev": true, + "optional": true, "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -21803,28 +28137,34 @@ "minipass": "^3.1.1" } }, + "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 + } + } + }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", "dev": true }, - "streamroller": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.0.4.tgz", - "integrity": "sha512-GI9NzeD+D88UFuIlJkKNDH/IsuR+qIN7Qh8EsmhoRZr9bQoehTraRgwtLUkZbpcAw+hLPfHOypmppz8YyGK68w==", - "dev": true, - "requires": { - "date-format": "^4.0.4", - "debug": "^4.3.3", - "fs-extra": "^10.0.1" - } - }, "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, + "devOptional": true, "requires": { "safe-buffer": "~5.2.0" }, @@ -21833,10 +28173,20 @@ "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 + "devOptional": 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-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -21855,10 +28205,22 @@ "ansi-regex": "^5.0.1" } }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true + }, "strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "devOptional": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, "stylus": { @@ -21894,6 +28256,33 @@ "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", @@ -21906,6 +28295,12 @@ "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", "dev": true }, + "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 + }, "tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -21926,6 +28321,16 @@ "yallist": "^4.0.0" } }, + "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.11.0", "resolved": "https://registry.npmjs.org/terser/-/terser-5.11.0.tgz", @@ -21963,6 +28368,13 @@ "uri-js": "^4.2.2" } }, + "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": {} + }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -22005,11 +28417,23 @@ "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 + }, + "throttleit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", + "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=", + "optional": true + }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true + "devOptional": true }, "thunky": { "version": "1.1.0", @@ -22018,14 +28442,20 @@ "dev": true }, "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "optional": true, "requires": { - "os-tmpdir": "~1.0.2" + "rimraf": "^3.0.0" } }, + "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", @@ -22035,7 +28465,6 @@ "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" } @@ -22050,18 +28479,43 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, + "optional": true, "requires": { "psl": "^1.1.28", "punycode": "^2.1.1" } }, + "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" + } + }, "tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "dev": true }, + "ts-jest": { + "version": "27.1.4", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.4.tgz", + "integrity": "sha512-qjkZlVPWVctAezwsOD1OPzbZ+k7zA5z3oxII4dGdZo5ggX/PL7kvwTM0pXTr10fAtbiVpJaL3bWd502zAhpgSQ==", + "dev": true, + "requires": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^27.0.0", + "json5": "2.x", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "7.x", + "yargs-parser": "20.x" + } + }, "ts-node": { "version": "10.7.0", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz", @@ -22081,6 +28535,14 @@ "make-error": "^1.1.1", "v8-compile-cache-lib": "^3.0.0", "yn": "3.1.1" + }, + "dependencies": { + "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 + } } }, "tslib": { @@ -22110,12 +28572,12 @@ }, "dependencies": { "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "requires": { - "minimist": "^1.2.5" + "minimist": "^1.2.6" } }, "semver": { @@ -22153,7 +28615,7 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.0.1" } @@ -22162,13 +28624,28 @@ "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "optional": 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" + } + }, + "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 + "devOptional": true }, "type-is": { "version": "1.6.18", @@ -22186,17 +28663,19 @@ "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", "dev": true }, - "typescript": { - "version": "4.5.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", - "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", - "dev": true + "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" + } }, - "ua-parser-js": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz", - "integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==", - "dev": true + "typescript": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz", + "integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==" }, "unicode-canonical-property-names-ecmascript": { "version": "2.0.0", @@ -22248,7 +28727,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true + "optional": true }, "unpipe": { "version": "1.0.0", @@ -22256,11 +28735,17 @@ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", "dev": true }, + "untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "optional": true + }, "uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, + "devOptional": true, "requires": { "punycode": "^2.1.0" } @@ -22269,7 +28754,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true + "devOptional": true }, "utils-merge": { "version": "1.0.1", @@ -22288,6 +28773,17 @@ "integrity": "sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA==", "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" + } + }, "validate-npm-package-name": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", @@ -22307,18 +28803,52 @@ "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, + "optional": true, "requires": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" } }, - "void-elements": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", - "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", - "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-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" + } + }, + "wait-on": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-6.0.1.tgz", + "integrity": "sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==", + "dev": true, + "requires": { + "axios": "^0.25.0", + "joi": "^17.6.0", + "lodash": "^4.17.21", + "minimist": "^1.2.5", + "rxjs": "^7.5.4" + } + }, + "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" + } }, "watchpack": { "version": "2.3.1", @@ -22343,111 +28873,30 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", - "dev": true, + "devOptional": true, "requires": { "defaults": "^1.0.3" } }, - "webdriver-js-extender": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz", - "integrity": "sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ==", - "dev": true, - "requires": { - "@types/selenium-webdriver": "^3.0.0", - "selenium-webdriver": "^3.0.1" - } + "web-streams-polyfill": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.0.tgz", + "integrity": "sha512-EqPmREeOzttaLRm5HS7io98goBgZ7IVz79aDvqjD0kYXLtFZTc0T/U6wHTPKyIjb+MdN7DFIIX6hgdBEpWmfPA==" }, - "webdriver-manager": { - "version": "12.1.8", - "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.1.8.tgz", - "integrity": "sha512-qJR36SXG2VwKugPcdwhaqcLQOD7r8P2Xiv9sfNbfZrKBnX243iAkOueX1yAmeNgIKhJ3YAT/F2gq6IiEZzahsg==", - "dev": true, - "requires": { - "adm-zip": "^0.4.9", - "chalk": "^1.1.1", - "del": "^2.2.0", - "glob": "^7.0.3", - "ini": "^1.3.4", - "minimist": "^1.2.0", - "q": "^1.4.1", - "request": "^2.87.0", - "rimraf": "^2.5.2", - "semver": "^5.3.0", - "xml2js": "^0.4.17" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } + "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.67.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.67.0.tgz", - "integrity": "sha512-LjFbfMh89xBDpUMgA1W9Ur6Rn/gnr2Cq1jjHFPo4v6a79/ypznSYbAyPgGhwsxBtMIaEmDD1oJoA7BEYw/Fbrw==", + "version": "5.70.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.70.0.tgz", + "integrity": "sha512-ZMWWy8CeuTTjCxbeaQI21xSswseF2oNOwc70QSKNePvmxE7XW36i7vpBMYZFAUHPwQiEbNGCEYIOOlyRbdGmxw==", "dev": true, "requires": { - "@types/eslint-scope": "^3.7.0", - "@types/estree": "^0.0.50", + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/wasm-edit": "1.11.1", "@webassemblyjs/wasm-parser": "1.11.1", @@ -22455,7 +28904,7 @@ "acorn-import-assertions": "^1.7.6", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.8.3", + "enhanced-resolve": "^5.9.2", "es-module-lexer": "^0.9.0", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -22484,6 +28933,13 @@ "uri-js": "^4.2.2" } }, + "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": {} + }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -22516,15 +28972,6 @@ "schema-utils": "^4.0.0" }, "dependencies": { - "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" - } - }, "schema-utils": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", @@ -22576,69 +29023,12 @@ "ws": "^8.1.0" }, "dependencies": { - "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" - } - }, "ansi-regex": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "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" - } - }, - "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" - } - }, - "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 - }, "schema-utils": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", @@ -22651,12 +29041,6 @@ "ajv-keywords": "^5.0.0" } }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, "strip-ansi": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", @@ -22665,6 +29049,13 @@ "requires": { "ansi-regex": "^6.0.1" } + }, + "ws": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", + "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "dev": true, + "requires": {} } } }, @@ -22710,21 +29101,41 @@ "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "dev": true }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "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-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==", + "devOptional": true, "requires": { "isexe": "^2.0.0" } }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, "wide-align": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", @@ -22740,6 +29151,12 @@ "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", "dev": true }, + "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 + }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -22778,26 +29195,35 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, - "ws": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", - "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", - "dev": true - }, - "xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "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": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" } }, - "xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "ws": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", + "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "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 }, "y18n": { @@ -22808,8 +29234,7 @@ "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "yaml": { "version": "1.10.2", @@ -22818,9 +29243,9 @@ "dev": true }, "yargs": { - "version": "17.3.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz", - "integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==", + "version": "17.4.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.4.0.tgz", + "integrity": "sha512-WJudfrk81yWFSOkZYpAZx4Nt7V4xp7S/uJkX0CnxovMCt1wCE8LNftPpNuF9X/u9gN5nsD7ycYtRcDf2pL3UiA==", "requires": { "cliui": "^7.0.2", "escalade": "^3.1.1", @@ -22829,12 +29254,30 @@ "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.0.0" + }, + "dependencies": { + "yargs-parser": { + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", + "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==" + } } }, "yargs-parser": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", - "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==" + "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 + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "optional": true, + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } }, "yn": { "version": "3.1.1", diff --git a/src-ui/package.json b/src-ui/package.json index dca4a3df7..e29b46275 100644 --- a/src-ui/package.json +++ b/src-ui/package.json @@ -7,53 +7,52 @@ "build": "ng build", "test": "ng test", "lint": "ng lint", - "e2e": "ng e2e" + "e2e": "ng e2e", + "cy:run": "cypress run", + "e2e:ci": "concurrently 'npm run start' 'wait-on http-get://localhost:4200 && npm run cy:run' --kill-others --success first" }, "private": true, "dependencies": { - "@angular/animations": "~13.2.4", - "@angular/common": "~13.2.5", - "@angular/compiler": "~13.2.4", - "@angular/core": "~13.2.4", - "@angular/forms": "~13.2.5", - "@angular/localize": "~13.2.4", - "@angular/platform-browser": "~13.2.5", - "@angular/platform-browser-dynamic": "~13.2.4", - "@angular/router": "~13.2.5", - "@ng-bootstrap/ng-bootstrap": "^12.0.0", + "@angular/common": "~13.3.1", + "@angular/compiler": "~13.3.1", + "@angular/core": "~13.3.1", + "@angular/forms": "~13.3.1", + "@angular/localize": "~13.3.1", + "@angular/platform-browser": "~13.3.1", + "@angular/platform-browser-dynamic": "~13.3.1", + "@angular/router": "~13.3.1", + "@ng-bootstrap/ng-bootstrap": "^12.0.1", "@ng-select/ng-select": "^8.1.1", - "@ngneat/dirty-check-forms": "^1.1.0", - "@popperjs/core": "^2.11.2", + "@ngneat/dirty-check-forms": "^3.0.2", + "@popperjs/core": "^2.11.4", "bootstrap": "^5.1.3", "file-saver": "^2.0.5", - "ng2-pdf-viewer": "^8.0.1", + "ng2-pdf-viewer": "^9.0.0", "ngx-color": "^7.3.3", "ngx-cookie-service": "^13.1.2", "ngx-file-drop": "^13.0.0", - "ngx-infinite-scroll": "^10.0.1", - "rxjs": "~6.6.7", + "rxjs": "~7.5.5", "tslib": "^2.3.1", "uuid": "^8.3.1", "zone.js": "~0.11.4" }, "devDependencies": { - "@angular-devkit/build-angular": "~13.2.5", - "@angular/cli": "~13.2.5", - "@angular/compiler-cli": "~13.2.4", - "@types/jasmine": "~3.10.3", - "@types/jasminewd2": "~2.0.10", - "@types/node": "^17.0.21", + "@angular-builders/jest": "13.0.3", + "@angular-devkit/build-angular": "~13.3.1", + "@angular/cli": "~13.3.1", + "@angular/compiler-cli": "~13.3.1", + "@types/jest": "27.4.1", + "@types/node": "^17.0.23", "codelyzer": "^6.0.2", - "jasmine-core": "~4.0.1", - "jasmine-spec-reporter": "~7.0.0", - "karma": "~6.3.16", - "karma-chrome-launcher": "~3.1.0", - "karma-coverage-istanbul-reporter": "~3.0.3", - "karma-jasmine": "~4.0.1", - "karma-jasmine-html-reporter": "^1.7.0", - "protractor": "~7.0.0", + "concurrently": "7.0.0", + "jest": "27.5.1", "ts-node": "~10.7.0", "tslint": "~6.1.3", - "typescript": "~4.5.5" + "typescript": "~4.6.3", + "wait-on": "~6.0.1" + }, + "optionalDependencies": { + "cypress": "~9.5.3", + "@cypress/schematic": "^1.6.0" } } diff --git a/src-ui/setup-jest.ts b/src-ui/setup-jest.ts new file mode 100644 index 000000000..5ada7e7c6 --- /dev/null +++ b/src-ui/setup-jest.ts @@ -0,0 +1,30 @@ +import 'jest-preset-angular/setup-jest' + +/* global mocks for jsdom */ +const mock = () => { + let storage: { [key: string]: string } = {} + return { + getItem: (key: string) => (key in storage ? storage[key] : null), + setItem: (key: string, value: string) => (storage[key] = value || ''), + removeItem: (key: string) => delete storage[key], + clear: () => (storage = {}), + } +} + +Object.defineProperty(window, 'localStorage', { value: mock() }) +Object.defineProperty(window, 'sessionStorage', { value: mock() }) +Object.defineProperty(window, 'getComputedStyle', { + value: () => ['-webkit-appearance'], +}) + +Object.defineProperty(document.body.style, 'transform', { + value: () => { + return { + enumerable: true, + configurable: true, + } + }, +}) + +/* output shorter and more meaningful Zone error stack traces */ +// Error.stackTraceLimit = 2 diff --git a/src-ui/src/app/app-routing.module.ts b/src-ui/src/app/app-routing.module.ts index c2ea53bb7..436d2fad4 100644 --- a/src-ui/src/app/app-routing.module.ts +++ b/src-ui/src/app/app-routing.module.ts @@ -1,39 +1,47 @@ -import { NgModule } from '@angular/core'; -import { Routes, RouterModule } from '@angular/router'; -import { AppFrameComponent } from './components/app-frame/app-frame.component'; -import { DashboardComponent } from './components/dashboard/dashboard.component'; -import { DocumentDetailComponent } from './components/document-detail/document-detail.component'; -import { DocumentListComponent } from './components/document-list/document-list.component'; -import { CorrespondentListComponent } from './components/manage/correspondent-list/correspondent-list.component'; -import { DocumentTypeListComponent } from './components/manage/document-type-list/document-type-list.component'; -import { LogsComponent } from './components/manage/logs/logs.component'; -import { SettingsComponent } from './components/manage/settings/settings.component'; -import { TagListComponent } from './components/manage/tag-list/tag-list.component'; -import { NotFoundComponent } from './components/not-found/not-found.component'; -import {DocumentAsnComponent} from "./components/document-asn/document-asn.component"; -import { DirtyFormGuard } from './guards/dirty-form.guard'; +import { NgModule } from '@angular/core' +import { Routes, RouterModule } from '@angular/router' +import { AppFrameComponent } from './components/app-frame/app-frame.component' +import { DashboardComponent } from './components/dashboard/dashboard.component' +import { DocumentDetailComponent } from './components/document-detail/document-detail.component' +import { DocumentListComponent } from './components/document-list/document-list.component' +import { CorrespondentListComponent } from './components/manage/correspondent-list/correspondent-list.component' +import { DocumentTypeListComponent } from './components/manage/document-type-list/document-type-list.component' +import { LogsComponent } from './components/manage/logs/logs.component' +import { SettingsComponent } from './components/manage/settings/settings.component' +import { TagListComponent } from './components/manage/tag-list/tag-list.component' +import { NotFoundComponent } from './components/not-found/not-found.component' +import { DocumentAsnComponent } from './components/document-asn/document-asn.component' +import { DirtyFormGuard } from './guards/dirty-form.guard' const routes: Routes = [ - {path: '', redirectTo: 'dashboard', pathMatch: 'full'}, - {path: '', component: AppFrameComponent, children: [ - {path: 'dashboard', component: DashboardComponent }, - {path: 'documents', component: DocumentListComponent }, - {path: 'view/:id', component: DocumentListComponent }, - {path: 'documents/:id', component: DocumentDetailComponent }, - {path: 'asn/:id', component: DocumentAsnComponent }, - {path: 'tags', component: TagListComponent }, - {path: 'documenttypes', component: DocumentTypeListComponent }, - {path: 'correspondents', component: CorrespondentListComponent }, - {path: 'logs', component: LogsComponent }, - {path: 'settings', component: SettingsComponent, canDeactivate: [DirtyFormGuard] }, - ]}, + { path: '', redirectTo: 'dashboard', pathMatch: 'full' }, + { + path: '', + component: AppFrameComponent, + children: [ + { path: 'dashboard', component: DashboardComponent }, + { path: 'documents', component: DocumentListComponent }, + { path: 'view/:id', component: DocumentListComponent }, + { path: 'documents/:id', component: DocumentDetailComponent }, + { path: 'asn/:id', component: DocumentAsnComponent }, + { path: 'tags', component: TagListComponent }, + { path: 'documenttypes', component: DocumentTypeListComponent }, + { path: 'correspondents', component: CorrespondentListComponent }, + { path: 'logs', component: LogsComponent }, + { + path: 'settings', + component: SettingsComponent, + canDeactivate: [DirtyFormGuard], + }, + ], + }, - {path: '404', component: NotFoundComponent}, - {path: '**', redirectTo: '/404', pathMatch: 'full'} -]; + { path: '404', component: NotFoundComponent }, + { path: '**', redirectTo: '/404', pathMatch: 'full' }, +] @NgModule({ imports: [RouterModule.forRoot(routes, { relativeLinkResolution: 'legacy' })], - exports: [RouterModule] + exports: [RouterModule], }) -export class AppRoutingModule { } +export class AppRoutingModule {} diff --git a/src-ui/src/app/app.component.html b/src-ui/src/app/app.component.html index d9b7dd09b..2b050ed3f 100644 --- a/src-ui/src/app/app.component.html +++ b/src-ui/src/app/app.component.html @@ -1,3 +1,13 @@ - + + +
+

Drop files to begin upload

+
+
+ +
+
+
diff --git a/src-ui/src/app/app.component.spec.ts b/src-ui/src/app/app.component.spec.ts deleted file mode 100644 index 969a50dd9..000000000 --- a/src-ui/src/app/app.component.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { RouterTestingModule } from '@angular/router/testing'; -import { AppComponent } from './app.component'; - -describe('AppComponent', () => { - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ - RouterTestingModule - ], - declarations: [ - AppComponent - ], - }).compileComponents(); - }); - - it('should create the app', () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app).toBeTruthy(); - }); - - it(`should have as title 'paperless-ui'`, () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app.title).toEqual('paperless-ui'); - }); - - it('should render title', () => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.nativeElement; - expect(compiled.querySelector('.content span').textContent).toContain('paperless-ui app is running!'); - }); -}); diff --git a/src-ui/src/app/app.component.ts b/src-ui/src/app/app.component.ts index c5ec9604d..f8c98fbc7 100644 --- a/src-ui/src/app/app.component.ts +++ b/src-ui/src/app/app.component.ts @@ -1,25 +1,36 @@ -import { SettingsService, SETTINGS_KEYS } from './services/settings.service'; -import { Component, OnDestroy, OnInit } from '@angular/core'; -import { Router } from '@angular/router'; -import { Subscription } from 'rxjs'; -import { ConsumerStatusService } from './services/consumer-status.service'; -import { ToastService } from './services/toast.service'; +import { SettingsService, SETTINGS_KEYS } from './services/settings.service' +import { Component, OnDestroy, OnInit } from '@angular/core' +import { Router } from '@angular/router' +import { Subscription } from 'rxjs' +import { ConsumerStatusService } from './services/consumer-status.service' +import { ToastService } from './services/toast.service' +import { NgxFileDropEntry } from 'ngx-file-drop' +import { UploadDocumentsService } from './services/upload-documents.service' @Component({ selector: 'app-root', templateUrl: './app.component.html', - styleUrls: ['./app.component.scss'] + styleUrls: ['./app.component.scss'], }) export class AppComponent implements OnInit, OnDestroy { + newDocumentSubscription: Subscription + successSubscription: Subscription + failedSubscription: Subscription - newDocumentSubscription: Subscription; - successSubscription: Subscription; - failedSubscription: Subscription; + private fileLeaveTimeoutID: any + fileIsOver: boolean = false + hidden: boolean = true - constructor (private settings: SettingsService, private consumerStatusService: ConsumerStatusService, private toastService: ToastService, private router: Router) { - let anyWindow = (window as any) - anyWindow.pdfWorkerSrc = 'assets/js/pdf.worker.min.js'; - this.settings.updateDarkModeSettings() + constructor( + private settings: SettingsService, + private consumerStatusService: ConsumerStatusService, + private toastService: ToastService, + private router: Router, + private uploadDocumentsService: UploadDocumentsService + ) { + let anyWindow = window as any + anyWindow.pdfWorkerSrc = 'assets/js/pdf.worker.min.js' + this.settings.updateAppearanceSettings() } ngOnDestroy(): void { @@ -36,7 +47,12 @@ export class AppComponent implements OnInit, OnDestroy { } private showNotification(key) { - if (this.router.url == '/dashboard' && this.settings.get(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD)) { + if ( + this.router.url == '/dashboard' && + this.settings.get( + SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD + ) + ) { return false } return this.settings.get(key) @@ -45,26 +61,82 @@ export class AppComponent implements OnInit, OnDestroy { ngOnInit(): void { this.consumerStatusService.connect() + this.successSubscription = this.consumerStatusService + .onDocumentConsumptionFinished() + .subscribe((status) => { + if ( + this.showNotification(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUCCESS) + ) { + this.toastService.show({ + title: $localize`Document added`, + delay: 10000, + content: $localize`Document ${status.filename} was added to paperless.`, + actionName: $localize`Open document`, + action: () => { + this.router.navigate(['documents', status.documentId]) + }, + }) + } + }) - this.successSubscription = this.consumerStatusService.onDocumentConsumptionFinished().subscribe(status => { - if (this.showNotification(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUCCESS)) { - this.toastService.show({title: $localize`Document added`, delay: 10000, content: $localize`Document ${status.filename} was added to paperless.`, actionName: $localize`Open document`, action: () => { - this.router.navigate(['documents', status.documentId]) - }}) - } - }) + this.failedSubscription = this.consumerStatusService + .onDocumentConsumptionFailed() + .subscribe((status) => { + if ( + this.showNotification(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_FAILED) + ) { + this.toastService.showError( + $localize`Could not add ${status.filename}\: ${status.message}` + ) + } + }) - this.failedSubscription = this.consumerStatusService.onDocumentConsumptionFailed().subscribe(status => { - if (this.showNotification(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_FAILED)) { - this.toastService.showError($localize`Could not add ${status.filename}\: ${status.message}`) - } - }) - - this.newDocumentSubscription = this.consumerStatusService.onDocumentDetected().subscribe(status => { - if (this.showNotification(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_NEW_DOCUMENT)) { - this.toastService.show({title: $localize`New document detected`, delay: 5000, content: $localize`Document ${status.filename} is being processed by paperless.`}) - } - }) + this.newDocumentSubscription = this.consumerStatusService + .onDocumentDetected() + .subscribe((status) => { + if ( + this.showNotification( + SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_NEW_DOCUMENT + ) + ) { + this.toastService.show({ + title: $localize`New document detected`, + delay: 5000, + content: $localize`Document ${status.filename} is being processed by paperless.`, + }) + } + }) } + public get dragDropEnabled(): boolean { + return !this.router.url.includes('dashboard') + } + + public fileOver() { + // allows transition + setTimeout(() => { + this.fileIsOver = true + }, 1) + this.hidden = false + // stop fileLeave timeout + clearTimeout(this.fileLeaveTimeoutID) + } + + public fileLeave(immediate: boolean = false) { + const ms = immediate ? 0 : 500 + + this.fileLeaveTimeoutID = setTimeout(() => { + this.fileIsOver = false + // await transition completed + setTimeout(() => { + this.hidden = true + }, 150) + }, ms) + } + + public dropped(files: NgxFileDropEntry[]) { + this.fileLeave(true) + this.uploadDocumentsService.uploadFiles(files) + this.toastService.showInfo($localize`Initiating upload...`, 3000) + } } diff --git a/src-ui/src/app/app.module.ts b/src-ui/src/app/app.module.ts index be6f6543b..e891d217d 100644 --- a/src-ui/src/app/app.module.ts +++ b/src-ui/src/app/app.module.ts @@ -1,86 +1,94 @@ -import { BrowserModule } from '@angular/platform-browser'; -import { NgModule } from '@angular/core'; - -import { AppRoutingModule } from './app-routing.module'; -import { AppComponent } from './app.component'; -import { NgbDateAdapter, NgbDateParserFormatter, NgbModule } from '@ng-bootstrap/ng-bootstrap'; -import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; -import { DocumentListComponent } from './components/document-list/document-list.component'; -import { DocumentDetailComponent } from './components/document-detail/document-detail.component'; -import { DashboardComponent } from './components/dashboard/dashboard.component'; -import { TagListComponent } from './components/manage/tag-list/tag-list.component'; -import { DocumentTypeListComponent } from './components/manage/document-type-list/document-type-list.component'; -import { LogsComponent } from './components/manage/logs/logs.component'; -import { SettingsComponent } from './components/manage/settings/settings.component'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { DatePipe, registerLocaleData } from '@angular/common'; -import { NotFoundComponent } from './components/not-found/not-found.component'; -import { CorrespondentListComponent } from './components/manage/correspondent-list/correspondent-list.component'; -import { ConfirmDialogComponent } from './components/common/confirm-dialog/confirm-dialog.component'; -import { CorrespondentEditDialogComponent } from './components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component'; -import { TagEditDialogComponent } from './components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component'; -import { DocumentTypeEditDialogComponent } from './components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component'; -import { TagComponent } from './components/common/tag/tag.component'; -import { PageHeaderComponent } from './components/common/page-header/page-header.component'; -import { AppFrameComponent } from './components/app-frame/app-frame.component'; -import { ToastsComponent } from './components/common/toasts/toasts.component'; -import { FilterEditorComponent } from './components/document-list/filter-editor/filter-editor.component'; -import { FilterableDropdownComponent } from './components/common/filterable-dropdown/filterable-dropdown.component'; -import { ToggleableDropdownButtonComponent } from './components/common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component'; -import { DateDropdownComponent } from './components/common/date-dropdown/date-dropdown.component'; -import { DocumentCardLargeComponent } from './components/document-list/document-card-large/document-card-large.component'; -import { DocumentCardSmallComponent } from './components/document-list/document-card-small/document-card-small.component'; -import { BulkEditorComponent } from './components/document-list/bulk-editor/bulk-editor.component'; -import { NgxFileDropModule } from 'ngx-file-drop'; -import { TextComponent } from './components/common/input/text/text.component'; -import { SelectComponent } from './components/common/input/select/select.component'; -import { CheckComponent } from './components/common/input/check/check.component'; -import { SaveViewConfigDialogComponent } from './components/document-list/save-view-config-dialog/save-view-config-dialog.component'; -import { InfiniteScrollModule } from 'ngx-infinite-scroll'; -import { TagsComponent } from './components/common/input/tags/tags.component'; -import { SortableDirective } from './directives/sortable.directive'; -import { CookieService } from 'ngx-cookie-service'; -import { CsrfInterceptor } from './interceptors/csrf.interceptor'; -import { SavedViewWidgetComponent } from './components/dashboard/widgets/saved-view-widget/saved-view-widget.component'; -import { StatisticsWidgetComponent } from './components/dashboard/widgets/statistics-widget/statistics-widget.component'; -import { UploadFileWidgetComponent } from './components/dashboard/widgets/upload-file-widget/upload-file-widget.component'; -import { WidgetFrameComponent } from './components/dashboard/widgets/widget-frame/widget-frame.component'; -import { PdfViewerModule } from 'ng2-pdf-viewer'; -import { WelcomeWidgetComponent } from './components/dashboard/widgets/welcome-widget/welcome-widget.component'; -import { YesNoPipe } from './pipes/yes-no.pipe'; -import { FileSizePipe } from './pipes/file-size.pipe'; -import { FilterPipe } from './pipes/filter.pipe'; -import { DocumentTitlePipe } from './pipes/document-title.pipe'; -import { MetadataCollapseComponent } from './components/document-detail/metadata-collapse/metadata-collapse.component'; -import { SelectDialogComponent } from './components/common/select-dialog/select-dialog.component'; -import { NgSelectModule } from '@ng-select/ng-select'; -import { NumberComponent } from './components/common/input/number/number.component'; -import { SafePipe } from './pipes/safe.pipe'; -import { CustomDatePipe } from './pipes/custom-date.pipe'; -import { DateComponent } from './components/common/input/date/date.component'; -import { ISODateTimeAdapter } from './utils/ngb-iso-date-time-adapter'; -import { LocalizedDateParserFormatter } from './utils/ngb-date-parser-formatter'; -import { ApiVersionInterceptor } from './interceptors/api-version.interceptor'; -import { ColorSliderModule } from 'ngx-color/slider'; -import { ColorComponent } from './components/common/input/color/color.component'; -import { DocumentAsnComponent } from './components/document-asn/document-asn.component'; - -import localeCs from '@angular/common/locales/cs'; -import localeDa from '@angular/common/locales/da'; -import localeDe from '@angular/common/locales/de'; -import localeEnGb from '@angular/common/locales/en-GB'; -import localeEs from '@angular/common/locales/es'; -import localeFr from '@angular/common/locales/fr'; -import localeIt from '@angular/common/locales/it'; -import localeLb from '@angular/common/locales/lb'; -import localeNl from '@angular/common/locales/nl'; -import localePl from '@angular/common/locales/pl'; -import localePt from '@angular/common/locales/pt'; -import localeSv from '@angular/common/locales/sv'; -import localeRo from '@angular/common/locales/ro'; -import localeRu from '@angular/common/locales/ru'; +import { BrowserModule } from '@angular/platform-browser' +import { NgModule } from '@angular/core' +import { AppRoutingModule } from './app-routing.module' +import { AppComponent } from './app.component' +import { + NgbDateAdapter, + NgbDateParserFormatter, + NgbModule, +} from '@ng-bootstrap/ng-bootstrap' +import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http' +import { DocumentListComponent } from './components/document-list/document-list.component' +import { DocumentDetailComponent } from './components/document-detail/document-detail.component' +import { DashboardComponent } from './components/dashboard/dashboard.component' +import { TagListComponent } from './components/manage/tag-list/tag-list.component' +import { DocumentTypeListComponent } from './components/manage/document-type-list/document-type-list.component' +import { CorrespondentListComponent } from './components/manage/correspondent-list/correspondent-list.component' +import { LogsComponent } from './components/manage/logs/logs.component' +import { SettingsComponent } from './components/manage/settings/settings.component' +import { FormsModule, ReactiveFormsModule } from '@angular/forms' +import { DatePipe, registerLocaleData } from '@angular/common' +import { NotFoundComponent } from './components/not-found/not-found.component' +import { ConfirmDialogComponent } from './components/common/confirm-dialog/confirm-dialog.component' +import { CorrespondentEditDialogComponent } from './components/common/edit-dialog/correspondent-edit-dialog/correspondent-edit-dialog.component' +import { TagEditDialogComponent } from './components/common/edit-dialog/tag-edit-dialog/tag-edit-dialog.component' +import { DocumentTypeEditDialogComponent } from './components/common/edit-dialog/document-type-edit-dialog/document-type-edit-dialog.component' +import { TagComponent } from './components/common/tag/tag.component' +import { PageHeaderComponent } from './components/common/page-header/page-header.component' +import { AppFrameComponent } from './components/app-frame/app-frame.component' +import { ToastsComponent } from './components/common/toasts/toasts.component' +import { FilterEditorComponent } from './components/document-list/filter-editor/filter-editor.component' +import { FilterableDropdownComponent } from './components/common/filterable-dropdown/filterable-dropdown.component' +import { ToggleableDropdownButtonComponent } from './components/common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component' +import { DateDropdownComponent } from './components/common/date-dropdown/date-dropdown.component' +import { DocumentCardLargeComponent } from './components/document-list/document-card-large/document-card-large.component' +import { DocumentCardSmallComponent } from './components/document-list/document-card-small/document-card-small.component' +import { BulkEditorComponent } from './components/document-list/bulk-editor/bulk-editor.component' +import { NgxFileDropModule } from 'ngx-file-drop' +import { TextComponent } from './components/common/input/text/text.component' +import { SelectComponent } from './components/common/input/select/select.component' +import { CheckComponent } from './components/common/input/check/check.component' +import { SaveViewConfigDialogComponent } from './components/document-list/save-view-config-dialog/save-view-config-dialog.component' +import { TagsComponent } from './components/common/input/tags/tags.component' +import { SortableDirective } from './directives/sortable.directive' +import { CookieService } from 'ngx-cookie-service' +import { CsrfInterceptor } from './interceptors/csrf.interceptor' +import { SavedViewWidgetComponent } from './components/dashboard/widgets/saved-view-widget/saved-view-widget.component' +import { StatisticsWidgetComponent } from './components/dashboard/widgets/statistics-widget/statistics-widget.component' +import { UploadFileWidgetComponent } from './components/dashboard/widgets/upload-file-widget/upload-file-widget.component' +import { WidgetFrameComponent } from './components/dashboard/widgets/widget-frame/widget-frame.component' +import { PdfViewerModule } from 'ng2-pdf-viewer' +import { WelcomeWidgetComponent } from './components/dashboard/widgets/welcome-widget/welcome-widget.component' +import { YesNoPipe } from './pipes/yes-no.pipe' +import { FileSizePipe } from './pipes/file-size.pipe' +import { FilterPipe } from './pipes/filter.pipe' +import { DocumentTitlePipe } from './pipes/document-title.pipe' +import { MetadataCollapseComponent } from './components/document-detail/metadata-collapse/metadata-collapse.component' +import { SelectDialogComponent } from './components/common/select-dialog/select-dialog.component' +import { NgSelectModule } from '@ng-select/ng-select' +import { NumberComponent } from './components/common/input/number/number.component' +import { SafeUrlPipe } from './pipes/safeurl.pipe' +import { SafeHtmlPipe } from './pipes/safehtml.pipe' +import { CustomDatePipe } from './pipes/custom-date.pipe' +import { DateComponent } from './components/common/input/date/date.component' +import { ISODateTimeAdapter } from './utils/ngb-iso-date-time-adapter' +import { LocalizedDateParserFormatter } from './utils/ngb-date-parser-formatter' +import { ApiVersionInterceptor } from './interceptors/api-version.interceptor' +import { ColorSliderModule } from 'ngx-color/slider' +import { ColorComponent } from './components/common/input/color/color.component' +import { DocumentAsnComponent } from './components/document-asn/document-asn.component' +import localeBe from '@angular/common/locales/be' +import localeCs from '@angular/common/locales/cs' +import localeDa from '@angular/common/locales/da' +import localeDe from '@angular/common/locales/de' +import localeEnGb from '@angular/common/locales/en-GB' +import localeEs from '@angular/common/locales/es' +import localeFr from '@angular/common/locales/fr' +import localeIt from '@angular/common/locales/it' +import localeLb from '@angular/common/locales/lb' +import localeNl from '@angular/common/locales/nl' +import localePl from '@angular/common/locales/pl' +import localePt from '@angular/common/locales/pt' +import localeRo from '@angular/common/locales/ro' +import localeRu from '@angular/common/locales/ru' +import localeSl from '@angular/common/locales/sl' +import localeSr from '@angular/common/locales/sr' +import localeSv from '@angular/common/locales/sv' +import localeTr from '@angular/common/locales/tr' +import localeZh from '@angular/common/locales/zh' +registerLocaleData(localeBe) registerLocaleData(localeCs) registerLocaleData(localeDa) registerLocaleData(localeDe) @@ -91,11 +99,15 @@ registerLocaleData(localeIt) registerLocaleData(localeLb) registerLocaleData(localeNl) registerLocaleData(localePl) -registerLocaleData(localePt, "pt-BR") -registerLocaleData(localePt, "pt-PT") +registerLocaleData(localePt, 'pt-BR') +registerLocaleData(localePt, 'pt-PT') registerLocaleData(localeRo) registerLocaleData(localeRu) +registerLocaleData(localeSl) +registerLocaleData(localeSr) registerLocaleData(localeSv) +registerLocaleData(localeTr) +registerLocaleData(localeZh) @NgModule({ declarations: [ @@ -104,8 +116,8 @@ registerLocaleData(localeSv) DocumentDetailComponent, DashboardComponent, TagListComponent, - CorrespondentListComponent, DocumentTypeListComponent, + CorrespondentListComponent, LogsComponent, SettingsComponent, NotFoundComponent, @@ -142,11 +154,12 @@ registerLocaleData(localeSv) MetadataCollapseComponent, SelectDialogComponent, NumberComponent, - SafePipe, + SafeUrlPipe, + SafeHtmlPipe, CustomDatePipe, DateComponent, ColorComponent, - DocumentAsnComponent + DocumentAsnComponent, ], imports: [ BrowserModule, @@ -156,27 +169,28 @@ registerLocaleData(localeSv) FormsModule, ReactiveFormsModule, NgxFileDropModule, - InfiniteScrollModule, PdfViewerModule, NgSelectModule, - ColorSliderModule + ColorSliderModule, ], providers: [ DatePipe, - CookieService, { + CookieService, + { provide: HTTP_INTERCEPTORS, useClass: CsrfInterceptor, - multi: true - },{ + multi: true, + }, + { provide: HTTP_INTERCEPTORS, useClass: ApiVersionInterceptor, - multi: true + multi: true, }, FilterPipe, DocumentTitlePipe, - {provide: NgbDateAdapter, useClass: ISODateTimeAdapter}, - {provide: NgbDateParserFormatter, useClass: LocalizedDateParserFormatter} + { provide: NgbDateAdapter, useClass: ISODateTimeAdapter }, + { provide: NgbDateParserFormatter, useClass: LocalizedDateParserFormatter }, ], - bootstrap: [AppComponent] + bootstrap: [AppComponent], }) -export class AppModule { } +export class AppModule {} diff --git a/src-ui/src/app/components/app-frame/app-frame.component.html b/src-ui/src/app/components/app-frame/app-frame.component.html index 235289074..d90d3b2d9 100644 --- a/src-ui/src/app/components/app-frame/app-frame.component.html +++ b/src-ui/src/app/components/app-frame/app-frame.component.html @@ -12,7 +12,7 @@
- + diff --git a/src-ui/src/app/components/app-frame/app-frame.component.scss b/src-ui/src/app/components/app-frame/app-frame.component.scss index 4b43c31bf..5fe408660 100644 --- a/src-ui/src/app/components/app-frame/app-frame.component.scss +++ b/src-ui/src/app/components/app-frame/app-frame.component.scss @@ -1,4 +1,3 @@ -@import "/src/theme"; /* * Sidebar */ @@ -35,22 +34,24 @@ .sidebar .nav-link { font-weight: 500; - color: #333; -} -.sidebar .nav-link .sidebaricon { - margin-right: 4px; - color: #999; -} + &:hover, &.active, &:focus { + color: var(--bs-primary); + } -.sidebar .nav-link.active { - color: $primary; - font-weight: bold; -} + &:focus-visible { + outline: none; + background-color: var(--bs-body-bg); + } -.sidebar .nav-link.active .sidebaricon, -.sidebar .nav-link:hover .sidebaricon { - color: inherit; + &.active { + font-weight: bold; + } + + .sidebaricon { + margin-right: 4px; + color: inherit; + } } .sidebar-heading { @@ -172,10 +173,29 @@ } &:focus { - background-color: #fff; - color: #212529; + background-color: rgba(0, 0, 0, 0.3); + color: var(--bs-light); flex-grow: 1; padding-left: 0.5rem; } } } + +.version-check { + animation: pulse 2s ease-in-out 0s 1; +} + +@keyframes pulse { + 0% { + opacity: 0; + } + 25% { + opacity: 100%; + } + 75% { + opacity: 0; + } + 100% { + opacity: 100%; + } +} diff --git a/src-ui/src/app/components/app-frame/app-frame.component.spec.ts b/src-ui/src/app/components/app-frame/app-frame.component.spec.ts deleted file mode 100644 index 2d0df437c..000000000 --- a/src-ui/src/app/components/app-frame/app-frame.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { AppFrameComponent } from './app-frame.component'; - -describe('AppFrameComponent', () => { - let component: AppFrameComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ AppFrameComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(AppFrameComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/components/app-frame/app-frame.component.ts b/src-ui/src/app/components/app-frame/app-frame.component.ts index 74f3cd5b5..a335aad1d 100644 --- a/src-ui/src/app/components/app-frame/app-frame.component.ts +++ b/src-ui/src/app/components/app-frame/app-frame.component.ts @@ -1,36 +1,53 @@ -import { Component } from '@angular/core'; -import { FormControl } from '@angular/forms'; -import { ActivatedRoute, Router, Params } from '@angular/router'; -import { from, Observable, Subscription, BehaviorSubject } from 'rxjs'; -import { debounceTime, distinctUntilChanged, map, switchMap, first } from 'rxjs/operators'; -import { PaperlessDocument } from 'src/app/data/paperless-document'; -import { OpenDocumentsService } from 'src/app/services/open-documents.service'; -import { SavedViewService } from 'src/app/services/rest/saved-view.service'; -import { SearchService } from 'src/app/services/rest/search.service'; -import { environment } from 'src/environments/environment'; -import { DocumentDetailComponent } from '../document-detail/document-detail.component'; -import { Meta } from '@angular/platform-browser'; -import { DocumentListViewService } from 'src/app/services/document-list-view.service'; -import { FILTER_FULLTEXT_QUERY } from 'src/app/data/filter-rule-type'; +import { Component } from '@angular/core' +import { FormControl } from '@angular/forms' +import { ActivatedRoute, Router, Params } from '@angular/router' +import { from, Observable, Subscription, BehaviorSubject } from 'rxjs' +import { + debounceTime, + distinctUntilChanged, + map, + switchMap, + first, +} from 'rxjs/operators' +import { PaperlessDocument } from 'src/app/data/paperless-document' +import { OpenDocumentsService } from 'src/app/services/open-documents.service' +import { SavedViewService } from 'src/app/services/rest/saved-view.service' +import { SearchService } from 'src/app/services/rest/search.service' +import { environment } from 'src/environments/environment' +import { DocumentDetailComponent } from '../document-detail/document-detail.component' +import { Meta } from '@angular/platform-browser' +import { DocumentListViewService } from 'src/app/services/document-list-view.service' +import { FILTER_FULLTEXT_QUERY } from 'src/app/data/filter-rule-type' +import { + RemoteVersionService, + AppRemoteVersion, +} from 'src/app/services/rest/remote-version.service' @Component({ selector: 'app-app-frame', templateUrl: './app-frame.component.html', - styleUrls: ['./app-frame.component.scss'] + styleUrls: ['./app-frame.component.scss'], }) export class AppFrameComponent { - - constructor ( + constructor( public router: Router, private activatedRoute: ActivatedRoute, private openDocumentsService: OpenDocumentsService, private searchService: SearchService, public savedViewService: SavedViewService, private list: DocumentListViewService, - private meta: Meta - ) { } + private meta: Meta, + private remoteVersionService: RemoteVersionService + ) { + this.remoteVersionService + .checkForUpdates() + .subscribe((appRemoteVersion: AppRemoteVersion) => { + this.appRemoteVersion = appRemoteVersion + }) + } versionString = `${environment.appTitle} ${environment.version}` + appRemoteVersion isMenuCollapsed: boolean = true @@ -48,14 +65,14 @@ export class AppFrameComponent { text$.pipe( debounceTime(200), distinctUntilChanged(), - map(term => { + map((term) => { if (term.lastIndexOf(' ') != -1) { return term.substring(term.lastIndexOf(' ') + 1) } else { return term } }), - switchMap(term => + switchMap((term) => term.length < 2 ? from([[]]) : this.searchService.autocomplete(term) ) ) @@ -66,49 +83,63 @@ export class AppFrameComponent { let lastSpaceIndex = currentSearch.lastIndexOf(' ') if (lastSpaceIndex != -1) { currentSearch = currentSearch.substring(0, lastSpaceIndex + 1) - currentSearch += event.item + " " + currentSearch += event.item + ' ' } else { - currentSearch = event.item + " " + currentSearch = event.item + ' ' } this.searchField.patchValue(currentSearch) } search() { this.closeMenu() - this.list.quickFilter([{rule_type: FILTER_FULLTEXT_QUERY, value: this.searchField.value}]) + this.list.quickFilter([ + { + rule_type: FILTER_FULLTEXT_QUERY, + value: (this.searchField.value as string).trim(), + }, + ]) } closeDocument(d: PaperlessDocument) { - this.openDocumentsService.closeDocument(d).pipe(first()).subscribe(confirmed => { - if (confirmed) { - this.closeMenu() - let route = this.activatedRoute.snapshot - while (route.firstChild) { - route = route.firstChild + this.openDocumentsService + .closeDocument(d) + .pipe(first()) + .subscribe((confirmed) => { + if (confirmed) { + this.closeMenu() + let route = this.activatedRoute.snapshot + while (route.firstChild) { + route = route.firstChild + } + if ( + route.component == DocumentDetailComponent && + route.params['id'] == d.id + ) { + this.router.navigate(['']) + } } - if (route.component == DocumentDetailComponent && route.params['id'] == d.id) { - this.router.navigate([""]) - } - } - }) + }) } closeAll() { // user may need to confirm losing unsaved changes - this.openDocumentsService.closeAll().pipe(first()).subscribe(confirmed => { - if (confirmed) { - this.closeMenu() + this.openDocumentsService + .closeAll() + .pipe(first()) + .subscribe((confirmed) => { + if (confirmed) { + this.closeMenu() - // TODO: is there a better way to do this? - let route = this.activatedRoute - while (route.firstChild) { - route = route.firstChild + // TODO: is there a better way to do this? + let route = this.activatedRoute + while (route.firstChild) { + route = route.firstChild + } + if (route.component === DocumentDetailComponent) { + this.router.navigate(['']) + } } - if (route.component === DocumentDetailComponent) { - this.router.navigate([""]) - } - } - }) + }) } get displayName() { @@ -123,5 +154,4 @@ export class AppFrameComponent { return null } } - } diff --git a/src-ui/src/app/components/common/confirm-dialog/confirm-dialog.component.html b/src-ui/src/app/components/common/confirm-dialog/confirm-dialog.component.html index 5518e1821..19d907c82 100644 --- a/src-ui/src/app/components/common/confirm-dialog/confirm-dialog.component.html +++ b/src-ui/src/app/components/common/confirm-dialog/confirm-dialog.component.html @@ -8,9 +8,12 @@

{{message}}

diff --git a/src-ui/src/app/components/common/confirm-dialog/confirm-dialog.component.spec.ts b/src-ui/src/app/components/common/confirm-dialog/confirm-dialog.component.spec.ts deleted file mode 100644 index fe08dc57a..000000000 --- a/src-ui/src/app/components/common/confirm-dialog/confirm-dialog.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { ConfirmDialogComponent } from './confirm-dialog.component'; - -describe('ConfirmDialogComponent', () => { - let component: ConfirmDialogComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ ConfirmDialogComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(ConfirmDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/components/common/confirm-dialog/confirm-dialog.component.ts b/src-ui/src/app/components/common/confirm-dialog/confirm-dialog.component.ts index 5e198992e..ddf0bfd7c 100644 --- a/src-ui/src/app/components/common/confirm-dialog/confirm-dialog.component.ts +++ b/src-ui/src/app/components/common/confirm-dialog/confirm-dialog.component.ts @@ -1,15 +1,14 @@ -import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; -import { Subject } from 'rxjs'; +import { Component, EventEmitter, Input, Output } from '@angular/core' +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' +import { interval, Subject, switchMap, take } from 'rxjs' @Component({ selector: 'app-confirm-dialog', templateUrl: './confirm-dialog.component.html', - styleUrls: ['./confirm-dialog.component.scss'] + styleUrls: ['./confirm-dialog.component.scss'], }) export class ConfirmDialogComponent { - - constructor(public activeModal: NgbActiveModal) { } + constructor(public activeModal: NgbActiveModal) {} @Output() public confirmClicked = new EventEmitter() @@ -24,7 +23,7 @@ export class ConfirmDialogComponent { message @Input() - btnClass = "btn-primary" + btnClass = 'btn-primary' @Input() btnCaption = $localize`Confirm` @@ -34,19 +33,28 @@ export class ConfirmDialogComponent { confirmButtonEnabled = true seconds = 0 + secondsTotal = 0 confirmSubject: Subject delayConfirm(seconds: number) { - this.confirmButtonEnabled = false + const refreshInterval = 0.15 // s + + this.secondsTotal = seconds this.seconds = seconds - setTimeout(() => { - if (this.seconds <= 1) { - this.confirmButtonEnabled = true - } else { - this.delayConfirm(seconds - 1) - } - }, 1000) + + interval(refreshInterval * 1000) + .pipe( + take(this.secondsTotal / refreshInterval + 2) // need 2 more for animation to complete after 0 + ) + .subscribe((count) => { + this.seconds = Math.max( + 0, + this.secondsTotal - refreshInterval * (count + 1) + ) + this.confirmButtonEnabled = + this.secondsTotal - refreshInterval * count < 0 + }) } cancel() { diff --git a/src-ui/src/app/components/common/date-dropdown/date-dropdown.component.html b/src-ui/src/app/components/common/date-dropdown/date-dropdown.component.html index 90cdc134e..6e5a7d928 100644 --- a/src-ui/src/app/components/common/date-dropdown/date-dropdown.component.html +++ b/src-ui/src/app/components/common/date-dropdown/date-dropdown.component.html @@ -20,8 +20,8 @@
- +
- +
diff --git a/src-ui/src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.scss b/src-ui/src/app/components/common/edit-dialog/correspondent-edit-dialog/correspondent-edit-dialog.component.scss similarity index 100% rename from src-ui/src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.scss rename to src-ui/src/app/components/common/edit-dialog/correspondent-edit-dialog/correspondent-edit-dialog.component.scss diff --git a/src-ui/src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.ts b/src-ui/src/app/components/common/edit-dialog/correspondent-edit-dialog/correspondent-edit-dialog.component.ts similarity index 57% rename from src-ui/src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.ts rename to src-ui/src/app/components/common/edit-dialog/correspondent-edit-dialog/correspondent-edit-dialog.component.ts index b2fe8a929..cba0a922a 100644 --- a/src-ui/src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.ts +++ b/src-ui/src/app/components/common/edit-dialog/correspondent-edit-dialog/correspondent-edit-dialog.component.ts @@ -1,19 +1,22 @@ -import { Component } from '@angular/core'; -import { FormControl, FormGroup } from '@angular/forms'; -import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; -import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component'; -import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent'; -import { CorrespondentService } from 'src/app/services/rest/correspondent.service'; -import { ToastService } from 'src/app/services/toast.service'; +import { Component } from '@angular/core' +import { FormControl, FormGroup } from '@angular/forms' +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' +import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component' +import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent' +import { CorrespondentService } from 'src/app/services/rest/correspondent.service' +import { ToastService } from 'src/app/services/toast.service' @Component({ selector: 'app-correspondent-edit-dialog', templateUrl: './correspondent-edit-dialog.component.html', - styleUrls: ['./correspondent-edit-dialog.component.scss'] + styleUrls: ['./correspondent-edit-dialog.component.scss'], }) export class CorrespondentEditDialogComponent extends EditDialogComponent { - - constructor(service: CorrespondentService, activeModal: NgbActiveModal, toastService: ToastService) { + constructor( + service: CorrespondentService, + activeModal: NgbActiveModal, + toastService: ToastService + ) { super(service, activeModal, toastService) } @@ -29,9 +32,8 @@ export class CorrespondentEditDialogComponent extends EditDialogComponent diff --git a/src-ui/src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.scss b/src-ui/src/app/components/common/edit-dialog/document-type-edit-dialog/document-type-edit-dialog.component.scss similarity index 100% rename from src-ui/src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.scss rename to src-ui/src/app/components/common/edit-dialog/document-type-edit-dialog/document-type-edit-dialog.component.scss diff --git a/src-ui/src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.ts b/src-ui/src/app/components/common/edit-dialog/document-type-edit-dialog/document-type-edit-dialog.component.ts similarity index 57% rename from src-ui/src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.ts rename to src-ui/src/app/components/common/edit-dialog/document-type-edit-dialog/document-type-edit-dialog.component.ts index b4a15d303..05d207f35 100644 --- a/src-ui/src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.ts +++ b/src-ui/src/app/components/common/edit-dialog/document-type-edit-dialog/document-type-edit-dialog.component.ts @@ -1,19 +1,22 @@ -import { Component } from '@angular/core'; -import { FormControl, FormGroup } from '@angular/forms'; -import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; -import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component'; -import { PaperlessDocumentType } from 'src/app/data/paperless-document-type'; -import { DocumentTypeService } from 'src/app/services/rest/document-type.service'; -import { ToastService } from 'src/app/services/toast.service'; +import { Component } from '@angular/core' +import { FormControl, FormGroup } from '@angular/forms' +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' +import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component' +import { PaperlessDocumentType } from 'src/app/data/paperless-document-type' +import { DocumentTypeService } from 'src/app/services/rest/document-type.service' +import { ToastService } from 'src/app/services/toast.service' @Component({ selector: 'app-document-type-edit-dialog', templateUrl: './document-type-edit-dialog.component.html', - styleUrls: ['./document-type-edit-dialog.component.scss'] + styleUrls: ['./document-type-edit-dialog.component.scss'], }) export class DocumentTypeEditDialogComponent extends EditDialogComponent { - - constructor(service: DocumentTypeService, activeModal: NgbActiveModal, toastService: ToastService) { + constructor( + service: DocumentTypeService, + activeModal: NgbActiveModal, + toastService: ToastService + ) { super(service, activeModal, toastService) } @@ -29,9 +32,8 @@ export class DocumentTypeEditDialogComponent extends EditDialogComponent { - let component: EditDialogComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ EditDialogComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(EditDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/components/common/edit-dialog/edit-dialog.component.ts b/src-ui/src/app/components/common/edit-dialog/edit-dialog.component.ts index 3faf18dbb..92b16a93d 100644 --- a/src-ui/src/app/components/common/edit-dialog/edit-dialog.component.ts +++ b/src-ui/src/app/components/common/edit-dialog/edit-dialog.component.ts @@ -1,20 +1,22 @@ -import { Directive, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { FormGroup } from '@angular/forms'; -import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; -import { Observable } from 'rxjs'; -import { map } from 'rxjs/operators'; -import { MATCHING_ALGORITHMS, MATCH_AUTO } from 'src/app/data/matching-model'; -import { ObjectWithId } from 'src/app/data/object-with-id'; -import { AbstractPaperlessService } from 'src/app/services/rest/abstract-paperless-service'; -import { ToastService } from 'src/app/services/toast.service'; +import { Directive, EventEmitter, Input, OnInit, Output } from '@angular/core' +import { FormGroup } from '@angular/forms' +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' +import { Observable } from 'rxjs' +import { map } from 'rxjs/operators' +import { MATCHING_ALGORITHMS, MATCH_AUTO } from 'src/app/data/matching-model' +import { ObjectWithId } from 'src/app/data/object-with-id' +import { AbstractPaperlessService } from 'src/app/services/rest/abstract-paperless-service' +import { ToastService } from 'src/app/services/toast.service' @Directive() -export abstract class EditDialogComponent implements OnInit { - +export abstract class EditDialogComponent + implements OnInit +{ constructor( private service: AbstractPaperlessService, private activeModal: NgbActiveModal, - private toastService: ToastService) { } + private toastService: ToastService + ) {} @Input() dialogMode: string = 'create' @@ -43,7 +45,7 @@ export abstract class EditDialogComponent implements OnI // wait to enable close button so it doesnt steal focus from input since its the first clickable element in the DOM setTimeout(() => { this.closeEnabled = true - }); + }) } getCreateTitle() { @@ -65,7 +67,7 @@ export abstract class EditDialogComponent implements OnI case 'edit': return this.getEditTitle() default: - break; + break } } @@ -78,25 +80,31 @@ export abstract class EditDialogComponent implements OnI } save() { - var newObject = Object.assign(Object.assign({}, this.object), this.objectForm.value) + var newObject = Object.assign( + Object.assign({}, this.object), + this.objectForm.value + ) var serverResponse: Observable switch (this.dialogMode) { case 'create': serverResponse = this.service.create(newObject) - break; + break case 'edit': serverResponse = this.service.update(newObject) default: - break; + break } this.networkActive = true - serverResponse.subscribe(result => { - this.activeModal.close() - this.success.emit(result) - }, error => { - this.error = error.error - this.networkActive = false - }) + serverResponse.subscribe( + (result) => { + this.activeModal.close() + this.success.emit(result) + }, + (error) => { + this.error = error.error + this.networkActive = false + } + ) } cancel() { diff --git a/src-ui/src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html b/src-ui/src/app/components/common/edit-dialog/tag-edit-dialog/tag-edit-dialog.component.html similarity index 91% rename from src-ui/src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html rename to src-ui/src/app/components/common/edit-dialog/tag-edit-dialog/tag-edit-dialog.component.html index fa9972eee..6ea3901a7 100644 --- a/src-ui/src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html +++ b/src-ui/src/app/components/common/edit-dialog/tag-edit-dialog/tag-edit-dialog.component.html @@ -15,7 +15,7 @@ diff --git a/src-ui/src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.scss b/src-ui/src/app/components/common/edit-dialog/tag-edit-dialog/tag-edit-dialog.component.scss similarity index 100% rename from src-ui/src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.scss rename to src-ui/src/app/components/common/edit-dialog/tag-edit-dialog/tag-edit-dialog.component.scss diff --git a/src-ui/src/app/components/common/edit-dialog/tag-edit-dialog/tag-edit-dialog.component.ts b/src-ui/src/app/components/common/edit-dialog/tag-edit-dialog/tag-edit-dialog.component.ts new file mode 100644 index 000000000..7b5b7abf7 --- /dev/null +++ b/src-ui/src/app/components/common/edit-dialog/tag-edit-dialog/tag-edit-dialog.component.ts @@ -0,0 +1,42 @@ +import { Component } from '@angular/core' +import { FormControl, FormGroup } from '@angular/forms' +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' +import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component' +import { PaperlessTag } from 'src/app/data/paperless-tag' +import { TagService } from 'src/app/services/rest/tag.service' +import { ToastService } from 'src/app/services/toast.service' +import { randomColor } from 'src/app/utils/color' + +@Component({ + selector: 'app-tag-edit-dialog', + templateUrl: './tag-edit-dialog.component.html', + styleUrls: ['./tag-edit-dialog.component.scss'], +}) +export class TagEditDialogComponent extends EditDialogComponent { + constructor( + service: TagService, + activeModal: NgbActiveModal, + toastService: ToastService + ) { + super(service, activeModal, toastService) + } + + getCreateTitle() { + return $localize`Create new tag` + } + + getEditTitle() { + return $localize`Edit tag` + } + + getForm(): FormGroup { + return new FormGroup({ + name: new FormControl(''), + color: new FormControl(randomColor()), + is_inbox_tag: new FormControl(false), + matching_algorithm: new FormControl(1), + match: new FormControl(''), + is_insensitive: new FormControl(true), + }) + } +} diff --git a/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.html b/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.html index babf25588..3e202dce9 100644 --- a/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.html +++ b/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.html @@ -6,7 +6,7 @@
 {{title}}
- {{selectionModel.selectionSize()}}selected + {{selectionModel.totalCount}}selected
selected @@ -18,10 +18,10 @@
diff --git a/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.scss b/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.scss index b6620b0c7..dfb989fea 100644 --- a/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.scss +++ b/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.scss @@ -1,5 +1,3 @@ -@import "/src/theme"; - .badge-corner { position: absolute; top: -8px; @@ -42,7 +40,7 @@ filter: brightness(0.5); &.active { - background-color: lighten($primary, 30%); + background-color: var(--pngx-primary-lighten-30); } } @@ -60,4 +58,4 @@ small > svg { .show .btn-outline-primary { color: #fff; -} \ No newline at end of file +} diff --git a/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.spec.ts b/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.spec.ts deleted file mode 100644 index 3eef95c16..000000000 --- a/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { FilterableDropodownComponent } from './filterable-dropdown.component'; - -describe('FilterableDropodownComponent', () => { - let component: FilterableDropodownComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ FilterableDropodownComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(FilterableDropodownComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts b/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts index c3b4c890b..9a16b4426 100644 --- a/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts +++ b/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts @@ -1,17 +1,23 @@ -import { Component, EventEmitter, Input, Output, ElementRef, ViewChild } from '@angular/core'; -import { FilterPipe } from 'src/app/pipes/filter.pipe'; +import { + Component, + EventEmitter, + Input, + Output, + ElementRef, + ViewChild, +} from '@angular/core' +import { FilterPipe } from 'src/app/pipes/filter.pipe' import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap' -import { ToggleableItemState } from './toggleable-dropdown-button/toggleable-dropdown-button.component'; -import { MatchingModel } from 'src/app/data/matching-model'; -import { Subject } from 'rxjs'; +import { ToggleableItemState } from './toggleable-dropdown-button/toggleable-dropdown-button.component' +import { MatchingModel } from 'src/app/data/matching-model' +import { Subject } from 'rxjs' export interface ChangedItems { - itemsToAdd: MatchingModel[], + itemsToAdd: MatchingModel[] itemsToRemove: MatchingModel[] } export class FilterableDropdownSelectionModel { - changed = new Subject() multiple = false @@ -22,14 +28,20 @@ export class FilterableDropdownSelectionModel { get itemsSorted(): MatchingModel[] { // TODO: this is getting called very often - return this.items.sort((a,b) => { + return this.items.sort((a, b) => { if (a.id == null && b.id != null) { return -1 } else if (a.id != null && b.id == null) { return 1 - } else if (this.getNonTemporary(a.id) == ToggleableItemState.NotSelected && this.getNonTemporary(b.id) != ToggleableItemState.NotSelected) { + } else if ( + this.getNonTemporary(a.id) == ToggleableItemState.NotSelected && + this.getNonTemporary(b.id) != ToggleableItemState.NotSelected + ) { return 1 - } else if (this.getNonTemporary(a.id) != ToggleableItemState.NotSelected && this.getNonTemporary(b.id) == ToggleableItemState.NotSelected) { + } else if ( + this.getNonTemporary(a.id) != ToggleableItemState.NotSelected && + this.getNonTemporary(b.id) == ToggleableItemState.NotSelected + ) { return -1 } else { return a.name.localeCompare(b.name) @@ -42,11 +54,17 @@ export class FilterableDropdownSelectionModel { private temporarySelectionStates = new Map() getSelectedItems() { - return this.items.filter(i => this.temporarySelectionStates.get(i.id) == ToggleableItemState.Selected) + return this.items.filter( + (i) => + this.temporarySelectionStates.get(i.id) == ToggleableItemState.Selected + ) } getExcludedItems() { - return this.items.filter(i => this.temporarySelectionStates.get(i.id) == ToggleableItemState.Excluded) + return this.items.filter( + (i) => + this.temporarySelectionStates.get(i.id) == ToggleableItemState.Excluded + ) } set(id: number, state: ToggleableItemState, fireEvent = true) { @@ -62,9 +80,16 @@ export class FilterableDropdownSelectionModel { toggle(id: number, fireEvent = true) { let state = this.temporarySelectionStates.get(id) - if (state == null || (state != ToggleableItemState.Selected && state != ToggleableItemState.Excluded)) { + if ( + state == null || + (state != ToggleableItemState.Selected && + state != ToggleableItemState.Excluded) + ) { this.temporarySelectionStates.set(id, ToggleableItemState.Selected) - } else if (state == ToggleableItemState.Selected || state == ToggleableItemState.Excluded) { + } else if ( + state == ToggleableItemState.Selected || + state == ToggleableItemState.Excluded + ) { this.temporarySelectionStates.delete(id) } @@ -91,7 +116,7 @@ export class FilterableDropdownSelectionModel { } } - exclude(id: number, fireEvent:boolean = true) { + exclude(id: number, fireEvent: boolean = true) { let state = this.temporarySelectionStates.get(id) if (state == null || state != ToggleableItemState.Excluded) { this.temporarySelectionStates.set(id, ToggleableItemState.Excluded) @@ -130,13 +155,19 @@ export class FilterableDropdownSelectionModel { } get(id: number) { - return this.temporarySelectionStates.get(id) || ToggleableItemState.NotSelected + return ( + this.temporarySelectionStates.get(id) || ToggleableItemState.NotSelected + ) } selectionSize() { return this.getSelectedItems().length } + get totalCount() { + return this.getSelectedItems().length + this.getExcludedItems().length + } + clear(fireEvent = true) { this.temporarySelectionStates.clear() this.temporaryLogicalOperator = this._logicalOperator = 'and' @@ -146,9 +177,19 @@ export class FilterableDropdownSelectionModel { } isDirty() { - if (!Array.from(this.temporarySelectionStates.keys()).every(id => this.temporarySelectionStates.get(id) == this.selectionStates.get(id))) { + if ( + !Array.from(this.temporarySelectionStates.keys()).every( + (id) => + this.temporarySelectionStates.get(id) == this.selectionStates.get(id) + ) + ) { return true - } else if (!Array.from(this.selectionStates.keys()).every(id => this.selectionStates.get(id) == this.temporarySelectionStates.get(id))) { + } else if ( + !Array.from(this.selectionStates.keys()).every( + (id) => + this.selectionStates.get(id) == this.temporarySelectionStates.get(id) + ) + ) { return true } else if (this.temporaryLogicalOperator !== this._logicalOperator) { return true @@ -158,7 +199,10 @@ export class FilterableDropdownSelectionModel { } isNoneSelected() { - return this.selectionSize() == 1 && this.get(null) == ToggleableItemState.Selected + return ( + this.selectionSize() == 1 && + this.get(null) == ToggleableItemState.Selected + ) } init(map) { @@ -183,8 +227,17 @@ export class FilterableDropdownSelectionModel { diff(): ChangedItems { return { - itemsToAdd: this.items.filter(item => this.temporarySelectionStates.get(item.id) == ToggleableItemState.Selected && this.selectionStates.get(item.id) != ToggleableItemState.Selected), - itemsToRemove: this.items.filter(item => !this.temporarySelectionStates.has(item.id) && this.selectionStates.has(item.id)), + itemsToAdd: this.items.filter( + (item) => + this.temporarySelectionStates.get(item.id) == + ToggleableItemState.Selected && + this.selectionStates.get(item.id) != ToggleableItemState.Selected + ), + itemsToRemove: this.items.filter( + (item) => + !this.temporarySelectionStates.has(item.id) && + this.selectionStates.has(item.id) + ), } } } @@ -192,10 +245,9 @@ export class FilterableDropdownSelectionModel { @Component({ selector: 'app-filterable-dropdown', templateUrl: './filterable-dropdown.component.html', - styleUrls: ['./filterable-dropdown.component.scss'] + styleUrls: ['./filterable-dropdown.component.scss'], }) export class FilterableDropdownComponent { - @ViewChild('listFilterTextInput') listFilterTextInput: ElementRef @ViewChild('dropdown') dropdown: NgbDropdown @@ -207,7 +259,7 @@ export class FilterableDropdownComponent { this._selectionModel.items = Array.from(items) this._selectionModel.items.unshift({ name: $localize`:Filter drop down element to filter for documents with no correspondent/type/tag assigned:Not assigned`, - id: null + id: null, }) } } @@ -225,7 +277,7 @@ export class FilterableDropdownComponent { model.items = this.selectionModel.items model.multiple = this.selectionModel.multiple } - model.changed.subscribe(updatedModel => { + model.changed.subscribe((updatedModel) => { this.selectionModelChange.next(updatedModel) }) this._selectionModel = model @@ -251,7 +303,7 @@ export class FilterableDropdownComponent { title: string @Input() - filterPlaceholder: string = "" + filterPlaceholder: string = '' @Input() icon: string @@ -272,14 +324,17 @@ export class FilterableDropdownComponent { open = new EventEmitter() get operatorToggleEnabled(): boolean { - return this.selectionModel.selectionSize() > 1 && this.selectionModel.getExcludedItems().length == 0 + return ( + this.selectionModel.selectionSize() > 1 && + this.selectionModel.getExcludedItems().length == 0 + ) } modelIsDirty: boolean = false constructor(private filterPipe: FilterPipe) { this.selectionModel = new FilterableDropdownSelectionModel() - this.selectionModelChange.subscribe(updatedModel => { + this.selectionModelChange.subscribe((updatedModel) => { this.modelIsDirty = updatedModel.isDirty() }) } @@ -296,12 +351,12 @@ export class FilterableDropdownComponent { dropdownOpenChange(open: boolean): void { if (open) { setTimeout(() => { - this.listFilterTextInput.nativeElement.focus(); + this.listFilterTextInput.nativeElement.focus() }, 0) if (this.editing) { this.selectionModel.reset() } - this.open.next() + this.open.next(this) } else { this.filterText = '' if (this.applyOnClose && this.selectionModel.isDirty()) { diff --git a/src-ui/src/app/components/common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component.spec.ts b/src-ui/src/app/components/common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component.spec.ts deleted file mode 100644 index ec2868d7c..000000000 --- a/src-ui/src/app/components/common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { ToggleableDropdownButtonComponent } from './toggleable-dropdown-button.component'; - -describe('ToggleableDropdownButtonComponent', () => { - let component: ToggleableDropdownButtonComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ ToggleableDropdownButtonComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(ToggleableDropdownButtonComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/components/common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component.ts b/src-ui/src/app/components/common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component.ts index a30f1863d..610824527 100644 --- a/src-ui/src/app/components/common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component.ts +++ b/src-ui/src/app/components/common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component.ts @@ -1,20 +1,19 @@ -import { Component, EventEmitter, Input, Output, OnInit } from '@angular/core'; -import { MatchingModel } from 'src/app/data/matching-model'; +import { Component, EventEmitter, Input, Output, OnInit } from '@angular/core' +import { MatchingModel } from 'src/app/data/matching-model' export enum ToggleableItemState { NotSelected = 0, Selected = 1, PartiallySelected = 2, - Excluded = 3 + Excluded = 3, } @Component({ selector: 'app-toggleable-dropdown-button', templateUrl: './toggleable-dropdown-button.component.html', - styleUrls: ['./toggleable-dropdown-button.component.scss'] + styleUrls: ['./toggleable-dropdown-button.component.scss'], }) export class ToggleableDropdownButtonComponent { - @Input() item: MatchingModel diff --git a/src-ui/src/app/components/common/input/abstract-input.ts b/src-ui/src/app/components/common/input/abstract-input.ts index 5165edc3b..113945749 100644 --- a/src-ui/src/app/components/common/input/abstract-input.ts +++ b/src-ui/src/app/components/common/input/abstract-input.ts @@ -1,30 +1,29 @@ -import { Directive, ElementRef, Input, OnInit, ViewChild } from '@angular/core'; -import { ControlValueAccessor } from '@angular/forms'; -import { v4 as uuidv4 } from 'uuid'; +import { Directive, ElementRef, Input, OnInit, ViewChild } from '@angular/core' +import { ControlValueAccessor } from '@angular/forms' +import { v4 as uuidv4 } from 'uuid' @Directive() export class AbstractInputComponent implements OnInit, ControlValueAccessor { - - @ViewChild("inputField") + @ViewChild('inputField') inputField: ElementRef - constructor() { } + constructor() {} - onChange = (newValue: T) => {}; + onChange = (newValue: T) => {} - onTouched = () => {}; + onTouched = () => {} writeValue(newValue: any): void { this.value = newValue } registerOnChange(fn: any): void { - this.onChange = fn; + this.onChange = fn } registerOnTouched(fn: any): void { - this.onTouched = fn; + this.onTouched = fn } setDisabledState?(isDisabled: boolean): void { - this.disabled = isDisabled; + this.disabled = isDisabled } focus() { @@ -37,7 +36,7 @@ export class AbstractInputComponent implements OnInit, ControlValueAccessor { title: string @Input() - disabled = false; + disabled = false @Input() error: string diff --git a/src-ui/src/app/components/common/input/check/check.component.spec.ts b/src-ui/src/app/components/common/input/check/check.component.spec.ts deleted file mode 100644 index 9649ed157..000000000 --- a/src-ui/src/app/components/common/input/check/check.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { CheckComponent } from './check.component'; - -describe('CheckComponent', () => { - let component: CheckComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ CheckComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(CheckComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/components/common/input/check/check.component.ts b/src-ui/src/app/components/common/input/check/check.component.ts index d452aad87..f4a6e527e 100644 --- a/src-ui/src/app/components/common/input/check/check.component.ts +++ b/src-ui/src/app/components/common/input/check/check.component.ts @@ -1,22 +1,22 @@ -import { Component, forwardRef, Input, OnInit } from '@angular/core'; -import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; -import { v4 as uuidv4 } from 'uuid'; -import { AbstractInputComponent } from '../abstract-input'; +import { Component, forwardRef, Input, OnInit } from '@angular/core' +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' +import { v4 as uuidv4 } from 'uuid' +import { AbstractInputComponent } from '../abstract-input' @Component({ - providers: [{ - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => CheckComponent), - multi: true - }], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => CheckComponent), + multi: true, + }, + ], selector: 'app-input-check', templateUrl: './check.component.html', - styleUrls: ['./check.component.scss'] + styleUrls: ['./check.component.scss'], }) export class CheckComponent extends AbstractInputComponent { - constructor() { super() } - } diff --git a/src-ui/src/app/components/common/input/color/color.component.html b/src-ui/src/app/components/common/input/color/color.component.html index a22d4f350..08cbf0bab 100644 --- a/src-ui/src/app/components/common/input/color/color.component.html +++ b/src-ui/src/app/components/common/input/color/color.component.html @@ -1,5 +1,5 @@
- +
    diff --git a/src-ui/src/app/components/common/input/color/color.component.spec.ts b/src-ui/src/app/components/common/input/color/color.component.spec.ts deleted file mode 100644 index 7c5d0d270..000000000 --- a/src-ui/src/app/components/common/input/color/color.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { ColorComponent } from './color.component'; - -describe('ColorComponent', () => { - let component: ColorComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ ColorComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(ColorComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/components/common/input/color/color.component.ts b/src-ui/src/app/components/common/input/color/color.component.ts index a7f3452f2..3efdda8c8 100644 --- a/src-ui/src/app/components/common/input/color/color.component.ts +++ b/src-ui/src/app/components/common/input/color/color.component.ts @@ -1,20 +1,21 @@ -import { Component, forwardRef } from '@angular/core'; -import { NG_VALUE_ACCESSOR } from '@angular/forms'; -import { randomColor } from 'src/app/utils/color'; -import { AbstractInputComponent } from '../abstract-input'; +import { Component, forwardRef } from '@angular/core' +import { NG_VALUE_ACCESSOR } from '@angular/forms' +import { randomColor } from 'src/app/utils/color' +import { AbstractInputComponent } from '../abstract-input' @Component({ - providers: [{ - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => ColorComponent), - multi: true - }], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => ColorComponent), + multi: true, + }, + ], selector: 'app-input-color', templateUrl: './color.component.html', - styleUrls: ['./color.component.scss'] + styleUrls: ['./color.component.scss'], }) export class ColorComponent extends AbstractInputComponent { - constructor() { super() } diff --git a/src-ui/src/app/components/common/input/date/date.component.html b/src-ui/src/app/components/common/input/date/date.component.html index 135bae411..ca6ec0b26 100644 --- a/src-ui/src/app/components/common/input/date/date.component.html +++ b/src-ui/src/app/components/common/input/date/date.component.html @@ -1,8 +1,9 @@
- +

diff --git a/src-ui/src/app/components/common/toasts/toasts.component.scss b/src-ui/src/app/components/common/toasts/toasts.component.scss index 4d1c95fce..d2aaf20b0 100644 --- a/src-ui/src/app/components/common/toasts/toasts.component.scss +++ b/src-ui/src/app/components/common/toasts/toasts.component.scss @@ -5,3 +5,7 @@ margin: 0.5em; z-index: 1200; } + +.toast:not(.show) { + display: block; // this corrects an ng-bootstrap bug that prevented animations +} \ No newline at end of file diff --git a/src-ui/src/app/components/common/toasts/toasts.component.spec.ts b/src-ui/src/app/components/common/toasts/toasts.component.spec.ts deleted file mode 100644 index 3486005f1..000000000 --- a/src-ui/src/app/components/common/toasts/toasts.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { ToastsComponent } from './toasts.component'; - -describe('ToastsComponent', () => { - let component: ToastsComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ ToastsComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(ToastsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/components/common/toasts/toasts.component.ts b/src-ui/src/app/components/common/toasts/toasts.component.ts index 8f142646d..ac7a693d6 100644 --- a/src-ui/src/app/components/common/toasts/toasts.component.ts +++ b/src-ui/src/app/components/common/toasts/toasts.component.ts @@ -1,15 +1,14 @@ -import { Component, OnDestroy, OnInit } from '@angular/core'; -import { Subscription } from 'rxjs'; -import { Toast, ToastService } from 'src/app/services/toast.service'; +import { Component, OnDestroy, OnInit } from '@angular/core' +import { Subscription } from 'rxjs' +import { Toast, ToastService } from 'src/app/services/toast.service' @Component({ selector: 'app-toasts', templateUrl: './toasts.component.html', - styleUrls: ['./toasts.component.scss'] + styleUrls: ['./toasts.component.scss'], }) export class ToastsComponent implements OnInit, OnDestroy { - - constructor(private toastService: ToastService) { } + constructor(private toastService: ToastService) {} subscription: Subscription @@ -20,7 +19,8 @@ export class ToastsComponent implements OnInit, OnDestroy { } ngOnInit(): void { - this.subscription = this.toastService.getToasts().subscribe(toasts => this.toasts = toasts) + this.subscription = this.toastService + .getToasts() + .subscribe((toasts) => (this.toasts = toasts)) } - } diff --git a/src-ui/src/app/components/dashboard/dashboard.component.spec.ts b/src-ui/src/app/components/dashboard/dashboard.component.spec.ts deleted file mode 100644 index 5ec4ff8fc..000000000 --- a/src-ui/src/app/components/dashboard/dashboard.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { DashboardComponent } from './dashboard.component'; - -describe('DashboardComponent', () => { - let component: DashboardComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ DashboardComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(DashboardComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/components/dashboard/dashboard.component.ts b/src-ui/src/app/components/dashboard/dashboard.component.ts index 5dd19006e..3dd648212 100644 --- a/src-ui/src/app/components/dashboard/dashboard.component.ts +++ b/src-ui/src/app/components/dashboard/dashboard.component.ts @@ -1,20 +1,15 @@ -import { Component, OnInit } from '@angular/core'; -import { Meta } from '@angular/platform-browser'; -import { PaperlessSavedView } from 'src/app/data/paperless-saved-view'; -import { SavedViewService } from 'src/app/services/rest/saved-view.service'; - +import { Component, OnInit } from '@angular/core' +import { Meta } from '@angular/platform-browser' +import { PaperlessSavedView } from 'src/app/data/paperless-saved-view' +import { SavedViewService } from 'src/app/services/rest/saved-view.service' @Component({ selector: 'app-dashboard', templateUrl: './dashboard.component.html', - styleUrls: ['./dashboard.component.scss'] + styleUrls: ['./dashboard.component.scss'], }) export class DashboardComponent implements OnInit { - - constructor( - private savedViewService: SavedViewService, - private meta: Meta - ) { } + constructor(private savedViewService: SavedViewService, private meta: Meta) {} get displayName() { let tagFullName = this.meta.getTag('name=full_name') @@ -39,9 +34,10 @@ export class DashboardComponent implements OnInit { savedViews: PaperlessSavedView[] = [] ngOnInit(): void { - this.savedViewService.listAll().subscribe(results => { - this.savedViews = results.results.filter(savedView => savedView.show_on_dashboard) + this.savedViewService.listAll().subscribe((results) => { + this.savedViews = results.results.filter( + (savedView) => savedView.show_on_dashboard + ) }) } - } diff --git a/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html b/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html index b94545881..01809d1c6 100644 --- a/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html +++ b/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html @@ -1,9 +1,9 @@ - Show all + Show all - +
@@ -11,9 +11,9 @@ - + - +
Created
{{doc.created | customDate}}{{doc.title | documentTitle}}{{doc.title | documentTitle}}
diff --git a/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.spec.ts b/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.spec.ts deleted file mode 100644 index f0095b618..000000000 --- a/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { SavedViewWidgetComponent } from './saved-view-widget.component'; - -describe('SavedViewWidgetComponent', () => { - let component: SavedViewWidgetComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ SavedViewWidgetComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(SavedViewWidgetComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.ts b/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.ts index 20bc26cdc..e677a6e2f 100644 --- a/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.ts +++ b/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.ts @@ -1,24 +1,26 @@ -import { Component, Input, OnDestroy, OnInit } from '@angular/core'; -import { Router } from '@angular/router'; -import { Subscription } from 'rxjs'; -import { PaperlessDocument } from 'src/app/data/paperless-document'; -import { PaperlessSavedView } from 'src/app/data/paperless-saved-view'; -import { DocumentListViewService } from 'src/app/services/document-list-view.service'; -import { ConsumerStatusService } from 'src/app/services/consumer-status.service'; -import { DocumentService } from 'src/app/services/rest/document.service'; +import { Component, Input, OnDestroy, OnInit } from '@angular/core' +import { Router } from '@angular/router' +import { Subscription } from 'rxjs' +import { PaperlessDocument } from 'src/app/data/paperless-document' +import { PaperlessSavedView } from 'src/app/data/paperless-saved-view' +import { DocumentListViewService } from 'src/app/services/document-list-view.service' +import { ConsumerStatusService } from 'src/app/services/consumer-status.service' +import { DocumentService } from 'src/app/services/rest/document.service' +import { PaperlessTag } from 'src/app/data/paperless-tag' +import { FILTER_HAS_TAGS_ALL } from 'src/app/data/filter-rule-type' @Component({ selector: 'app-saved-view-widget', templateUrl: './saved-view-widget.component.html', - styleUrls: ['./saved-view-widget.component.scss'] + styleUrls: ['./saved-view-widget.component.scss'], }) export class SavedViewWidgetComponent implements OnInit, OnDestroy { - constructor( private documentService: DocumentService, private router: Router, private list: DocumentListViewService, - private consumerStatusService: ConsumerStatusService) { } + private consumerStatusService: ConsumerStatusService + ) {} @Input() savedView: PaperlessSavedView @@ -29,9 +31,11 @@ export class SavedViewWidgetComponent implements OnInit, OnDestroy { ngOnInit(): void { this.reload() - this.subscription = this.consumerStatusService.onDocumentConsumptionFinished().subscribe(status => { - this.reload() - }) + this.subscription = this.consumerStatusService + .onDocumentConsumptionFinished() + .subscribe((status) => { + this.reload() + }) } ngOnDestroy(): void { @@ -39,9 +43,17 @@ export class SavedViewWidgetComponent implements OnInit, OnDestroy { } reload() { - this.documentService.listFiltered(1,10,this.savedView.sort_field, this.savedView.sort_reverse, this.savedView.filter_rules).subscribe(result => { - this.documents = result.results - }) + this.documentService + .listFiltered( + 1, + 10, + this.savedView.sort_field, + this.savedView.sort_reverse, + this.savedView.filter_rules + ) + .subscribe((result) => { + this.documents = result.results + }) } showAll() { @@ -49,8 +61,13 @@ export class SavedViewWidgetComponent implements OnInit, OnDestroy { this.router.navigate(['view', this.savedView.id]) } else { this.list.loadSavedView(this.savedView, true) - this.router.navigate(["documents"]) + this.router.navigate(['documents']) } } + clickTag(tag: PaperlessTag) { + this.list.quickFilter([ + { rule_type: FILTER_HAS_TAGS_ALL, value: tag.id.toString() }, + ]) + } } diff --git a/src-ui/src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.spec.ts b/src-ui/src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.spec.ts deleted file mode 100644 index e8e44ca54..000000000 --- a/src-ui/src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { StatisticsWidgetComponent } from './statistics-widget.component'; - -describe('StatisticsWidgetComponent', () => { - let component: StatisticsWidgetComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ StatisticsWidgetComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(StatisticsWidgetComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.ts b/src-ui/src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.ts index f1488a66f..a13839f19 100644 --- a/src-ui/src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.ts +++ b/src-ui/src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.ts @@ -1,24 +1,24 @@ -import { HttpClient } from '@angular/common/http'; -import { Component, OnDestroy, OnInit } from '@angular/core'; -import { Observable, Subscription } from 'rxjs'; -import { ConsumerStatusService } from 'src/app/services/consumer-status.service'; -import { environment } from 'src/environments/environment'; +import { HttpClient } from '@angular/common/http' +import { Component, OnDestroy, OnInit } from '@angular/core' +import { Observable, Subscription } from 'rxjs' +import { ConsumerStatusService } from 'src/app/services/consumer-status.service' +import { environment } from 'src/environments/environment' export interface Statistics { documents_total?: number documents_inbox?: number } - @Component({ selector: 'app-statistics-widget', templateUrl: './statistics-widget.component.html', - styleUrls: ['./statistics-widget.component.scss'] + styleUrls: ['./statistics-widget.component.scss'], }) export class StatisticsWidgetComponent implements OnInit, OnDestroy { - - constructor(private http: HttpClient, - private consumerStatusService: ConsumerStatusService) { } + constructor( + private http: HttpClient, + private consumerStatusService: ConsumerStatusService + ) {} statistics: Statistics = {} @@ -29,20 +29,21 @@ export class StatisticsWidgetComponent implements OnInit, OnDestroy { } reload() { - this.getStatistics().subscribe(statistics => { + this.getStatistics().subscribe((statistics) => { this.statistics = statistics }) } ngOnInit(): void { this.reload() - this.subscription = this.consumerStatusService.onDocumentConsumptionFinished().subscribe(status => { - this.reload() - }) + this.subscription = this.consumerStatusService + .onDocumentConsumptionFinished() + .subscribe((status) => { + this.reload() + }) } ngOnDestroy(): void { this.subscription.unsubscribe() } - } diff --git a/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.scss b/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.scss index c13a7bd47..0e81d8bb5 100644 --- a/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.scss +++ b/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.scss @@ -1,5 +1,3 @@ -@import "/src/theme"; - form { position: relative; } @@ -33,3 +31,7 @@ form { mix-blend-mode: soft-light; pointer-events: none; } + +::ng-deep .ngx-file-drop__drop-zone--over { + background-color: var(--pngx-primary-faded) !important; +} diff --git a/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.spec.ts b/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.spec.ts deleted file mode 100644 index 88e8efa2e..000000000 --- a/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { UploadFileWidgetComponent } from './upload-file-widget.component'; - -describe('UploadFileWidgetComponent', () => { - let component: UploadFileWidgetComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ UploadFileWidgetComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(UploadFileWidgetComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts b/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts index e74e2bc41..e2f59a0a4 100644 --- a/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts +++ b/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts @@ -1,23 +1,27 @@ -import { HttpEventType } from '@angular/common/http'; -import { Component, OnInit } from '@angular/core'; -import { FileSystemFileEntry, NgxFileDropEntry } from 'ngx-file-drop'; -import { ConsumerStatusService, FileStatus, FileStatusPhase } from 'src/app/services/consumer-status.service'; -import { DocumentService } from 'src/app/services/rest/document.service'; +import { HttpEventType } from '@angular/common/http' +import { Component, OnInit } from '@angular/core' +import { FileSystemFileEntry, NgxFileDropEntry } from 'ngx-file-drop' +import { + ConsumerStatusService, + FileStatus, + FileStatusPhase, +} from 'src/app/services/consumer-status.service' +import { UploadDocumentsService } from 'src/app/services/upload-documents.service' const MAX_ALERTS = 5 @Component({ selector: 'app-upload-file-widget', templateUrl: './upload-file-widget.component.html', - styleUrls: ['./upload-file-widget.component.scss'] + styleUrls: ['./upload-file-widget.component.scss'], }) export class UploadFileWidgetComponent implements OnInit { alertsExpanded = false constructor( - private documentService: DocumentService, - private consumerStatusService: ConsumerStatusService - ) { } + private consumerStatusService: ConsumerStatusService, + private uploadDocumentsService: UploadDocumentsService + ) {} getStatus() { return this.consumerStatusService.getConsumerStatus().slice(0, MAX_ALERTS) @@ -25,7 +29,8 @@ export class UploadFileWidgetComponent implements OnInit { getStatusSummary() { let strings = [] - let countUploadingAndProcessing = this.consumerStatusService.getConsumerStatusNotCompleted().length + let countUploadingAndProcessing = + this.consumerStatusService.getConsumerStatusNotCompleted().length let countFailed = this.getStatusFailed().length let countSuccess = this.getStatusSuccess().length if (countUploadingAndProcessing > 0) { @@ -37,16 +42,21 @@ export class UploadFileWidgetComponent implements OnInit { if (countSuccess > 0) { strings.push($localize`Added: ${countSuccess}`) } - return strings.join($localize`:this string is used to separate processing, failed and added on the file upload widget:, `) + return strings.join( + $localize`:this string is used to separate processing, failed and added on the file upload widget:, ` + ) } getStatusHidden() { - if (this.consumerStatusService.getConsumerStatus().length < MAX_ALERTS) return [] + if (this.consumerStatusService.getConsumerStatus().length < MAX_ALERTS) + return [] else return this.consumerStatusService.getConsumerStatus().slice(MAX_ALERTS) } getStatusUploading() { - return this.consumerStatusService.getConsumerStatus(FileStatusPhase.UPLOADING) + return this.consumerStatusService.getConsumerStatus( + FileStatusPhase.UPLOADING + ) } getStatusFailed() { @@ -64,7 +74,7 @@ export class UploadFileWidgetComponent implements OnInit { let current = 0 let max = 0 - this.getStatusUploading().forEach(status => { + this.getStatusUploading().forEach((status) => { current += status.currentPhaseProgress max += status.currentPhaseMaxProgress }) @@ -73,18 +83,21 @@ export class UploadFileWidgetComponent implements OnInit { } isFinished(status: FileStatus) { - return status.phase == FileStatusPhase.FAILED || status.phase == FileStatusPhase.SUCCESS + return ( + status.phase == FileStatusPhase.FAILED || + status.phase == FileStatusPhase.SUCCESS + ) } getStatusColor(status: FileStatus) { switch (status.phase) { case FileStatusPhase.PROCESSING: case FileStatusPhase.UPLOADING: - return "primary" + return 'primary' case FileStatusPhase.FAILED: - return "danger" + return 'danger' case FileStatusPhase.SUCCESS: - return "success" + return 'success' } } @@ -96,51 +109,13 @@ export class UploadFileWidgetComponent implements OnInit { this.consumerStatusService.dismissCompleted() } - ngOnInit(): void { - } + ngOnInit(): void {} - public fileOver(event){ - } + public fileOver(event) {} - public fileLeave(event){ - } + public fileLeave(event) {} public dropped(files: NgxFileDropEntry[]) { - for (const droppedFile of files) { - if (droppedFile.fileEntry.isFile) { - - const fileEntry = droppedFile.fileEntry as FileSystemFileEntry; - fileEntry.file((file: File) => { - let formData = new FormData() - formData.append('document', file, file.name) - let status = this.consumerStatusService.newFileUpload(file.name) - - status.message = $localize`Connecting...` - - this.documentService.uploadDocument(formData).subscribe(event => { - if (event.type == HttpEventType.UploadProgress) { - status.updateProgress(FileStatusPhase.UPLOADING, event.loaded, event.total) - status.message = $localize`Uploading...` - } else if (event.type == HttpEventType.Response) { - status.taskId = event.body["task_id"] - status.message = $localize`Upload complete, waiting...` - } - - }, error => { - switch (error.status) { - case 400: { - this.consumerStatusService.fail(status, error.error.document) - break; - } - default: { - this.consumerStatusService.fail(status, $localize`HTTP error: ${error.status} ${error.statusText}`) - break; - } - } - - }) - }); - } - } + this.uploadDocumentsService.uploadFiles(files) } } diff --git a/src-ui/src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.spec.ts b/src-ui/src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.spec.ts deleted file mode 100644 index 5e8c2494b..000000000 --- a/src-ui/src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { WelcomeWidgetComponent } from './welcome-widget.component'; - -describe('WelcomeWidgetComponent', () => { - let component: WelcomeWidgetComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ WelcomeWidgetComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(WelcomeWidgetComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.ts b/src-ui/src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.ts index 71a87189c..9873932ee 100644 --- a/src-ui/src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.ts +++ b/src-ui/src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.ts @@ -1,15 +1,12 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit } from '@angular/core' @Component({ selector: 'app-welcome-widget', templateUrl: './welcome-widget.component.html', - styleUrls: ['./welcome-widget.component.scss'] + styleUrls: ['./welcome-widget.component.scss'], }) export class WelcomeWidgetComponent implements OnInit { + constructor() {} - constructor() { } - - ngOnInit(): void { - } - + ngOnInit(): void {} } diff --git a/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.html b/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.html index 1cd440306..a9d3d306a 100644 --- a/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.html +++ b/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.html @@ -6,7 +6,7 @@
-
+
diff --git a/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.spec.ts b/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.spec.ts deleted file mode 100644 index ea1696750..000000000 --- a/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { WidgetFrameComponent } from './widget-frame.component'; - -describe('WidgetFrameComponent', () => { - let component: WidgetFrameComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ WidgetFrameComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(WidgetFrameComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.ts b/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.ts index 38d6b0023..f21f6ca35 100644 --- a/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.ts +++ b/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.ts @@ -1,18 +1,15 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, Input, OnInit } from '@angular/core' @Component({ selector: 'app-widget-frame', templateUrl: './widget-frame.component.html', - styleUrls: ['./widget-frame.component.scss'] + styleUrls: ['./widget-frame.component.scss'], }) export class WidgetFrameComponent implements OnInit { - - constructor() { } + constructor() {} @Input() title: string - ngOnInit(): void { - } - + ngOnInit(): void {} } diff --git a/src-ui/src/app/components/document-asn/document-asn.component.spec.ts b/src-ui/src/app/components/document-asn/document-asn.component.spec.ts deleted file mode 100644 index 5a9826f8d..000000000 --- a/src-ui/src/app/components/document-asn/document-asn.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { DocumentAsnComponent } from './document-asn.component'; - -describe('DocumentASNComponentComponent', () => { - let component: DocumentAsnComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ DocumentAsnComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(DocumentAsnComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/components/document-asn/document-asn.component.ts b/src-ui/src/app/components/document-asn/document-asn.component.ts index 550c331b9..4fb9f474a 100644 --- a/src-ui/src/app/components/document-asn/document-asn.component.ts +++ b/src-ui/src/app/components/document-asn/document-asn.component.ts @@ -1,34 +1,33 @@ -import { Component, OnInit } from '@angular/core'; -import {DocumentService} from "../../services/rest/document.service"; -import {ActivatedRoute, Router} from "@angular/router"; -import {FILTER_ASN} from "../../data/filter-rule-type"; +import { Component, OnInit } from '@angular/core' +import { DocumentService } from '../../services/rest/document.service' +import { ActivatedRoute, Router } from '@angular/router' +import { FILTER_ASN } from '../../data/filter-rule-type' @Component({ selector: 'app-document-asncomponent', templateUrl: './document-asn.component.html', - styleUrls: ['./document-asn.component.scss'] + styleUrls: ['./document-asn.component.scss'], }) export class DocumentAsnComponent implements OnInit { - asn: string constructor( private documentsService: DocumentService, private route: ActivatedRoute, - private router: Router) { } - + private router: Router + ) {} ngOnInit(): void { - - this.route.paramMap.subscribe(paramMap => { - this.asn = paramMap.get('id'); - this.documentsService.listAllFilteredIds([{rule_type: FILTER_ASN, value: this.asn}]).subscribe(documentId => { - if (documentId.length == 1) { - this.router.navigate(['documents', documentId[0]]) - } else { - this.router.navigate(['404']) - } - }) + this.route.paramMap.subscribe((paramMap) => { + this.asn = paramMap.get('id') + this.documentsService + .listAllFilteredIds([{ rule_type: FILTER_ASN, value: this.asn }]) + .subscribe((documentId) => { + if (documentId.length == 1) { + this.router.navigate(['documents', documentId[0]]) + } else { + this.router.navigate(['404']) + } + }) }) - } } diff --git a/src-ui/src/app/components/document-detail/document-detail.component.html b/src-ui/src/app/components/document-detail/document-detail.component.html index b62d805c3..f9fecdf85 100644 --- a/src-ui/src/app/components/document-detail/document-detail.component.html +++ b/src-ui/src/app/components/document-detail/document-detail.component.html @@ -34,11 +34,25 @@  More like this - + +
+ + +
+ @@ -121,20 +135,27 @@
  • - Preview - - -
    - + Preview + +
    + +
    + +
    + + + +
    + + + +
    +
    + +
    +
    - - - - - - - -
    +
  • @@ -146,17 +167,23 @@
    -
    +
    - +
    - +
    - + +
    +
    + +
    +
    +
    diff --git a/src-ui/src/app/components/document-detail/document-detail.component.scss b/src-ui/src/app/components/document-detail/document-detail.component.scss index 5512b6bb0..c5823fd08 100644 --- a/src-ui/src/app/components/document-detail/document-detail.component.scss +++ b/src-ui/src/app/components/document-detail/document-detail.component.scss @@ -17,3 +17,10 @@ --page-margin: 1px 0 -8px; width: 100% !important; } + +.password-prompt { + position: absolute; + top: 30%; + left: 30%; + right: 30%; +} diff --git a/src-ui/src/app/components/document-detail/document-detail.component.spec.ts b/src-ui/src/app/components/document-detail/document-detail.component.spec.ts deleted file mode 100644 index 0e4923e2e..000000000 --- a/src-ui/src/app/components/document-detail/document-detail.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { DocumentDetailComponent } from './document-detail.component'; - -describe('DocumentDetailComponent', () => { - let component: DocumentDetailComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ DocumentDetailComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(DocumentDetailComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/components/document-detail/document-detail.component.ts b/src-ui/src/app/components/document-detail/document-detail.component.ts index e751f59f8..f6fdc1b86 100644 --- a/src-ui/src/app/components/document-detail/document-detail.component.ts +++ b/src-ui/src/app/components/document-detail/document-detail.component.ts @@ -1,38 +1,49 @@ -import { Component, OnInit, OnDestroy, ViewChild, ElementRef } from '@angular/core'; -import { FormControl, FormGroup } from '@angular/forms'; -import { ActivatedRoute, Router } from '@angular/router'; -import { NgbModal, NgbNav } from '@ng-bootstrap/ng-bootstrap'; -import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent'; -import { PaperlessDocument } from 'src/app/data/paperless-document'; -import { PaperlessDocumentMetadata } from 'src/app/data/paperless-document-metadata'; -import { PaperlessDocumentType } from 'src/app/data/paperless-document-type'; -import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe'; -import { DocumentListViewService } from 'src/app/services/document-list-view.service'; -import { OpenDocumentsService } from 'src/app/services/open-documents.service'; -import { CorrespondentService } from 'src/app/services/rest/correspondent.service'; -import { DocumentTypeService } from 'src/app/services/rest/document-type.service'; -import { DocumentService } from 'src/app/services/rest/document.service'; -import { ConfirmDialogComponent } from '../common/confirm-dialog/confirm-dialog.component'; -import { CorrespondentEditDialogComponent } from '../manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component'; -import { DocumentTypeEditDialogComponent } from '../manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component'; -import { PDFDocumentProxy } from 'ng2-pdf-viewer'; -import { ToastService } from 'src/app/services/toast.service'; -import { TextComponent } from '../common/input/text/text.component'; -import { SettingsService, SETTINGS_KEYS } from 'src/app/services/settings.service'; -import { dirtyCheck, DirtyComponent } from '@ngneat/dirty-check-forms'; -import { Observable, Subject, BehaviorSubject } from 'rxjs'; -import { first, takeUntil, switchMap, map, debounceTime, distinctUntilChanged } from 'rxjs/operators'; -import { PaperlessDocumentSuggestions } from 'src/app/data/paperless-document-suggestions'; -import { FILTER_FULLTEXT_MORELIKE } from 'src/app/data/filter-rule-type'; +import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core' +import { FormControl, FormGroup } from '@angular/forms' +import { ActivatedRoute, Router } from '@angular/router' +import { NgbModal, NgbNav } from '@ng-bootstrap/ng-bootstrap' +import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent' +import { PaperlessDocument } from 'src/app/data/paperless-document' +import { PaperlessDocumentMetadata } from 'src/app/data/paperless-document-metadata' +import { PaperlessDocumentType } from 'src/app/data/paperless-document-type' +import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe' +import { DocumentListViewService } from 'src/app/services/document-list-view.service' +import { OpenDocumentsService } from 'src/app/services/open-documents.service' +import { CorrespondentService } from 'src/app/services/rest/correspondent.service' +import { DocumentTypeService } from 'src/app/services/rest/document-type.service' +import { DocumentService } from 'src/app/services/rest/document.service' +import { ConfirmDialogComponent } from '../common/confirm-dialog/confirm-dialog.component' +import { CorrespondentEditDialogComponent } from '../common/edit-dialog/correspondent-edit-dialog/correspondent-edit-dialog.component' +import { DocumentTypeEditDialogComponent } from '../common/edit-dialog/document-type-edit-dialog/document-type-edit-dialog.component' +import { PDFDocumentProxy } from 'ng2-pdf-viewer' +import { ToastService } from 'src/app/services/toast.service' +import { TextComponent } from '../common/input/text/text.component' +import { + SettingsService, + SETTINGS_KEYS, +} from 'src/app/services/settings.service' +import { dirtyCheck, DirtyComponent } from '@ngneat/dirty-check-forms' +import { Observable, Subject, BehaviorSubject } from 'rxjs' +import { + first, + takeUntil, + switchMap, + map, + debounceTime, + distinctUntilChanged, +} from 'rxjs/operators' +import { PaperlessDocumentSuggestions } from 'src/app/data/paperless-document-suggestions' +import { FILTER_FULLTEXT_MORELIKE } from 'src/app/data/filter-rule-type' @Component({ selector: 'app-document-detail', templateUrl: './document-detail.component.html', - styleUrls: ['./document-detail.component.scss'] + styleUrls: ['./document-detail.component.scss'], }) -export class DocumentDetailComponent implements OnInit, OnDestroy, DirtyComponent { - - @ViewChild("inputTitle") +export class DocumentDetailComponent + implements OnInit, OnDestroy, DirtyComponent +{ + @ViewChild('inputTitle') titleInput: TextComponent expandOriginalMetadata = false @@ -63,7 +74,7 @@ export class DocumentDetailComponent implements OnInit, OnDestroy, DirtyComponen correspondent: new FormControl(), document_type: new FormControl(), archive_serial_number: new FormControl(), - tags: new FormControl([]) + tags: new FormControl([]), }) previewCurrentPage: number = 1 @@ -73,11 +84,21 @@ export class DocumentDetailComponent implements OnInit, OnDestroy, DirtyComponen isDirty$: Observable unsubscribeNotifier: Subject = new Subject() + requiresPassword: boolean = false + password: string + + ogDate: Date + @ViewChild('nav') nav: NgbNav @ViewChild('pdfPreview') set pdfPreview(element) { // this gets called when compontent added or removed from DOM - if (element && element.nativeElement.offsetParent !== null && this.nav?.activeId == 4) { // its visible - setTimeout(()=> this.nav?.select(1)); + if ( + element && + element.nativeElement.offsetParent !== null && + this.nav?.activeId == 4 + ) { + // its visible + setTimeout(() => this.nav?.select(1)) } } @@ -92,16 +113,19 @@ export class DocumentDetailComponent implements OnInit, OnDestroy, DirtyComponen private documentListViewService: DocumentListViewService, private documentTitlePipe: DocumentTitlePipe, private toastService: ToastService, - private settings: SettingsService) { - this.titleSubject.pipe( + private settings: SettingsService + ) { + this.titleSubject + .pipe( debounceTime(1000), distinctUntilChanged(), takeUntil(this.unsubscribeNotifier) - ).subscribe(titleValue => { + ) + .subscribe((titleValue) => { this.title = titleValue - this.documentForm.patchValue({'title': titleValue}) + this.documentForm.patchValue({ title: titleValue }) }) - } + } titleKeyUp(event) { this.titleSubject.next(event.target?.value) @@ -112,188 +136,357 @@ export class DocumentDetailComponent implements OnInit, OnDestroy, DirtyComponen } getContentType() { - return this.metadata?.has_archive_version ? 'application/pdf' : this.metadata?.original_mime_type + return this.metadata?.has_archive_version + ? 'application/pdf' + : this.metadata?.original_mime_type } ngOnInit(): void { - this.documentForm.valueChanges.pipe(takeUntil(this.unsubscribeNotifier)).subscribe(wow => { - Object.assign(this.document, this.documentForm.value) - }) + this.documentForm.valueChanges + .pipe(takeUntil(this.unsubscribeNotifier)) + .subscribe((changes) => { + if (this.ogDate) { + let newDate = new Date(changes['created']) + newDate.setHours( + this.ogDate.getHours(), + this.ogDate.getMinutes(), + this.ogDate.getSeconds(), + this.ogDate.getMilliseconds() + ) + this.documentForm.patchValue( + { created: this.formatDate(newDate) }, + { emitEvent: false } + ) + } - this.correspondentService.listAll().pipe(first()).subscribe(result => this.correspondents = result.results) - this.documentTypeService.listAll().pipe(first()).subscribe(result => this.documentTypes = result.results) - - this.route.paramMap.pipe(switchMap(paramMap => { - const documentId = +paramMap.get('id') - return this.documentsService.get(documentId) - })).pipe(switchMap((doc) => { - this.documentId = doc.id - this.previewUrl = this.documentsService.getPreviewUrl(this.documentId) - this.downloadUrl = this.documentsService.getDownloadUrl(this.documentId) - this.downloadOriginalUrl = this.documentsService.getDownloadUrl(this.documentId, true) - this.suggestions = null - if (this.openDocumentService.getOpenDocument(this.documentId)) { - this.updateComponent(this.openDocumentService.getOpenDocument(this.documentId)) - } else { - this.openDocumentService.openDocument(doc) - this.updateComponent(doc) - } - - // Initialize dirtyCheck - this.store = new BehaviorSubject({ - title: doc.title, - content: doc.content, - created: doc.created, - correspondent: doc.correspondent, - document_type: doc.document_type, - archive_serial_number: doc.archive_serial_number, - tags: [...doc.tags] + Object.assign(this.document, this.documentForm.value) }) - this.isDirty$ = dirtyCheck(this.documentForm, this.store.asObservable()) + this.correspondentService + .listAll() + .pipe(first()) + .subscribe((result) => (this.correspondents = result.results)) + this.documentTypeService + .listAll() + .pipe(first()) + .subscribe((result) => (this.documentTypes = result.results)) - return this.isDirty$.pipe(map(dirty => ({doc, dirty}))) - })) - .pipe(takeUntil(this.unsubscribeNotifier)) - .subscribe(({doc, dirty}) => { - this.openDocumentService.setDirty(doc.id, dirty) - }, error => {this.router.navigate(['404'])}) + this.route.paramMap + .pipe( + switchMap((paramMap) => { + const documentId = +paramMap.get('id') + return this.documentsService.get(documentId) + }) + ) + .pipe( + switchMap((doc) => { + this.documentId = doc.id + this.previewUrl = this.documentsService.getPreviewUrl(this.documentId) + this.downloadUrl = this.documentsService.getDownloadUrl( + this.documentId + ) + this.downloadOriginalUrl = this.documentsService.getDownloadUrl( + this.documentId, + true + ) + this.suggestions = null + if (this.openDocumentService.getOpenDocument(this.documentId)) { + this.updateComponent( + this.openDocumentService.getOpenDocument(this.documentId) + ) + } else { + this.openDocumentService.openDocument(doc) + this.updateComponent(doc) + } + + this.ogDate = new Date(doc.created) + + // Initialize dirtyCheck + this.store = new BehaviorSubject({ + title: doc.title, + content: doc.content, + created: this.formatDate(this.ogDate), + correspondent: doc.correspondent, + document_type: doc.document_type, + archive_serial_number: doc.archive_serial_number, + tags: [...doc.tags], + }) + + // ensure we're always starting with 24-char ISO8601 string + this.documentForm.patchValue( + { created: this.formatDate(this.ogDate) }, + { emitEvent: false } + ) + + this.isDirty$ = dirtyCheck( + this.documentForm, + this.store.asObservable() + ) + + return this.isDirty$.pipe(map((dirty) => ({ doc, dirty }))) + }) + ) + .pipe(takeUntil(this.unsubscribeNotifier)) + .subscribe({ + next: ({ doc, dirty }) => { + this.openDocumentService.setDirty(doc.id, dirty) + }, + error: (error) => { + this.router.navigate(['404']) + }, + }) } - ngOnDestroy() : void { - this.unsubscribeNotifier.next(); - this.unsubscribeNotifier.complete(); + ngOnDestroy(): void { + this.unsubscribeNotifier.next(this) + this.unsubscribeNotifier.complete() } updateComponent(doc: PaperlessDocument) { this.document = doc - this.documentsService.getMetadata(doc.id).pipe(first()).subscribe(result => { - this.metadata = result - }, error => { - this.metadata = null - }) - this.documentsService.getSuggestions(doc.id).pipe(first()).subscribe(result => { - this.suggestions = result - }, error => { - this.suggestions = null - }) + this.documentsService + .getMetadata(doc.id) + .pipe(first()) + .subscribe({ + next: (result) => { + this.metadata = result + }, + error: (error) => { + this.metadata = null + }, + }) + this.documentsService + .getSuggestions(doc.id) + .pipe(first()) + .subscribe({ + next: (result) => { + this.suggestions = result + }, + error: (error) => { + this.suggestions = null + }, + }) this.title = this.documentTitlePipe.transform(doc.title) this.documentForm.patchValue(doc) } createDocumentType(newName: string) { - var modal = this.modalService.open(DocumentTypeEditDialogComponent, {backdrop: 'static'}) + var modal = this.modalService.open(DocumentTypeEditDialogComponent, { + backdrop: 'static', + }) modal.componentInstance.dialogMode = 'create' if (newName) modal.componentInstance.object = { name: newName } - modal.componentInstance.success.pipe(switchMap(newDocumentType => { - return this.documentTypeService.listAll().pipe(map(documentTypes => ({newDocumentType, documentTypes}))) - })) - .pipe(takeUntil(this.unsubscribeNotifier)) - .subscribe(({newDocumentType, documentTypes}) => { - this.documentTypes = documentTypes.results - this.documentForm.get('document_type').setValue(newDocumentType.id) - }) + modal.componentInstance.success + .pipe( + switchMap((newDocumentType) => { + return this.documentTypeService + .listAll() + .pipe(map((documentTypes) => ({ newDocumentType, documentTypes }))) + }) + ) + .pipe(takeUntil(this.unsubscribeNotifier)) + .subscribe(({ newDocumentType, documentTypes }) => { + this.documentTypes = documentTypes.results + this.documentForm.get('document_type').setValue(newDocumentType.id) + }) } createCorrespondent(newName: string) { - var modal = this.modalService.open(CorrespondentEditDialogComponent, {backdrop: 'static'}) + var modal = this.modalService.open(CorrespondentEditDialogComponent, { + backdrop: 'static', + }) modal.componentInstance.dialogMode = 'create' if (newName) modal.componentInstance.object = { name: newName } - modal.componentInstance.success.pipe(switchMap(newCorrespondent => { - return this.correspondentService.listAll().pipe(map(correspondents => ({newCorrespondent, correspondents}))) - })) - .pipe(takeUntil(this.unsubscribeNotifier)) - .subscribe(({newCorrespondent, correspondents}) => { - this.correspondents = correspondents.results - this.documentForm.get('correspondent').setValue(newCorrespondent.id) - }) + modal.componentInstance.success + .pipe( + switchMap((newCorrespondent) => { + return this.correspondentService + .listAll() + .pipe( + map((correspondents) => ({ newCorrespondent, correspondents })) + ) + }) + ) + .pipe(takeUntil(this.unsubscribeNotifier)) + .subscribe(({ newCorrespondent, correspondents }) => { + this.correspondents = correspondents.results + this.documentForm.get('correspondent').setValue(newCorrespondent.id) + }) } discard() { - this.documentsService.get(this.documentId).pipe(first()).subscribe(doc => { - Object.assign(this.document, doc) - this.title = doc.title - this.documentForm.patchValue(doc) - }, error => {this.router.navigate(['404'])}) + this.documentsService + .get(this.documentId) + .pipe(first()) + .subscribe( + (doc) => { + Object.assign(this.document, doc) + this.title = doc.title + this.documentForm.patchValue(doc) + }, + (error) => { + this.router.navigate(['404']) + } + ) } save() { this.networkActive = true this.store.next(this.documentForm.value) - this.documentsService.update(this.document).pipe(first()).subscribe(result => { - this.close() - this.networkActive = false - this.error = null - }, error => { - this.networkActive = false - this.error = error.error - }) + this.documentsService + .update(this.document) + .pipe(first()) + .subscribe({ + next: (result) => { + this.close() + this.networkActive = false + this.error = null + }, + error: (error) => { + this.networkActive = false + this.error = error.error + }, + }) } saveEditNext() { this.networkActive = true this.store.next(this.documentForm.value) - this.documentsService.update(this.document).pipe(switchMap(updateResult => { - return this.documentListViewService.getNext(this.documentId).pipe(map(nextDocId => ({nextDocId, updateResult}))) - })).pipe(switchMap(({nextDocId, updateResult}) => { - if (nextDocId && updateResult) return this.openDocumentService.closeDocument(this.document).pipe(map(closeResult => ({updateResult, nextDocId, closeResult}))) - })) - .pipe(first()) - .subscribe(({updateResult, nextDocId, closeResult}) => { - this.error = null - this.networkActive = false - if (closeResult && updateResult && nextDocId) { - this.router.navigate(['documents', nextDocId]) - this.titleInput?.focus() - } - }, error => { - this.networkActive = false - this.error = error.error - }) + this.documentsService + .update(this.document) + .pipe( + switchMap((updateResult) => { + return this.documentListViewService + .getNext(this.documentId) + .pipe(map((nextDocId) => ({ nextDocId, updateResult }))) + }) + ) + .pipe( + switchMap(({ nextDocId, updateResult }) => { + if (nextDocId && updateResult) + return this.openDocumentService + .closeDocument(this.document) + .pipe( + map((closeResult) => ({ updateResult, nextDocId, closeResult })) + ) + }) + ) + .pipe(first()) + .subscribe({ + next: ({ updateResult, nextDocId, closeResult }) => { + this.error = null + this.networkActive = false + if (closeResult && updateResult && nextDocId) { + this.router.navigate(['documents', nextDocId]) + this.titleInput?.focus() + } + }, + error: (error) => { + this.networkActive = false + this.error = error.error + }, + }) } close() { - this.openDocumentService.closeDocument(this.document).pipe(first()).subscribe(closed => { - if (!closed) return; - if (this.documentListViewService.activeSavedViewId) { - this.router.navigate(['view', this.documentListViewService.activeSavedViewId]) - } else { - this.router.navigate(['documents']) - } - }) + this.openDocumentService + .closeDocument(this.document) + .pipe(first()) + .subscribe((closed) => { + if (!closed) return + if (this.documentListViewService.activeSavedViewId) { + this.router.navigate([ + 'view', + this.documentListViewService.activeSavedViewId, + ]) + } else { + this.router.navigate(['documents']) + } + }) } delete() { - let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) + let modal = this.modalService.open(ConfirmDialogComponent, { + backdrop: 'static', + }) modal.componentInstance.title = $localize`Confirm delete` modal.componentInstance.messageBold = $localize`Do you really want to delete document "${this.document.title}"?` modal.componentInstance.message = $localize`The files for this document will be deleted permanently. This operation cannot be undone.` - modal.componentInstance.btnClass = "btn-danger" + modal.componentInstance.btnClass = 'btn-danger' modal.componentInstance.btnCaption = $localize`Delete document` - modal.componentInstance.confirmClicked.pipe(switchMap(() => { - modal.componentInstance.buttonsEnabled = false - return this.documentsService.delete(this.document) - })) - .pipe(takeUntil(this.unsubscribeNotifier)) - .subscribe(() => { - modal.close() - this.close() - }, error => { - this.toastService.showError($localize`Error deleting document: ${JSON.stringify(error)}`) - modal.componentInstance.buttonsEnabled = true - }) + modal.componentInstance.confirmClicked + .pipe( + switchMap(() => { + modal.componentInstance.buttonsEnabled = false + return this.documentsService.delete(this.document) + }) + ) + .pipe(takeUntil(this.unsubscribeNotifier)) + .subscribe( + () => { + modal.close() + this.close() + }, + (error) => { + this.toastService.showError( + $localize`Error deleting document: ${JSON.stringify(error)}` + ) + modal.componentInstance.buttonsEnabled = true + } + ) } moreLike() { - this.documentListViewService.quickFilter([{rule_type: FILTER_FULLTEXT_MORELIKE, value: this.documentId.toString()}]) + this.documentListViewService.quickFilter([ + { + rule_type: FILTER_FULLTEXT_MORELIKE, + value: this.documentId.toString(), + }, + ]) } hasNext() { return this.documentListViewService.hasNext(this.documentId) } - pdfPreviewLoaded(pdf: PDFDocumentProxy) { - this.previewNumPages = pdf.numPages + hasPrevious() { + return this.documentListViewService.hasPrevious(this.documentId) } + nextDoc() { + this.documentListViewService + .getNext(this.document.id) + .subscribe((nextDocId: number) => { + this.router.navigate(['documents', nextDocId]) + }) + } + + previousDoc() { + this.documentListViewService + .getPrevious(this.document.id) + .subscribe((prevDocId: number) => { + this.router.navigate(['documents', prevDocId]) + }) + } + + pdfPreviewLoaded(pdf: PDFDocumentProxy) { + this.previewNumPages = pdf.numPages + if (this.password) this.requiresPassword = false + } + + onError(event) { + if (event.name == 'PasswordException') { + this.requiresPassword = true + } + } + + onPasswordKeyUp(event: KeyboardEvent) { + if ('Enter' == event.key) { + this.password = (event.target as HTMLInputElement).value + } + } + + formatDate(date: Date): string { + return date.toISOString().split('.')[0] + 'Z' + } } diff --git a/src-ui/src/app/components/document-detail/metadata-collapse/metadata-collapse.component.spec.ts b/src-ui/src/app/components/document-detail/metadata-collapse/metadata-collapse.component.spec.ts deleted file mode 100644 index 2bd96760b..000000000 --- a/src-ui/src/app/components/document-detail/metadata-collapse/metadata-collapse.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { MetadataCollapseComponent } from './metadata-collapse.component'; - -describe('MetadataCollapseComponent', () => { - let component: MetadataCollapseComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ MetadataCollapseComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(MetadataCollapseComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/components/document-detail/metadata-collapse/metadata-collapse.component.ts b/src-ui/src/app/components/document-detail/metadata-collapse/metadata-collapse.component.ts index 34bbbd655..efef478b6 100644 --- a/src-ui/src/app/components/document-detail/metadata-collapse/metadata-collapse.component.ts +++ b/src-ui/src/app/components/document-detail/metadata-collapse/metadata-collapse.component.ts @@ -1,13 +1,12 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, Input, OnInit } from '@angular/core' @Component({ selector: 'app-metadata-collapse', templateUrl: './metadata-collapse.component.html', - styleUrls: ['./metadata-collapse.component.scss'] + styleUrls: ['./metadata-collapse.component.scss'], }) export class MetadataCollapseComponent implements OnInit { - - constructor() { } + constructor() {} expand = false @@ -17,7 +16,5 @@ export class MetadataCollapseComponent implements OnInit { @Input() title = $localize`Metadata` - ngOnInit(): void { - } - + ngOnInit(): void {} } diff --git a/src-ui/src/app/components/document-list/bulk-editor/bulk-editor.component.html b/src-ui/src/app/components/document-list/bulk-editor/bulk-editor.component.html index 0a92cd083..631b558d0 100644 --- a/src-ui/src/app/components/document-list/bulk-editor/bulk-editor.component.html +++ b/src-ui/src/app/components/document-list/bulk-editor/bulk-editor.component.html @@ -57,13 +57,18 @@
    -
    - + diff --git a/src-ui/src/app/components/document-list/bulk-editor/bulk-editor.component.spec.ts b/src-ui/src/app/components/document-list/bulk-editor/bulk-editor.component.spec.ts deleted file mode 100644 index 140d73301..000000000 --- a/src-ui/src/app/components/document-list/bulk-editor/bulk-editor.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { BulkEditorComponent } from './bulk-editor.component'; - -describe('BulkEditorComponent', () => { - let component: BulkEditorComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ BulkEditorComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(BulkEditorComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/components/document-list/bulk-editor/bulk-editor.component.ts b/src-ui/src/app/components/document-list/bulk-editor/bulk-editor.component.ts index 310290291..c451f851e 100644 --- a/src-ui/src/app/components/document-list/bulk-editor/bulk-editor.component.ts +++ b/src-ui/src/app/components/document-list/bulk-editor/bulk-editor.component.ts @@ -1,29 +1,37 @@ -import { Component } from '@angular/core'; -import { PaperlessTag } from 'src/app/data/paperless-tag'; -import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent'; -import { PaperlessDocumentType } from 'src/app/data/paperless-document-type'; -import { TagService } from 'src/app/services/rest/tag.service'; -import { CorrespondentService } from 'src/app/services/rest/correspondent.service'; -import { DocumentTypeService } from 'src/app/services/rest/document-type.service'; -import { DocumentListViewService } from 'src/app/services/document-list-view.service'; -import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; -import { DocumentService, SelectionDataItem } from 'src/app/services/rest/document.service'; -import { OpenDocumentsService } from 'src/app/services/open-documents.service'; -import { ConfirmDialogComponent } from 'src/app/components/common/confirm-dialog/confirm-dialog.component'; -import { ChangedItems, FilterableDropdownSelectionModel } from '../../common/filterable-dropdown/filterable-dropdown.component'; -import { ToggleableItemState } from '../../common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component'; -import { MatchingModel } from 'src/app/data/matching-model'; -import { SettingsService, SETTINGS_KEYS } from 'src/app/services/settings.service'; -import { ToastService } from 'src/app/services/toast.service'; -import { saveAs } from 'file-saver'; +import { Component } from '@angular/core' +import { PaperlessTag } from 'src/app/data/paperless-tag' +import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent' +import { PaperlessDocumentType } from 'src/app/data/paperless-document-type' +import { TagService } from 'src/app/services/rest/tag.service' +import { CorrespondentService } from 'src/app/services/rest/correspondent.service' +import { DocumentTypeService } from 'src/app/services/rest/document-type.service' +import { DocumentListViewService } from 'src/app/services/document-list-view.service' +import { NgbModal } from '@ng-bootstrap/ng-bootstrap' +import { + DocumentService, + SelectionDataItem, +} from 'src/app/services/rest/document.service' +import { OpenDocumentsService } from 'src/app/services/open-documents.service' +import { ConfirmDialogComponent } from 'src/app/components/common/confirm-dialog/confirm-dialog.component' +import { + ChangedItems, + FilterableDropdownSelectionModel, +} from '../../common/filterable-dropdown/filterable-dropdown.component' +import { ToggleableItemState } from '../../common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component' +import { MatchingModel } from 'src/app/data/matching-model' +import { + SettingsService, + SETTINGS_KEYS, +} from 'src/app/services/settings.service' +import { ToastService } from 'src/app/services/toast.service' +import { saveAs } from 'file-saver' @Component({ selector: 'app-bulk-editor', templateUrl: './bulk-editor.component.html', - styleUrls: ['./bulk-editor.component.scss'] + styleUrls: ['./bulk-editor.component.scss'], }) export class BulkEditorComponent { - tags: PaperlessTag[] correspondents: PaperlessCorrespondent[] documentTypes: PaperlessDocumentType[] @@ -31,6 +39,7 @@ export class BulkEditorComponent { tagSelectionModel = new FilterableDropdownSelectionModel() correspondentSelectionModel = new FilterableDropdownSelectionModel() documentTypeSelectionModel = new FilterableDropdownSelectionModel() + awaitingDownload: boolean constructor( private documentTypeService: DocumentTypeService, @@ -42,43 +51,63 @@ export class BulkEditorComponent { private openDocumentService: OpenDocumentsService, private settings: SettingsService, private toastService: ToastService - ) { } + ) {} - applyOnClose: boolean = this.settings.get(SETTINGS_KEYS.BULK_EDIT_APPLY_ON_CLOSE) - showConfirmationDialogs: boolean = this.settings.get(SETTINGS_KEYS.BULK_EDIT_CONFIRMATION_DIALOGS) + applyOnClose: boolean = this.settings.get( + SETTINGS_KEYS.BULK_EDIT_APPLY_ON_CLOSE + ) + showConfirmationDialogs: boolean = this.settings.get( + SETTINGS_KEYS.BULK_EDIT_CONFIRMATION_DIALOGS + ) ngOnInit() { - this.tagService.listAll().subscribe(result => this.tags = result.results) - this.correspondentService.listAll().subscribe(result => this.correspondents = result.results) - this.documentTypeService.listAll().subscribe(result => this.documentTypes = result.results) + this.tagService + .listAll() + .subscribe((result) => (this.tags = result.results)) + this.correspondentService + .listAll() + .subscribe((result) => (this.correspondents = result.results)) + this.documentTypeService + .listAll() + .subscribe((result) => (this.documentTypes = result.results)) } private executeBulkOperation(modal, method: string, args) { if (modal) { modal.componentInstance.buttonsEnabled = false } - this.documentService.bulkEdit(Array.from(this.list.selected), method, args).subscribe( - response => { - this.list.reload() - this.list.reduceSelectionToFilter() - this.list.selected.forEach(id => { - this.openDocumentService.refreshDocument(id) - }) - if (modal) { - modal.close() + this.documentService + .bulkEdit(Array.from(this.list.selected), method, args) + .subscribe( + (response) => { + this.list.reload() + this.list.reduceSelectionToFilter() + this.list.selected.forEach((id) => { + this.openDocumentService.refreshDocument(id) + }) + if (modal) { + modal.close() + } + }, + (error) => { + if (modal) { + modal.componentInstance.buttonsEnabled = true + } + this.toastService.showError( + $localize`Error executing bulk operation: ${JSON.stringify( + error.error + )}` + ) } - }, error => { - if (modal) { - modal.componentInstance.buttonsEnabled = true - } - this.toastService.showError($localize`Error executing bulk operation: ${JSON.stringify(error.error)}`) - } - ) + ) } - private applySelectionData(items: SelectionDataItem[], selectionModel: FilterableDropdownSelectionModel) { + private applySelectionData( + items: SelectionDataItem[], + selectionModel: FilterableDropdownSelectionModel + ) { let selectionData = new Map() - items.forEach(i => { + items.forEach((i) => { if (i.document_count == this.list.selected.size) { selectionData.set(i.id, ToggleableItemState.Selected) } else if (i.document_count > 0) { @@ -89,129 +118,212 @@ export class BulkEditorComponent { } openTagsDropdown() { - this.documentService.getSelectionData(Array.from(this.list.selected)).subscribe(s => { - this.applySelectionData(s.selected_tags, this.tagSelectionModel) - }) + this.documentService + .getSelectionData(Array.from(this.list.selected)) + .subscribe((s) => { + this.applySelectionData(s.selected_tags, this.tagSelectionModel) + }) } openDocumentTypeDropdown() { - this.documentService.getSelectionData(Array.from(this.list.selected)).subscribe(s => { - this.applySelectionData(s.selected_document_types, this.documentTypeSelectionModel) - }) + this.documentService + .getSelectionData(Array.from(this.list.selected)) + .subscribe((s) => { + this.applySelectionData( + s.selected_document_types, + this.documentTypeSelectionModel + ) + }) } openCorrespondentDropdown() { - this.documentService.getSelectionData(Array.from(this.list.selected)).subscribe(s => { - this.applySelectionData(s.selected_correspondents, this.correspondentSelectionModel) - }) + this.documentService + .getSelectionData(Array.from(this.list.selected)) + .subscribe((s) => { + this.applySelectionData( + s.selected_correspondents, + this.correspondentSelectionModel + ) + }) } private _localizeList(items: MatchingModel[]) { if (items.length == 0) { - return "" + return '' } else if (items.length == 1) { return $localize`"${items[0].name}"` } else if (items.length == 2) { return $localize`:This is for messages like 'modify "tag1" and "tag2"':"${items[0].name}" and "${items[1].name}"` } else { - let list = items.slice(0, items.length - 1).map(i => $localize`"${i.name}"`).join($localize`:this is used to separate enumerations and should probably be a comma and a whitespace in most languages:, `) - return $localize`:this is for messages like 'modify "tag1", "tag2" and "tag3"':${list} and "${items[items.length - 1].name}"` + let list = items + .slice(0, items.length - 1) + .map((i) => $localize`"${i.name}"`) + .join( + $localize`:this is used to separate enumerations and should probably be a comma and a whitespace in most languages:, ` + ) + return $localize`:this is for messages like 'modify "tag1", "tag2" and "tag3"':${list} and "${ + items[items.length - 1].name + }"` } } setTags(changedTags: ChangedItems) { - if (changedTags.itemsToAdd.length == 0 && changedTags.itemsToRemove.length == 0) return + if ( + changedTags.itemsToAdd.length == 0 && + changedTags.itemsToRemove.length == 0 + ) + return if (this.showConfirmationDialogs) { - let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) + let modal = this.modalService.open(ConfirmDialogComponent, { + backdrop: 'static', + }) modal.componentInstance.title = $localize`Confirm tags assignment` - if (changedTags.itemsToAdd.length == 1 && changedTags.itemsToRemove.length == 0) { + if ( + changedTags.itemsToAdd.length == 1 && + changedTags.itemsToRemove.length == 0 + ) { let tag = changedTags.itemsToAdd[0] modal.componentInstance.message = $localize`This operation will add the tag "${tag.name}" to ${this.list.selected.size} selected document(s).` - } else if (changedTags.itemsToAdd.length > 1 && changedTags.itemsToRemove.length == 0) { - modal.componentInstance.message = $localize`This operation will add the tags ${this._localizeList(changedTags.itemsToAdd)} to ${this.list.selected.size} selected document(s).` - } else if (changedTags.itemsToAdd.length == 0 && changedTags.itemsToRemove.length == 1) { + } else if ( + changedTags.itemsToAdd.length > 1 && + changedTags.itemsToRemove.length == 0 + ) { + modal.componentInstance.message = $localize`This operation will add the tags ${this._localizeList( + changedTags.itemsToAdd + )} to ${this.list.selected.size} selected document(s).` + } else if ( + changedTags.itemsToAdd.length == 0 && + changedTags.itemsToRemove.length == 1 + ) { let tag = changedTags.itemsToRemove[0] modal.componentInstance.message = $localize`This operation will remove the tag "${tag.name}" from ${this.list.selected.size} selected document(s).` - } else if (changedTags.itemsToAdd.length == 0 && changedTags.itemsToRemove.length > 1) { - modal.componentInstance.message = $localize`This operation will remove the tags ${this._localizeList(changedTags.itemsToRemove)} from ${this.list.selected.size} selected document(s).` + } else if ( + changedTags.itemsToAdd.length == 0 && + changedTags.itemsToRemove.length > 1 + ) { + modal.componentInstance.message = $localize`This operation will remove the tags ${this._localizeList( + changedTags.itemsToRemove + )} from ${this.list.selected.size} selected document(s).` } else { - modal.componentInstance.message = $localize`This operation will add the tags ${this._localizeList(changedTags.itemsToAdd)} and remove the tags ${this._localizeList(changedTags.itemsToRemove)} on ${this.list.selected.size} selected document(s).` + modal.componentInstance.message = $localize`This operation will add the tags ${this._localizeList( + changedTags.itemsToAdd + )} and remove the tags ${this._localizeList( + changedTags.itemsToRemove + )} on ${this.list.selected.size} selected document(s).` } - modal.componentInstance.btnClass = "btn-warning" + modal.componentInstance.btnClass = 'btn-warning' modal.componentInstance.btnCaption = $localize`Confirm` modal.componentInstance.confirmClicked.subscribe(() => { - this.executeBulkOperation(modal, 'modify_tags', {"add_tags": changedTags.itemsToAdd.map(t => t.id), "remove_tags": changedTags.itemsToRemove.map(t => t.id)}) + this.executeBulkOperation(modal, 'modify_tags', { + add_tags: changedTags.itemsToAdd.map((t) => t.id), + remove_tags: changedTags.itemsToRemove.map((t) => t.id), + }) }) } else { - this.executeBulkOperation(null, 'modify_tags', {"add_tags": changedTags.itemsToAdd.map(t => t.id), "remove_tags": changedTags.itemsToRemove.map(t => t.id)}) + this.executeBulkOperation(null, 'modify_tags', { + add_tags: changedTags.itemsToAdd.map((t) => t.id), + remove_tags: changedTags.itemsToRemove.map((t) => t.id), + }) } } setCorrespondents(changedCorrespondents: ChangedItems) { - if (changedCorrespondents.itemsToAdd.length == 0 && changedCorrespondents.itemsToRemove.length == 0) return + if ( + changedCorrespondents.itemsToAdd.length == 0 && + changedCorrespondents.itemsToRemove.length == 0 + ) + return - let correspondent = changedCorrespondents.itemsToAdd.length > 0 ? changedCorrespondents.itemsToAdd[0] : null + let correspondent = + changedCorrespondents.itemsToAdd.length > 0 + ? changedCorrespondents.itemsToAdd[0] + : null if (this.showConfirmationDialogs) { - let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) + let modal = this.modalService.open(ConfirmDialogComponent, { + backdrop: 'static', + }) modal.componentInstance.title = $localize`Confirm correspondent assignment` if (correspondent) { modal.componentInstance.message = $localize`This operation will assign the correspondent "${correspondent.name}" to ${this.list.selected.size} selected document(s).` } else { modal.componentInstance.message = $localize`This operation will remove the correspondent from ${this.list.selected.size} selected document(s).` } - modal.componentInstance.btnClass = "btn-warning" + modal.componentInstance.btnClass = 'btn-warning' modal.componentInstance.btnCaption = $localize`Confirm` modal.componentInstance.confirmClicked.subscribe(() => { - this.executeBulkOperation(modal, 'set_correspondent', {"correspondent": correspondent ? correspondent.id : null}) + this.executeBulkOperation(modal, 'set_correspondent', { + correspondent: correspondent ? correspondent.id : null, + }) }) } else { - this.executeBulkOperation(null, 'set_correspondent', {"correspondent": correspondent ? correspondent.id : null}) + this.executeBulkOperation(null, 'set_correspondent', { + correspondent: correspondent ? correspondent.id : null, + }) } } setDocumentTypes(changedDocumentTypes: ChangedItems) { - if (changedDocumentTypes.itemsToAdd.length == 0 && changedDocumentTypes.itemsToRemove.length == 0) return + if ( + changedDocumentTypes.itemsToAdd.length == 0 && + changedDocumentTypes.itemsToRemove.length == 0 + ) + return - let documentType = changedDocumentTypes.itemsToAdd.length > 0 ? changedDocumentTypes.itemsToAdd[0] : null + let documentType = + changedDocumentTypes.itemsToAdd.length > 0 + ? changedDocumentTypes.itemsToAdd[0] + : null if (this.showConfirmationDialogs) { - let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) + let modal = this.modalService.open(ConfirmDialogComponent, { + backdrop: 'static', + }) modal.componentInstance.title = $localize`Confirm document type assignment` if (documentType) { modal.componentInstance.message = $localize`This operation will assign the document type "${documentType.name}" to ${this.list.selected.size} selected document(s).` } else { modal.componentInstance.message = $localize`This operation will remove the document type from ${this.list.selected.size} selected document(s).` } - modal.componentInstance.btnClass = "btn-warning" + modal.componentInstance.btnClass = 'btn-warning' modal.componentInstance.btnCaption = $localize`Confirm` modal.componentInstance.confirmClicked.subscribe(() => { - this.executeBulkOperation(modal, 'set_document_type', {"document_type": documentType ? documentType.id : null}) + this.executeBulkOperation(modal, 'set_document_type', { + document_type: documentType ? documentType.id : null, + }) }) } else { - this.executeBulkOperation(null, 'set_document_type', {"document_type": documentType ? documentType.id : null}) + this.executeBulkOperation(null, 'set_document_type', { + document_type: documentType ? documentType.id : null, + }) } } applyDelete() { - let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) + let modal = this.modalService.open(ConfirmDialogComponent, { + backdrop: 'static', + }) modal.componentInstance.delayConfirm(5) modal.componentInstance.title = $localize`Delete confirm` modal.componentInstance.messageBold = $localize`This operation will permanently delete ${this.list.selected.size} selected document(s).` modal.componentInstance.message = $localize`This operation cannot be undone.` - modal.componentInstance.btnClass = "btn-danger" + modal.componentInstance.btnClass = 'btn-danger' modal.componentInstance.btnCaption = $localize`Delete document(s)` modal.componentInstance.confirmClicked.subscribe(() => { modal.componentInstance.buttonsEnabled = false - this.executeBulkOperation(modal, "delete", {}) + this.executeBulkOperation(modal, 'delete', {}) }) } - downloadSelected(content = "archive") { - this.documentService.bulkDownload(Array.from(this.list.selected), content).subscribe((result: any) => { - saveAs(result, 'documents.zip'); - }) + downloadSelected(content = 'archive') { + this.awaitingDownload = true + this.documentService + .bulkDownload(Array.from(this.list.selected), content) + .subscribe((result: any) => { + saveAs(result, 'documents.zip') + this.awaitingDownload = false + }) } } diff --git a/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.html b/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.html index 668ad094d..5c8f651ba 100644 --- a/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.html +++ b/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.html @@ -17,7 +17,7 @@
    - {{(document.correspondent$ | async)?.name}} + {{(document.correspondent$ | async)?.name}} {{(document.correspondent$ | async)?.name}}: {{document.title | documentTitle}} @@ -51,7 +51,7 @@  View - + diff --git a/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.scss b/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.scss index e67c0be5d..e3398c245 100644 --- a/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.scss +++ b/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.scss @@ -1,5 +1,3 @@ -@import "/src/theme"; - .result-content { overflow-wrap: anywhere; } @@ -52,7 +50,7 @@ } .card-selected { - border-color: $primary; + border-color: var(--bs-primary); .document-card-check { display: block; @@ -60,7 +58,7 @@ } .doc-img-background-selected { - background-color: $primaryFaded; + background-color: var(--pngx-primary-faded); } .card-info { @@ -90,3 +88,7 @@ span ::ng-deep .match { color: black; background-color: rgb(255, 211, 66); } + +a { + cursor: pointer; +} diff --git a/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.spec.ts b/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.spec.ts deleted file mode 100644 index 72b48f139..000000000 --- a/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { DocumentCardLargeComponent } from './document-card-large.component'; - -describe('DocumentCardLargeComponent', () => { - let component: DocumentCardLargeComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ DocumentCardLargeComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(DocumentCardLargeComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.ts b/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.ts index d8f29ef5a..1c4e9a7aa 100644 --- a/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.ts +++ b/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.ts @@ -1,20 +1,36 @@ -import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; -import { DomSanitizer } from '@angular/platform-browser'; -import { PaperlessDocument } from 'src/app/data/paperless-document'; -import { DocumentService } from 'src/app/services/rest/document.service'; -import { SettingsService, SETTINGS_KEYS } from 'src/app/services/settings.service'; -import { NgbPopover } from '@ng-bootstrap/ng-bootstrap'; -import { DocumentListViewService } from 'src/app/services/document-list-view.service'; -import { FILTER_FULLTEXT_MORELIKE } from 'src/app/data/filter-rule-type'; +import { + Component, + EventEmitter, + Input, + OnInit, + Output, + ViewChild, +} from '@angular/core' +import { DomSanitizer } from '@angular/platform-browser' +import { PaperlessDocument } from 'src/app/data/paperless-document' +import { DocumentService } from 'src/app/services/rest/document.service' +import { + SettingsService, + SETTINGS_KEYS, +} from 'src/app/services/settings.service' +import { NgbPopover } from '@ng-bootstrap/ng-bootstrap' +import { DocumentListViewService } from 'src/app/services/document-list-view.service' +import { FILTER_FULLTEXT_MORELIKE } from 'src/app/data/filter-rule-type' @Component({ selector: 'app-document-card-large', templateUrl: './document-card-large.component.html', - styleUrls: ['./document-card-large.component.scss', '../popover-preview/popover-preview.scss'] + styleUrls: [ + './document-card-large.component.scss', + '../popover-preview/popover-preview.scss', + ], }) export class DocumentCardLargeComponent implements OnInit { - - constructor(private documentService: DocumentService, private sanitizer: DomSanitizer, private settingsService: SettingsService) { } + constructor( + private documentService: DocumentService, + private sanitizer: DomSanitizer, + private settingsService: SettingsService + ) {} @Input() selected = false @@ -39,7 +55,7 @@ export class DocumentCardLargeComponent implements OnInit { clickDocumentType = new EventEmitter() @Output() - clickMoreLike= new EventEmitter() + clickMoreLike = new EventEmitter() @ViewChild('popover') popover: NgbPopover @@ -49,17 +65,16 @@ export class DocumentCardLargeComponent implements OnInit { get searchScoreClass() { if (this.document.__search_hit__) { if (this.document.__search_hit__.score > 0.7) { - return "success" + return 'success' } else if (this.document.__search_hit__.score > 0.3) { - return "warning" + return 'warning' } else { - return "danger" + return 'danger' } } } - ngOnInit(): void { - } + ngOnInit(): void {} getIsThumbInverted() { return this.settingsService.get(SETTINGS_KEYS.DARK_MODE_THUMB_INVERTED) @@ -90,7 +105,7 @@ export class DocumentCardLargeComponent implements OnInit { } else { this.popover.close() } - }, 600); + }, 600) } } diff --git a/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.html b/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.html index 850f7714d..2e8d29b7f 100644 --- a/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.html +++ b/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.html @@ -23,7 +23,7 @@

    - {{(document.correspondent$ | async)?.name}}: + {{(document.correspondent$ | async)?.name}}: {{document.title | documentTitle}}

    @@ -77,7 +77,7 @@ - + diff --git a/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.scss b/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.scss index cdf2cf7c9..4d03d0a4d 100644 --- a/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.scss +++ b/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.scss @@ -1,5 +1,3 @@ -@import "/src/theme"; - .card-text { font-size: 90%; } @@ -37,7 +35,7 @@ } .card-selected { - border-color: $primary; + border-color:var(--bs-primary); .document-card-check { display: block; @@ -45,7 +43,7 @@ } .doc-img-background-selected { - background-color: $primaryFaded; + background-color: var(--pngx-primary-faded); } .card-info { @@ -57,7 +55,7 @@ &:hover, &:focus { background-color: transparent !important; - color: $primary; + color: var(--bs-primary); } } @@ -76,3 +74,7 @@ text-align: left !important; font-size: 90%; } + +a { + cursor: pointer; +} diff --git a/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.spec.ts b/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.spec.ts deleted file mode 100644 index 4ed43b2e2..000000000 --- a/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { DocumentCardSmallComponent } from './document-card-small.component'; - -describe('DocumentCardSmallComponent', () => { - let component: DocumentCardSmallComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ DocumentCardSmallComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(DocumentCardSmallComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.ts b/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.ts index 10c2c5d23..cbff950a2 100644 --- a/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.ts +++ b/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.ts @@ -1,18 +1,33 @@ -import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; -import { map } from 'rxjs/operators'; -import { PaperlessDocument } from 'src/app/data/paperless-document'; -import { DocumentService } from 'src/app/services/rest/document.service'; -import { SettingsService, SETTINGS_KEYS } from 'src/app/services/settings.service'; -import { NgbPopover } from '@ng-bootstrap/ng-bootstrap'; +import { + Component, + EventEmitter, + Input, + OnInit, + Output, + ViewChild, +} from '@angular/core' +import { map } from 'rxjs/operators' +import { PaperlessDocument } from 'src/app/data/paperless-document' +import { DocumentService } from 'src/app/services/rest/document.service' +import { + SettingsService, + SETTINGS_KEYS, +} from 'src/app/services/settings.service' +import { NgbPopover } from '@ng-bootstrap/ng-bootstrap' @Component({ selector: 'app-document-card-small', templateUrl: './document-card-small.component.html', - styleUrls: ['./document-card-small.component.scss', '../popover-preview/popover-preview.scss'] + styleUrls: [ + './document-card-small.component.scss', + '../popover-preview/popover-preview.scss', + ], }) export class DocumentCardSmallComponent implements OnInit { - - constructor(private documentService: DocumentService, private settingsService: SettingsService) { } + constructor( + private documentService: DocumentService, + private settingsService: SettingsService + ) {} @Input() selected = false @@ -39,8 +54,7 @@ export class DocumentCardSmallComponent implements OnInit { mouseOnPreview = false popoverHidden = true - ngOnInit(): void { - } + ngOnInit(): void {} getIsThumbInverted() { return this.settingsService.get(SETTINGS_KEYS.DARK_MODE_THUMB_INVERTED) @@ -60,7 +74,7 @@ export class DocumentCardSmallComponent implements OnInit { getTagsLimited$() { return this.document.tags$.pipe( - map(tags => { + map((tags) => { if (tags.length > 7) { this.moreTags = tags.length - 6 return tags.slice(0, 6) @@ -84,7 +98,7 @@ export class DocumentCardSmallComponent implements OnInit { } else { this.popover.close() } - }, 600); + }, 600) } } diff --git a/src-ui/src/app/components/document-list/document-list.component.html b/src-ui/src/app/components/document-list/document-list.component.html index e7ee95796..1ce61f931 100644 --- a/src-ui/src/app/components/document-list/document-list.component.html +++ b/src-ui/src/app/components/document-list/document-list.component.html @@ -75,28 +75,32 @@ -
    +
    -
    -

    - -

    - Loading... - - {list.collectionSize, plural, =1 {Selected {{list.selected.size}} of one document} other {Selected {{list.selected.size}} of {{list.collectionSize || 0}} documents}} - - {list.collectionSize, plural, =1 {One document} other {{{list.collectionSize || 0}} documents}} (filtered) - -

    - -
    + +
    +

    + +

    + Loading... + + {list.collectionSize, plural, =1 {Selected {{list.selected.size}} of one document} other {Selected {{list.selected.size}} of {{list.collectionSize || 0}} documents}} + + {list.collectionSize, plural, =1 {One document} other {{{list.collectionSize || 0}} documents}} (filtered) + +

    + +
    +
    + + - + @@ -147,10 +151,10 @@ i18n>Added - +
    - +
    @@ -159,7 +163,7 @@ -
    {{(d.correspondent$ | async)?.name}} + {{(d.correspondent$ | async)?.name}} @@ -168,7 +172,7 @@ - {{(d.document_type$ | async)?.name}} + {{(d.document_type$ | async)?.name}} @@ -181,9 +185,12 @@ -
    +
    +
    + +
    diff --git a/src-ui/src/app/components/document-list/document-list.component.scss b/src-ui/src/app/components/document-list/document-list.component.scss index a14158f77..b2d138d7f 100644 --- a/src-ui/src/app/components/document-list/document-list.component.scss +++ b/src-ui/src/app/components/document-list/document-list.component.scss @@ -1,11 +1,13 @@ -@import "/src/theme"; +::ng-deep app-document-list app-page-header > div.mb-3 { + margin-bottom: 0 !important; +} tr { user-select: none; } .table-row-selected { - background-color: $primaryFaded; + background-color: var(--pngx-primary-faded); } $paperless-card-breakpoints: ( @@ -53,3 +55,7 @@ $paperless-card-breakpoints: ( margin-left: 0; } } + +a { + cursor: pointer; +} diff --git a/src-ui/src/app/components/document-list/document-list.component.spec.ts b/src-ui/src/app/components/document-list/document-list.component.spec.ts deleted file mode 100644 index 9230b4631..000000000 --- a/src-ui/src/app/components/document-list/document-list.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { DocumentListComponent } from './document-list.component'; - -describe('DocumentListComponent', () => { - let component: DocumentListComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ DocumentListComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(DocumentListComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/components/document-list/document-list.component.ts b/src-ui/src/app/components/document-list/document-list.component.ts index 390da80c6..9e058fb64 100644 --- a/src-ui/src/app/components/document-list/document-list.component.ts +++ b/src-ui/src/app/components/document-list/document-list.component.ts @@ -1,47 +1,73 @@ -import { Component, OnDestroy, OnInit, QueryList, ViewChild, ViewChildren } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; -import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; -import { Subscription } from 'rxjs'; -import { FilterRule, isFullTextFilterRule } from 'src/app/data/filter-rule'; -import { FILTER_FULLTEXT_MORELIKE } from 'src/app/data/filter-rule-type'; -import { PaperlessDocument } from 'src/app/data/paperless-document'; -import { PaperlessSavedView } from 'src/app/data/paperless-saved-view'; -import { SortableDirective, SortEvent } from 'src/app/directives/sortable.directive'; -import { ConsumerStatusService } from 'src/app/services/consumer-status.service'; -import { DocumentListViewService } from 'src/app/services/document-list-view.service'; -import { DOCUMENT_SORT_FIELDS, DOCUMENT_SORT_FIELDS_FULLTEXT } from 'src/app/services/rest/document.service'; -import { SavedViewService } from 'src/app/services/rest/saved-view.service'; -import { ToastService } from 'src/app/services/toast.service'; -import { FilterEditorComponent } from './filter-editor/filter-editor.component'; -import { SaveViewConfigDialogComponent } from './save-view-config-dialog/save-view-config-dialog.component'; +import { + AfterViewInit, + Component, + OnDestroy, + OnInit, + QueryList, + ViewChild, + ViewChildren, +} from '@angular/core' +import { ActivatedRoute, Router } from '@angular/router' +import { NgbModal } from '@ng-bootstrap/ng-bootstrap' +import { + filter, + first, + map, + Subject, + Subscription, + switchMap, + takeUntil, +} from 'rxjs' +import { FilterRule, isFullTextFilterRule } from 'src/app/data/filter-rule' +import { + FILTER_FULLTEXT_MORELIKE, + FILTER_RULE_TYPES, +} from 'src/app/data/filter-rule-type' +import { PaperlessDocument } from 'src/app/data/paperless-document' +import { PaperlessSavedView } from 'src/app/data/paperless-saved-view' +import { + SortableDirective, + SortEvent, +} from 'src/app/directives/sortable.directive' +import { ConsumerStatusService } from 'src/app/services/consumer-status.service' +import { DocumentListViewService } from 'src/app/services/document-list-view.service' +import { + DocumentService, + DOCUMENT_SORT_FIELDS, + DOCUMENT_SORT_FIELDS_FULLTEXT, +} from 'src/app/services/rest/document.service' +import { SavedViewService } from 'src/app/services/rest/saved-view.service' +import { ToastService } from 'src/app/services/toast.service' +import { FilterEditorComponent } from './filter-editor/filter-editor.component' +import { SaveViewConfigDialogComponent } from './save-view-config-dialog/save-view-config-dialog.component' @Component({ selector: 'app-document-list', templateUrl: './document-list.component.html', - styleUrls: ['./document-list.component.scss'] + styleUrls: ['./document-list.component.scss'], }) -export class DocumentListComponent implements OnInit, OnDestroy { - +export class DocumentListComponent implements OnInit, OnDestroy, AfterViewInit { constructor( public list: DocumentListViewService, + private documentService: DocumentService, public savedViewService: SavedViewService, public route: ActivatedRoute, private router: Router, private toastService: ToastService, private modalService: NgbModal, private consumerStatusService: ConsumerStatusService - ) { } + ) {} - @ViewChild("filterEditor") + @ViewChild('filterEditor') private filterEditor: FilterEditorComponent - @ViewChildren(SortableDirective) headers: QueryList; + @ViewChildren(SortableDirective) headers: QueryList displayMode = 'smallCards' // largeCards, smallCards, details unmodifiedFilterRules: FilterRule[] = [] - private consumptionFinishedSubscription: Subscription + private unsubscribeNotifier: Subject = new Subject() get isFiltered() { return this.list.filterRules?.length > 0 @@ -52,7 +78,9 @@ export class DocumentListComponent implements OnInit, OnDestroy { } getSortFields() { - return isFullTextFilterRule(this.list.filterRules) ? DOCUMENT_SORT_FIELDS_FULLTEXT : DOCUMENT_SORT_FIELDS + return isFullTextFilterRule(this.list.filterRules) + ? DOCUMENT_SORT_FIELDS_FULLTEXT + : DOCUMENT_SORT_FIELDS } onSort(event: SortEvent) { @@ -71,32 +99,97 @@ export class DocumentListComponent implements OnInit, OnDestroy { if (localStorage.getItem('document-list:displayMode') != null) { this.displayMode = localStorage.getItem('document-list:displayMode') } - this.consumptionFinishedSubscription = this.consumerStatusService.onDocumentConsumptionFinished().subscribe(() => { - this.list.reload() - }) - this.route.paramMap.subscribe(params => { - if (params.has('id')) { - this.savedViewService.getCached(+params.get('id')).subscribe(view => { - if (!view) { - this.router.navigate(["404"]) - return - } - this.list.activateSavedView(view) - this.list.reload() - this.unmodifiedFilterRules = view.filter_rules + + this.consumerStatusService + .onDocumentConsumptionFinished() + .pipe(takeUntil(this.unsubscribeNotifier)) + .subscribe(() => { + this.list.reload() + }) + + this.route.paramMap + .pipe( + filter((params) => params.has('id')), // only on saved view + switchMap((params) => { + return this.savedViewService + .getCached(+params.get('id')) + .pipe(map((view) => ({ params, view }))) }) - } else { + ) + .pipe(takeUntil(this.unsubscribeNotifier)) + .subscribe(({ view, params }) => { + if (!view) { + this.router.navigate(['404']) + return + } + this.list.activateSavedView(view) + this.list.reload() + this.unmodifiedFilterRules = view.filter_rules + }) + + const allFilterRuleQueryParams: string[] = FILTER_RULE_TYPES.map( + (rt) => rt.filtervar + ) + + this.route.queryParamMap + .pipe( + filter(() => !this.route.snapshot.paramMap.has('id')), // only when not on saved view + takeUntil(this.unsubscribeNotifier) + ) + .subscribe((queryParams) => { + // transform query params to filter rules + let filterRulesFromQueryParams: FilterRule[] = [] + allFilterRuleQueryParams + .filter((frqp) => queryParams.has(frqp)) + .forEach((filterQueryParamName) => { + const filterQueryParamValues: string[] = queryParams + .get(filterQueryParamName) + .split(',') + + filterRulesFromQueryParams = filterRulesFromQueryParams.concat( + // map all values to filter rules + filterQueryParamValues.map((val) => { + return { + rule_type: FILTER_RULE_TYPES.find( + (rt) => rt.filtervar == filterQueryParamName + ).id, + value: val, + } + }) + ) + }) + this.list.activateSavedView(null) + this.list.filterRules = filterRulesFromQueryParams this.list.reload() this.unmodifiedFilterRules = [] - } - }) + }) + } + + ngAfterViewInit(): void { + this.filterEditor.filterRulesChange + .pipe(takeUntil(this.unsubscribeNotifier)) + .subscribe({ + next: (filterRules) => { + const params = + this.documentService.filterRulesToQueryParams(filterRules) + + // if we were on a saved view we navigate 'away' to /documents + let base = [] + if (this.route.snapshot.paramMap.has('id')) base = ['/documents'] + + this.router.navigate(base, { + relativeTo: this.route, + queryParams: params, + }) + }, + }) } ngOnDestroy() { - if (this.consumptionFinishedSubscription) { - this.consumptionFinishedSubscription.unsubscribe() - } + // unsubscribes all + this.unsubscribeNotifier.next(this) + this.unsubscribeNotifier.complete() } loadViewConfig(view: PaperlessSavedView) { @@ -110,19 +203,26 @@ export class DocumentListComponent implements OnInit, OnDestroy { id: this.list.activeSavedViewId, filter_rules: this.list.filterRules, sort_field: this.list.sortField, - sort_reverse: this.list.sortReverse + sort_reverse: this.list.sortReverse, } - this.savedViewService.patch(savedView).subscribe(result => { - this.toastService.showInfo($localize`View "${this.list.activeSavedViewTitle}" saved successfully.`) - this.unmodifiedFilterRules = this.list.filterRules - }) + this.savedViewService + .patch(savedView) + .pipe(first()) + .subscribe((result) => { + this.toastService.showInfo( + $localize`View "${this.list.activeSavedViewTitle}" saved successfully.` + ) + this.unmodifiedFilterRules = this.list.filterRules + }) } } saveViewConfigAs() { - let modal = this.modalService.open(SaveViewConfigDialogComponent, {backdrop: 'static'}) + let modal = this.modalService.open(SaveViewConfigDialogComponent, { + backdrop: 'static', + }) modal.componentInstance.defaultName = this.filterEditor.generateFilterName() - modal.componentInstance.saveClicked.subscribe(formValue => { + modal.componentInstance.saveClicked.pipe(first()).subscribe((formValue) => { modal.componentInstance.buttonsEnabled = false let savedView: PaperlessSavedView = { name: formValue.name, @@ -130,16 +230,28 @@ export class DocumentListComponent implements OnInit, OnDestroy { show_in_sidebar: formValue.showInSideBar, filter_rules: this.list.filterRules, sort_reverse: this.list.sortReverse, - sort_field: this.list.sortField + sort_field: this.list.sortField, } - this.savedViewService.create(savedView).subscribe(() => { - modal.close() - this.toastService.showInfo($localize`View "${savedView.name}" created successfully.`) - }, error => { - modal.componentInstance.error = error.error - modal.componentInstance.buttonsEnabled = true - }) + this.savedViewService + .create(savedView) + .pipe(first()) + .subscribe({ + next: () => { + modal.close() + this.toastService.showInfo( + $localize`View "${savedView.name}" created successfully.` + ) + }, + error: (httpError) => { + let error = httpError.error + if (error.filter_rules) { + error.filter_rules = error.filter_rules.map((r) => r.value) + } + modal.componentInstance.error = error + modal.componentInstance.buttonsEnabled = true + }, + }) }) } @@ -170,7 +282,9 @@ export class DocumentListComponent implements OnInit, OnDestroy { } clickMoreLike(documentID: number) { - this.list.quickFilter([{rule_type: FILTER_FULLTEXT_MORELIKE, value: documentID.toString()}]) + this.list.quickFilter([ + { rule_type: FILTER_FULLTEXT_MORELIKE, value: documentID.toString() }, + ]) } trackByDocumentId(index, item: PaperlessDocument) { diff --git a/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.html b/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.html index 892947ae4..6280cff10 100644 --- a/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.html +++ b/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.html @@ -8,7 +8,7 @@
    - +
    @@ -50,7 +50,7 @@
    -
    +
    +
    +
    + Theme Color +
    +
    + +
    +
    + +
    +
    +

    Bulk editing

    diff --git a/src-ui/src/app/components/manage/settings/settings.component.spec.ts b/src-ui/src/app/components/manage/settings/settings.component.spec.ts deleted file mode 100644 index a3a508b0e..000000000 --- a/src-ui/src/app/components/manage/settings/settings.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { SettingsComponent } from './settings.component'; - -describe('SettingsComponent', () => { - let component: SettingsComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ SettingsComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(SettingsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/components/manage/settings/settings.component.ts b/src-ui/src/app/components/manage/settings/settings.component.ts index 2ca146dc4..45785c709 100644 --- a/src-ui/src/app/components/manage/settings/settings.component.ts +++ b/src-ui/src/app/components/manage/settings/settings.component.ts @@ -1,38 +1,49 @@ -import { Component, Inject, LOCALE_ID, OnInit, OnDestroy, Renderer2 } from '@angular/core'; -import { FormControl, FormGroup } from '@angular/forms'; -import { PaperlessSavedView } from 'src/app/data/paperless-saved-view'; -import { DocumentListViewService } from 'src/app/services/document-list-view.service'; -import { SavedViewService } from 'src/app/services/rest/saved-view.service'; -import { LanguageOption, SettingsService, SETTINGS_KEYS } from 'src/app/services/settings.service'; -import { ToastService } from 'src/app/services/toast.service'; -import { dirtyCheck, DirtyComponent } from '@ngneat/dirty-check-forms'; -import { Observable, Subscription, BehaviorSubject } from 'rxjs'; +import { + Component, + Inject, + LOCALE_ID, + OnInit, + OnDestroy, + Renderer2, +} from '@angular/core' +import { FormControl, FormGroup } from '@angular/forms' +import { PaperlessSavedView } from 'src/app/data/paperless-saved-view' +import { DocumentListViewService } from 'src/app/services/document-list-view.service' +import { SavedViewService } from 'src/app/services/rest/saved-view.service' +import { + LanguageOption, + SettingsService, + SETTINGS_KEYS, +} from 'src/app/services/settings.service' +import { ToastService } from 'src/app/services/toast.service' +import { dirtyCheck, DirtyComponent } from '@ngneat/dirty-check-forms' +import { Observable, Subscription, BehaviorSubject } from 'rxjs' @Component({ selector: 'app-settings', templateUrl: './settings.component.html', - styleUrls: ['./settings.component.scss'] + styleUrls: ['./settings.component.scss'], }) export class SettingsComponent implements OnInit, OnDestroy, DirtyComponent { - savedViewGroup = new FormGroup({}) settingsForm = new FormGroup({ - 'bulkEditConfirmationDialogs': new FormControl(null), - 'bulkEditApplyOnClose': new FormControl(null), - 'documentListItemPerPage': new FormControl(null), - 'darkModeUseSystem': new FormControl(null), - 'darkModeEnabled': new FormControl(null), - 'darkModeInvertThumbs': new FormControl(null), - 'useNativePdfViewer': new FormControl(null), - 'savedViews': this.savedViewGroup, - 'displayLanguage': new FormControl(null), - 'dateLocale': new FormControl(null), - 'dateFormat': new FormControl(null), - 'notificationsConsumerNewDocument': new FormControl(null), - 'notificationsConsumerSuccess': new FormControl(null), - 'notificationsConsumerFailed': new FormControl(null), - 'notificationsConsumerSuppressOnDashboard': new FormControl(null), + bulkEditConfirmationDialogs: new FormControl(null), + bulkEditApplyOnClose: new FormControl(null), + documentListItemPerPage: new FormControl(null), + darkModeUseSystem: new FormControl(null), + darkModeEnabled: new FormControl(null), + darkModeInvertThumbs: new FormControl(null), + themeColor: new FormControl(null), + useNativePdfViewer: new FormControl(null), + savedViews: this.savedViewGroup, + displayLanguage: new FormControl(null), + dateLocale: new FormControl(null), + dateFormat: new FormControl(null), + notificationsConsumerNewDocument: new FormControl(null), + notificationsConsumerSuccess: new FormControl(null), + notificationsConsumerFailed: new FormControl(null), + notificationsConsumerSuppressOnDashboard: new FormControl(null), }) savedViews: PaperlessSavedView[] @@ -40,9 +51,14 @@ export class SettingsComponent implements OnInit, OnDestroy, DirtyComponent { store: BehaviorSubject storeSub: Subscription isDirty$: Observable + isDirty: Boolean = false get computedDateLocale(): string { - return this.settingsForm.value.dateLocale || this.settingsForm.value.displayLanguage || this.currentLocale + return ( + this.settingsForm.value.dateLocale || + this.settingsForm.value.displayLanguage || + this.currentLocale + ) } constructor( @@ -51,97 +67,181 @@ export class SettingsComponent implements OnInit, OnDestroy, DirtyComponent { private toastService: ToastService, private settings: SettingsService, @Inject(LOCALE_ID) public currentLocale: string - ) { } + ) {} ngOnInit() { - this.savedViewService.listAll().subscribe(r => { + this.savedViewService.listAll().subscribe((r) => { this.savedViews = r.results let storeData = { - 'bulkEditConfirmationDialogs': this.settings.get(SETTINGS_KEYS.BULK_EDIT_CONFIRMATION_DIALOGS), - 'bulkEditApplyOnClose': this.settings.get(SETTINGS_KEYS.BULK_EDIT_APPLY_ON_CLOSE), - 'documentListItemPerPage': this.settings.get(SETTINGS_KEYS.DOCUMENT_LIST_SIZE), - 'darkModeUseSystem': this.settings.get(SETTINGS_KEYS.DARK_MODE_USE_SYSTEM), - 'darkModeEnabled': this.settings.get(SETTINGS_KEYS.DARK_MODE_ENABLED), - 'darkModeInvertThumbs': this.settings.get(SETTINGS_KEYS.DARK_MODE_THUMB_INVERTED), - 'useNativePdfViewer': this.settings.get(SETTINGS_KEYS.USE_NATIVE_PDF_VIEWER), - 'savedViews': {}, - 'displayLanguage': this.settings.getLanguage(), - 'dateLocale': this.settings.get(SETTINGS_KEYS.DATE_LOCALE), - 'dateFormat': this.settings.get(SETTINGS_KEYS.DATE_FORMAT), - 'notificationsConsumerNewDocument': this.settings.get(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_NEW_DOCUMENT), - 'notificationsConsumerSuccess': this.settings.get(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUCCESS), - 'notificationsConsumerFailed': this.settings.get(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_FAILED), - 'notificationsConsumerSuppressOnDashboard': this.settings.get(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD), + bulkEditConfirmationDialogs: this.settings.get( + SETTINGS_KEYS.BULK_EDIT_CONFIRMATION_DIALOGS + ), + bulkEditApplyOnClose: this.settings.get( + SETTINGS_KEYS.BULK_EDIT_APPLY_ON_CLOSE + ), + documentListItemPerPage: this.settings.get( + SETTINGS_KEYS.DOCUMENT_LIST_SIZE + ), + darkModeUseSystem: this.settings.get( + SETTINGS_KEYS.DARK_MODE_USE_SYSTEM + ), + darkModeEnabled: this.settings.get(SETTINGS_KEYS.DARK_MODE_ENABLED), + darkModeInvertThumbs: this.settings.get( + SETTINGS_KEYS.DARK_MODE_THUMB_INVERTED + ), + themeColor: this.settings.get(SETTINGS_KEYS.THEME_COLOR), + useNativePdfViewer: this.settings.get( + SETTINGS_KEYS.USE_NATIVE_PDF_VIEWER + ), + savedViews: {}, + displayLanguage: this.settings.getLanguage(), + dateLocale: this.settings.get(SETTINGS_KEYS.DATE_LOCALE), + dateFormat: this.settings.get(SETTINGS_KEYS.DATE_FORMAT), + notificationsConsumerNewDocument: this.settings.get( + SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_NEW_DOCUMENT + ), + notificationsConsumerSuccess: this.settings.get( + SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUCCESS + ), + notificationsConsumerFailed: this.settings.get( + SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_FAILED + ), + notificationsConsumerSuppressOnDashboard: this.settings.get( + SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD + ), } for (let view of this.savedViews) { storeData.savedViews[view.id.toString()] = { - "id": view.id, - "name": view.name, - "show_on_dashboard": view.show_on_dashboard, - "show_in_sidebar": view.show_in_sidebar + id: view.id, + name: view.name, + show_on_dashboard: view.show_on_dashboard, + show_in_sidebar: view.show_in_sidebar, } - this.savedViewGroup.addControl(view.id.toString(), new FormGroup({ - "id": new FormControl(null), - "name": new FormControl(null), - "show_on_dashboard": new FormControl(null), - "show_in_sidebar": new FormControl(null) - })) + this.savedViewGroup.addControl( + view.id.toString(), + new FormGroup({ + id: new FormControl(null), + name: new FormControl(null), + show_on_dashboard: new FormControl(null), + show_in_sidebar: new FormControl(null), + }) + ) } this.store = new BehaviorSubject(storeData) - this.storeSub = this.store.asObservable().subscribe(state => { + this.storeSub = this.store.asObservable().subscribe((state) => { this.settingsForm.patchValue(state, { emitEvent: false }) }) // Initialize dirtyCheck this.isDirty$ = dirtyCheck(this.settingsForm, this.store.asObservable()) + + // Record dirty in case we need to 'undo' appearance settings if not saved on close + this.isDirty$.subscribe((dirty) => { + this.isDirty = dirty + }) + + // "Live" visual changes prior to save + this.settingsForm.valueChanges.subscribe(() => { + this.settings.updateAppearanceSettings( + this.settingsForm.get('darkModeUseSystem').value, + this.settingsForm.get('darkModeEnabled').value, + this.settingsForm.get('themeColor').value + ) + }) }) } ngOnDestroy() { - this.storeSub && this.storeSub.unsubscribe(); + if (this.isDirty) this.settings.updateAppearanceSettings() // in case user changed appearance but didnt save + this.storeSub && this.storeSub.unsubscribe() } deleteSavedView(savedView: PaperlessSavedView) { this.savedViewService.delete(savedView).subscribe(() => { this.savedViewGroup.removeControl(savedView.id.toString()) this.savedViews.splice(this.savedViews.indexOf(savedView), 1) - this.toastService.showInfo($localize`Saved view "${savedView.name}" deleted.`) + this.toastService.showInfo( + $localize`Saved view "${savedView.name}" deleted.` + ) }) } private saveLocalSettings() { - this.settings.set(SETTINGS_KEYS.BULK_EDIT_APPLY_ON_CLOSE, this.settingsForm.value.bulkEditApplyOnClose) - this.settings.set(SETTINGS_KEYS.BULK_EDIT_CONFIRMATION_DIALOGS, this.settingsForm.value.bulkEditConfirmationDialogs) - this.settings.set(SETTINGS_KEYS.DOCUMENT_LIST_SIZE, this.settingsForm.value.documentListItemPerPage) - this.settings.set(SETTINGS_KEYS.DARK_MODE_USE_SYSTEM, this.settingsForm.value.darkModeUseSystem) - this.settings.set(SETTINGS_KEYS.DARK_MODE_ENABLED, (this.settingsForm.value.darkModeEnabled == true).toString()) - this.settings.set(SETTINGS_KEYS.DARK_MODE_THUMB_INVERTED, (this.settingsForm.value.darkModeInvertThumbs == true).toString()) - this.settings.set(SETTINGS_KEYS.USE_NATIVE_PDF_VIEWER, this.settingsForm.value.useNativePdfViewer) - this.settings.set(SETTINGS_KEYS.DATE_LOCALE, this.settingsForm.value.dateLocale) - this.settings.set(SETTINGS_KEYS.DATE_FORMAT, this.settingsForm.value.dateFormat) - this.settings.set(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_NEW_DOCUMENT, this.settingsForm.value.notificationsConsumerNewDocument) - this.settings.set(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUCCESS, this.settingsForm.value.notificationsConsumerSuccess) - this.settings.set(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_FAILED, this.settingsForm.value.notificationsConsumerFailed) - this.settings.set(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD, this.settingsForm.value.notificationsConsumerSuppressOnDashboard) + this.settings.set( + SETTINGS_KEYS.BULK_EDIT_APPLY_ON_CLOSE, + this.settingsForm.value.bulkEditApplyOnClose + ) + this.settings.set( + SETTINGS_KEYS.BULK_EDIT_CONFIRMATION_DIALOGS, + this.settingsForm.value.bulkEditConfirmationDialogs + ) + this.settings.set( + SETTINGS_KEYS.DOCUMENT_LIST_SIZE, + this.settingsForm.value.documentListItemPerPage + ) + this.settings.set( + SETTINGS_KEYS.DARK_MODE_USE_SYSTEM, + this.settingsForm.value.darkModeUseSystem + ) + this.settings.set( + SETTINGS_KEYS.DARK_MODE_ENABLED, + (this.settingsForm.value.darkModeEnabled == true).toString() + ) + this.settings.set( + SETTINGS_KEYS.DARK_MODE_THUMB_INVERTED, + (this.settingsForm.value.darkModeInvertThumbs == true).toString() + ) + this.settings.set( + SETTINGS_KEYS.THEME_COLOR, + this.settingsForm.value.themeColor.toString() + ) + this.settings.set( + SETTINGS_KEYS.USE_NATIVE_PDF_VIEWER, + this.settingsForm.value.useNativePdfViewer + ) + this.settings.set( + SETTINGS_KEYS.DATE_LOCALE, + this.settingsForm.value.dateLocale + ) + this.settings.set( + SETTINGS_KEYS.DATE_FORMAT, + this.settingsForm.value.dateFormat + ) + this.settings.set( + SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_NEW_DOCUMENT, + this.settingsForm.value.notificationsConsumerNewDocument + ) + this.settings.set( + SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUCCESS, + this.settingsForm.value.notificationsConsumerSuccess + ) + this.settings.set( + SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_FAILED, + this.settingsForm.value.notificationsConsumerFailed + ) + this.settings.set( + SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD, + this.settingsForm.value.notificationsConsumerSuppressOnDashboard + ) this.settings.setLanguage(this.settingsForm.value.displayLanguage) this.store.next(this.settingsForm.value) this.documentListViewService.updatePageSize() - this.settings.updateDarkModeSettings() + this.settings.updateAppearanceSettings() this.toastService.showInfo($localize`Settings saved successfully.`) } get displayLanguageOptions(): LanguageOption[] { - return [ - {code: "", name: $localize`Use system language`} - ].concat(this.settings.getLanguageOptions()) + return [{ code: '', name: $localize`Use system language` }].concat( + this.settings.getLanguageOptions() + ) } get dateLocaleOptions(): LanguageOption[] { return [ - {code: "", name: $localize`Use date format of display language`} + { code: '', name: $localize`Use date format of display language` }, ].concat(this.settings.getDateLocaleOptions()) } @@ -155,14 +255,24 @@ export class SettingsComponent implements OnInit, OnDestroy, DirtyComponent { x.push(this.savedViewGroup.value[id]) } if (x.length > 0) { - this.savedViewService.patchMany(x).subscribe(s => { - this.saveLocalSettings() - }, error => { - this.toastService.showError($localize`Error while storing settings on server: ${JSON.stringify(error.error)}`) - }) + this.savedViewService.patchMany(x).subscribe( + (s) => { + this.saveLocalSettings() + }, + (error) => { + this.toastService.showError( + $localize`Error while storing settings on server: ${JSON.stringify( + error.error + )}` + ) + } + ) } else { this.saveLocalSettings() } + } + clearThemeColor() { + this.settingsForm.get('themeColor').patchValue('') } } diff --git a/src-ui/src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.spec.ts b/src-ui/src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.spec.ts deleted file mode 100644 index 378cefdab..000000000 --- a/src-ui/src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { TagEditDialogComponent } from './tag-edit-dialog.component'; - -describe('TagEditDialogComponent', () => { - let component: TagEditDialogComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ TagEditDialogComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(TagEditDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.ts b/src-ui/src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.ts deleted file mode 100644 index 623b033ec..000000000 --- a/src-ui/src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Component } from '@angular/core'; -import { FormControl, FormGroup } from '@angular/forms'; -import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; -import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component'; -import { PaperlessTag } from 'src/app/data/paperless-tag'; -import { TagService } from 'src/app/services/rest/tag.service'; -import { ToastService } from 'src/app/services/toast.service'; -import { randomColor } from 'src/app/utils/color'; - -@Component({ - selector: 'app-tag-edit-dialog', - templateUrl: './tag-edit-dialog.component.html', - styleUrls: ['./tag-edit-dialog.component.scss'] -}) -export class TagEditDialogComponent extends EditDialogComponent { - - constructor(service: TagService, activeModal: NgbActiveModal, toastService: ToastService) { - super(service, activeModal, toastService) - } - - getCreateTitle() { - return $localize`Create new tag` - } - - getEditTitle() { - return $localize`Edit tag` - } - - getForm(): FormGroup { - return new FormGroup({ - name: new FormControl(''), - color: new FormControl(randomColor()), - is_inbox_tag: new FormControl(false), - matching_algorithm: new FormControl(1), - match: new FormControl(""), - is_insensitive: new FormControl(true) - }) - } - -} diff --git a/src-ui/src/app/components/manage/tag-list/tag-list.component.html b/src-ui/src/app/components/manage/tag-list/tag-list.component.html deleted file mode 100644 index 3ca89a37f..000000000 --- a/src-ui/src/app/components/manage/tag-list/tag-list.component.html +++ /dev/null @@ -1,55 +0,0 @@ - - - - -
    -
    -
    - - -
    -
    - - -
    - - - - - - - - - - - - - - - - - - - - -
    NameColorMatchingDocument countActions
    {{ tag.name }}{{tag.color}}{{ getMatching(tag) }}{{ tag.document_count }} -
    - - - -
    -
    diff --git a/src-ui/src/app/components/manage/tag-list/tag-list.component.scss b/src-ui/src/app/components/manage/tag-list/tag-list.component.scss deleted file mode 100644 index e69de29bb..000000000 diff --git a/src-ui/src/app/components/manage/tag-list/tag-list.component.spec.ts b/src-ui/src/app/components/manage/tag-list/tag-list.component.spec.ts deleted file mode 100644 index 0623f541a..000000000 --- a/src-ui/src/app/components/manage/tag-list/tag-list.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { TagListComponent } from './tag-list.component'; - -describe('TagListComponent', () => { - let component: TagListComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ TagListComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(TagListComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/components/manage/tag-list/tag-list.component.ts b/src-ui/src/app/components/manage/tag-list/tag-list.component.ts index 6d93d7dd4..01a1614bf 100644 --- a/src-ui/src/app/components/manage/tag-list/tag-list.component.ts +++ b/src-ui/src/app/components/manage/tag-list/tag-list.component.ts @@ -1,33 +1,47 @@ -import { Component } from '@angular/core'; -import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; -import { FILTER_HAS_TAGS_ALL } from 'src/app/data/filter-rule-type'; -import { PaperlessTag } from 'src/app/data/paperless-tag'; -import { DocumentListViewService } from 'src/app/services/document-list-view.service'; -import { TagService } from 'src/app/services/rest/tag.service'; -import { ToastService } from 'src/app/services/toast.service'; -import { GenericListComponent } from '../generic-list/generic-list.component'; -import { TagEditDialogComponent } from './tag-edit-dialog/tag-edit-dialog.component'; +import { Component } from '@angular/core' +import { NgbModal } from '@ng-bootstrap/ng-bootstrap' +import { FILTER_HAS_TAGS_ALL } from 'src/app/data/filter-rule-type' +import { PaperlessTag } from 'src/app/data/paperless-tag' +import { DocumentListViewService } from 'src/app/services/document-list-view.service' +import { TagService } from 'src/app/services/rest/tag.service' +import { ToastService } from 'src/app/services/toast.service' +import { TagEditDialogComponent } from '../../common/edit-dialog/tag-edit-dialog/tag-edit-dialog.component' +import { ManagementListComponent } from '../management-list/management-list.component' @Component({ selector: 'app-tag-list', - templateUrl: './tag-list.component.html', - styleUrls: ['./tag-list.component.scss'] + templateUrl: './../management-list/management-list.component.html', + styleUrls: ['./../management-list/management-list.component.scss'], }) -export class TagListComponent extends GenericListComponent { - - constructor(tagService: TagService, modalService: NgbModal, - private list: DocumentListViewService, - toastService: ToastService +export class TagListComponent extends ManagementListComponent { + constructor( + tagService: TagService, + modalService: NgbModal, + toastService: ToastService, + list: DocumentListViewService ) { - super(tagService, modalService, TagEditDialogComponent, toastService) + super( + tagService, + modalService, + TagEditDialogComponent, + toastService, + list, + FILTER_HAS_TAGS_ALL, + $localize`tag`, + [ + { + key: 'color', + name: $localize`Color`, + rendersHtml: true, + valueFn: (t: PaperlessTag) => { + return `${t.color}` + }, + }, + ] + ) } getDeleteMessage(object: PaperlessTag) { return $localize`Do you really want to delete the tag "${object.name}"?` } - - filterDocuments(object: PaperlessTag) { - this.list.quickFilter([{rule_type: FILTER_HAS_TAGS_ALL, value: object.id.toString()}]) - - } } diff --git a/src-ui/src/app/components/not-found/not-found.component.spec.ts b/src-ui/src/app/components/not-found/not-found.component.spec.ts deleted file mode 100644 index 9d41c99a6..000000000 --- a/src-ui/src/app/components/not-found/not-found.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { NotFoundComponent } from './not-found.component'; - -describe('NotFoundComponent', () => { - let component: NotFoundComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ NotFoundComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(NotFoundComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/components/not-found/not-found.component.ts b/src-ui/src/app/components/not-found/not-found.component.ts index 7cb4124f1..7051da161 100644 --- a/src-ui/src/app/components/not-found/not-found.component.ts +++ b/src-ui/src/app/components/not-found/not-found.component.ts @@ -1,15 +1,12 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit } from '@angular/core' @Component({ selector: 'app-not-found', templateUrl: './not-found.component.html', - styleUrls: ['./not-found.component.scss'] + styleUrls: ['./not-found.component.scss'], }) export class NotFoundComponent implements OnInit { + constructor() {} - constructor() { } - - ngOnInit(): void { - } - + ngOnInit(): void {} } diff --git a/src-ui/src/app/data/filter-rule-type.ts b/src-ui/src/app/data/filter-rule-type.ts index c72997618..337fee545 100644 --- a/src-ui/src/app/data/filter-rule-type.ts +++ b/src-ui/src/app/data/filter-rule-type.ts @@ -27,40 +27,160 @@ export const FILTER_FULLTEXT_QUERY = 20 export const FILTER_FULLTEXT_MORELIKE = 21 export const FILTER_RULE_TYPES: FilterRuleType[] = [ + { + id: FILTER_TITLE, + filtervar: 'title__icontains', + datatype: 'string', + multi: false, + default: '', + }, + { + id: FILTER_CONTENT, + filtervar: 'content__icontains', + datatype: 'string', + multi: false, + default: '', + }, - {id: FILTER_TITLE, filtervar: "title__icontains", datatype: "string", multi: false, default: ""}, - {id: FILTER_CONTENT, filtervar: "content__icontains", datatype: "string", multi: false, default: ""}, + { + id: FILTER_ASN, + filtervar: 'archive_serial_number', + datatype: 'number', + multi: false, + }, - {id: FILTER_ASN, filtervar: "archive_serial_number", datatype: "number", multi: false}, + { + id: FILTER_CORRESPONDENT, + filtervar: 'correspondent__id', + isnull_filtervar: 'correspondent__isnull', + datatype: 'correspondent', + multi: false, + }, + { + id: FILTER_DOCUMENT_TYPE, + filtervar: 'document_type__id', + isnull_filtervar: 'document_type__isnull', + datatype: 'document_type', + multi: false, + }, - {id: FILTER_CORRESPONDENT, filtervar: "correspondent__id", isnull_filtervar: "correspondent__isnull", datatype: "correspondent", multi: false}, - {id: FILTER_DOCUMENT_TYPE, filtervar: "document_type__id", isnull_filtervar: "document_type__isnull", datatype: "document_type", multi: false}, + { + id: FILTER_IS_IN_INBOX, + filtervar: 'is_in_inbox', + datatype: 'boolean', + multi: false, + default: true, + }, + { + id: FILTER_HAS_TAGS_ALL, + filtervar: 'tags__id__all', + datatype: 'tag', + multi: true, + }, + { + id: FILTER_HAS_TAGS_ANY, + filtervar: 'tags__id__in', + datatype: 'tag', + multi: true, + }, + { + id: FILTER_DOES_NOT_HAVE_TAG, + filtervar: 'tags__id__none', + datatype: 'tag', + multi: true, + }, + { + id: FILTER_HAS_ANY_TAG, + filtervar: 'is_tagged', + datatype: 'boolean', + multi: false, + default: true, + }, - {id: FILTER_IS_IN_INBOX, filtervar: "is_in_inbox", datatype: "boolean", multi: false, default: true}, - {id: FILTER_HAS_TAGS_ALL, filtervar: "tags__id__all", datatype: "tag", multi: true}, - {id: FILTER_HAS_TAGS_ANY, filtervar: "tags__id__in", datatype: "tag", multi: true}, - {id: FILTER_DOES_NOT_HAVE_TAG, filtervar: "tags__id__none", datatype: "tag", multi: true}, - {id: FILTER_HAS_ANY_TAG, filtervar: "is_tagged", datatype: "boolean", multi: false, default: true}, + { + id: FILTER_CREATED_BEFORE, + filtervar: 'created__date__lt', + datatype: 'date', + multi: false, + }, + { + id: FILTER_CREATED_AFTER, + filtervar: 'created__date__gt', + datatype: 'date', + multi: false, + }, - {id: FILTER_CREATED_BEFORE, filtervar: "created__date__lt", datatype: "date", multi: false}, - {id: FILTER_CREATED_AFTER, filtervar: "created__date__gt", datatype: "date", multi: false}, + { + id: FILTER_CREATED_YEAR, + filtervar: 'created__year', + datatype: 'number', + multi: false, + }, + { + id: FILTER_CREATED_MONTH, + filtervar: 'created__month', + datatype: 'number', + multi: false, + }, + { + id: FILTER_CREATED_DAY, + filtervar: 'created__day', + datatype: 'number', + multi: false, + }, - {id: FILTER_CREATED_YEAR, filtervar: "created__year", datatype: "number", multi: false}, - {id: FILTER_CREATED_MONTH, filtervar: "created__month", datatype: "number", multi: false}, - {id: FILTER_CREATED_DAY, filtervar: "created__day", datatype: "number", multi: false}, + { + id: FILTER_ADDED_BEFORE, + filtervar: 'added__date__lt', + datatype: 'date', + multi: false, + }, + { + id: FILTER_ADDED_AFTER, + filtervar: 'added__date__gt', + datatype: 'date', + multi: false, + }, - {id: FILTER_ADDED_BEFORE, filtervar: "added__date__lt", datatype: "date", multi: false}, - {id: FILTER_ADDED_AFTER, filtervar: "added__date__gt", datatype: "date", multi: false}, + { + id: FILTER_MODIFIED_BEFORE, + filtervar: 'modified__date__lt', + datatype: 'date', + multi: false, + }, + { + id: FILTER_MODIFIED_AFTER, + filtervar: 'modified__date__gt', + datatype: 'date', + multi: false, + }, + { + id: FILTER_ASN_ISNULL, + filtervar: 'archive_serial_number__isnull', + datatype: 'boolean', + multi: false, + }, - {id: FILTER_MODIFIED_BEFORE, filtervar: "modified__date__lt", datatype: "date", multi: false}, - {id: FILTER_MODIFIED_AFTER, filtervar: "modified__date__gt", datatype: "date", multi: false}, - {id: FILTER_ASN_ISNULL, filtervar: "archive_serial_number__isnull", datatype: "boolean", multi: false}, + { + id: FILTER_TITLE_CONTENT, + filtervar: 'title_content', + datatype: 'string', + multi: false, + }, - {id: FILTER_TITLE_CONTENT, filtervar: "title_content", datatype: "string", multi: false}, + { + id: FILTER_FULLTEXT_QUERY, + filtervar: 'query', + datatype: 'string', + multi: false, + }, - {id: FILTER_FULLTEXT_QUERY, filtervar: "query", datatype: "string", multi: false}, - - {id: FILTER_FULLTEXT_MORELIKE, filtervar: "more_like_id", datatype: "number", multi: false}, + { + id: FILTER_FULLTEXT_MORELIKE, + filtervar: 'more_like_id', + datatype: 'number', + multi: false, + }, ] export interface FilterRuleType { diff --git a/src-ui/src/app/data/filter-rule.ts b/src-ui/src/app/data/filter-rule.ts index c8b790e21..75819ad52 100644 --- a/src-ui/src/app/data/filter-rule.ts +++ b/src-ui/src/app/data/filter-rule.ts @@ -1,10 +1,13 @@ -import { FILTER_FULLTEXT_MORELIKE, FILTER_FULLTEXT_QUERY } from "./filter-rule-type" +import { + FILTER_FULLTEXT_MORELIKE, + FILTER_FULLTEXT_QUERY, +} from './filter-rule-type' export function cloneFilterRules(filterRules: FilterRule[]): FilterRule[] { if (filterRules) { let newRules: FilterRule[] = [] for (let rule of filterRules) { - newRules.push({rule_type: rule.rule_type, value: rule.value}) + newRules.push({ rule_type: rule.rule_type, value: rule.value }) } return newRules } else { @@ -13,7 +16,13 @@ export function cloneFilterRules(filterRules: FilterRule[]): FilterRule[] { } export function isFullTextFilterRule(filterRules: FilterRule[]): boolean { - return filterRules.find(r => r.rule_type == FILTER_FULLTEXT_QUERY || r.rule_type == FILTER_FULLTEXT_MORELIKE) != null + return ( + filterRules.find( + (r) => + r.rule_type == FILTER_FULLTEXT_QUERY || + r.rule_type == FILTER_FULLTEXT_MORELIKE + ) != null + ) } export interface FilterRule { diff --git a/src-ui/src/app/data/matching-model.ts b/src-ui/src/app/data/matching-model.ts index 49cb5cad4..e228893d6 100644 --- a/src-ui/src/app/data/matching-model.ts +++ b/src-ui/src/app/data/matching-model.ts @@ -1,5 +1,4 @@ -import { ObjectWithId } from './object-with-id'; - +import { ObjectWithId } from './object-with-id' export const MATCH_ANY = 1 export const MATCH_ALL = 2 @@ -9,26 +8,48 @@ export const MATCH_FUZZY = 5 export const MATCH_AUTO = 6 export const MATCHING_ALGORITHMS = [ - {id: MATCH_ANY, shortName: $localize`Any word`, name: $localize`Any: Document contains any of these words (space separated)`}, - {id: MATCH_ALL, shortName: $localize`All words`, name: $localize`All: Document contains all of these words (space separated)`}, - {id: MATCH_LITERAL, shortName: $localize`Exact match`, name: $localize`Exact: Document contains this string`}, - {id: MATCH_REGEX, shortName: $localize`Regular expression`, name: $localize`Regular expression: Document matches this regular expression`}, - {id: MATCH_FUZZY, shortName: $localize`Fuzzy word`, name: $localize`Fuzzy: Document contains a word similar to this word`}, - {id: MATCH_AUTO, shortName: $localize`Automatic`, name: $localize`Auto: Learn matching automatically`}, + { + id: MATCH_ANY, + shortName: $localize`Any word`, + name: $localize`Any: Document contains any of these words (space separated)`, + }, + { + id: MATCH_ALL, + shortName: $localize`All words`, + name: $localize`All: Document contains all of these words (space separated)`, + }, + { + id: MATCH_LITERAL, + shortName: $localize`Exact match`, + name: $localize`Exact: Document contains this string`, + }, + { + id: MATCH_REGEX, + shortName: $localize`Regular expression`, + name: $localize`Regular expression: Document matches this regular expression`, + }, + { + id: MATCH_FUZZY, + shortName: $localize`Fuzzy word`, + name: $localize`Fuzzy: Document contains a word similar to this word`, + }, + { + id: MATCH_AUTO, + shortName: $localize`Automatic`, + name: $localize`Auto: Learn matching automatically`, + }, ] export interface MatchingModel extends ObjectWithId { + name?: string - name?: string + slug?: string - slug?: string + match?: string - match?: string + matching_algorithm?: number - matching_algorithm?: number - - is_insensitive?: boolean - - document_count?: number + is_insensitive?: boolean + document_count?: number } diff --git a/src-ui/src/app/data/object-with-id.ts b/src-ui/src/app/data/object-with-id.ts index e81548f4e..4f5e89c83 100644 --- a/src-ui/src/app/data/object-with-id.ts +++ b/src-ui/src/app/data/object-with-id.ts @@ -1,5 +1,3 @@ export interface ObjectWithId { - - id?: number - + id?: number } diff --git a/src-ui/src/app/data/paperless-correspondent.ts b/src-ui/src/app/data/paperless-correspondent.ts index 3f5bb5719..142efd452 100644 --- a/src-ui/src/app/data/paperless-correspondent.ts +++ b/src-ui/src/app/data/paperless-correspondent.ts @@ -1,7 +1,5 @@ -import { MatchingModel } from './matching-model'; +import { MatchingModel } from './matching-model' export interface PaperlessCorrespondent extends MatchingModel { - last_correspondence?: Date - } diff --git a/src-ui/src/app/data/paperless-document-metadata.ts b/src-ui/src/app/data/paperless-document-metadata.ts index a1063adf9..1f9155b3a 100644 --- a/src-ui/src/app/data/paperless-document-metadata.ts +++ b/src-ui/src/app/data/paperless-document-metadata.ts @@ -1,5 +1,4 @@ export interface PaperlessDocumentMetadata { - original_checksum?: string archived_checksum?: string @@ -9,5 +8,4 @@ export interface PaperlessDocumentMetadata { media_filename?: string has_archive_version?: boolean - } diff --git a/src-ui/src/app/data/paperless-document-suggestions.ts b/src-ui/src/app/data/paperless-document-suggestions.ts index cc68b2b27..0a27df349 100644 --- a/src-ui/src/app/data/paperless-document-suggestions.ts +++ b/src-ui/src/app/data/paperless-document-suggestions.ts @@ -1,9 +1,7 @@ export interface PaperlessDocumentSuggestions { - tags?: number[] correspondents?: number[] document_types?: number[] - } diff --git a/src-ui/src/app/data/paperless-document-type.ts b/src-ui/src/app/data/paperless-document-type.ts index b1d002461..1aec65bc7 100644 --- a/src-ui/src/app/data/paperless-document-type.ts +++ b/src-ui/src/app/data/paperless-document-type.ts @@ -1,5 +1,3 @@ -import { MatchingModel } from './matching-model'; +import { MatchingModel } from './matching-model' -export interface PaperlessDocumentType extends MatchingModel { - -} +export interface PaperlessDocumentType extends MatchingModel {} diff --git a/src-ui/src/app/data/paperless-document.ts b/src-ui/src/app/data/paperless-document.ts index e7412278b..92a5aee45 100644 --- a/src-ui/src/app/data/paperless-document.ts +++ b/src-ui/src/app/data/paperless-document.ts @@ -5,50 +5,46 @@ import { PaperlessDocumentType } from './paperless-document-type' import { Observable } from 'rxjs' export interface SearchHit { - score?: number rank?: number highlights?: string - } export interface PaperlessDocument extends ObjectWithId { + correspondent$?: Observable - correspondent$?: Observable + correspondent?: number - correspondent?: number + document_type$?: Observable - document_type$?: Observable + document_type?: number - document_type?: number + title?: string - title?: string + content?: string - content?: string + file_type?: string - file_type?: string + tags$?: Observable - tags$?: Observable + tags?: number[] - tags?: number[] + checksum?: string - checksum?: string + created?: Date - created?: Date + modified?: Date - modified?: Date + added?: Date - added?: Date + file_name?: string - file_name?: string + download_url?: string - download_url?: string + thumbnail_url?: string - thumbnail_url?: string - - archive_serial_number?: number - - __search_hit__?: SearchHit + archive_serial_number?: number + __search_hit__?: SearchHit } diff --git a/src-ui/src/app/data/paperless-saved-view.ts b/src-ui/src/app/data/paperless-saved-view.ts index 8a4cd58b7..90c07e56a 100644 --- a/src-ui/src/app/data/paperless-saved-view.ts +++ b/src-ui/src/app/data/paperless-saved-view.ts @@ -1,8 +1,7 @@ -import { FilterRule } from './filter-rule'; -import { ObjectWithId } from './object-with-id'; +import { FilterRule } from './filter-rule' +import { ObjectWithId } from './object-with-id' export interface PaperlessSavedView extends ObjectWithId { - name?: string show_on_dashboard?: boolean @@ -14,5 +13,4 @@ export interface PaperlessSavedView extends ObjectWithId { sort_reverse: boolean filter_rules: FilterRule[] - } diff --git a/src-ui/src/app/data/paperless-tag.ts b/src-ui/src/app/data/paperless-tag.ts index a999666c4..7265ae187 100644 --- a/src-ui/src/app/data/paperless-tag.ts +++ b/src-ui/src/app/data/paperless-tag.ts @@ -1,11 +1,9 @@ -import { MatchingModel } from "./matching-model"; +import { MatchingModel } from './matching-model' export interface PaperlessTag extends MatchingModel { + color?: string - color?: string - - text_color?: string - - is_inbox_tag?: boolean + text_color?: string + is_inbox_tag?: boolean } diff --git a/src-ui/src/app/data/results.ts b/src-ui/src/app/data/results.ts index 839c79ed0..dbf99c5a1 100644 --- a/src-ui/src/app/data/results.ts +++ b/src-ui/src/app/data/results.ts @@ -1,7 +1,5 @@ export interface Results { - count: number results: T[] - } diff --git a/src-ui/src/app/data/storage-keys.ts b/src-ui/src/app/data/storage-keys.ts index ec91c06ac..77ee40c32 100644 --- a/src-ui/src/app/data/storage-keys.ts +++ b/src-ui/src/app/data/storage-keys.ts @@ -1,7 +1,7 @@ export const OPEN_DOCUMENT_SERVICE = { - DOCUMENTS: 'open-documents-service:openDocuments' + DOCUMENTS: 'open-documents-service:openDocuments', } export const DOCUMENT_LIST_SERVICE = { - CURRENT_VIEW_CONFIG: 'document-list-service:currentViewConfig' + CURRENT_VIEW_CONFIG: 'document-list-service:currentViewConfig', } diff --git a/src-ui/src/app/data/websocket-consumer-status-message.ts b/src-ui/src/app/data/websocket-consumer-status-message.ts index c20882067..aecdda7c0 100644 --- a/src-ui/src/app/data/websocket-consumer-status-message.ts +++ b/src-ui/src/app/data/websocket-consumer-status-message.ts @@ -1,5 +1,4 @@ export interface WebsocketConsumerStatusMessage { - filename?: string task_id?: string current_progress?: number @@ -7,5 +6,4 @@ export interface WebsocketConsumerStatusMessage { status?: string message?: string document_id: number - } diff --git a/src-ui/src/app/directives/sortable.directive.spec.ts b/src-ui/src/app/directives/sortable.directive.spec.ts index f77b499de..03f6d8c71 100644 --- a/src-ui/src/app/directives/sortable.directive.spec.ts +++ b/src-ui/src/app/directives/sortable.directive.spec.ts @@ -1,8 +1,8 @@ -import { SortableDirective } from './sortable.directive'; +import { SortableDirective } from './sortable.directive' describe('SortableDirective', () => { it('should create an instance', () => { - const directive = new SortableDirective(); - expect(directive).toBeTruthy(); - }); -}); + const directive = new SortableDirective() + expect(directive).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/directives/sortable.directive.ts b/src-ui/src/app/directives/sortable.directive.ts index 22750273d..85d65e398 100644 --- a/src-ui/src/app/directives/sortable.directive.ts +++ b/src-ui/src/app/directives/sortable.directive.ts @@ -1,4 +1,4 @@ -import { Directive, EventEmitter, Input, Output } from '@angular/core'; +import { Directive, EventEmitter, Input, Output } from '@angular/core' export interface SortEvent { column: string @@ -10,15 +10,14 @@ export interface SortEvent { host: { '[class.asc]': 'currentSortField == sortable && !currentSortReverse', '[class.des]': 'currentSortField == sortable && currentSortReverse', - '(click)': 'rotate()' - } + '(click)': 'rotate()', + }, }) export class SortableDirective { - - constructor() { } + constructor() {} @Input() - sortable: string = ''; + sortable: string = '' @Input() currentSortReverse: boolean = false @@ -26,15 +25,18 @@ export class SortableDirective { @Input() currentSortField: string - @Output() sort = new EventEmitter(); + @Output() sort = new EventEmitter() rotate() { if (this.currentSortField != this.sortable) { - this.sort.emit({column: this.sortable, reverse: false}); - } else if (this.currentSortField == this.sortable && !this.currentSortReverse) { - this.sort.emit({column: this.currentSortField, reverse: true}); + this.sort.emit({ column: this.sortable, reverse: false }) + } else if ( + this.currentSortField == this.sortable && + !this.currentSortReverse + ) { + this.sort.emit({ column: this.currentSortField, reverse: true }) } else { - this.sort.emit({column: null, reverse: false}); + this.sort.emit({ column: null, reverse: false }) } } } diff --git a/src-ui/src/app/guards/dirty-form.guard.ts b/src-ui/src/app/guards/dirty-form.guard.ts index 4e7bc39ea..1205f3b0e 100644 --- a/src-ui/src/app/guards/dirty-form.guard.ts +++ b/src-ui/src/app/guards/dirty-form.guard.ts @@ -1,22 +1,24 @@ -import { Injectable } from '@angular/core'; -import { DirtyCheckGuard } from '@ngneat/dirty-check-forms'; -import { Observable, Subject } from 'rxjs'; -import { map } from 'rxjs/operators'; -import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; -import { ConfirmDialogComponent } from 'src/app/components/common/confirm-dialog/confirm-dialog.component'; +import { Injectable } from '@angular/core' +import { DirtyCheckGuard } from '@ngneat/dirty-check-forms' +import { Observable, Subject } from 'rxjs' +import { map } from 'rxjs/operators' +import { NgbModal } from '@ng-bootstrap/ng-bootstrap' +import { ConfirmDialogComponent } from 'src/app/components/common/confirm-dialog/confirm-dialog.component' @Injectable({ providedIn: 'root' }) export class DirtyFormGuard extends DirtyCheckGuard { constructor(private modalService: NgbModal) { - super(); + super() } confirmChanges(): Observable { - let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) + let modal = this.modalService.open(ConfirmDialogComponent, { + backdrop: 'static', + }) modal.componentInstance.title = $localize`Unsaved Changes` modal.componentInstance.messageBold = $localize`You have unsaved changes.` modal.componentInstance.message = $localize`Are you sure you want to leave?` - modal.componentInstance.btnClass = "btn-warning" + modal.componentInstance.btnClass = 'btn-warning' modal.componentInstance.btnCaption = $localize`Leave page` modal.componentInstance.confirmClicked.subscribe(() => { modal.componentInstance.buttonsEnabled = false diff --git a/src-ui/src/app/interceptors/api-version.interceptor.spec.ts b/src-ui/src/app/interceptors/api-version.interceptor.spec.ts deleted file mode 100644 index 7ad51f687..000000000 --- a/src-ui/src/app/interceptors/api-version.interceptor.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { ApiVersionInterceptor } from './api-version.interceptor'; - -describe('ApiVersionInterceptor', () => { - beforeEach(() => TestBed.configureTestingModule({ - providers: [ - ApiVersionInterceptor - ] - })); - - it('should be created', () => { - const interceptor: ApiVersionInterceptor = TestBed.inject(ApiVersionInterceptor); - expect(interceptor).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/interceptors/api-version.interceptor.ts b/src-ui/src/app/interceptors/api-version.interceptor.ts index 4df2efba6..eb246c580 100644 --- a/src-ui/src/app/interceptors/api-version.interceptor.ts +++ b/src-ui/src/app/interceptors/api-version.interceptor.ts @@ -1,25 +1,27 @@ -import { Injectable } from '@angular/core'; +import { Injectable } from '@angular/core' import { HttpRequest, HttpHandler, HttpEvent, - HttpInterceptor -} from '@angular/common/http'; -import { Observable } from 'rxjs'; -import { environment } from 'src/environments/environment'; + HttpInterceptor, +} from '@angular/common/http' +import { Observable } from 'rxjs' +import { environment } from 'src/environments/environment' @Injectable() export class ApiVersionInterceptor implements HttpInterceptor { - constructor() {} - intercept(request: HttpRequest, next: HttpHandler): Observable> { + intercept( + request: HttpRequest, + next: HttpHandler + ): Observable> { request = request.clone({ - setHeaders: { - 'Accept': `application/json; version=${environment.apiVersion}` - } - }) + setHeaders: { + Accept: `application/json; version=${environment.apiVersion}`, + }, + }) - return next.handle(request); + return next.handle(request) } } diff --git a/src-ui/src/app/interceptors/csrf.interceptor.spec.ts b/src-ui/src/app/interceptors/csrf.interceptor.spec.ts index 64e20c110..df387acc1 100644 --- a/src-ui/src/app/interceptors/csrf.interceptor.spec.ts +++ b/src-ui/src/app/interceptors/csrf.interceptor.spec.ts @@ -1,16 +1,16 @@ -import { TestBed } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing' -import { CsrfInterceptor } from './csrf.interceptor'; +import { CsrfInterceptor } from './csrf.interceptor' describe('CsrfInterceptor', () => { - beforeEach(() => TestBed.configureTestingModule({ - providers: [ - CsrfInterceptor - ] - })); + beforeEach(() => + TestBed.configureTestingModule({ + providers: [CsrfInterceptor], + }) + ) it('should be created', () => { - const interceptor: CsrfInterceptor = TestBed.inject(CsrfInterceptor); - expect(interceptor).toBeTruthy(); - }); -}); + const interceptor: CsrfInterceptor = TestBed.inject(CsrfInterceptor) + expect(interceptor).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/interceptors/csrf.interceptor.ts b/src-ui/src/app/interceptors/csrf.interceptor.ts index 1817e3a66..eb136e489 100644 --- a/src-ui/src/app/interceptors/csrf.interceptor.ts +++ b/src-ui/src/app/interceptors/csrf.interceptor.ts @@ -1,35 +1,35 @@ -import { Injectable } from '@angular/core'; +import { Injectable } from '@angular/core' import { HttpRequest, HttpHandler, HttpEvent, - HttpInterceptor -} from '@angular/common/http'; -import { Observable } from 'rxjs'; -import { CookieService } from 'ngx-cookie-service'; -import { Meta } from '@angular/platform-browser'; + HttpInterceptor, +} from '@angular/common/http' +import { Observable } from 'rxjs' +import { CookieService } from 'ngx-cookie-service' +import { Meta } from '@angular/platform-browser' @Injectable() export class CsrfInterceptor implements HttpInterceptor { + constructor(private cookieService: CookieService, private meta: Meta) {} - constructor(private cookieService: CookieService, private meta: Meta) { - - } - - intercept(request: HttpRequest, next: HttpHandler): Observable> { - let prefix = "" + intercept( + request: HttpRequest, + next: HttpHandler + ): Observable> { + let prefix = '' if (this.meta.getTag('name=cookie_prefix')) { prefix = this.meta.getTag('name=cookie_prefix').content } - let csrfToken = this.cookieService.get(`${prefix?prefix:''}csrftoken`) + let csrfToken = this.cookieService.get(`${prefix ? prefix : ''}csrftoken`) if (csrfToken) { - request = request.clone({ + request = request.clone({ setHeaders: { - 'X-CSRFToken': csrfToken - } + 'X-CSRFToken': csrfToken, + }, }) } - return next.handle(request); + return next.handle(request) } } diff --git a/src-ui/src/app/pipes/custom-date.pipe.spec.ts b/src-ui/src/app/pipes/custom-date.pipe.spec.ts deleted file mode 100644 index 822966baf..000000000 --- a/src-ui/src/app/pipes/custom-date.pipe.spec.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { CustomDatePipe } from './custom-date.pipe'; - -describe('CustomDatePipe', () => { - it('create an instance', () => { - const pipe = new CustomDatePipe(); - expect(pipe).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/pipes/custom-date.pipe.ts b/src-ui/src/app/pipes/custom-date.pipe.ts index 71f386b8c..bf5ab1457 100644 --- a/src-ui/src/app/pipes/custom-date.pipe.ts +++ b/src-ui/src/app/pipes/custom-date.pipe.ts @@ -1,32 +1,47 @@ -import { DatePipe } from '@angular/common'; -import { Inject, LOCALE_ID, Pipe, PipeTransform } from '@angular/core'; -import { SettingsService, SETTINGS_KEYS } from '../services/settings.service'; +import { DatePipe } from '@angular/common' +import { Inject, LOCALE_ID, Pipe, PipeTransform } from '@angular/core' +import { SettingsService, SETTINGS_KEYS } from '../services/settings.service' const FORMAT_TO_ISO_FORMAT = { - "longDate": "y-MM-dd", - "mediumDate": "y-MM-dd", - "shortDate": "y-MM-dd" + longDate: 'y-MM-dd', + mediumDate: 'y-MM-dd', + shortDate: 'y-MM-dd', } @Pipe({ - name: 'customDate' + name: 'customDate', }) export class CustomDatePipe implements PipeTransform { - private defaultLocale: string - constructor(@Inject(LOCALE_ID) locale: string, private datePipe: DatePipe, private settings: SettingsService) { + constructor( + @Inject(LOCALE_ID) locale: string, + private datePipe: DatePipe, + private settings: SettingsService + ) { this.defaultLocale = locale } - transform(value: any, format?: string, timezone?: string, locale?: string): string | null { - let l = locale || this.settings.get(SETTINGS_KEYS.DATE_LOCALE) || this.defaultLocale + transform( + value: any, + format?: string, + timezone?: string, + locale?: string + ): string | null { + let l = + locale || + this.settings.get(SETTINGS_KEYS.DATE_LOCALE) || + this.defaultLocale let f = format || this.settings.get(SETTINGS_KEYS.DATE_FORMAT) - if (l == "iso-8601") { + if (l == 'iso-8601') { return this.datePipe.transform(value, FORMAT_TO_ISO_FORMAT[f], timezone) } else { - return this.datePipe.transform(value, format || this.settings.get(SETTINGS_KEYS.DATE_FORMAT), timezone, l) + return this.datePipe.transform( + value, + format || this.settings.get(SETTINGS_KEYS.DATE_FORMAT), + timezone, + l + ) } } - } diff --git a/src-ui/src/app/pipes/document-title.pipe.spec.ts b/src-ui/src/app/pipes/document-title.pipe.spec.ts index 29835abd6..08afd244e 100644 --- a/src-ui/src/app/pipes/document-title.pipe.spec.ts +++ b/src-ui/src/app/pipes/document-title.pipe.spec.ts @@ -1,8 +1,8 @@ -import { DocumentTitlePipe } from './document-title.pipe'; +import { DocumentTitlePipe } from './document-title.pipe' describe('DocumentTitlePipe', () => { it('create an instance', () => { - const pipe = new DocumentTitlePipe(); - expect(pipe).toBeTruthy(); - }); -}); + const pipe = new DocumentTitlePipe() + expect(pipe).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/pipes/document-title.pipe.ts b/src-ui/src/app/pipes/document-title.pipe.ts index 60a552ca8..e9611a926 100644 --- a/src-ui/src/app/pipes/document-title.pipe.ts +++ b/src-ui/src/app/pipes/document-title.pipe.ts @@ -1,10 +1,9 @@ -import { Pipe, PipeTransform } from '@angular/core'; +import { Pipe, PipeTransform } from '@angular/core' @Pipe({ - name: 'documentTitle' + name: 'documentTitle', }) export class DocumentTitlePipe implements PipeTransform { - transform(value: string): string { if (value) { return value @@ -12,5 +11,4 @@ export class DocumentTitlePipe implements PipeTransform { return $localize`(no title)` } } - } diff --git a/src-ui/src/app/pipes/file-size.pipe.spec.ts b/src-ui/src/app/pipes/file-size.pipe.spec.ts index 8c7a39d22..b84500fad 100644 --- a/src-ui/src/app/pipes/file-size.pipe.spec.ts +++ b/src-ui/src/app/pipes/file-size.pipe.spec.ts @@ -1,8 +1,8 @@ -import { FileSizePipe } from './file-size.pipe'; +import { FileSizePipe } from './file-size.pipe' describe('FileSizePipe', () => { it('create an instance', () => { - const pipe = new FileSizePipe(); - expect(pipe).toBeTruthy(); - }); -}); + const pipe = new FileSizePipe() + expect(pipe).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/pipes/file-size.pipe.ts b/src-ui/src/app/pipes/file-size.pipe.ts index 4ac1e4d61..83f07d837 100644 --- a/src-ui/src/app/pipes/file-size.pipe.ts +++ b/src-ui/src/app/pipes/file-size.pipe.ts @@ -22,12 +22,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -import { Pipe, PipeTransform } from '@angular/core'; +import { Pipe, PipeTransform } from '@angular/core' -type unit = 'bytes' | 'KB' | 'MB' | 'GB' | 'TB' | 'PB'; +type unit = 'bytes' | 'KB' | 'MB' | 'GB' | 'TB' | 'PB' type unitPrecisionMap = { - [u in unit]: number; -}; + [u in unit]: number +} const defaultPrecisionMap: unitPrecisionMap = { bytes: 0, @@ -35,8 +35,8 @@ const defaultPrecisionMap: unitPrecisionMap = { MB: 1, GB: 1, TB: 2, - PB: 2 -}; + PB: 2, +} /* * Convert bytes into largest possible unit. @@ -55,23 +55,26 @@ const defaultPrecisionMap: unitPrecisionMap = { */ @Pipe({ name: 'fileSize' }) export class FileSizePipe implements PipeTransform { - private readonly units: unit[] = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB']; + private readonly units: unit[] = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB'] - transform(bytes: number = 0, precision: number | unitPrecisionMap = defaultPrecisionMap): string { - if (isNaN(parseFloat(String(bytes))) || !isFinite(bytes)) return '?'; + transform( + bytes: number = 0, + precision: number | unitPrecisionMap = defaultPrecisionMap + ): string { + if (isNaN(parseFloat(String(bytes))) || !isFinite(bytes)) return '?' - let unitIndex = 0; + let unitIndex = 0 while (bytes >= 1024) { - bytes /= 1024; - unitIndex++; + bytes /= 1024 + unitIndex++ } - const unit = this.units[unitIndex]; + const unit = this.units[unitIndex] if (typeof precision === 'number') { - return `${bytes.toFixed(+precision)} ${unit}`; + return `${bytes.toFixed(+precision)} ${unit}` } - return `${bytes.toFixed(precision[unit])} ${unit}`; + return `${bytes.toFixed(precision[unit])} ${unit}` } } diff --git a/src-ui/src/app/pipes/filter.pipe.ts b/src-ui/src/app/pipes/filter.pipe.ts index 0be1be507..d48c2ad5d 100644 --- a/src-ui/src/app/pipes/filter.pipe.ts +++ b/src-ui/src/app/pipes/filter.pipe.ts @@ -1,18 +1,20 @@ -import { Pipe, PipeTransform } from '@angular/core'; -import { MatchingModel } from '../data/matching-model'; +import { Pipe, PipeTransform } from '@angular/core' +import { MatchingModel } from '../data/matching-model' @Pipe({ - name: 'filter' + name: 'filter', }) export class FilterPipe implements PipeTransform { transform(items: MatchingModel[], searchText: string): MatchingModel[] { - if (!items) return []; - if (!searchText) return items; + if (!items) return [] + if (!searchText) return items - return items.filter(item => { - return Object.keys(item).some(key => { - return String(item[key]).toLowerCase().includes(searchText.toLowerCase()); - }); - }); - } + return items.filter((item) => { + return Object.keys(item).some((key) => { + return String(item[key]) + .toLowerCase() + .includes(searchText.toLowerCase()) + }) + }) + } } diff --git a/src-ui/src/app/pipes/safe.pipe.spec.ts b/src-ui/src/app/pipes/safe.pipe.spec.ts deleted file mode 100644 index 49ee0ad14..000000000 --- a/src-ui/src/app/pipes/safe.pipe.spec.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { SafePipe } from './safe.pipe'; - -describe('SafePipe', () => { - it('create an instance', () => { - const pipe = new SafePipe(); - expect(pipe).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/pipes/safe.pipe.ts b/src-ui/src/app/pipes/safe.pipe.ts deleted file mode 100644 index 3aa987c08..000000000 --- a/src-ui/src/app/pipes/safe.pipe.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; -import { DomSanitizer } from '@angular/platform-browser'; - -@Pipe({ - name: 'safe' -}) -export class SafePipe implements PipeTransform { - - constructor(private sanitizer: DomSanitizer) { } - - transform(url) { - if (url == null) { - return this.sanitizer.bypassSecurityTrustResourceUrl("") - } else { - return this.sanitizer.bypassSecurityTrustResourceUrl(url); - } - } - -} diff --git a/src-ui/src/app/pipes/safehtml.pipe.ts b/src-ui/src/app/pipes/safehtml.pipe.ts new file mode 100644 index 000000000..6fba1e75e --- /dev/null +++ b/src-ui/src/app/pipes/safehtml.pipe.ts @@ -0,0 +1,13 @@ +import { Pipe, PipeTransform } from '@angular/core' +import { DomSanitizer } from '@angular/platform-browser' + +@Pipe({ + name: 'safeHtml', +}) +export class SafeHtmlPipe implements PipeTransform { + constructor(private sanitizer: DomSanitizer) {} + + transform(html) { + return this.sanitizer.bypassSecurityTrustHtml(html) + } +} diff --git a/src-ui/src/app/pipes/safeurl.pipe.ts b/src-ui/src/app/pipes/safeurl.pipe.ts new file mode 100644 index 000000000..4d19d099f --- /dev/null +++ b/src-ui/src/app/pipes/safeurl.pipe.ts @@ -0,0 +1,17 @@ +import { Pipe, PipeTransform } from '@angular/core' +import { DomSanitizer } from '@angular/platform-browser' + +@Pipe({ + name: 'safeUrl', +}) +export class SafeUrlPipe implements PipeTransform { + constructor(private sanitizer: DomSanitizer) {} + + transform(url) { + if (url == null) { + return this.sanitizer.bypassSecurityTrustResourceUrl('') + } else { + return this.sanitizer.bypassSecurityTrustResourceUrl(url) + } + } +} diff --git a/src-ui/src/app/pipes/yes-no.pipe.spec.ts b/src-ui/src/app/pipes/yes-no.pipe.spec.ts index 80acd8acd..3da9518e9 100644 --- a/src-ui/src/app/pipes/yes-no.pipe.spec.ts +++ b/src-ui/src/app/pipes/yes-no.pipe.spec.ts @@ -1,8 +1,8 @@ -import { YesNoPipe } from './yes-no.pipe'; +import { YesNoPipe } from './yes-no.pipe' describe('YesNoPipe', () => { it('create an instance', () => { - const pipe = new YesNoPipe(); - expect(pipe).toBeTruthy(); - }); -}); + const pipe = new YesNoPipe() + expect(pipe).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/pipes/yes-no.pipe.ts b/src-ui/src/app/pipes/yes-no.pipe.ts index f12c844a5..3912e9a92 100644 --- a/src-ui/src/app/pipes/yes-no.pipe.ts +++ b/src-ui/src/app/pipes/yes-no.pipe.ts @@ -1,12 +1,10 @@ -import { Pipe, PipeTransform } from '@angular/core'; +import { Pipe, PipeTransform } from '@angular/core' @Pipe({ - name: 'yesno' + name: 'yesno', }) export class YesNoPipe implements PipeTransform { - transform(value: boolean): unknown { return value ? $localize`Yes` : $localize`No` } - } diff --git a/src-ui/src/app/services/consumer-status.service.spec.ts b/src-ui/src/app/services/consumer-status.service.spec.ts deleted file mode 100644 index d19f455e2..000000000 --- a/src-ui/src/app/services/consumer-status.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { ConsumerStatusService } from './consumer-status.service'; - -describe('ConsumerStatusService', () => { - let service: ConsumerStatusService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(ConsumerStatusService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/services/consumer-status.service.ts b/src-ui/src/app/services/consumer-status.service.ts index 4a729b29d..176227bef 100644 --- a/src-ui/src/app/services/consumer-status.service.ts +++ b/src-ui/src/app/services/consumer-status.service.ts @@ -1,34 +1,33 @@ -import { Injectable } from '@angular/core'; -import { Subject } from 'rxjs'; -import { environment } from 'src/environments/environment'; -import { WebsocketConsumerStatusMessage } from '../data/websocket-consumer-status-message'; +import { Injectable } from '@angular/core' +import { Subject } from 'rxjs' +import { environment } from 'src/environments/environment' +import { WebsocketConsumerStatusMessage } from '../data/websocket-consumer-status-message' export enum FileStatusPhase { STARTED = 0, UPLOADING = 1, PROCESSING = 2, SUCCESS = 3, - FAILED = 4 + FAILED = 4, } export const FILE_STATUS_MESSAGES = { - "document_already_exists": $localize`Document already exists.`, - "file_not_found": $localize`File not found.`, - "pre_consume_script_not_found": $localize`:Pre-Consume is a term that appears like that in the documentation as well and does not need a specific translation:Pre-consume script does not exist.`, - "pre_consume_script_error": $localize`:Pre-Consume is a term that appears like that in the documentation as well and does not need a specific translation:Error while executing pre-consume script.`, - "post_consume_script_not_found": $localize`:Post-Consume is a term that appears like that in the documentation as well and does not need a specific translation:Post-consume script does not exist.`, - "post_consume_script_error": $localize`:Post-Consume is a term that appears like that in the documentation as well and does not need a specific translation:Error while executing post-consume script.`, - "new_file": $localize`Received new file.`, - "unsupported_type": $localize`File type not supported.`, - "parsing_document": $localize`Processing document...`, - "generating_thumbnail": $localize`Generating thumbnail...`, - "parse_date": $localize`Retrieving date from document...`, - "save_document": $localize`Saving document...`, - "finished": $localize`Finished.` + document_already_exists: $localize`Document already exists.`, + file_not_found: $localize`File not found.`, + pre_consume_script_not_found: $localize`:Pre-Consume is a term that appears like that in the documentation as well and does not need a specific translation:Pre-consume script does not exist.`, + pre_consume_script_error: $localize`:Pre-Consume is a term that appears like that in the documentation as well and does not need a specific translation:Error while executing pre-consume script.`, + post_consume_script_not_found: $localize`:Post-Consume is a term that appears like that in the documentation as well and does not need a specific translation:Post-consume script does not exist.`, + post_consume_script_error: $localize`:Post-Consume is a term that appears like that in the documentation as well and does not need a specific translation:Error while executing post-consume script.`, + new_file: $localize`Received new file.`, + unsupported_type: $localize`File type not supported.`, + parsing_document: $localize`Processing document...`, + generating_thumbnail: $localize`Generating thumbnail...`, + parse_date: $localize`Retrieving date from document...`, + save_document: $localize`Saving document...`, + finished: $localize`Finished.`, } export class FileStatus { - filename: string taskId: string @@ -48,16 +47,22 @@ export class FileStatus { case FileStatusPhase.STARTED: return 0.0 case FileStatusPhase.UPLOADING: - return this.currentPhaseProgress / this.currentPhaseMaxProgress * 0.2 + return (this.currentPhaseProgress / this.currentPhaseMaxProgress) * 0.2 case FileStatusPhase.PROCESSING: - return (this.currentPhaseProgress / this.currentPhaseMaxProgress * 0.8) + 0.2 + return ( + (this.currentPhaseProgress / this.currentPhaseMaxProgress) * 0.8 + 0.2 + ) case FileStatusPhase.SUCCESS: case FileStatusPhase.FAILED: return 1.0 } } - updateProgress(status: FileStatusPhase, currentProgress?: number, maxProgress?: number) { + updateProgress( + status: FileStatusPhase, + currentProgress?: number, + maxProgress?: number + ) { if (status >= this.phase) { this.phase = status if (currentProgress != null) { @@ -68,15 +73,13 @@ export class FileStatus { } } } - } @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class ConsumerStatusService { - - constructor() { } + constructor() {} private statusWebSocket: WebSocket @@ -87,7 +90,11 @@ export class ConsumerStatusService { private documentConsumptionFailedSubject = new Subject() private get(taskId: string, filename?: string) { - let status = this.consumerStatus.find(e => e.taskId == taskId) || this.consumerStatus.find(e => e.filename == filename && e.taskId == null) + let status = + this.consumerStatus.find((e) => e.taskId == taskId) || + this.consumerStatus.find( + (e) => e.filename == filename && e.taskId == null + ) let created = false if (!status) { status = new FileStatus() @@ -96,7 +103,7 @@ export class ConsumerStatusService { } status.taskId = taskId status.filename = filename - return {'status': status, 'created': created} + return { status: status, created: created } } newFileUpload(filename: string): FileStatus { @@ -108,33 +115,48 @@ export class ConsumerStatusService { getConsumerStatus(phase?: FileStatusPhase) { if (phase != null) { - return this.consumerStatus.filter(s => s.phase == phase) + return this.consumerStatus.filter((s) => s.phase == phase) } else { return this.consumerStatus } } getConsumerStatusNotCompleted() { - return this.consumerStatus.filter(s => s.phase < FileStatusPhase.SUCCESS) + return this.consumerStatus.filter((s) => s.phase < FileStatusPhase.SUCCESS) } getConsumerStatusCompleted() { - return this.consumerStatus.filter(s => s.phase == FileStatusPhase.FAILED || s.phase == FileStatusPhase.SUCCESS) + return this.consumerStatus.filter( + (s) => + s.phase == FileStatusPhase.FAILED || s.phase == FileStatusPhase.SUCCESS + ) } connect() { this.disconnect() - this.statusWebSocket = new WebSocket(`${environment.webSocketProtocol}//${environment.webSocketHost}${environment.webSocketBaseUrl}status/`); + this.statusWebSocket = new WebSocket( + `${environment.webSocketProtocol}//${environment.webSocketHost}${environment.webSocketBaseUrl}status/` + ) this.statusWebSocket.onmessage = (ev) => { let statusMessage: WebsocketConsumerStatusMessage = JSON.parse(ev['data']) - let statusMessageGet = this.get(statusMessage.task_id, statusMessage.filename) + let statusMessageGet = this.get( + statusMessage.task_id, + statusMessage.filename + ) let status = statusMessageGet.status let created = statusMessageGet.created - status.updateProgress(FileStatusPhase.PROCESSING, statusMessage.current_progress, statusMessage.max_progress) - if (statusMessage.message && statusMessage.message in FILE_STATUS_MESSAGES) { + status.updateProgress( + FileStatusPhase.PROCESSING, + statusMessage.current_progress, + statusMessage.max_progress + ) + if ( + statusMessage.message && + statusMessage.message in FILE_STATUS_MESSAGES + ) { status.message = FILE_STATUS_MESSAGES[statusMessage.message] } else if (statusMessage.message) { status.message = statusMessage.message @@ -144,11 +166,11 @@ export class ConsumerStatusService { if (created && statusMessage.status == 'STARTING') { this.documentDetectedSubject.next(status) } - if (statusMessage.status == "SUCCESS") { + if (statusMessage.status == 'SUCCESS') { status.phase = FileStatusPhase.SUCCESS this.documentConsumptionFinishedSubject.next(status) } - if (statusMessage.status == "FAILED") { + if (statusMessage.status == 'FAILED') { status.phase = FileStatusPhase.FAILED this.documentConsumptionFailedSubject.next(status) } @@ -171,9 +193,11 @@ export class ConsumerStatusService { dismiss(status: FileStatus) { let index if (status.taskId != null) { - index = this.consumerStatus.findIndex(s => s.taskId == status.taskId) + index = this.consumerStatus.findIndex((s) => s.taskId == status.taskId) } else { - index = this.consumerStatus.findIndex(s => s.filename == status.filename) + index = this.consumerStatus.findIndex( + (s) => s.filename == status.filename + ) } if (index > -1) { @@ -182,7 +206,9 @@ export class ConsumerStatusService { } dismissCompleted() { - this.consumerStatus = this.consumerStatus.filter(status => status.phase != FileStatusPhase.SUCCESS) + this.consumerStatus = this.consumerStatus.filter( + (status) => status.phase != FileStatusPhase.SUCCESS + ) } onDocumentConsumptionFinished() { @@ -196,5 +222,4 @@ export class ConsumerStatusService { onDocumentDetected() { return this.documentDetectedSubject } - } diff --git a/src-ui/src/app/services/document-list-view.service.spec.ts b/src-ui/src/app/services/document-list-view.service.spec.ts deleted file mode 100644 index 92a1177aa..000000000 --- a/src-ui/src/app/services/document-list-view.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { DocumentListViewService } from './document-list-view.service'; - -describe('DocumentListViewService', () => { - let service: DocumentListViewService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(DocumentListViewService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/services/document-list-view.service.ts b/src-ui/src/app/services/document-list-view.service.ts index 4e1a8aad4..b0d246a32 100644 --- a/src-ui/src/app/services/document-list-view.service.ts +++ b/src-ui/src/app/services/document-list-view.service.ts @@ -1,18 +1,21 @@ -import { Injectable } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; -import { Observable } from 'rxjs'; -import { cloneFilterRules, FilterRule, isFullTextFilterRule } from '../data/filter-rule'; -import { PaperlessDocument } from '../data/paperless-document'; -import { PaperlessSavedView } from '../data/paperless-saved-view'; -import { DOCUMENT_LIST_SERVICE } from '../data/storage-keys'; -import { DocumentService } from './rest/document.service'; -import { SettingsService, SETTINGS_KEYS } from './settings.service'; +import { Injectable } from '@angular/core' +import { ActivatedRoute, Router } from '@angular/router' +import { Observable } from 'rxjs' +import { + cloneFilterRules, + FilterRule, + isFullTextFilterRule, +} from '../data/filter-rule' +import { PaperlessDocument } from '../data/paperless-document' +import { PaperlessSavedView } from '../data/paperless-saved-view' +import { DOCUMENT_LIST_SERVICE } from '../data/storage-keys' +import { DocumentService, DOCUMENT_SORT_FIELDS } from './rest/document.service' +import { SettingsService, SETTINGS_KEYS } from './settings.service' /** * Captures the current state of the list view. */ interface ListViewState { - /** * Title of the document list view. Either "Documents" (localized) or the name of a saved view. */ @@ -49,7 +52,6 @@ interface ListViewState { * Contains the IDs of all selected documents. */ selected?: Set - } /** @@ -59,10 +61,9 @@ interface ListViewState { * and saved views on request. See below. */ @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class DocumentListViewService { - isReloading: boolean = false error: string = null @@ -89,16 +90,19 @@ export class DocumentListViewService { documents: [], currentPage: 1, collectionSize: null, - sortField: "created", + sortField: 'created', sortReverse: true, filterRules: [], - selected: new Set() + selected: new Set(), } } private get activeListViewState() { if (!this.listViewStates.has(this._activeSavedViewId)) { - this.listViewStates.set(this._activeSavedViewId, this.defaultListViewState()) + this.listViewStates.set( + this._activeSavedViewId, + this.defaultListViewState() + ) } return this.listViewStates.get(this._activeSavedViewId) } @@ -131,13 +135,16 @@ export class DocumentListViewService { this.error = null let activeListViewState = this.activeListViewState - this.documentService.listFiltered( - activeListViewState.currentPage, - this.currentPageSize, - activeListViewState.sortField, - activeListViewState.sortReverse, - activeListViewState.filterRules).subscribe( - result => { + this.documentService + .listFiltered( + activeListViewState.currentPage, + this.currentPageSize, + activeListViewState.sortField, + activeListViewState.sortReverse, + activeListViewState.filterRules + ) + .subscribe({ + next: (result) => { this.isReloading = false activeListViewState.collectionSize = result.count activeListViewState.documents = result.results @@ -146,21 +153,42 @@ export class DocumentListViewService { } this.rangeSelectionAnchorIndex = this.lastRangeSelectionToIndex = null }, - error => { + error: (error) => { this.isReloading = false if (activeListViewState.currentPage != 1 && error.status == 404) { // this happens when applying a filter: the current page might not be available anymore due to the reduced result set. activeListViewState.currentPage = 1 this.reload() } else { - this.error = error.error + let errorMessage + if ( + typeof error.error !== 'string' && + Object.keys(error.error).length > 0 + ) { + // e.g. { archive_serial_number: Array } + errorMessage = Object.keys(error.error) + .map((fieldName) => { + const fieldError: Array = error.error[fieldName] + return `${ + DOCUMENT_SORT_FIELDS.find((f) => f.field == fieldName)?.name + }: ${fieldError[0]}` + }) + .join(', ') + } else { + errorMessage = error.error + } + this.error = errorMessage } - }) + }, + }) } set filterRules(filterRules: FilterRule[]) { - if (!isFullTextFilterRule(filterRules) && this.activeListViewState.sortField == "score") { - this.activeListViewState.sortField = "created" + if ( + !isFullTextFilterRule(filterRules) && + this.activeListViewState.sortField == 'score' + ) { + this.activeListViewState.sortField = 'created' } this.activeListViewState.filterRules = filterRules this.reload() @@ -228,27 +256,21 @@ export class DocumentListViewService { currentPage: this.activeListViewState.currentPage, filterRules: this.activeListViewState.filterRules, sortField: this.activeListViewState.sortField, - sortReverse: this.activeListViewState.sortReverse + sortReverse: this.activeListViewState.sortReverse, } - localStorage.setItem(DOCUMENT_LIST_SERVICE.CURRENT_VIEW_CONFIG, JSON.stringify(savedState)) + localStorage.setItem( + DOCUMENT_LIST_SERVICE.CURRENT_VIEW_CONFIG, + JSON.stringify(savedState) + ) } } quickFilter(filterRules: FilterRule[]) { - this._activeSavedViewId = null - this.activeListViewState.filterRules = filterRules - this.activeListViewState.currentPage = 1 - if (isFullTextFilterRule(filterRules)) { - this.activeListViewState.sortField = "score" - this.activeListViewState.sortReverse = false - } - this.reduceSelectionToFilter() - this.saveDocumentListView() - if (this.router.url == "/documents") { - this.reload() - } else { - this.router.navigate(["documents"]) - } + const params = this.documentService.filterRulesToQueryParams(filterRules) + this.router.navigate(['/documents'], { + relativeTo: this.route, + queryParams: params, + }) } getLastPage(): number { @@ -257,19 +279,29 @@ export class DocumentListViewService { hasNext(doc: number) { if (this.documents) { - let index = this.documents.findIndex(d => d.id == doc) - return index != -1 && (this.currentPage < this.getLastPage() || (index + 1) < this.documents.length) + let index = this.documents.findIndex((d) => d.id == doc) + return ( + index != -1 && + (this.currentPage < this.getLastPage() || + index + 1 < this.documents.length) + ) + } + } + + hasPrevious(doc: number) { + if (this.documents) { + let index = this.documents.findIndex((d) => d.id == doc) + return index != -1 && !(index == 0 && this.currentPage == 1) } } getNext(currentDocId: number): Observable { - return new Observable(nextDocId => { + return new Observable((nextDocId) => { if (this.documents != null) { + let index = this.documents.findIndex((d) => d.id == currentDocId) - let index = this.documents.findIndex(d => d.id == currentDocId) - - if (index != -1 && (index + 1) < this.documents.length) { - nextDocId.next(this.documents[index+1].id) + if (index != -1 && index + 1 < this.documents.length) { + nextDocId.next(this.documents[index + 1].id) nextDocId.complete() } else if (index != -1 && this.currentPage < this.getLastPage()) { this.currentPage += 1 @@ -286,6 +318,29 @@ export class DocumentListViewService { }) } + getPrevious(currentDocId: number): Observable { + return new Observable((prevDocId) => { + if (this.documents != null) { + let index = this.documents.findIndex((d) => d.id == currentDocId) + + if (index != 0) { + prevDocId.next(this.documents[index - 1].id) + prevDocId.complete() + } else if (this.currentPage > 1) { + this.currentPage -= 1 + this.reload(() => { + prevDocId.next(this.documents[this.documents.length - 1].id) + prevDocId.complete() + }) + } else { + prevDocId.complete() + } + } else { + prevDocId.complete() + } + }) + } + updatePageSize() { let newPageSize = this.settings.get(SETTINGS_KEYS.DOCUMENT_LIST_SIZE) if (newPageSize != this.currentPageSize) { @@ -300,23 +355,27 @@ export class DocumentListViewService { reduceSelectionToFilter() { if (this.selected.size > 0) { - this.documentService.listAllFilteredIds(this.filterRules).subscribe(ids => { - for (let id of this.selected) { - if (!ids.includes(id)) { - this.selected.delete(id) + this.documentService + .listAllFilteredIds(this.filterRules) + .subscribe((ids) => { + for (let id of this.selected) { + if (!ids.includes(id)) { + this.selected.delete(id) + } } - } - }) + }) } } selectAll() { - this.documentService.listAllFilteredIds(this.filterRules).subscribe(ids => ids.forEach(id => this.selected.add(id))) + this.documentService + .listAllFilteredIds(this.filterRules) + .subscribe((ids) => ids.forEach((id) => this.selected.add(id))) } selectPage() { this.selected.clear() - this.documents.forEach(doc => { + this.documents.forEach((doc) => { this.selected.add(doc.id) }) } @@ -335,36 +394,58 @@ export class DocumentListViewService { selectRangeTo(d: PaperlessDocument) { if (this.rangeSelectionAnchorIndex !== null) { const documentToIndex = this.documentIndexInCurrentView(d.id) - const fromIndex = Math.min(this.rangeSelectionAnchorIndex, documentToIndex) + const fromIndex = Math.min( + this.rangeSelectionAnchorIndex, + documentToIndex + ) const toIndex = Math.max(this.rangeSelectionAnchorIndex, documentToIndex) if (this.lastRangeSelectionToIndex !== null) { // revert the old selection - this.documents.slice(Math.min(this.rangeSelectionAnchorIndex, this.lastRangeSelectionToIndex), Math.max(this.rangeSelectionAnchorIndex, this.lastRangeSelectionToIndex) + 1).forEach(d => { - this.selected.delete(d.id) - }) + this.documents + .slice( + Math.min( + this.rangeSelectionAnchorIndex, + this.lastRangeSelectionToIndex + ), + Math.max( + this.rangeSelectionAnchorIndex, + this.lastRangeSelectionToIndex + ) + 1 + ) + .forEach((d) => { + this.selected.delete(d.id) + }) } - this.documents.slice(fromIndex, toIndex + 1).forEach(d => { + this.documents.slice(fromIndex, toIndex + 1).forEach((d) => { this.selected.add(d.id) }) this.lastRangeSelectionToIndex = documentToIndex - } else { // e.g. shift key but was first click + } else { + // e.g. shift key but was first click this.toggleSelected(d) } } documentIndexInCurrentView(documentID: number): number { - return this.documents.map(d => d.id).indexOf(documentID) + return this.documents.map((d) => d.id).indexOf(documentID) } - constructor(private documentService: DocumentService, private settings: SettingsService, private router: Router, private route: ActivatedRoute) { - let documentListViewConfigJson = localStorage.getItem(DOCUMENT_LIST_SERVICE.CURRENT_VIEW_CONFIG) + constructor( + private documentService: DocumentService, + private settings: SettingsService, + private router: Router, + private route: ActivatedRoute + ) { + let documentListViewConfigJson = localStorage.getItem( + DOCUMENT_LIST_SERVICE.CURRENT_VIEW_CONFIG + ) if (documentListViewConfigJson) { try { let savedState: ListViewState = JSON.parse(documentListViewConfigJson) // Remove null elements from the restored state - Object.keys(savedState).forEach(k => { + Object.keys(savedState).forEach((k) => { if (savedState[k] == null) { delete savedState[k] } diff --git a/src-ui/src/app/services/open-documents.service.spec.ts b/src-ui/src/app/services/open-documents.service.spec.ts deleted file mode 100644 index c0d0c7a4b..000000000 --- a/src-ui/src/app/services/open-documents.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { OpenDocumentsService } from './open-documents.service'; - -describe('OpenDocumentsService', () => { - let service: OpenDocumentsService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(OpenDocumentsService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/services/open-documents.service.ts b/src-ui/src/app/services/open-documents.service.ts index 92802c765..5297a38bf 100644 --- a/src-ui/src/app/services/open-documents.service.ts +++ b/src-ui/src/app/services/open-documents.service.ts @@ -1,23 +1,27 @@ -import { Injectable } from '@angular/core'; -import { PaperlessDocument } from '../data/paperless-document'; -import { OPEN_DOCUMENT_SERVICE } from '../data/storage-keys'; -import { DocumentService } from './rest/document.service'; -import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; -import { ConfirmDialogComponent } from 'src/app/components/common/confirm-dialog/confirm-dialog.component'; -import { Observable, Subject, of } from 'rxjs'; -import { first } from 'rxjs/operators'; +import { Injectable } from '@angular/core' +import { PaperlessDocument } from '../data/paperless-document' +import { OPEN_DOCUMENT_SERVICE } from '../data/storage-keys' +import { DocumentService } from './rest/document.service' +import { NgbModal } from '@ng-bootstrap/ng-bootstrap' +import { ConfirmDialogComponent } from 'src/app/components/common/confirm-dialog/confirm-dialog.component' +import { Observable, Subject, of } from 'rxjs' +import { first } from 'rxjs/operators' @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class OpenDocumentsService { - private MAX_OPEN_DOCUMENTS = 5 - constructor(private documentService: DocumentService, private modalService: NgbModal) { + constructor( + private documentService: DocumentService, + private modalService: NgbModal + ) { if (sessionStorage.getItem(OPEN_DOCUMENT_SERVICE.DOCUMENTS)) { try { - this.openDocuments = JSON.parse(sessionStorage.getItem(OPEN_DOCUMENT_SERVICE.DOCUMENTS)) + this.openDocuments = JSON.parse( + sessionStorage.getItem(OPEN_DOCUMENT_SERVICE.DOCUMENTS) + ) } catch (e) { sessionStorage.removeItem(OPEN_DOCUMENT_SERVICE.DOCUMENTS) this.openDocuments = [] @@ -29,14 +33,17 @@ export class OpenDocumentsService { private dirtyDocuments: Set = new Set() refreshDocument(id: number) { - let index = this.openDocuments.findIndex(doc => doc.id == id) + let index = this.openDocuments.findIndex((doc) => doc.id == id) if (index > -1) { - this.documentService.get(id).subscribe(doc => { - this.openDocuments[index] = doc - }, error => { - this.openDocuments.splice(index, 1) - this.save() - }) + this.documentService.get(id).subscribe( + (doc) => { + this.openDocuments[index] = doc + }, + (error) => { + this.openDocuments.splice(index, 1) + this.save() + } + ) } } @@ -45,11 +52,11 @@ export class OpenDocumentsService { } getOpenDocument(id: number): PaperlessDocument { - return this.openDocuments.find(d => d.id == id) + return this.openDocuments.find((d) => d.id == id) } openDocument(doc: PaperlessDocument) { - if (this.openDocuments.find(d => d.id == doc.id) == null) { + if (this.openDocuments.find((d) => d.id == doc.id) == null) { this.openDocuments.unshift(doc) if (this.openDocuments.length > this.MAX_OPEN_DOCUMENTS) { this.openDocuments.pop() @@ -64,18 +71,20 @@ export class OpenDocumentsService { } closeDocument(doc: PaperlessDocument): Observable { - let index = this.openDocuments.findIndex(d => d.id == doc.id) - if (index == -1) return of(true); + let index = this.openDocuments.findIndex((d) => d.id == doc.id) + if (index == -1) return of(true) if (!this.dirtyDocuments.has(doc.id)) { this.openDocuments.splice(index, 1) this.save() return of(true) } else { - let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) + let modal = this.modalService.open(ConfirmDialogComponent, { + backdrop: 'static', + }) modal.componentInstance.title = $localize`Unsaved Changes` modal.componentInstance.messageBold = $localize`You have unsaved changes.` modal.componentInstance.message = $localize`Are you sure you want to close this document?` - modal.componentInstance.btnClass = "btn-warning" + modal.componentInstance.btnClass = 'btn-warning' modal.componentInstance.btnCaption = $localize`Close document` modal.componentInstance.confirmClicked.pipe(first()).subscribe(() => { modal.componentInstance.buttonsEnabled = false @@ -92,11 +101,13 @@ export class OpenDocumentsService { closeAll(): Observable { if (this.dirtyDocuments.size) { - let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) + let modal = this.modalService.open(ConfirmDialogComponent, { + backdrop: 'static', + }) modal.componentInstance.title = $localize`Unsaved Changes` modal.componentInstance.messageBold = $localize`You have unsaved changes.` modal.componentInstance.message = $localize`Are you sure you want to close all documents?` - modal.componentInstance.btnClass = "btn-warning" + modal.componentInstance.btnClass = 'btn-warning' modal.componentInstance.btnCaption = $localize`Close documents` modal.componentInstance.confirmClicked.pipe(first()).subscribe(() => { modal.componentInstance.buttonsEnabled = false @@ -117,7 +128,9 @@ export class OpenDocumentsService { } save() { - sessionStorage.setItem(OPEN_DOCUMENT_SERVICE.DOCUMENTS, JSON.stringify(this.openDocuments)) + sessionStorage.setItem( + OPEN_DOCUMENT_SERVICE.DOCUMENTS, + JSON.stringify(this.openDocuments) + ) } - } diff --git a/src-ui/src/app/services/rest/abstract-name-filter-service.ts b/src-ui/src/app/services/rest/abstract-name-filter-service.ts index d605fef49..568803fb8 100644 --- a/src-ui/src/app/services/rest/abstract-name-filter-service.ts +++ b/src-ui/src/app/services/rest/abstract-name-filter-service.ts @@ -1,14 +1,20 @@ import { ObjectWithId } from 'src/app/data/object-with-id' import { AbstractPaperlessService } from './abstract-paperless-service' -export abstract class AbstractNameFilterService extends AbstractPaperlessService { - - listFiltered(page?: number, pageSize?: number, sortField?: string, sortReverse?: boolean, nameFilter?: string) { +export abstract class AbstractNameFilterService< + T extends ObjectWithId +> extends AbstractPaperlessService { + listFiltered( + page?: number, + pageSize?: number, + sortField?: string, + sortReverse?: boolean, + nameFilter?: string + ) { let params = {} if (nameFilter) { - params = {'name__icontains': nameFilter} + params = { name__icontains: nameFilter } } return this.list(page, pageSize, sortField, sortReverse, params) } - } diff --git a/src-ui/src/app/services/rest/abstract-paperless-service.spec.ts b/src-ui/src/app/services/rest/abstract-paperless-service.spec.ts deleted file mode 100644 index f95a9cb39..000000000 --- a/src-ui/src/app/services/rest/abstract-paperless-service.spec.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { AbstractPaperlessService } from './abstract-paperless-service'; - -describe('AbstractPaperlessService', () => { - it('should create an instance', () => { - expect(new AbstractPaperlessService()).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/services/rest/abstract-paperless-service.ts b/src-ui/src/app/services/rest/abstract-paperless-service.ts index 8ad1a2141..9a5664c9d 100644 --- a/src-ui/src/app/services/rest/abstract-paperless-service.ts +++ b/src-ui/src/app/services/rest/abstract-paperless-service.ts @@ -6,10 +6,9 @@ import { Results } from 'src/app/data/results' import { environment } from 'src/environments/environment' export abstract class AbstractPaperlessService { - protected baseUrl: string = environment.apiBaseUrl - constructor(protected http: HttpClient, private resourceName: string) { } + constructor(protected http: HttpClient, private resourceName: string) {} protected getResourceUrl(id?: number, action?: string): string { let url = `${this.baseUrl}${this.resourceName}/` @@ -30,7 +29,13 @@ export abstract class AbstractPaperlessService { } } - list(page?: number, pageSize?: number, sortField?: string, sortReverse?: boolean, extraParams?): Observable> { + list( + page?: number, + pageSize?: number, + sortField?: string, + sortReverse?: boolean, + extraParams? + ): Observable> { let httpParams = new HttpParams() if (page) { httpParams = httpParams.set('page', page.toString()) @@ -47,30 +52,39 @@ export abstract class AbstractPaperlessService { httpParams = httpParams.set(extraParamKey, extraParams[extraParamKey]) } } - return this.http.get>(this.getResourceUrl(), {params: httpParams}) + return this.http.get>(this.getResourceUrl(), { + params: httpParams, + }) } private _listAll: Observable> - listAll(sortField?: string, sortReverse?: boolean, extraParams?): Observable> { + listAll( + sortField?: string, + sortReverse?: boolean, + extraParams? + ): Observable> { if (!this._listAll) { - this._listAll = this.list(1, 100000, sortField, sortReverse, extraParams).pipe( - publishReplay(1), - refCount() - ) + this._listAll = this.list( + 1, + 100000, + sortField, + sortReverse, + extraParams + ).pipe(publishReplay(1), refCount()) } return this._listAll } getCached(id: number): Observable { return this.listAll().pipe( - map(list => list.results.find(o => o.id == id)) + map((list) => list.results.find((o) => o.id == id)) ) } getCachedMany(ids: number[]): Observable { return this.listAll().pipe( - map(list => ids.map(id => list.results.find(o => o.id == id))) + map((list) => ids.map((id) => list.results.find((o) => o.id == id))) ) } @@ -101,5 +115,4 @@ export abstract class AbstractPaperlessService { this.clearCache() return this.http.patch(this.getResourceUrl(o.id), o) } - } diff --git a/src-ui/src/app/services/rest/correspondent.service.spec.ts b/src-ui/src/app/services/rest/correspondent.service.spec.ts deleted file mode 100644 index a3377fded..000000000 --- a/src-ui/src/app/services/rest/correspondent.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { CorrespondentService } from './correspondent.service'; - -describe('CorrespondentService', () => { - let service: CorrespondentService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(CorrespondentService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/services/rest/correspondent.service.ts b/src-ui/src/app/services/rest/correspondent.service.ts index 7eac24971..c56dcce5a 100644 --- a/src-ui/src/app/services/rest/correspondent.service.ts +++ b/src-ui/src/app/services/rest/correspondent.service.ts @@ -1,15 +1,13 @@ -import { HttpClient } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent'; -import { AbstractNameFilterService } from './abstract-name-filter-service'; +import { HttpClient } from '@angular/common/http' +import { Injectable } from '@angular/core' +import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent' +import { AbstractNameFilterService } from './abstract-name-filter-service' @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class CorrespondentService extends AbstractNameFilterService { - constructor(http: HttpClient) { super(http, 'correspondents') } - } diff --git a/src-ui/src/app/services/rest/document-type.service.spec.ts b/src-ui/src/app/services/rest/document-type.service.spec.ts deleted file mode 100644 index adcca11ef..000000000 --- a/src-ui/src/app/services/rest/document-type.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { DocumentTypeService } from './document-type.service'; - -describe('DocumentTypeService', () => { - let service: DocumentTypeService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(DocumentTypeService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/services/rest/document-type.service.ts b/src-ui/src/app/services/rest/document-type.service.ts index 4f5b7d0ce..e2d96cb3a 100644 --- a/src-ui/src/app/services/rest/document-type.service.ts +++ b/src-ui/src/app/services/rest/document-type.service.ts @@ -1,13 +1,12 @@ -import { HttpClient } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { PaperlessDocumentType } from 'src/app/data/paperless-document-type'; -import { AbstractNameFilterService } from './abstract-name-filter-service'; +import { HttpClient } from '@angular/common/http' +import { Injectable } from '@angular/core' +import { PaperlessDocumentType } from 'src/app/data/paperless-document-type' +import { AbstractNameFilterService } from './abstract-name-filter-service' @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class DocumentTypeService extends AbstractNameFilterService { - constructor(http: HttpClient) { super(http, 'document_types') } diff --git a/src-ui/src/app/services/rest/document.service.spec.ts b/src-ui/src/app/services/rest/document.service.spec.ts deleted file mode 100644 index 49475199d..000000000 --- a/src-ui/src/app/services/rest/document.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { DocumentService } from './document.service'; - -describe('DocumentService', () => { - let service: DocumentService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(DocumentService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/services/rest/document.service.ts b/src-ui/src/app/services/rest/document.service.ts index c6bc61dc8..d06282bb8 100644 --- a/src-ui/src/app/services/rest/document.service.ts +++ b/src-ui/src/app/services/rest/document.service.ts @@ -1,31 +1,34 @@ -import { Injectable } from '@angular/core'; -import { PaperlessDocument } from 'src/app/data/paperless-document'; -import { PaperlessDocumentMetadata } from 'src/app/data/paperless-document-metadata'; -import { AbstractPaperlessService } from './abstract-paperless-service'; -import { HttpClient, HttpParams } from '@angular/common/http'; -import { Observable } from 'rxjs'; -import { Results } from 'src/app/data/results'; -import { FilterRule } from 'src/app/data/filter-rule'; -import { map } from 'rxjs/operators'; -import { CorrespondentService } from './correspondent.service'; -import { DocumentTypeService } from './document-type.service'; -import { TagService } from './tag.service'; -import { FILTER_RULE_TYPES } from 'src/app/data/filter-rule-type'; -import { PaperlessDocumentSuggestions } from 'src/app/data/paperless-document-suggestions'; +import { Injectable } from '@angular/core' +import { PaperlessDocument } from 'src/app/data/paperless-document' +import { PaperlessDocumentMetadata } from 'src/app/data/paperless-document-metadata' +import { AbstractPaperlessService } from './abstract-paperless-service' +import { HttpClient, HttpParams } from '@angular/common/http' +import { Observable } from 'rxjs' +import { Results } from 'src/app/data/results' +import { FilterRule } from 'src/app/data/filter-rule' +import { map } from 'rxjs/operators' +import { CorrespondentService } from './correspondent.service' +import { DocumentTypeService } from './document-type.service' +import { TagService } from './tag.service' +import { FILTER_RULE_TYPES } from 'src/app/data/filter-rule-type' +import { PaperlessDocumentSuggestions } from 'src/app/data/paperless-document-suggestions' export const DOCUMENT_SORT_FIELDS = [ { field: 'archive_serial_number', name: $localize`ASN` }, - { field: "correspondent__name", name: $localize`Correspondent` }, + { field: 'correspondent__name', name: $localize`Correspondent` }, { field: 'title', name: $localize`Title` }, - { field: "document_type__name", name: $localize`Document type` }, + { field: 'document_type__name', name: $localize`Document type` }, { field: 'created', name: $localize`Created` }, { field: 'added', name: $localize`Added` }, - { field: 'modified', name: $localize`Modified` } + { field: 'modified', name: $localize`Modified` }, ] export const DOCUMENT_SORT_FIELDS_FULLTEXT = [ ...DOCUMENT_SORT_FIELDS, - { field: 'score', name: $localize`:Score is a value returned by the full text search engine and specifies how well a result matches the given query:Search score` } + { + field: 'score', + name: $localize`:Score is a value returned by the full text search engine and specifies how well a result matches the given query:Search score`, + }, ] export interface SelectionDataItem { @@ -40,23 +43,29 @@ export interface SelectionData { } @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class DocumentService extends AbstractPaperlessService { - private _searchQuery: string - constructor(http: HttpClient, private correspondentService: CorrespondentService, private documentTypeService: DocumentTypeService, private tagService: TagService) { + constructor( + http: HttpClient, + private correspondentService: CorrespondentService, + private documentTypeService: DocumentTypeService, + private tagService: TagService + ) { super(http, 'documents') } - private filterRulesToQueryParams(filterRules: FilterRule[]) { + public filterRulesToQueryParams(filterRules: FilterRule[]): Object { if (filterRules) { let params = {} for (let rule of filterRules) { - let ruleType = FILTER_RULE_TYPES.find(t => t.id == rule.rule_type) + let ruleType = FILTER_RULE_TYPES.find((t) => t.id == rule.rule_type) if (ruleType.multi) { - params[ruleType.filtervar] = params[ruleType.filtervar] ? params[ruleType.filtervar] + "," + rule.value : rule.value + params[ruleType.filtervar] = params[ruleType.filtervar] + ? params[ruleType.filtervar] + ',' + rule.value + : rule.value } else if (ruleType.isnull_filtervar && rule.value == null) { params[ruleType.isnull_filtervar] = true } else { @@ -71,7 +80,9 @@ export class DocumentService extends AbstractPaperlessService addObservablesToDocument(doc: PaperlessDocument) { if (doc.correspondent) { - doc.correspondent$ = this.correspondentService.getCached(doc.correspondent) + doc.correspondent$ = this.correspondentService.getCached( + doc.correspondent + ) } if (doc.document_type) { doc.document_type$ = this.documentTypeService.getCached(doc.document_type) @@ -82,26 +93,39 @@ export class DocumentService extends AbstractPaperlessService return doc } - listFiltered(page?: number, pageSize?: number, sortField?: string, sortReverse?: boolean, filterRules?: FilterRule[], extraParams = {}): Observable> { - return this.list(page, pageSize, sortField, sortReverse, Object.assign(extraParams, this.filterRulesToQueryParams(filterRules))).pipe( - map(results => { - results.results.forEach(doc => this.addObservablesToDocument(doc)) + listFiltered( + page?: number, + pageSize?: number, + sortField?: string, + sortReverse?: boolean, + filterRules?: FilterRule[], + extraParams = {} + ): Observable> { + return this.list( + page, + pageSize, + sortField, + sortReverse, + Object.assign(extraParams, this.filterRulesToQueryParams(filterRules)) + ).pipe( + map((results) => { + results.results.forEach((doc) => this.addObservablesToDocument(doc)) return results }) ) } listAllFilteredIds(filterRules?: FilterRule[]): Observable { - return this.listFiltered(1, 100000, null, null, filterRules, {"fields": "id"}).pipe( - map(response => response.results.map(doc => doc.id)) - ) + return this.listFiltered(1, 100000, null, null, filterRules, { + fields: 'id', + }).pipe(map((response) => response.results.map((doc) => doc.id))) } getPreviewUrl(id: number, original: boolean = false): string { let url = this.getResourceUrl(id, 'preview') if (this._searchQuery) url += `#search="${this._searchQuery}"` if (original) { - url += "?original=true" + url += '?original=true' } return url } @@ -113,41 +137,55 @@ export class DocumentService extends AbstractPaperlessService getDownloadUrl(id: number, original: boolean = false): string { let url = this.getResourceUrl(id, 'download') if (original) { - url += "?original=true" + url += '?original=true' } return url } uploadDocument(formData) { - return this.http.post(this.getResourceUrl(null, 'post_document'), formData, {reportProgress: true, observe: "events"}) + return this.http.post( + this.getResourceUrl(null, 'post_document'), + formData, + { reportProgress: true, observe: 'events' } + ) } getMetadata(id: number): Observable { - return this.http.get(this.getResourceUrl(id, 'metadata')) + return this.http.get( + this.getResourceUrl(id, 'metadata') + ) } bulkEdit(ids: number[], method: string, args: any) { return this.http.post(this.getResourceUrl(null, 'bulk_edit'), { - 'documents': ids, - 'method': method, - 'parameters': args + documents: ids, + method: method, + parameters: args, }) } getSelectionData(ids: number[]): Observable { - return this.http.post(this.getResourceUrl(null, 'selection_data'), {"documents": ids}) + return this.http.post( + this.getResourceUrl(null, 'selection_data'), + { documents: ids } + ) } getSuggestions(id: number): Observable { - return this.http.get(this.getResourceUrl(id, 'suggestions')) + return this.http.get( + this.getResourceUrl(id, 'suggestions') + ) } - bulkDownload(ids: number[], content="both") { - return this.http.post(this.getResourceUrl(null, 'bulk_download'), {"documents": ids, "content": content}, { responseType: 'blob' }) + bulkDownload(ids: number[], content = 'both') { + return this.http.post( + this.getResourceUrl(null, 'bulk_download'), + { documents: ids, content: content }, + { responseType: 'blob' } + ) } public set searchQuery(query: string) { this._searchQuery = query } - } diff --git a/src-ui/src/app/services/rest/log.service.spec.ts b/src-ui/src/app/services/rest/log.service.spec.ts deleted file mode 100644 index 4a99f7727..000000000 --- a/src-ui/src/app/services/rest/log.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { LogService } from './log.service'; - -describe('LogService', () => { - let service: LogService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(LogService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/services/rest/log.service.ts b/src-ui/src/app/services/rest/log.service.ts index 3abf2fb6f..d1a797eeb 100644 --- a/src-ui/src/app/services/rest/log.service.ts +++ b/src-ui/src/app/services/rest/log.service.ts @@ -1,15 +1,13 @@ -import { HttpClient } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; -import { environment } from 'src/environments/environment'; +import { HttpClient } from '@angular/common/http' +import { Injectable } from '@angular/core' +import { Observable } from 'rxjs' +import { environment } from 'src/environments/environment' @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class LogService { - - constructor(private http: HttpClient) { - } + constructor(private http: HttpClient) {} list(): Observable { return this.http.get(`${environment.apiBaseUrl}logs/`) diff --git a/src-ui/src/app/services/rest/remote-version.service.ts b/src-ui/src/app/services/rest/remote-version.service.ts new file mode 100644 index 000000000..ab1b5a66b --- /dev/null +++ b/src-ui/src/app/services/rest/remote-version.service.ts @@ -0,0 +1,23 @@ +import { HttpClient } from '@angular/common/http' +import { Injectable } from '@angular/core' +import { map, Observable } from 'rxjs' +import { environment } from 'src/environments/environment' + +export interface AppRemoteVersion { + version: string + update_available: boolean + feature_is_set: boolean +} + +@Injectable({ + providedIn: 'root', +}) +export class RemoteVersionService { + constructor(private http: HttpClient) {} + + public checkForUpdates(): Observable { + return this.http.get( + `${environment.apiBaseUrl}remote_version/` + ) + } +} diff --git a/src-ui/src/app/services/rest/saved-view.service.spec.ts b/src-ui/src/app/services/rest/saved-view.service.spec.ts deleted file mode 100644 index 588cf6347..000000000 --- a/src-ui/src/app/services/rest/saved-view.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { SavedViewService } from './saved-view.service'; - -describe('SavedViewService', () => { - let service: SavedViewService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(SavedViewService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/services/rest/saved-view.service.ts b/src-ui/src/app/services/rest/saved-view.service.ts index c765de7f4..dae205cb3 100644 --- a/src-ui/src/app/services/rest/saved-view.service.ts +++ b/src-ui/src/app/services/rest/saved-view.service.ts @@ -1,22 +1,21 @@ -import { HttpClient } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { combineLatest, Observable } from 'rxjs'; -import { tap } from 'rxjs/operators'; -import { PaperlessSavedView } from 'src/app/data/paperless-saved-view'; -import { AbstractPaperlessService } from './abstract-paperless-service'; +import { HttpClient } from '@angular/common/http' +import { Injectable } from '@angular/core' +import { combineLatest, Observable } from 'rxjs' +import { tap } from 'rxjs/operators' +import { PaperlessSavedView } from 'src/app/data/paperless-saved-view' +import { AbstractPaperlessService } from './abstract-paperless-service' @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class SavedViewService extends AbstractPaperlessService { - constructor(http: HttpClient) { super(http, 'saved_views') this.reload() } private reload() { - this.listAll().subscribe(r => this.savedViews = r.results) + this.listAll().subscribe((r) => (this.savedViews = r.results)) } private savedViews: PaperlessSavedView[] = [] @@ -26,34 +25,28 @@ export class SavedViewService extends AbstractPaperlessService v.show_in_sidebar) + return this.savedViews.filter((v) => v.show_in_sidebar) } get dashboardViews() { - return this.savedViews.filter(v => v.show_on_dashboard) + return this.savedViews.filter((v) => v.show_on_dashboard) } create(o: PaperlessSavedView) { - return super.create(o).pipe( - tap(() => this.reload()) - ) + return super.create(o).pipe(tap(() => this.reload())) } update(o: PaperlessSavedView) { - return super.update(o).pipe( - tap(() => this.reload()) - ) + return super.update(o).pipe(tap(() => this.reload())) } patchMany(objects: PaperlessSavedView[]): Observable { - return combineLatest(objects.map(o => super.patch(o))).pipe( + return combineLatest(objects.map((o) => super.patch(o))).pipe( tap(() => this.reload()) ) } delete(o: PaperlessSavedView) { - return super.delete(o).pipe( - tap(() => this.reload()) - ) + return super.delete(o).pipe(tap(() => this.reload())) } } diff --git a/src-ui/src/app/services/rest/search.service.spec.ts b/src-ui/src/app/services/rest/search.service.spec.ts deleted file mode 100644 index 23c42c7bb..000000000 --- a/src-ui/src/app/services/rest/search.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { SearchService } from './search.service'; - -describe('SearchService', () => { - let service: SearchService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(SearchService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/services/rest/search.service.ts b/src-ui/src/app/services/rest/search.service.ts index c14a5c58f..4a75230d9 100644 --- a/src-ui/src/app/services/rest/search.service.ts +++ b/src-ui/src/app/services/rest/search.service.ts @@ -1,19 +1,20 @@ -import { HttpClient, HttpParams } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; -import { map } from 'rxjs/operators'; -import { environment } from 'src/environments/environment'; -import { DocumentService } from './document.service'; - +import { HttpClient, HttpParams } from '@angular/common/http' +import { Injectable } from '@angular/core' +import { Observable } from 'rxjs' +import { map } from 'rxjs/operators' +import { environment } from 'src/environments/environment' +import { DocumentService } from './document.service' @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class SearchService { - - constructor(private http: HttpClient) { } + constructor(private http: HttpClient) {} autocomplete(term: string): Observable { - return this.http.get(`${environment.apiBaseUrl}search/autocomplete/`, {params: new HttpParams().set('term', term)}) + return this.http.get( + `${environment.apiBaseUrl}search/autocomplete/`, + { params: new HttpParams().set('term', term) } + ) } } diff --git a/src-ui/src/app/services/rest/tag.service.spec.ts b/src-ui/src/app/services/rest/tag.service.spec.ts deleted file mode 100644 index f091e933f..000000000 --- a/src-ui/src/app/services/rest/tag.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { TagService } from './tag.service'; - -describe('TagService', () => { - let service: TagService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(TagService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/services/rest/tag.service.ts b/src-ui/src/app/services/rest/tag.service.ts index 7bc55b0c9..f15369c62 100644 --- a/src-ui/src/app/services/rest/tag.service.ts +++ b/src-ui/src/app/services/rest/tag.service.ts @@ -1,13 +1,12 @@ -import { HttpClient } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { PaperlessTag } from 'src/app/data/paperless-tag'; -import { AbstractNameFilterService } from './abstract-name-filter-service'; +import { HttpClient } from '@angular/common/http' +import { Injectable } from '@angular/core' +import { PaperlessTag } from 'src/app/data/paperless-tag' +import { AbstractNameFilterService } from './abstract-name-filter-service' @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class TagService extends AbstractNameFilterService { - constructor(http: HttpClient) { super(http, 'tags') } diff --git a/src-ui/src/app/services/settings.service.spec.ts b/src-ui/src/app/services/settings.service.spec.ts deleted file mode 100644 index 359cb6b7a..000000000 --- a/src-ui/src/app/services/settings.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { SettingsService } from './settings.service'; - -describe('SettingsService', () => { - let service: SettingsService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(SettingsService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/services/settings.service.ts b/src-ui/src/app/services/settings.service.ts index 35f157226..1a424e4ca 100644 --- a/src-ui/src/app/services/settings.service.ts +++ b/src-ui/src/app/services/settings.service.ts @@ -1,7 +1,19 @@ -import { DOCUMENT } from '@angular/common'; -import { Inject, Injectable, LOCALE_ID, Renderer2, RendererFactory2 } from '@angular/core'; -import { Meta } from '@angular/platform-browser'; -import { CookieService } from 'ngx-cookie-service'; +import { DOCUMENT } from '@angular/common' +import { + Inject, + Injectable, + LOCALE_ID, + Renderer2, + RendererFactory2, + RendererStyleFlags2, +} from '@angular/core' +import { Meta } from '@angular/platform-browser' +import { CookieService } from 'ngx-cookie-service' +import { + BRIGHTNESS, + estimateBrightnessForColor, + hexToHsl, +} from 'src/app/utils/color' export interface PaperlessSettings { key: string @@ -21,43 +33,77 @@ export interface LanguageOption { } export const SETTINGS_KEYS = { - BULK_EDIT_CONFIRMATION_DIALOGS: 'general-settings:bulk-edit:confirmation-dialogs', + BULK_EDIT_CONFIRMATION_DIALOGS: + 'general-settings:bulk-edit:confirmation-dialogs', BULK_EDIT_APPLY_ON_CLOSE: 'general-settings:bulk-edit:apply-on-close', DOCUMENT_LIST_SIZE: 'general-settings:documentListSize', DARK_MODE_USE_SYSTEM: 'general-settings:dark-mode:use-system', DARK_MODE_ENABLED: 'general-settings:dark-mode:enabled', DARK_MODE_THUMB_INVERTED: 'general-settings:dark-mode:thumb-inverted', + THEME_COLOR: 'general-settings:theme:color', USE_NATIVE_PDF_VIEWER: 'general-settings:document-details:native-pdf-viewer', DATE_LOCALE: 'general-settings:date-display:date-locale', DATE_FORMAT: 'general-settings:date-display:date-format', - NOTIFICATIONS_CONSUMER_NEW_DOCUMENT: 'general-settings:notifications:consumer-new-documents', - NOTIFICATIONS_CONSUMER_SUCCESS: 'general-settings:notifications:consumer-success', - NOTIFICATIONS_CONSUMER_FAILED: 'general-settings:notifications:consumer-failed', - NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD: 'general-settings:notifications:consumer-suppress-on-dashboard', + NOTIFICATIONS_CONSUMER_NEW_DOCUMENT: + 'general-settings:notifications:consumer-new-documents', + NOTIFICATIONS_CONSUMER_SUCCESS: + 'general-settings:notifications:consumer-success', + NOTIFICATIONS_CONSUMER_FAILED: + 'general-settings:notifications:consumer-failed', + NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD: + 'general-settings:notifications:consumer-suppress-on-dashboard', } const SETTINGS: PaperlessSettings[] = [ - {key: SETTINGS_KEYS.BULK_EDIT_CONFIRMATION_DIALOGS, type: "boolean", default: true}, - {key: SETTINGS_KEYS.BULK_EDIT_APPLY_ON_CLOSE, type: "boolean", default: false}, - {key: SETTINGS_KEYS.DOCUMENT_LIST_SIZE, type: "number", default: 50}, - {key: SETTINGS_KEYS.DARK_MODE_USE_SYSTEM, type: "boolean", default: true}, - {key: SETTINGS_KEYS.DARK_MODE_ENABLED, type: "boolean", default: false}, - {key: SETTINGS_KEYS.DARK_MODE_THUMB_INVERTED, type: "boolean", default: true}, - {key: SETTINGS_KEYS.USE_NATIVE_PDF_VIEWER, type: "boolean", default: false}, - {key: SETTINGS_KEYS.DATE_LOCALE, type: "string", default: ""}, - {key: SETTINGS_KEYS.DATE_FORMAT, type: "string", default: "mediumDate"}, - {key: SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_NEW_DOCUMENT, type: "boolean", default: true}, - {key: SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUCCESS, type: "boolean", default: true}, - {key: SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_FAILED, type: "boolean", default: true}, - {key: SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD, type: "boolean", default: true}, + { + key: SETTINGS_KEYS.BULK_EDIT_CONFIRMATION_DIALOGS, + type: 'boolean', + default: true, + }, + { + key: SETTINGS_KEYS.BULK_EDIT_APPLY_ON_CLOSE, + type: 'boolean', + default: false, + }, + { key: SETTINGS_KEYS.DOCUMENT_LIST_SIZE, type: 'number', default: 50 }, + { key: SETTINGS_KEYS.DARK_MODE_USE_SYSTEM, type: 'boolean', default: true }, + { key: SETTINGS_KEYS.DARK_MODE_ENABLED, type: 'boolean', default: false }, + { + key: SETTINGS_KEYS.DARK_MODE_THUMB_INVERTED, + type: 'boolean', + default: true, + }, + { key: SETTINGS_KEYS.THEME_COLOR, type: 'string', default: '' }, + { key: SETTINGS_KEYS.USE_NATIVE_PDF_VIEWER, type: 'boolean', default: false }, + { key: SETTINGS_KEYS.DATE_LOCALE, type: 'string', default: '' }, + { key: SETTINGS_KEYS.DATE_FORMAT, type: 'string', default: 'mediumDate' }, + { + key: SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_NEW_DOCUMENT, + type: 'boolean', + default: true, + }, + { + key: SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUCCESS, + type: 'boolean', + default: true, + }, + { + key: SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_FAILED, + type: 'boolean', + default: true, + }, + { + key: SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD, + type: 'boolean', + default: true, + }, ] @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class SettingsService { - - private renderer: Renderer2; + private renderer: Renderer2 constructor( private rendererFactory: RendererFactory2, @@ -66,58 +112,220 @@ export class SettingsService { private meta: Meta, @Inject(LOCALE_ID) private localeId: string ) { - this.renderer = rendererFactory.createRenderer(null, null); + this.renderer = rendererFactory.createRenderer(null, null) - this.updateDarkModeSettings() + this.updateAppearanceSettings() } - updateDarkModeSettings(): void { - let darkModeUseSystem = this.get(SETTINGS_KEYS.DARK_MODE_USE_SYSTEM) - let darkModeEnabled = this.get(SETTINGS_KEYS.DARK_MODE_ENABLED) + public updateAppearanceSettings( + darkModeUseSystem = null, + darkModeEnabled = null, + themeColor = null + ): void { + darkModeUseSystem ??= this.get(SETTINGS_KEYS.DARK_MODE_USE_SYSTEM) + darkModeEnabled ??= this.get(SETTINGS_KEYS.DARK_MODE_ENABLED) + themeColor ??= this.get(SETTINGS_KEYS.THEME_COLOR) if (darkModeUseSystem) { this.renderer.addClass(this.document.body, 'color-scheme-system') this.renderer.removeClass(this.document.body, 'color-scheme-dark') } else { this.renderer.removeClass(this.document.body, 'color-scheme-system') - darkModeEnabled ? this.renderer.addClass(this.document.body, 'color-scheme-dark') : this.renderer.removeClass(this.document.body, 'color-scheme-dark') + darkModeEnabled + ? this.renderer.addClass(this.document.body, 'color-scheme-dark') + : this.renderer.removeClass(this.document.body, 'color-scheme-dark') } + // remove these in case they were there + this.renderer.removeClass(this.document.body, 'primary-dark') + this.renderer.removeClass(this.document.body, 'primary-light') + + if (themeColor) { + const hsl = hexToHsl(themeColor) + const bgBrightnessEstimate = estimateBrightnessForColor(themeColor) + + if (bgBrightnessEstimate == BRIGHTNESS.DARK) { + this.renderer.addClass(this.document.body, 'primary-dark') + this.renderer.removeClass(this.document.body, 'primary-light') + } else { + this.renderer.addClass(this.document.body, 'primary-light') + this.renderer.removeClass(this.document.body, 'primary-dark') + } + this.renderer.setStyle( + document.body, + '--pngx-primary', + `${+hsl.h * 360},${hsl.s * 100}%`, + RendererStyleFlags2.DashCase + ) + this.renderer.setStyle( + document.body, + '--pngx-primary-lightness', + `${hsl.l * 100}%`, + RendererStyleFlags2.DashCase + ) + } else { + this.renderer.removeStyle( + document.body, + '--pngx-primary', + RendererStyleFlags2.DashCase + ) + this.renderer.removeStyle( + document.body, + '--pngx-primary-lightness', + RendererStyleFlags2.DashCase + ) + } } getLanguageOptions(): LanguageOption[] { const languages = [ - {code: "en-us", name: $localize`English (US)`, englishName: "English (US)", dateInputFormat: "mm/dd/yyyy"}, - {code: "cs-cz", name: $localize`Czech`, englishName: "Czech", dateInputFormat: "dd.mm.yyyy"}, - {code: "da-dk", name: $localize`Danish`, englishName: "Danish", dateInputFormat: "dd.mm.yyyy"}, - {code: "de-de", name: $localize`German`, englishName: "German", dateInputFormat: "dd.mm.yyyy"}, - {code: "en-gb", name: $localize`English (GB)`, englishName: "English (GB)", dateInputFormat: "dd/mm/yyyy"}, - {code: "es-es", name: $localize`Spanish`, englishName: "Spanish", dateInputFormat: "dd/mm/yyyy"}, - {code: "fr-fr", name: $localize`French`, englishName: "French", dateInputFormat: "dd/mm/yyyy"}, - {code: "it-it", name: $localize`Italian`, englishName: "Italian", dateInputFormat: "dd/mm/yyyy"}, - {code: "lb-lu", name: $localize`Luxembourgish`, englishName: "Luxembourgish", dateInputFormat: "dd.mm.yyyy"}, - {code: "nl-nl", name: $localize`Dutch`, englishName: "Dutch", dateInputFormat: "dd-mm-yyyy"}, - {code: "pl-pl", name: $localize`Polish`, englishName: "Polish", dateInputFormat: "dd.mm.yyyy"}, - {code: "pt-br", name: $localize`Portuguese (Brazil)`, englishName: "Portuguese (Brazil)", dateInputFormat: "dd/mm/yyyy"}, - {code: "pt-pt", name: $localize`Portuguese`, englishName: "Portuguese", dateInputFormat: "dd/mm/yyyy"}, - {code: "ro-ro", name: $localize`Romanian`, englishName: "Romanian", dateInputFormat: "dd.mm.yyyy"}, - {code: "ru-ru", name: $localize`Russian`, englishName: "Russian", dateInputFormat: "dd.mm.yyyy"}, - {code: "sv-se", name: $localize`Swedish`, englishName: "Swedish", dateInputFormat: "yyyy-mm-dd"} + { + code: 'en-us', + name: $localize`English (US)`, + englishName: 'English (US)', + dateInputFormat: 'mm/dd/yyyy', + }, + { + code: 'be-by', + name: $localize`Belarusian`, + englishName: 'Belarusian', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'cs-cz', + name: $localize`Czech`, + englishName: 'Czech', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'da-dk', + name: $localize`Danish`, + englishName: 'Danish', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'de-de', + name: $localize`German`, + englishName: 'German', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'en-gb', + name: $localize`English (GB)`, + englishName: 'English (GB)', + dateInputFormat: 'dd/mm/yyyy', + }, + { + code: 'es-es', + name: $localize`Spanish`, + englishName: 'Spanish', + dateInputFormat: 'dd/mm/yyyy', + }, + { + code: 'fr-fr', + name: $localize`French`, + englishName: 'French', + dateInputFormat: 'dd/mm/yyyy', + }, + { + code: 'it-it', + name: $localize`Italian`, + englishName: 'Italian', + dateInputFormat: 'dd/mm/yyyy', + }, + { + code: 'lb-lu', + name: $localize`Luxembourgish`, + englishName: 'Luxembourgish', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'nl-nl', + name: $localize`Dutch`, + englishName: 'Dutch', + dateInputFormat: 'dd-mm-yyyy', + }, + { + code: 'pl-pl', + name: $localize`Polish`, + englishName: 'Polish', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'pt-br', + name: $localize`Portuguese (Brazil)`, + englishName: 'Portuguese (Brazil)', + dateInputFormat: 'dd/mm/yyyy', + }, + { + code: 'pt-pt', + name: $localize`Portuguese`, + englishName: 'Portuguese', + dateInputFormat: 'dd/mm/yyyy', + }, + { + code: 'ro-ro', + name: $localize`Romanian`, + englishName: 'Romanian', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'ru-ru', + name: $localize`Russian`, + englishName: 'Russian', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'sl-si', + name: $localize`Slovenian`, + englishName: 'Slovenian', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'sr-cs', + name: $localize`Serbian`, + englishName: 'Serbian', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'sv-se', + name: $localize`Swedish`, + englishName: 'Swedish', + dateInputFormat: 'yyyy-mm-dd', + }, + { + code: 'tr-tr', + name: $localize`Turkish`, + englishName: 'Turkish', + dateInputFormat: 'yyyy-mm-dd', + }, + { + code: 'zh-cn', + name: $localize`Chinese Simplified`, + englishName: 'Chinese Simplified', + dateInputFormat: 'yyyy-mm-dd', + }, ] // Sort languages by localized name at runtime - languages.sort((a, b) => { return a.name < b.name ? -1 : 1 }) + languages.sort((a, b) => { + return a.name < b.name ? -1 : 1 + }) return languages } getDateLocaleOptions(): LanguageOption[] { - let isoOption: LanguageOption = {code: "iso-8601", name: $localize`ISO 8601`, dateInputFormat: "yyyy-mm-dd"} + let isoOption: LanguageOption = { + code: 'iso-8601', + name: $localize`ISO 8601`, + dateInputFormat: 'yyyy-mm-dd', + } return [isoOption].concat(this.getLanguageOptions()) } private getLanguageCookieName() { - let prefix = "" + let prefix = '' if (this.meta.getTag('name=cookie_prefix')) { prefix = this.meta.getTag('name=cookie_prefix').content } @@ -137,12 +345,18 @@ export class SettingsService { } getLocalizedDateInputFormat(): string { - let dateLocale = this.get(SETTINGS_KEYS.DATE_LOCALE) || this.getLanguage() || this.localeId.toLowerCase() - return this.getDateLocaleOptions().find(o => o.code == dateLocale)?.dateInputFormat || "yyyy-mm-dd" + let dateLocale = + this.get(SETTINGS_KEYS.DATE_LOCALE) || + this.getLanguage() || + this.localeId.toLowerCase() + return ( + this.getDateLocaleOptions().find((o) => o.code == dateLocale) + ?.dateInputFormat || 'yyyy-mm-dd' + ) } get(key: string): any { - let setting = SETTINGS.find(s => s.key == key) + let setting = SETTINGS.find((s) => s.key == key) if (!setting) { return null @@ -152,11 +366,11 @@ export class SettingsService { if (value != null) { switch (setting.type) { - case "boolean": + case 'boolean': return JSON.parse(value) - case "number": + case 'number': return +value - case "string": + case 'string': return value default: return value diff --git a/src-ui/src/app/services/toast.service.spec.ts b/src-ui/src/app/services/toast.service.spec.ts deleted file mode 100644 index e0413db84..000000000 --- a/src-ui/src/app/services/toast.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { ToastService } from './toast.service'; - -describe('ToastService', () => { - let service: ToastService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(ToastService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src-ui/src/app/services/toast.service.ts b/src-ui/src/app/services/toast.service.ts index fc522e2df..7c35b624c 100644 --- a/src-ui/src/app/services/toast.service.ts +++ b/src-ui/src/app/services/toast.service.ts @@ -1,8 +1,7 @@ -import { Injectable } from '@angular/core'; -import { Subject, zip } from 'rxjs'; +import { Injectable } from '@angular/core' +import { Subject, zip } from 'rxjs' export interface Toast { - title: string content: string @@ -12,15 +11,13 @@ export interface Toast { action?: any actionName?: string - } @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class ToastService { - - constructor() { } + constructor() {} private toasts: Toast[] = [] @@ -32,15 +29,15 @@ export class ToastService { } showError(content: string, delay: number = 10000) { - this.show({title: $localize`Error`, content: content, delay: delay}) + this.show({ title: $localize`Error`, content: content, delay: delay }) } showInfo(content: string, delay: number = 5000) { - this.show({title: $localize`Information`, content: content, delay: delay}) + this.show({ title: $localize`Information`, content: content, delay: delay }) } closeToast(toast: Toast) { - let index = this.toasts.findIndex(t => t == toast) + let index = this.toasts.findIndex((t) => t == toast) if (index > -1) { this.toasts.splice(index, 1) this.toastsSubject.next(this.toasts) @@ -50,5 +47,4 @@ export class ToastService { getToasts() { return this.toastsSubject } - } diff --git a/src-ui/src/app/services/upload-documents.service.ts b/src-ui/src/app/services/upload-documents.service.ts new file mode 100644 index 000000000..5e7ef7fbe --- /dev/null +++ b/src-ui/src/app/services/upload-documents.service.ts @@ -0,0 +1,74 @@ +import { Injectable } from '@angular/core' +import { HttpEventType } from '@angular/common/http' +import { FileSystemFileEntry, NgxFileDropEntry } from 'ngx-file-drop' +import { + ConsumerStatusService, + FileStatusPhase, +} from './consumer-status.service' +import { DocumentService } from './rest/document.service' +import { Subscription } from 'rxjs' + +@Injectable({ + providedIn: 'root', +}) +export class UploadDocumentsService { + private uploadSubscriptions: Array = [] + + constructor( + private documentService: DocumentService, + private consumerStatusService: ConsumerStatusService + ) {} + + uploadFiles(files: NgxFileDropEntry[]) { + for (const droppedFile of files) { + if (droppedFile.fileEntry.isFile) { + const fileEntry = droppedFile.fileEntry as FileSystemFileEntry + fileEntry.file((file: File) => { + let formData = new FormData() + formData.append('document', file, file.name) + let status = this.consumerStatusService.newFileUpload(file.name) + + status.message = $localize`Connecting...` + + this.uploadSubscriptions[file.name] = this.documentService + .uploadDocument(formData) + .subscribe({ + next: (event) => { + if (event.type == HttpEventType.UploadProgress) { + status.updateProgress( + FileStatusPhase.UPLOADING, + event.loaded, + event.total + ) + status.message = $localize`Uploading...` + } else if (event.type == HttpEventType.Response) { + status.taskId = event.body['task_id'] + status.message = $localize`Upload complete, waiting...` + this.uploadSubscriptions[file.name]?.complete() + } + }, + error: (error) => { + switch (error.status) { + case 400: { + this.consumerStatusService.fail( + status, + error.error.document + ) + break + } + default: { + this.consumerStatusService.fail( + status, + $localize`HTTP error: ${error.status} ${error.statusText}` + ) + break + } + } + this.uploadSubscriptions[file.name]?.complete() + }, + }) + }) + } + } + } +} diff --git a/src-ui/src/app/utils/color.ts b/src-ui/src/app/utils/color.ts index d320cc2b9..e23a91c5f 100644 --- a/src-ui/src/app/utils/color.ts +++ b/src-ui/src/app/utils/color.ts @@ -1,12 +1,18 @@ +import { HSL, RGB } from 'ngx-color' + +export const BRIGHTNESS = { + LIGHT: 'light', + DARK: 'dark', +} function componentToHex(c) { var hex = Math.floor(c).toString(16) - return hex.length == 1 ? "0" + hex : hex + return hex.length == 1 ? '0' + hex : hex } /** - * https://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c * + * https://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c * Converts an HSL color value to RGB. Conversion formula * adapted from http://en.wikipedia.org/wiki/HSL_color_space. * Assumes h, s, and l are contained in the set [0, 1] and @@ -17,32 +23,115 @@ function componentToHex(c) { * @param Number l The lightness * @return Array The RGB representation */ -function hslToRgb(h, s, l){ +function hslToRgb(h, s, l) { var r, g, b - if(s == 0){ - r = g = b = l // achromatic - }else{ - function hue2rgb(p, q, t){ - if(t < 0) t += 1 - if(t > 1) t -= 1 - if(t < 1/6) return p + (q - p) * 6 * t - if(t < 1/2) return q - if(t < 2/3) return p + (q - p) * (2/3 - t) * 6 - return p - } + if (s == 0) { + r = g = b = l // achromatic + } else { + function hue2rgb(p, q, t) { + if (t < 0) t += 1 + if (t > 1) t -= 1 + if (t < 1 / 6) return p + (q - p) * 6 * t + if (t < 1 / 2) return q + if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6 + return p + } - var q = l < 0.5 ? l * (1 + s) : l + s - l * s - var p = 2 * l - q - r = hue2rgb(p, q, h + 1/3) - g = hue2rgb(p, q, h) - b = hue2rgb(p, q, h - 1/3) + var q = l < 0.5 ? l * (1 + s) : l + s - l * s + var p = 2 * l - q + r = hue2rgb(p, q, h + 1 / 3) + g = hue2rgb(p, q, h) + b = hue2rgb(p, q, h - 1 / 3) } return [r * 255, g * 255, b * 255] } +/** + * https://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c + * Converts an RGB color value to HSL. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes r, g, and b are contained in the set [0, 255] and + * returns h, s, and l in the set [0, 1]. + * + * @param Number r The red color value + * @param Number g The green color value + * @param Number b The blue color value + * @return Array The HSL representation + */ +export function rgbToHsl(r, g, b) { + ;(r /= 255), (g /= 255), (b /= 255) + var max = Math.max(r, g, b), + min = Math.min(r, g, b) + var h, + s, + l = (max + min) / 2 + + if (max == min) { + h = s = 0 // achromatic + } else { + var d = max - min + s = l > 0.5 ? d / (2 - max - min) : d / (max + min) + switch (max) { + case r: + h = (g - b) / d + (g < b ? 6 : 0) + break + case g: + h = (b - r) / d + 2 + break + case b: + h = (r - g) / d + 4 + break + } + h /= 6 + } + + return [h, s, l] +} + +export function hexToHsl(hex: string): HSL { + const rgb = hexToRGB(hex) + const hsl = rgbToHsl(rgb.r, rgb.g, rgb.b) + return { h: hsl[0], s: hsl[1], l: hsl[2] } +} + +export function hexToRGB(hex: string): RGB { + hex = hex.replace('#', '') + let aRgbHex = hex.match(/.{1,2}/g) + return { + r: parseInt(aRgbHex[0], 16), + g: parseInt(aRgbHex[1], 16), + b: parseInt(aRgbHex[2], 16), + } +} + +export function computeLuminance(color: RGB) { + // Formula: http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef + const colorKeys = Object.keys(color) + for (var i = 0; i < 3; i++) { + var rgb = color[colorKeys[i]] + rgb /= 255 + rgb = rgb < 0.03928 ? rgb / 12.92 : Math.pow((rgb + 0.055) / 1.055, 2.4) + color[i] = rgb + } + return 0.2126 * color[0] + 0.7152 * color[1] + 0.0722 * color[2] +} + +export function estimateBrightnessForColor(colorHex: string) { + // See + // Adapted from https://api.flutter.dev/flutter/material/ThemeData/estimateBrightnessForColor.html + const rgb = hexToRGB(colorHex) + const luminance = computeLuminance(rgb) + const kThreshold = 0.15 + return (luminance + 0.05) * (luminance + 0.05) > kThreshold + ? BRIGHTNESS.LIGHT + : BRIGHTNESS.DARK +} + export function randomColor() { let rgb = hslToRgb(Math.random(), 0.6, Math.random() * 0.4 + 0.4) - return `#${componentToHex(rgb[0])}${componentToHex(rgb[1])}${componentToHex(rgb[2])}` + return `#${componentToHex(rgb[0])}${componentToHex(rgb[1])}${componentToHex( + rgb[2] + )}` } diff --git a/src-ui/src/app/utils/ngb-date-parser-formatter.ts b/src-ui/src/app/utils/ngb-date-parser-formatter.ts index 07d31a525..ff7706819 100644 --- a/src-ui/src/app/utils/ngb-date-parser-formatter.ts +++ b/src-ui/src/app/utils/ngb-date-parser-formatter.ts @@ -1,9 +1,13 @@ -import { Injectable } from "@angular/core" -import { NgbDateParserFormatter, NgbDateStruct } from "@ng-bootstrap/ng-bootstrap" -import { SettingsService } from "../services/settings.service" +import { Injectable } from '@angular/core' +import { + NgbDateParserFormatter, + NgbDateStruct, +} from '@ng-bootstrap/ng-bootstrap' +import { SettingsService } from '../services/settings.service' @Injectable() export class LocalizedDateParserFormatter extends NgbDateParserFormatter { + private separatorRegExp: RegExp = /[\.,\/-]+/ constructor(private settings: SettingsService) { super() @@ -19,23 +23,86 @@ export class LocalizedDateParserFormatter extends NgbDateParserFormatter { */ private getDateParseRegex() { return new RegExp( - "^" + this.getDateInputFormat() - .replace('dd', '(?[0-9]+)') - .replace('mm', '(?[0-9]+)') - .replace('yyyy', '(?[0-9]+)') - .split('.').join('\\.\\s*') + "$" // allow whitespace(s) after dot (specific for German) - ) + '^' + + this.getDateInputFormat() + .replace('dd', '(?[0-9]+)') + .replace('mm', '(?[0-9]+)') + .replace('yyyy', '(?[0-9]+)') + .split('.') + .join('\\.\\s*') + + '$' // allow whitespace(s) after dot (specific for German) + ) + } + + /** + * This adds date separators if none are entered. + * It also adds the current year if it wasn't entered. + * + * This allows users to just enter 1003, 100322, 10032022 and + * have it expanded to 10.03.2022, in the case of the German format. + * (All other formats are also supported) + * + * It also strips any separators before running formatting and pads + * any parts of the string, e.g. allowing for 1/2/22, + * which allows quick entry of the date on the numpad. + */ + private preformatDateInput(value: string): string { + const inputFormat = this.getDateInputFormat() + const dateSeparator = inputFormat.replace(/[dmy]/gi, '').charAt(0) + + if (this.separatorRegExp.test(value)) { + // split on separator, pad & re-join without separator + value = value + .split(this.separatorRegExp) + .map((segment) => segment.padStart(2, '0')) + .join('') + } + + if (value.length == 4 && inputFormat.substring(0, 4) != 'yyyy') { + return [ + value.substring(0, 2), + value.substring(2, 4), + new Date().getFullYear(), + ].join(dateSeparator) + } else if (value.length == 4 && inputFormat.substring(0, 4) == 'yyyy') { + return [ + new Date().getFullYear(), + value.substring(0, 2), + value.substring(2, 4), + ].join(dateSeparator) + } else if (value.length == 6) { + return [ + value.substring(0, 2), + value.substring(2, 4), + value.substring(4, 6), + ].join(dateSeparator) + } else if (value.length == 8 && inputFormat.substring(0, 4) != 'yyyy') { + return [ + value.substring(0, 2), + value.substring(2, 4), + value.substring(4, 8), + ].join(dateSeparator) + } else if (value.length == 8 && inputFormat.substring(0, 4) == 'yyyy') { + return [ + value.substring(0, 4), + value.substring(4, 6), + value.substring(6, 8), + ].join(dateSeparator) + } else { + return value + } } parse(value: string): NgbDateStruct | null { + value = this.preformatDateInput(value) let match = this.getDateParseRegex().exec(value) if (match) { let dateStruct = { day: +match.groups.day, month: +match.groups.month, - year: +match.groups.year + year: +match.groups.year, } - if (dateStruct.year <= (new Date().getFullYear() - 2000)) { + if (dateStruct.year <= new Date().getFullYear() - 2000) { dateStruct.year += 2000 } else if (dateStruct.year < 100) { dateStruct.year += 1900 @@ -49,9 +116,9 @@ export class LocalizedDateParserFormatter extends NgbDateParserFormatter { format(date: NgbDateStruct | null): string { if (date) { return this.getDateInputFormat() - .replace('dd', date.day.toString().padStart(2, '0')) - .replace('mm', date.month.toString().padStart(2, '0')) - .replace('yyyy', date.year.toString().padStart(4, '0')) + .replace('dd', date.day.toString().padStart(2, '0')) + .replace('mm', date.month.toString().padStart(2, '0')) + .replace('yyyy', date.year.toString().padStart(4, '0')) } else { return null } diff --git a/src-ui/src/app/utils/ngb-iso-date-adapter.ts b/src-ui/src/app/utils/ngb-iso-date-adapter.ts index e43602a16..7aa2214b5 100644 --- a/src-ui/src/app/utils/ngb-iso-date-adapter.ts +++ b/src-ui/src/app/utils/ngb-iso-date-adapter.ts @@ -1,16 +1,15 @@ -import { Injectable } from "@angular/core"; -import { NgbDateAdapter, NgbDateStruct } from "@ng-bootstrap/ng-bootstrap"; +import { Injectable } from '@angular/core' +import { NgbDateAdapter, NgbDateStruct } from '@ng-bootstrap/ng-bootstrap' @Injectable() export class ISODateAdapter extends NgbDateAdapter { - fromModel(value: string | null): NgbDateStruct | null { if (value) { let date = new Date(value) return { - day : date.getDate(), - month : date.getMonth() + 1, - year : date.getFullYear() + day: date.getDate(), + month: date.getMonth() + 1, + year: date.getFullYear(), } } else { return null @@ -19,7 +18,13 @@ export class ISODateAdapter extends NgbDateAdapter { toModel(date: NgbDateStruct | null): string | null { if (date) { - return date.year.toString().padStart(4, '0') + "-" + date.month.toString().padStart(2, '0') + "-" + date.day.toString().padStart(2, '0') + return ( + date.year.toString().padStart(4, '0') + + '-' + + date.month.toString().padStart(2, '0') + + '-' + + date.day.toString().padStart(2, '0') + ) } else { return null } diff --git a/src-ui/src/app/utils/ngb-iso-date-time-adapter.ts b/src-ui/src/app/utils/ngb-iso-date-time-adapter.ts index 21a97a19a..b9acc38ec 100644 --- a/src-ui/src/app/utils/ngb-iso-date-time-adapter.ts +++ b/src-ui/src/app/utils/ngb-iso-date-time-adapter.ts @@ -1,16 +1,15 @@ -import { Injectable } from "@angular/core"; -import { NgbDateAdapter, NgbDateStruct } from "@ng-bootstrap/ng-bootstrap"; +import { Injectable } from '@angular/core' +import { NgbDateAdapter, NgbDateStruct } from '@ng-bootstrap/ng-bootstrap' @Injectable() export class ISODateTimeAdapter extends NgbDateAdapter { - fromModel(value: string | null): NgbDateStruct | null { if (value) { let date = new Date(value) return { - day : date.getDate(), - month : date.getMonth() + 1, - year : date.getFullYear() + day: date.getDate(), + month: date.getMonth() + 1, + year: date.getFullYear(), } } else { return null @@ -18,6 +17,8 @@ export class ISODateTimeAdapter extends NgbDateAdapter { } toModel(date: NgbDateStruct | null): string | null { - return date ? new Date(date.year, date.month - 1, date.day).toISOString() : null + return date + ? new Date(date.year, date.month - 1, date.day).toISOString() + : null } } diff --git a/src-ui/src/assets/bootstrap-icons.svg b/src-ui/src/assets/bootstrap-icons.svg index f7731a14b..e94852cbd 100644 --- a/src-ui/src/assets/bootstrap-icons.svg +++ b/src-ui/src/assets/bootstrap-icons.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src-ui/src/environments/environment.prod.ts b/src-ui/src/environments/environment.prod.ts index 36ad4ef2a..9e04ddada 100644 --- a/src-ui/src/environments/environment.prod.ts +++ b/src-ui/src/environments/environment.prod.ts @@ -2,11 +2,11 @@ const base_url = new URL(document.baseURI) export const environment = { production: true, - apiBaseUrl: document.baseURI + "api/", - apiVersion: "2", - appTitle: "Paperless-ngx", - version: "1.6.0", + apiBaseUrl: document.baseURI + 'api/', + apiVersion: '2', + appTitle: 'Paperless-ngx', + version: '1.7.0-rc1', webSocketHost: window.location.host, - webSocketProtocol: (window.location.protocol == "https:" ? "wss:" : "ws:"), - webSocketBaseUrl: base_url.pathname + "ws/", -}; + webSocketProtocol: window.location.protocol == 'https:' ? 'wss:' : 'ws:', + webSocketBaseUrl: base_url.pathname + 'ws/', +} diff --git a/src-ui/src/environments/environment.ts b/src-ui/src/environments/environment.ts index 9841a51c5..4386bef1e 100644 --- a/src-ui/src/environments/environment.ts +++ b/src-ui/src/environments/environment.ts @@ -4,14 +4,14 @@ export const environment = { production: false, - apiBaseUrl: "http://localhost:8000/api/", - apiVersion: "2", - appTitle: "Paperless-ngx", - version: "DEVELOPMENT", - webSocketHost: "localhost:8000", - webSocketProtocol: "ws:", - webSocketBaseUrl: "/ws/", -}; + apiBaseUrl: 'http://localhost:8000/api/', + apiVersion: '2', + appTitle: 'Paperless-ngx', + version: 'DEVELOPMENT', + webSocketHost: 'localhost:8000', + webSocketProtocol: 'ws:', + webSocketBaseUrl: '/ws/', +} /* * For easier debugging in development mode, you can import the following file diff --git a/src-ui/src/locale/messages.be_BY.xlf b/src-ui/src/locale/messages.be_BY.xlf new file mode 100644 index 000000000..f8f6e5fb5 --- /dev/null +++ b/src-ui/src/locale/messages.be_BY.xlf @@ -0,0 +1,2808 @@ + + + + + + Document added + + src/app/app.component.ts + 51 + + Дакумент дададзены + + + Document was added to paperless. + + src/app/app.component.ts + 51 + + Дакумент быў дададзены Ñž paperless-ngx. + + + Open document + + src/app/app.component.ts + 51 + + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 45 + + Ðдкрыць дакумент + + + Could not add : + + src/app/app.component.ts + 59 + + Ðемагчыма дадаць : + + + New document detected + + src/app/app.component.ts + 65 + + Знойдзены новы дакумент + + + Document is being processed by paperless. + + src/app/app.component.ts + 65 + + Дакумент апрацоўваецца paperless-ngx. + + + Paperless-ngx + + src/app/components/app-frame/app-frame.component.html + 11 + + app title + Paperless-ngx + + + Search documents + + src/app/components/app-frame/app-frame.component.html + 18 + + Пошук дакументаў + + + Logged in as + + src/app/components/app-frame/app-frame.component.html + 34 + + Увайшоў Ñк + + + Settings + + src/app/components/app-frame/app-frame.component.html + 40 + + + src/app/components/app-frame/app-frame.component.html + 147 + + + src/app/components/manage/settings/settings.component.html + 1 + + Ðаладкі + + + Logout + + src/app/components/app-frame/app-frame.component.html + 45 + + Выхад + + + Dashboard + + src/app/components/app-frame/app-frame.component.html + 61 + + + src/app/components/dashboard/dashboard.component.html + 1 + + ПанÑль ÐºÑ–Ñ€Ð°Ð²Ð°Ð½Ð½Ñ + + + Documents + + src/app/components/app-frame/app-frame.component.html + 68 + + + src/app/components/document-list/document-list.component.ts + 51 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 37 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 35 + + + src/app/components/manage/tag-list/tag-list.component.html + 38 + + Дакументы + + + Saved views + + src/app/components/app-frame/app-frame.component.html + 74 + + + src/app/components/manage/settings/settings.component.html + 134 + + Ð—Ð°Ñ…Ð°Ð²Ð°Ð½Ñ‹Ñ Ð²Ñ‹Ð³Ð»Ñды + + + Open documents + + src/app/components/app-frame/app-frame.component.html + 87 + + Ðдкрыць дакументы + + + Close all + + src/app/components/app-frame/app-frame.component.html + 106 + + Закрыць уÑÑ‘ + + + Manage + + src/app/components/app-frame/app-frame.component.html + 112 + + Кіраванне + + + Correspondents + + src/app/components/app-frame/app-frame.component.html + 119 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 1 + + КарÑÑпандÑнты + + + Tags + + src/app/components/app-frame/app-frame.component.html + 126 + + + src/app/components/common/input/tags/tags.component.html + 2 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 28 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 18 + + + src/app/components/manage/tag-list/tag-list.component.html + 1 + + ТÑгі + + + Document types + + src/app/components/app-frame/app-frame.component.html + 133 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 1 + + Тыпы дакументаў + + + Logs + + src/app/components/app-frame/app-frame.component.html + 140 + + + src/app/components/manage/logs/logs.component.html + 1 + + Логі + + + Admin + + src/app/components/app-frame/app-frame.component.html + 154 + + Кіраўнік + + + Info + + src/app/components/app-frame/app-frame.component.html + 160 + + Ð†Ð½Ñ„Ð°Ñ€Ð¼Ð°Ñ†Ñ‹Ñ + + + Documentation + + src/app/components/app-frame/app-frame.component.html + 167 + + Ð”Ð°ÐºÑƒÐ¼ÐµÐ½Ñ‚Ð°Ñ†Ñ‹Ñ + + + GitHub + + src/app/components/app-frame/app-frame.component.html + 175 + + GitHub + + + Suggest an idea + + src/app/components/app-frame/app-frame.component.html + 181 + + Прапанаваць ідÑÑŽ + + + Cancel + + src/app/components/common/confirm-dialog/confirm-dialog.component.html + 11 + + + src/app/components/common/select-dialog/select-dialog.component.html + 12 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 6 + + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 13 + + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 14 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 16 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 18 + + СкаÑаваць + + + Confirmation + + src/app/components/common/confirm-dialog/confirm-dialog.component.ts + 18 + + ПацвÑрджÑнне + + + Confirm + + src/app/components/common/confirm-dialog/confirm-dialog.component.ts + 30 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 143 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 166 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 189 + + Пацвердзіць + + + After + + src/app/components/common/date-dropdown/date-dropdown.component.html + 13 + + ПаÑÐ»Ñ + + + Clear + + src/app/components/common/date-dropdown/date-dropdown.component.html + 18 + + + src/app/components/common/date-dropdown/date-dropdown.component.html + 41 + + ÐчыÑціць + + + Before + + src/app/components/common/date-dropdown/date-dropdown.component.html + 36 + + Перад + + + Last 7 days + + src/app/components/common/date-dropdown/date-dropdown.component.ts + 34 + + За Ð°Ð¿Ð¾ÑˆÐ½Ñ–Ñ 7 дзён + + + Last month + + src/app/components/common/date-dropdown/date-dropdown.component.ts + 35 + + Ðпошні меÑÑц + + + Last 3 months + + src/app/components/common/date-dropdown/date-dropdown.component.ts + 36 + + За Ð°Ð¿Ð¾ÑˆÐ½Ñ–Ñ 3 меÑÑцы + + + Last year + + src/app/components/common/date-dropdown/date-dropdown.component.ts + 37 + + Ðпошні год + + + Create new item + + src/app/components/common/edit-dialog/edit-dialog.component.ts + 50 + + Стварыць новы Ñлемент + + + Edit item + + src/app/components/common/edit-dialog/edit-dialog.component.ts + 54 + + РÑдагаваць Ñлемент + + + Could not save element: + + src/app/components/common/edit-dialog/edit-dialog.component.ts + 58 + + Ðемагчыма захаваць Ñлемент: + + + Apply + + src/app/components/common/filterable-dropdown/filterable-dropdown.component.html + 39 + + Ужыць + + + Click again to exclude items. + + src/app/components/common/filterable-dropdown/filterable-dropdown.component.html + 45 + + ÐаціÑніце зноў, каб выключыць Ñлементы. + + + Not assigned + + src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts + 209 + + Filter drop down element to filter for documents with no correspondent/type/tag assigned + Ðе прызначана + + + Invalid date. + + src/app/components/common/input/date/date.component.html + 12 + + ÐÑÐ¿Ñ€Ð°Ð²Ñ–Ð»ÑŒÐ½Ð°Ñ Ð´Ð°Ñ‚Ð°. + + + Add item + + src/app/components/common/input/select/select.component.html + 11 + + Used for both types and correspondents + Дадаць Ñлемент + + + Suggestions: + + src/app/components/common/input/select/select.component.html + 29 + + + src/app/components/common/input/tags/tags.component.html + 42 + + Прапановы: + + + Add tag + + src/app/components/common/input/tags/tags.component.html + 11 + + Дадаць Ñ‚Ñг + + + Select + + src/app/components/common/select-dialog/select-dialog.component.html + 13 + + + src/app/components/common/select-dialog/select-dialog.component.ts + 18 + + + src/app/components/document-list/document-list.component.html + 7 + + Выбраць + + + Please select an object + + src/app/components/common/select-dialog/select-dialog.component.ts + 21 + + Калі лаÑка, абÑрыце аб'ект + + + Hello , welcome to Paperless-ngx! + + src/app/components/dashboard/dashboard.component.ts + 33 + + Прывітанне, , запрашаем у Paperless-ngx! + + + Welcome to Paperless-ngx! + + src/app/components/dashboard/dashboard.component.ts + 35 + + Вітаем у Paperless-ngx! + + + Show all + + src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html + 3 + + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 27 + + Паказаць уÑÑ‘ + + + Created + + src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html + 9 + + + src/app/components/document-list/document-list.component.html + 141 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 41 + + + src/app/services/rest/document.service.ts + 21 + + Створана + + + Title + + src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html + 10 + + + src/app/components/document-detail/document-detail.component.html + 55 + + + src/app/components/document-list/document-list.component.html + 129 + + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 88 + + + src/app/services/rest/document.service.ts + 19 + + Ðазва + + + Statistics + + src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html + 1 + + СтатыÑтыка + + + Documents in inbox: + + src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html + 3 + + Дакументы ва ўваходных: + + + Total documents: + + src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html + 4 + + УÑÑго дакументаў: + + + Upload new documents + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 1 + + Загрузіць Ð½Ð¾Ð²Ñ‹Ñ Ð´Ð°ÐºÑƒÐ¼ÐµÐ½Ñ‚Ñ‹ + + + Dismiss completed + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 4 + + This button dismisses all status messages about processed documents on the dashboard (failed and successful) + Схаваць Ð·Ð°Ð²ÐµÑ€ÑˆÐ°Ð½Ñ‹Ñ + + + Drop documents here or + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 13 + + ПерацÑгнуць дакументы або + + + Browse files + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 13 + + Загрузіце файлы + + + {VAR_PLURAL, plural, =1 {One more document} other { more documents}} + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 25 + + This is shown as a summary line when there are more than 5 document in the processing pipeline. + {VAR_PLURAL, plural, =1 {Ð¯ÑˆÑ‡Ñ Ð´Ð°ÐºÑƒÐ¼ÐµÐ½Ñ‚: 1} other {Ð¯ÑˆÑ‡Ñ Ð´Ð°ÐºÑƒÐ¼ÐµÐ½Ñ‚Ð°Ñž: }} + + + Processing: + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 32 + + Ðпрацоўваюцца: + + + Failed: + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 35 + + Памылка: + + + Added: + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 38 + + Дададзена: + + + , + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 40 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 117 + + this string is used to separate processing, failed and added on the file upload widget + , + + + Connecting... + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 118 + + ПадключÑнне... + + + Uploading... + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 123 + + Загрузка... + + + Upload complete, waiting... + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 126 + + Загрузка завершана, чакайце... + + + HTTP error: + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 136 + + Памылка HTTP: + + + First steps + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 1 + + ÐŸÐµÑ€ÑˆÑ‹Ñ ÐºÑ€Ð¾ÐºÑ– + + + Paperless is running! :) + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 5 + + Paperless-ngx працуе! :) + + + You can start uploading documents by dropping them in the file upload box to the right or by dropping them in the configured consumption folder and they'll start showing up in the documents list. After you've added some metadata to your documents, use the filtering mechanisms of paperless to create custom views (such as 'Recently added', 'Tagged TODO') and they will appear on the dashboard instead of this message. + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 6,7 + + Ð’Ñ‹ можаце пачаць загружаць дакументы, апуÑціўшы Ñ–Ñ… у поле Ð´Ð»Ñ Ð·Ð°Ð³Ñ€ÑƒÐ·ÐºÑ– файлаў Ñправа або перакінуўшы Ñ–Ñ… у наладжаную папку ÑпажываннÑ, Ñ– Ñны пачнуць адлюÑтроўвацца Ñž ÑпіÑе дакументаў. ПаÑÐ»Ñ Ñ‚Ð°Ð³Ð¾, Ñк вы дадалі Ð½ÐµÐºÐ°Ñ‚Ð¾Ñ€Ñ‹Ñ Ð¼ÐµÑ‚Ð°Ð´Ð°Ð´Ð·ÐµÐ½Ñ‹Ñ Ñž Ñвае дакументы, выкарыÑтоўвайце механізмы фільтрацыі paperless-ngx, каб Ñтварыць карыÑÑ‚Ð°Ð»ÑŒÐ½Ñ–Ñ†ÐºÑ–Ñ Ð²Ñ–Ð´Ñ‹ (напрыклад, «ÐÑдаўна дададзеныÑ», «З пазнакай TODO»), Ñ– Ñны з'ÑвÑцца на галоўнай панÑлі замеÑÑ‚ гÑтага паведамленнÑ. + + + Paperless offers some more features that try to make your life easier: + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 8 + + Paperless-ngx прапануе ÑÑˆÑ‡Ñ Ð½ÐµÐºÐ°Ð»ÑŒÐºÑ– функцый, ÑÐºÑ–Ñ Ñпрабуюць палегчыць вам жыццё: + + + Once you've got a couple documents in paperless and added metadata to them, paperless can assign that metadata to new documents automatically. + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 10 + + ПаÑÐ»Ñ Ñ‚Ð°Ð³Ð¾, Ñк вы атрымаеце пару дакументаў у беÑпапÑровым выглÑдзе Ñ– дадаÑце да Ñ–Ñ… метададзеныÑ, Paperless-ngx можа аўтаматычна прызначыць гÑÑ‚Ñ‹Ñ Ð¼ÐµÑ‚Ð°Ð´Ð°Ð´Ð·ÐµÐ½Ñ‹Ñ Ð½Ð¾Ð²Ñ‹Ð¼ дакументам. + + + You can configure paperless to read your mails and add documents from attached files. + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 11 + + Ð’Ñ‹ можаце наладзіць Paperless-ngx доÑтуп да Ñ‡Ñ‹Ñ‚Ð°Ð½Ð½Ñ Ð²Ð°ÑˆÐ°Ð¹ пошты Ñ– Ð´Ð°Ð´Ð°Ð½Ð½Ñ Ð´Ð°ÐºÑƒÐ¼ÐµÐ½Ñ‚Ð°Ñž з укладзеных файлаў. + + + Consult the documentation on how to use these features. The section on basic usage also has some information on how to use paperless in general. + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 13 + + ЗвÑрніцеÑÑ Ð´Ð° дакументацыі аб выкарыÑтанні гÑÑ‚Ñ‹Ñ… функцый. У раздзеле аб базавым выкарыÑтанні такÑама Ñ‘Ñць Ð½ÐµÐºÐ°Ñ‚Ð¾Ñ€Ð°Ñ Ñ–Ð½Ñ„Ð°Ñ€Ð¼Ð°Ñ†Ñ‹Ñ Ð°Ð± тым, Ñк выкарыÑтоўваць Paperless-ngx у цÑлым. + + + Searching document with asn + + src/app/components/document-asn/document-asn.component.html + 1 + + Пошук дакумента з asn + + + Page + + src/app/components/document-detail/document-detail.component.html + 3 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 15 + + Старонка + + + of + + src/app/components/document-detail/document-detail.component.html + 5 + + з + + + Delete + + src/app/components/document-detail/document-detail.component.html + 11 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 76 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 48 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 46 + + + src/app/components/manage/generic-list/generic-list.component.ts + 106 + + + src/app/components/manage/settings/settings.component.html + 159 + + + src/app/components/manage/tag-list/tag-list.component.html + 49 + + Выдаліць + + + Download + + src/app/components/document-detail/document-detail.component.html + 19 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 63 + + + src/app/components/document-list/document-card-large/document-card-large.component.html + 60 + + + src/app/components/document-list/document-card-small/document-card-small.component.html + 82 + + Спампаваць + + + Download original + + src/app/components/document-detail/document-detail.component.html + 25 + + Спампаваць арыгінал + + + More like this + + src/app/components/document-detail/document-detail.component.html + 34 + + + src/app/components/document-list/document-card-large/document-card-large.component.html + 38 + + Больш падобнага + + + Close + + src/app/components/document-detail/document-detail.component.html + 40 + + Закрыць + + + Details + + src/app/components/document-detail/document-detail.component.html + 52 + + ПадрабÑзнаÑці + + + Archive serial number + + src/app/components/document-detail/document-detail.component.html + 56 + + Парадкавы нумар архіва + + + Date created + + src/app/components/document-detail/document-detail.component.html + 57 + + Дата ÑтварÑÐ½Ð½Ñ + + + Correspondent + + src/app/components/document-detail/document-detail.component.html + 58 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 38 + + + src/app/components/document-list/document-list.component.html + 123 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 26 + + + src/app/services/rest/document.service.ts + 18 + + КарÑÑпандÑнт + + + Document type + + src/app/components/document-detail/document-detail.component.html + 60 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 47 + + + src/app/components/document-list/document-list.component.html + 135 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 33 + + + src/app/services/rest/document.service.ts + 20 + + Тып дакумента + + + Content + + src/app/components/document-detail/document-detail.component.html + 68 + + ЗмеÑÑ‚ + + + Metadata + + src/app/components/document-detail/document-detail.component.html + 77 + + + src/app/components/document-detail/metadata-collapse/metadata-collapse.component.ts + 18 + + ÐœÐµÑ‚Ð°Ð´Ð°Ð½Ñ‹Ñ + + + Date modified + + src/app/components/document-detail/document-detail.component.html + 83 + + Дата змÑÐ½ÐµÐ½Ð½Ñ + + + Date added + + src/app/components/document-detail/document-detail.component.html + 87 + + Дата Ð´Ð°Ð´Ð°Ð½Ð½Ñ + + + Media filename + + src/app/components/document-detail/document-detail.component.html + 91 + + Ð†Ð¼Ñ Ð¼ÐµÐ´Ñ‹Ñфайла + + + Original MD5 checksum + + src/app/components/document-detail/document-detail.component.html + 95 + + ÐÑ€Ñ‹Ð³Ñ–Ð½Ð°Ð»ÑŒÐ½Ð°Ñ ÐºÐ°Ð½Ñ‚Ñ€Ð¾Ð»ÑŒÐ½Ð°Ñ Ñума MD5 + + + Original file size + + src/app/components/document-detail/document-detail.component.html + 99 + + Ðрыгінальны памер файла + + + Original mime type + + src/app/components/document-detail/document-detail.component.html + 103 + + Ðрыгінальны MIME тып + + + Archive MD5 checksum + + src/app/components/document-detail/document-detail.component.html + 107 + + MD5 Ñума архіва + + + Archive file size + + src/app/components/document-detail/document-detail.component.html + 111 + + Памер файла архіва + + + Original document metadata + + src/app/components/document-detail/document-detail.component.html + 117 + + ÐÑ€Ñ‹Ð³Ñ–Ð½Ð°Ð»ÑŒÐ½Ñ‹Ñ Ð¼ÐµÑ‚Ð°Ð´Ð°Ð´Ð·ÐµÐ½Ñ‹Ñ Ð´Ð°ÐºÑƒÐ¼ÐµÐ½Ñ‚Ð° + + + Archived document metadata + + src/app/components/document-detail/document-detail.component.html + 118 + + ÐœÐµÑ‚Ð°Ð´Ð°Ð´Ð·ÐµÐ½Ñ‹Ñ Ð°Ñ€Ñ…Ñ–ÑžÐ½Ð°Ð³Ð° дакумента + + + Discard + + src/app/components/document-detail/document-detail.component.html + 143 + + Ðдхіліць + + + Save & next + + src/app/components/document-detail/document-detail.component.html + 144 + + Захаваць & наÑтупны + + + Save + + src/app/components/document-detail/document-detail.component.html + 145 + + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 14 + + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 15 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 17 + + + src/app/components/manage/settings/settings.component.html + 173 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 19 + + Захаваць + + + Confirm delete + + src/app/components/document-detail/document-detail.component.ts + 267 + + + src/app/components/manage/generic-list/generic-list.component.ts + 102 + + Пацвердзіце выдаленне + + + Do you really want to delete document ""? + + src/app/components/document-detail/document-detail.component.ts + 268 + + Ð’Ñ‹ Ñапраўды хочаце выдаліць дакумент ""? + + + The files for this document will be deleted permanently. This operation cannot be undone. + + src/app/components/document-detail/document-detail.component.ts + 269 + + Файлы Ð´Ð»Ñ Ð³Ñтага дакумента будуць выдалены назаўÑёды. ГÑтую аперацыю нельга адмÑніць. + + + Delete document + + src/app/components/document-detail/document-detail.component.ts + 271 + + Выдаліць дакумент + + + Error deleting document: + + src/app/components/document-detail/document-detail.component.ts + 281 + + Памылка Ð²Ñ‹Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð´Ð°ÐºÑƒÐ¼ÐµÐ½Ñ‚Ð°: + + + Select: + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 10 + + Выбраць: + + + All + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 20 + + УÑÑ‘ + + + Edit: + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 27 + + РÑдагаваць: + + + Filter tags + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 29 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 19 + + Фільтраваць Ñ‚Ñгі + + + Filter correspondents + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 39 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 27 + + Фільтр карÑÑпандÑнтаў + + + Filter document types + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 48 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 34 + + Фільтр тыпаў дакументаў + + + Download originals + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 68 + + Спампаваць арыгіналы + + + Error executing bulk operation: + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 74 + + Памылка пры выкананні маÑавай аперацыі: + + + "" + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 113 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 117 + + "" + + + "" and "" + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 115 + + This is for messages like 'modify "tag1" and "tag2"' + "" Ñ– "" + + + and "" + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 118 + + this is for messages like 'modify "tag1", "tag2" and "tag3"' + Ñ– "" + + + Confirm tags assignment + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 127 + + ПацвÑрдзіць прызначÑнне Ñ‚Ñгаў + + + This operation will add the tag "" to selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 130 + + ГÑÑ‚Ð°Ñ Ð°Ð¿ÐµÑ€Ð°Ñ†Ñ‹Ñ Ð´Ð°Ð´Ð°Ñць Ñ‚Ñг "" да выбраных дакументаў. + + + This operation will add the tags to selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 132 + + ГÑÑ‚Ð°Ñ Ð°Ð¿ÐµÑ€Ð°Ñ†Ñ‹Ñ Ð´Ð°Ð´Ð°Ñць Ñ‚Ñгі "" да выбраных дакументаў. + + + This operation will remove the tag "" from selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 135 + + ГÑÑ‚Ð°Ñ Ð°Ð¿ÐµÑ€Ð°Ñ†Ñ‹Ñ Ð²Ñ‹Ð´Ð°Ð»Ñ–Ñ†ÑŒ Ñ‚Ñг "" з выбраных дакументаў. + + + This operation will remove the tags from selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 137 + + ГÑÑ‚Ð°Ñ Ð°Ð¿ÐµÑ€Ð°Ñ†Ñ‹Ñ Ð²Ñ‹Ð´Ð°Ð»Ñ–Ñ†ÑŒ Ñ‚Ñгі "" з выбраных дакументаў. + + + This operation will add the tags and remove the tags on selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 139 + + ГÑÑ‚Ð°Ñ Ð°Ð¿ÐµÑ€Ð°Ñ†Ñ‹Ñ Ð´Ð°Ð´Ð°Ñць Ñ‚Ñгі Ñ– выдаліць Ñ‚Ñгі на выбраных дакументах. + + + Confirm correspondent assignment + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 159 + + Пацвердзіць прызначÑнне карÑÑпандÑнта + + + This operation will assign the correspondent "" to selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 161 + + ГÑÑ‚Ð°Ñ Ð°Ð¿ÐµÑ€Ð°Ñ†Ñ‹Ñ Ð¿Ñ€Ñ‹Ð·Ð½Ð°Ñ‡Ñ‹Ñ†ÑŒ карÑÑпандÑнта "" абраным дакументам. + + + This operation will remove the correspondent from selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 163 + + ГÑÑ‚Ð°Ñ Ð°Ð¿ÐµÑ€Ð°Ñ†Ñ‹Ñ Ð²Ñ‹Ð´Ð°Ð»Ñ–Ñ†ÑŒ карÑÑпандÑнта з выбраных дакументаў. + + + Confirm document type assignment + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 182 + + Пацвердзіце прызначÑнне тыпу дакумента + + + This operation will assign the document type "" to selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 184 + + ГÑÑ‚Ð°Ñ Ð°Ð¿ÐµÑ€Ð°Ñ†Ñ‹Ñ Ð¿Ñ€Ñ‹Ñвоіць тып "" абраным дакументам. + + + This operation will remove the document type from selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 186 + + ГÑÑ‚Ð°Ñ Ð°Ð¿ÐµÑ€Ð°Ñ†Ñ‹Ñ Ð²Ñ‹Ð´Ð°Ð»Ñ–Ñ†ÑŒ тып з абраных дакументаў. + + + Delete confirm + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 201 + + Пацвердзіце выдаленне + + + This operation will permanently delete selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 202 + + ГÑÑ‚Ð°Ñ Ð°Ð¿ÐµÑ€Ð°Ñ†Ñ‹Ñ Ð½Ð°Ð·Ð°ÑžÐ¶Ð´Ñ‹ выдаліць абраных дакументаў. + + + This operation cannot be undone. + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 203 + + ГÑтую аперацыю нельга адмÑніць. + + + Delete document(s) + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 205 + + Выдаліць дакумент(Ñ‹) + + + Filter by correspondent + + src/app/components/document-list/document-card-large/document-card-large.component.html + 20 + + + src/app/components/document-list/document-card-small/document-card-small.component.html + 26 + + Фільтр па карÑÑпандÑнту + + + Filter by tag + + src/app/components/document-list/document-card-large/document-card-large.component.html + 24 + + + src/app/components/document-list/document-card-small/document-card-small.component.html + 15 + + Фільтр па Ñ‚Ñгу + + + Edit + + src/app/components/document-list/document-card-large/document-card-large.component.html + 43 + + + src/app/components/document-list/document-card-small/document-card-small.component.html + 66 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 42 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 40 + + + src/app/components/manage/tag-list/tag-list.component.html + 43 + + РÑдагаваць + + + View + + src/app/components/document-list/document-card-large/document-card-large.component.html + 51 + + ПраглÑд + + + Score: + + src/app/components/document-list/document-card-large/document-card-large.component.html + 87 + + Ðдзнака: + + + Created: + + src/app/components/document-list/document-card-small/document-card-small.component.html + 43 + + Створана: + + + Added: + + src/app/components/document-list/document-card-small/document-card-small.component.html + 44 + + Дададзена: + + + Modified: + + src/app/components/document-list/document-card-small/document-card-small.component.html + 45 + + Мадыфікавана: + + + Select none + + src/app/components/document-list/document-list.component.html + 10 + + Ðічога не выбіраць + + + Select page + + src/app/components/document-list/document-list.component.html + 11 + + Выбраць Ñтаронку + + + Select all + + src/app/components/document-list/document-list.component.html + 12 + + Выбраць уÑÑ‘ + + + Sort + + src/app/components/document-list/document-list.component.html + 39 + + Сартаваць + + + Views + + src/app/components/document-list/document-list.component.html + 64 + + ПраглÑды + + + Save "" + + src/app/components/document-list/document-list.component.html + 71 + + Захаваць "" + + + Save as... + + src/app/components/document-list/document-list.component.html + 72 + + Захаваць Ñк... + + + Loading... + + src/app/components/document-list/document-list.component.html + 87 + + Загрузка... + + + {VAR_PLURAL, plural, =1 {Selected of one document} other {Selected of documents}} + + src/app/components/document-list/document-list.component.html + 89 + + {VAR_PLURAL, plural, =1 {Выдзелена дакументаў: з 1} other {Выдзелена дакументаў: з }} + + + {VAR_PLURAL, plural, =1 {One document} other { documents}} + + src/app/components/document-list/document-list.component.html + 91 + + {VAR_PLURAL, plural, =1 {Ðдзін дакумент} other { дакумента(аў)}} + + + (filtered) + + src/app/components/document-list/document-list.component.html + 91 + + (адфільтравана) + + + ASN + + src/app/components/document-list/document-list.component.html + 117 + + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 90 + + + src/app/services/rest/document.service.ts + 17 + + ASN + + + Added + + src/app/components/document-list/document-list.component.html + 147 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 48 + + + src/app/services/rest/document.service.ts + 22 + + Дададзена + + + View "" saved successfully. + + src/app/components/document-list/document-list.component.ts + 116 + + ПраглÑд "" паÑпÑхова захаваны. + + + View "" created successfully. + + src/app/components/document-list/document-list.component.ts + 138 + + ПраглÑд "" Ñтвораны паÑпÑхова. + + + Reset filters + + src/app/components/document-list/filter-editor/filter-editor.component.html + 57 + + Скінуць фільтры + + + Correspondent: + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 37 + + КарÑÑпандÑнт: + + + Without correspondent + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 39 + + Без карÑÑпандÑнта + + + Type: + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 44 + + Тып: + + + Without document type + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 46 + + Без тыпу дакумента + + + Tag: + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 50 + + ТÑг: + + + Without any tag + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 54 + + Без уÑÑлÑкага Ñ‚Ñга + + + Title: + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 58 + + Ðазва: + + + ASN: + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 61 + + ASN: + + + Title & content + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 89 + + Ðазва & змеÑÑ‚ + + + Advanced search + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 91 + + Пашыраны пошук + + + More like + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 94 + + Больш падобных + + + Save current view + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 3 + + Захаваць цÑперашні праглÑд + + + Name + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 8 + + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 8 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 9 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 19 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 9 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 9 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 19 + + + src/app/components/manage/settings/settings.component.html + 141 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 8 + + + src/app/components/manage/tag-list/tag-list.component.html + 9 + + + src/app/components/manage/tag-list/tag-list.component.html + 19 + + Ðазва + + + Show in sidebar + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 9 + + + src/app/components/manage/settings/settings.component.html + 153 + + Паказаць у бакавой панÑлі + + + Show on dashboard + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 10 + + + src/app/components/manage/settings/settings.component.html + 149 + + Паказаць на панÑлі + + + Matching algorithm + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 9 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 10 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 13 + + Ðлгарытм ÑупаÑÑ‚Ð°ÑžÐ»ÐµÐ½Ð½Ñ + + + Matching pattern + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 10 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 11 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 14 + + Шаблон ÑÑƒÐ¿Ð°Ð´Ð·ÐµÐ½Ð½Ñ + + + Case insensitive + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 11 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 12 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 15 + + Без уліку Ñ€ÑгіÑтра + + + Create new correspondent + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.ts + 21 + + Стварыць новага карÑÑпандÑнта + + + Edit correspondent + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.ts + 25 + + РÑдагаваць карÑÑпандÑнта + + + Create + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 2 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 2 + + + src/app/components/manage/tag-list/tag-list.component.html + 2 + + Стварыць + + + Filter by: + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 8 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 8 + + + src/app/components/manage/tag-list/tag-list.component.html + 8 + + Фільтр па: + + + Matching + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 20 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 20 + + + src/app/components/manage/tag-list/tag-list.component.html + 21 + + Ð¡ÑƒÐ¿Ð°Ð´Ð·ÐµÐ½Ð½Ñ + + + Document count + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 21 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 21 + + + src/app/components/manage/tag-list/tag-list.component.html + 22 + + КолькаÑць дакументаў + + + Last correspondence + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 22 + + ÐпошнÑÑ ÐºÐ°Ñ€ÑÑпандÑÐ½Ñ†Ñ‹Ñ + + + Actions + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 23 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 22 + + + src/app/components/manage/settings/settings.component.html + 158 + + + src/app/components/manage/tag-list/tag-list.component.html + 23 + + ДзеÑнні + + + Do you really want to delete the correspondent ""? + + src/app/components/manage/correspondent-list/correspondent-list.component.ts + 26 + + Ð’Ñ‹ Ñапраўды хочаце выдаліць карÑÑпандÑнта ""? + + + Create new document type + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.ts + 21 + + Стварыць новы тып дакумента + + + Edit document type + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.ts + 25 + + РÑдагаваць тып дакумента + + + Do you really want to delete the document type ""? + + src/app/components/manage/document-type-list/document-type-list.component.ts + 26 + + Ð’Ñ‹ Ñапраўды хочаце выдаліць тып дакумента ""? + + + Automatic + + src/app/components/manage/generic-list/generic-list.component.ts + 39 + + + src/app/data/matching-model.ts + 17 + + Ðўтаматычна + + + Do you really want to delete this element? + + src/app/components/manage/generic-list/generic-list.component.ts + 97 + + Ð’Ñ‹ Ñапраўды жадаеце выдаліць гÑÑ‚Ñ‹ Ñлемент? + + + Associated documents will not be deleted. + + src/app/components/manage/generic-list/generic-list.component.ts + 104 + + ЗвÑÐ·Ð°Ð½Ñ‹Ñ Ð´Ð°ÐºÑƒÐ¼ÐµÐ½Ñ‚Ñ‹ не будуць выдалены. + + + Error while deleting element: + + src/app/components/manage/generic-list/generic-list.component.ts + 114 + + Памылка пры выдаленні Ñлемента: + + + General settings + + src/app/components/manage/settings/settings.component.html + 10 + + ÐÐ³ÑƒÐ»ÑŒÐ½Ñ‹Ñ Ð½Ð°Ð»Ð°Ð´Ñ‹ + + + Appearance + + src/app/components/manage/settings/settings.component.html + 13 + + Знешні выглÑд + + + Display language + + src/app/components/manage/settings/settings.component.html + 17 + + Мова інтÑрфейÑу + + + You need to reload the page after applying a new language. + + src/app/components/manage/settings/settings.component.html + 25 + + Вам Ñ‚Ñ€Ñба перазагрузіць Ñтаронку паÑÐ»Ñ Ð¿Ñ€Ñ‹Ð¼ÑÐ½ÐµÐ½Ð½Ñ Ð½Ð¾Ð²Ð°Ð¹ мовы. + + + Date display + + src/app/components/manage/settings/settings.component.html + 32 + + ÐдлюÑтраванне даты + + + Date format + + src/app/components/manage/settings/settings.component.html + 45 + + Фармат даты + + + Short: + + src/app/components/manage/settings/settings.component.html + 51 + + Кароткі: + + + Medium: + + src/app/components/manage/settings/settings.component.html + 55 + + СÑÑ€Ñдні: + + + Long: + + src/app/components/manage/settings/settings.component.html + 59 + + Доўгі: + + + Items per page + + src/app/components/manage/settings/settings.component.html + 67 + + Элементаў на Ñтаронцы + + + Document editor + + src/app/components/manage/settings/settings.component.html + 83 + + РÑдактар дакументаў + + + Use PDF viewer provided by the browser + + src/app/components/manage/settings/settings.component.html + 87 + + ВыкарыÑтоўваць праглÑднік PDF убудаваны Ñž браўзÑÑ€ + + + This is usually faster for displaying large PDF documents, but it might not work on some browsers. + + src/app/components/manage/settings/settings.component.html + 87 + + Звычайна гÑта хутчÑй Ð´Ð»Ñ Ð°Ð´Ð»ÑŽÑÑ‚Ñ€Ð°Ð²Ð°Ð½Ð½Ñ Ð²Ñлікіх дакументаў PDF, але можа не працаваць у некаторых браўзерах. + + + Dark mode + + src/app/components/manage/settings/settings.component.html + 94 + + Цёмны Ñ€Ñжым + + + Use system settings + + src/app/components/manage/settings/settings.component.html + 97 + + ВыкарыÑтоўваць ÑÑ–ÑÑ‚ÑÐ¼Ð½Ñ‹Ñ Ð½Ð°Ð»Ð°Ð´Ñ‹ + + + Enable dark mode + + src/app/components/manage/settings/settings.component.html + 98 + + Уключыць цёмны Ñ€Ñжым + + + Invert thumbnails in dark mode + + src/app/components/manage/settings/settings.component.html + 99 + + Інверціраваць мініÑцюры Ñž цёмным Ñ€Ñжыме + + + Bulk editing + + src/app/components/manage/settings/settings.component.html + 103 + + МаÑавае Ñ€Ñдагаванне + + + Show confirmation dialogs + + src/app/components/manage/settings/settings.component.html + 107 + + Паказаць дыÑÐ»Ð¾Ð³Ð°Ð²Ñ‹Ñ Ð°ÐºÐ½Ð¾ Ð¿Ð°Ñ†Ð²ÐµÑ€Ð´Ð¶Ð°Ð½Ð½Ñ + + + Deleting documents will always ask for confirmation. + + src/app/components/manage/settings/settings.component.html + 107 + + Пры выдаленні дакументаў заўÑёды будзе запытвацца пацверджанне. + + + Apply on close + + src/app/components/manage/settings/settings.component.html + 108 + + Ужыць пры зачыненні + + + Notifications + + src/app/components/manage/settings/settings.component.html + 116 + + ÐпавÑшчÑнні + + + Document processing + + src/app/components/manage/settings/settings.component.html + 119 + + Ðпрацоўка дакумента + + + Show notifications when new documents are detected + + src/app/components/manage/settings/settings.component.html + 123 + + Паказваць апавÑшчÑнні пры выÑўленні новых дакументаў + + + Show notifications when document processing completes successfully + + src/app/components/manage/settings/settings.component.html + 124 + + Паказваць апавÑшчÑнні, калі апрацоўка дакумента завершана паÑпÑхова + + + Show notifications when document processing fails + + src/app/components/manage/settings/settings.component.html + 125 + + Паказваць апавÑшчÑнні, калі апрацоўка дакумента нÑÑžÐ´Ð°Ð»Ð°Ñ + + + Suppress notifications on dashboard + + src/app/components/manage/settings/settings.component.html + 126 + + Схаваць апавÑшчÑÐ½Ð½Ñ Ð½Ð° галоўнай панÑлі + + + This will suppress all messages about document processing status on the dashboard. + + src/app/components/manage/settings/settings.component.html + 126 + + ГÑта адключыць уÑе паведамленні аб Ñтатуце апрацоўкі дакументаў на галоўнай панÑлі. + + + Appears on + + src/app/components/manage/settings/settings.component.html + 146 + + З'ÑўлÑецца на + + + No saved views defined. + + src/app/components/manage/settings/settings.component.html + 163 + + ÐÑма захаваных праглÑдаў. + + + Saved view "" deleted. + + src/app/components/manage/settings/settings.component.ts + 111 + + Захаваны выглÑд "" выдалены. + + + Settings saved successfully. + + src/app/components/manage/settings/settings.component.ts + 133 + + Ðалады паÑпÑхова захаваны. + + + Use system language + + src/app/components/manage/settings/settings.component.ts + 138 + + ВыкарыÑтоўваць мову ÑÑ–ÑÑ‚Ñмы + + + Use date format of display language + + src/app/components/manage/settings/settings.component.ts + 144 + + ВыкарыÑтоўваць фармат даты мовы адлюÑÑ‚Ñ€Ð°Ð²Ð°Ð½Ð½Ñ + + + Error while storing settings on server: + + src/app/components/manage/settings/settings.component.ts + 161 + + Памылка пры захаванні налад на Ñерверы: + + + Color + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 10 + + + src/app/components/manage/tag-list/tag-list.component.html + 20 + + Колер + + + Inbox tag + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 12 + + ТÑг паштовай Ñкрыні + + + Inbox tags are automatically assigned to all consumed documents. + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 12 + + ТÑгі ўваходнÑй Ñкрыні аўтаматычна прыÑвойваюцца ÑžÑім Ñпажываным дакументам. + + + Create new tag + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.ts + 22 + + Стварыць новы Ñ‚Ñг + + + Edit tag + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.ts + 26 + + РÑдагаваць Ñ‚Ñг + + + Do you really want to delete the tag ""? + + src/app/components/manage/tag-list/tag-list.component.ts + 26 + + Ð’Ñ‹ Ñапраўды хочаце выдаліць Ñ‚Ñг ""? + + + 404 Not Found + + src/app/components/not-found/not-found.component.html + 7 + + 404 Ðе знойдзена + + + Any word + + src/app/data/matching-model.ts + 12 + + Любое Ñлова + + + Any: Document contains any of these words (space separated) + + src/app/data/matching-model.ts + 12 + + Любы: дакумент змÑшчае любое з гÑÑ‚Ñ‹Ñ… Ñлоў (Ð¿Ð°Ð´Ð·ÐµÐ»ÐµÐ½Ñ‹Ñ Ð¿Ñ€Ð°Ð±ÐµÐ»Ð°Ð¼) + + + All words + + src/app/data/matching-model.ts + 13 + + УÑе Ñловы + + + All: Document contains all of these words (space separated) + + src/app/data/matching-model.ts + 13 + + УÑе: дакумент змÑшчае ÑžÑе гÑÑ‚Ñ‹Ñ Ñловы (Ð¿Ð°Ð´Ð·ÐµÐ»ÐµÐ½Ñ‹Ñ Ð¿Ñ€Ð°Ð±ÐµÐ»Ð°Ð¼) + + + Exact match + + src/app/data/matching-model.ts + 14 + + Дакладнае Ñупадзенне + + + Exact: Document contains this string + + src/app/data/matching-model.ts + 14 + + Дакладна: дакумент змÑшчае гÑÑ‚Ñ‹ радок + + + Regular expression + + src/app/data/matching-model.ts + 15 + + РÑгулÑрны выраз + + + Regular expression: Document matches this regular expression + + src/app/data/matching-model.ts + 15 + + РÑгулÑрны выраз: Дакумент адпавÑдае гÑтаму Ñ€ÑгулÑрнаму выразу + + + Fuzzy word + + src/app/data/matching-model.ts + 16 + + Ðевыразнае Ñлова + + + Fuzzy: Document contains a word similar to this word + + src/app/data/matching-model.ts + 16 + + Ðевыразна: Дакумент змÑшчае Ñлова, падобнае да гÑтага Ñлова + + + Auto: Learn matching automatically + + src/app/data/matching-model.ts + 17 + + Ðўтаматычны: вучыцеÑÑ Ð°ÑžÑ‚Ð°Ð¼Ð°Ñ‚Ñ‹Ñ‡Ð½Ð° + + + Unsaved Changes + + src/app/guards/dirty-form.guard.ts + 16 + + + src/app/services/open-documents.service.ts + 75 + + + src/app/services/open-documents.service.ts + 96 + + ÐÐµÐ·Ð°Ñ…Ð°Ð²Ð°Ð½Ñ‹Ñ Ð·Ð¼ÐµÐ½Ñ‹ + + + You have unsaved changes. + + src/app/guards/dirty-form.guard.ts + 17 + + + src/app/services/open-documents.service.ts + 76 + + + src/app/services/open-documents.service.ts + 97 + + У Ð²Ð°Ñ Ñ‘Ñць Ð½ÐµÐ·Ð°Ñ…Ð°Ð²Ð°Ð½Ñ‹Ñ Ð·Ð¼ÐµÐ½Ñ‹. + + + Are you sure you want to leave? + + src/app/guards/dirty-form.guard.ts + 18 + + Ð’Ñ‹ ўпÑўнены, што хочаце ÑÑ‹Ñці? + + + Leave page + + src/app/guards/dirty-form.guard.ts + 20 + + Пакінуць Ñтаронку + + + (no title) + + src/app/pipes/document-title.pipe.ts + 12 + + (нÑма назвы) + + + Yes + + src/app/pipes/yes-no.pipe.ts + 9 + + Так + + + No + + src/app/pipes/yes-no.pipe.ts + 9 + + Ðе + + + Document already exists. + + src/app/services/consumer-status.service.ts + 15 + + Дакумент ужо Ñ–Ñнуе. + + + File not found. + + src/app/services/consumer-status.service.ts + 16 + + Файл не знойдзены. + + + Pre-consume script does not exist. + + src/app/services/consumer-status.service.ts + 17 + + Pre-Consume is a term that appears like that in the documentation as well and does not need a specific translation + Скрыпт перадапрацоўкі не Ñ–Ñнуе. + + + Error while executing pre-consume script. + + src/app/services/consumer-status.service.ts + 18 + + Pre-Consume is a term that appears like that in the documentation as well and does not need a specific translation + Памылка пры выкананні Ñкрыпту перадапрацоўкі. + + + Post-consume script does not exist. + + src/app/services/consumer-status.service.ts + 19 + + Post-Consume is a term that appears like that in the documentation as well and does not need a specific translation + Скрыпт поÑтапрацоўкі не Ñ–Ñнуе. + + + Error while executing post-consume script. + + src/app/services/consumer-status.service.ts + 20 + + Post-Consume is a term that appears like that in the documentation as well and does not need a specific translation + Памылка пры выкананні Ñкрыпту поÑтапрацоўкі. + + + Received new file. + + src/app/services/consumer-status.service.ts + 21 + + Ðтрыманы новы файл. + + + File type not supported. + + src/app/services/consumer-status.service.ts + 22 + + Тып файла не падтрымліваецца. + + + Processing document... + + src/app/services/consumer-status.service.ts + 23 + + Ðпрацоўка дакумента... + + + Generating thumbnail... + + src/app/services/consumer-status.service.ts + 24 + + СтварÑнне мініÑцюры... + + + Retrieving date from document... + + src/app/services/consumer-status.service.ts + 25 + + Ðтрыманне даты з дакумента... + + + Saving document... + + src/app/services/consumer-status.service.ts + 26 + + Захаванне дакумента... + + + Finished. + + src/app/services/consumer-status.service.ts + 27 + + Завершана. + + + Are you sure you want to close this document? + + src/app/services/open-documents.service.ts + 77 + + Ð’Ñ‹ ўпÑўнены, што хочаце закрыць гÑÑ‚Ñ‹ дакумент? + + + Close document + + src/app/services/open-documents.service.ts + 79 + + Закрыць дакумент + + + Are you sure you want to close all documents? + + src/app/services/open-documents.service.ts + 98 + + Ð’Ñ‹ ўпÑўнены, што хочаце закрыць уÑе дакументы? + + + Close documents + + src/app/services/open-documents.service.ts + 100 + + Закрыць дакументы + + + Modified + + src/app/services/rest/document.service.ts + 23 + + Зменена + + + Search score + + src/app/services/rest/document.service.ts + 28 + + Score is a value returned by the full text search engine and specifies how well a result matches the given query + РÑлевантнаÑць + + + English (US) + + src/app/services/settings.service.ts + 90 + + ÐнглійÑÐºÐ°Ñ (ЗШÐ) + + + Czech + + src/app/services/settings.service.ts + 91 + + ЧÑшÑÐºÐ°Ñ + + + Danish + + src/app/services/settings.service.ts + 92 + + Ð”Ð°Ñ†ÐºÐ°Ñ + + + German + + src/app/services/settings.service.ts + 93 + + ÐÑÐ¼ÐµÑ†ÐºÐ°Ñ + + + English (GB) + + src/app/services/settings.service.ts + 94 + + ÐнглійÑÐºÐ°Ñ (Ð’ÑлікабрытаніÑ) + + + Spanish + + src/app/services/settings.service.ts + 95 + + ІÑпанÑÐºÐ°Ñ + + + French + + src/app/services/settings.service.ts + 96 + + ФранцузÑÐºÐ°Ñ + + + Italian + + src/app/services/settings.service.ts + 97 + + ІтальÑнÑÐºÐ°Ñ + + + Luxembourgish + + src/app/services/settings.service.ts + 98 + + ЛюкÑембургÑÐºÐ°Ñ + + + Dutch + + src/app/services/settings.service.ts + 99 + + ÐідÑрландÑÐºÐ°Ñ + + + Polish + + src/app/services/settings.service.ts + 100 + + ПольÑÐºÐ°Ñ + + + Portuguese (Brazil) + + src/app/services/settings.service.ts + 101 + + ПартугальÑÐºÐ°Ñ (БразіліÑ) + + + Portuguese + + src/app/services/settings.service.ts + 102 + + ПартугальÑÐºÐ°Ñ + + + Romanian + + src/app/services/settings.service.ts + 103 + + РумынÑÐºÐ°Ñ + + + Russian + + src/app/services/settings.service.ts + 104 + + РуÑÐºÐ°Ñ + + + Swedish + + src/app/services/settings.service.ts + 105 + + ШведÑÐºÐ°Ñ + + + ISO 8601 + + src/app/services/settings.service.ts + 115 + + ISO 8601 + + + Error + + src/app/services/toast.service.ts + 35 + + Памылка + + + Information + + src/app/services/toast.service.ts + 39 + + Ð†Ð½Ñ„Ð°Ñ€Ð¼Ð°Ñ†Ñ‹Ñ + + + + diff --git a/src-ui/src/locale/messages.da_DK.xlf b/src-ui/src/locale/messages.da_DK.xlf index 80bfc8e7b..d0f170456 100644 --- a/src-ui/src/locale/messages.da_DK.xlf +++ b/src-ui/src/locale/messages.da_DK.xlf @@ -616,7 +616,7 @@ 4 This button dismisses all status messages about processed documents on the dashboard (failed and successful) - Afskedig afsluttede + Ryd afsluttede Drop documents here or @@ -2016,7 +2016,7 @@ src/app/components/manage/settings/settings.component.html 17 - Visning sprog + Visningssprog You need to reload the page after applying a new language. @@ -2232,7 +2232,7 @@ src/app/components/manage/settings/settings.component.html 163 - Ingen gemte visninger angivet. + Ingen gemte visninger. Saved view "" deleted. diff --git a/src-ui/src/locale/messages.es_ES.xlf b/src-ui/src/locale/messages.es_ES.xlf index 9b9ffa717..67fb80b72 100644 --- a/src-ui/src/locale/messages.es_ES.xlf +++ b/src-ui/src/locale/messages.es_ES.xlf @@ -61,7 +61,7 @@ 11 app title - Paperless-ngx + Paperless-ngx Search documents @@ -185,7 +185,7 @@ src/app/components/manage/correspondent-list/correspondent-list.component.html 1 - Tipos de documento + Interlocutores Tags @@ -233,7 +233,7 @@ src/app/components/manage/logs/logs.component.html 1 - Logs + Logs Admin @@ -265,7 +265,7 @@ src/app/components/app-frame/app-frame.component.html 175 - GitHub + GitHub Suggest an idea @@ -433,7 +433,7 @@ src/app/components/common/filterable-dropdown/filterable-dropdown.component.html 45 - Click again to exclude items. + Haga clic de nuevo para excluir los elementos. Not assigned @@ -511,7 +511,7 @@ src/app/components/dashboard/dashboard.component.ts 33 - Hello , welcome to Paperless-ngx! + Hola , bienvenido a Paperless-ngx! Welcome to Paperless-ngx! @@ -519,7 +519,7 @@ src/app/components/dashboard/dashboard.component.ts 35 - Welcome to Paperless-ngx! + ¡Bienvenido a Paperless-ngx! Show all @@ -678,7 +678,7 @@ 117 this string is used to separate processing, failed and added on the file upload widget - , + , Connecting... @@ -1222,7 +1222,7 @@ src/app/components/document-list/bulk-editor/bulk-editor.component.ts 117 - "" + "" "" and "" @@ -1520,7 +1520,7 @@ src/app/components/document-list/document-list.component.html 87 - Loading... + Cargando... {VAR_PLURAL, plural, =1 {Selected of one document} other {Selected of documents}} @@ -2284,7 +2284,7 @@ src/app/components/manage/tag-list/tag-list.component.html 20 - Color + Color Inbox tag @@ -2436,7 +2436,7 @@ src/app/services/open-documents.service.ts 96 - Unsaved Changes + Cambios sin guardar You have unsaved changes. @@ -2452,7 +2452,7 @@ src/app/services/open-documents.service.ts 97 - You have unsaved changes. + Tiene cambios sin guardar. Are you sure you want to leave? @@ -2460,7 +2460,7 @@ src/app/guards/dirty-form.guard.ts 18 - Are you sure you want to leave? + ¿Está seguro que quiere salir? Leave page @@ -2468,7 +2468,7 @@ src/app/guards/dirty-form.guard.ts 20 - Leave page + Salir de la página (no title) @@ -2492,7 +2492,7 @@ src/app/pipes/yes-no.pipe.ts 9 - No + No Document already exists. @@ -2608,7 +2608,7 @@ src/app/services/open-documents.service.ts 77 - Are you sure you want to close this document? + ¿Está seguro de querer cerrar este documento? Close document @@ -2616,7 +2616,7 @@ src/app/services/open-documents.service.ts 79 - Close document + Cerrar documento Are you sure you want to close all documents? @@ -2624,7 +2624,7 @@ src/app/services/open-documents.service.ts 98 - Are you sure you want to close all documents? + ¿Está seguro de querer cerrar todos los documentos? Close documents @@ -2632,7 +2632,7 @@ src/app/services/open-documents.service.ts 100 - Close documents + Cerrar documentos Modified @@ -2665,7 +2665,7 @@ src/app/services/settings.service.ts 91 - Czech + Checo Danish @@ -2673,7 +2673,7 @@ src/app/services/settings.service.ts 92 - Danish + Danés German @@ -2721,7 +2721,7 @@ src/app/services/settings.service.ts 98 - Luxembourgish + Luxemburgués Dutch @@ -2785,7 +2785,7 @@ src/app/services/settings.service.ts 115 - ISO 8601 + ISO 8601 Error @@ -2793,7 +2793,7 @@ src/app/services/toast.service.ts 35 - Error + Error Information diff --git a/src-ui/src/locale/messages.fi_FI.xlf b/src-ui/src/locale/messages.fi_FI.xlf new file mode 100644 index 000000000..39bcbd679 --- /dev/null +++ b/src-ui/src/locale/messages.fi_FI.xlf @@ -0,0 +1,2808 @@ + + + + + + Document added + + src/app/app.component.ts + 51 + + Dokumentti lisätty + + + Document was added to paperless. + + src/app/app.component.ts + 51 + + Document was added to paperless. + + + Open document + + src/app/app.component.ts + 51 + + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 45 + + Open document + + + Could not add : + + src/app/app.component.ts + 59 + + Could not add : + + + New document detected + + src/app/app.component.ts + 65 + + New document detected + + + Document is being processed by paperless. + + src/app/app.component.ts + 65 + + Document is being processed by paperless. + + + Paperless-ngx + + src/app/components/app-frame/app-frame.component.html + 11 + + app title + Paperless-ngx + + + Search documents + + src/app/components/app-frame/app-frame.component.html + 18 + + Search documents + + + Logged in as + + src/app/components/app-frame/app-frame.component.html + 34 + + Logged in as + + + Settings + + src/app/components/app-frame/app-frame.component.html + 40 + + + src/app/components/app-frame/app-frame.component.html + 147 + + + src/app/components/manage/settings/settings.component.html + 1 + + Settings + + + Logout + + src/app/components/app-frame/app-frame.component.html + 45 + + Logout + + + Dashboard + + src/app/components/app-frame/app-frame.component.html + 61 + + + src/app/components/dashboard/dashboard.component.html + 1 + + Dashboard + + + Documents + + src/app/components/app-frame/app-frame.component.html + 68 + + + src/app/components/document-list/document-list.component.ts + 51 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 37 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 35 + + + src/app/components/manage/tag-list/tag-list.component.html + 38 + + Documents + + + Saved views + + src/app/components/app-frame/app-frame.component.html + 74 + + + src/app/components/manage/settings/settings.component.html + 134 + + Saved views + + + Open documents + + src/app/components/app-frame/app-frame.component.html + 87 + + Open documents + + + Close all + + src/app/components/app-frame/app-frame.component.html + 106 + + Close all + + + Manage + + src/app/components/app-frame/app-frame.component.html + 112 + + Manage + + + Correspondents + + src/app/components/app-frame/app-frame.component.html + 119 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 1 + + Correspondents + + + Tags + + src/app/components/app-frame/app-frame.component.html + 126 + + + src/app/components/common/input/tags/tags.component.html + 2 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 28 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 18 + + + src/app/components/manage/tag-list/tag-list.component.html + 1 + + Tags + + + Document types + + src/app/components/app-frame/app-frame.component.html + 133 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 1 + + Document types + + + Logs + + src/app/components/app-frame/app-frame.component.html + 140 + + + src/app/components/manage/logs/logs.component.html + 1 + + Logs + + + Admin + + src/app/components/app-frame/app-frame.component.html + 154 + + Admin + + + Info + + src/app/components/app-frame/app-frame.component.html + 160 + + Info + + + Documentation + + src/app/components/app-frame/app-frame.component.html + 167 + + Documentation + + + GitHub + + src/app/components/app-frame/app-frame.component.html + 175 + + GitHub + + + Suggest an idea + + src/app/components/app-frame/app-frame.component.html + 181 + + Suggest an idea + + + Cancel + + src/app/components/common/confirm-dialog/confirm-dialog.component.html + 11 + + + src/app/components/common/select-dialog/select-dialog.component.html + 12 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 6 + + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 13 + + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 14 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 16 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 18 + + Cancel + + + Confirmation + + src/app/components/common/confirm-dialog/confirm-dialog.component.ts + 18 + + Confirmation + + + Confirm + + src/app/components/common/confirm-dialog/confirm-dialog.component.ts + 30 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 143 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 166 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 189 + + Confirm + + + After + + src/app/components/common/date-dropdown/date-dropdown.component.html + 13 + + After + + + Clear + + src/app/components/common/date-dropdown/date-dropdown.component.html + 18 + + + src/app/components/common/date-dropdown/date-dropdown.component.html + 41 + + Clear + + + Before + + src/app/components/common/date-dropdown/date-dropdown.component.html + 36 + + Before + + + Last 7 days + + src/app/components/common/date-dropdown/date-dropdown.component.ts + 34 + + Last 7 days + + + Last month + + src/app/components/common/date-dropdown/date-dropdown.component.ts + 35 + + Last month + + + Last 3 months + + src/app/components/common/date-dropdown/date-dropdown.component.ts + 36 + + Last 3 months + + + Last year + + src/app/components/common/date-dropdown/date-dropdown.component.ts + 37 + + Last year + + + Create new item + + src/app/components/common/edit-dialog/edit-dialog.component.ts + 50 + + Create new item + + + Edit item + + src/app/components/common/edit-dialog/edit-dialog.component.ts + 54 + + Edit item + + + Could not save element: + + src/app/components/common/edit-dialog/edit-dialog.component.ts + 58 + + Could not save element: + + + Apply + + src/app/components/common/filterable-dropdown/filterable-dropdown.component.html + 39 + + Apply + + + Click again to exclude items. + + src/app/components/common/filterable-dropdown/filterable-dropdown.component.html + 45 + + Click again to exclude items. + + + Not assigned + + src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts + 209 + + Filter drop down element to filter for documents with no correspondent/type/tag assigned + Not assigned + + + Invalid date. + + src/app/components/common/input/date/date.component.html + 12 + + Invalid date. + + + Add item + + src/app/components/common/input/select/select.component.html + 11 + + Used for both types and correspondents + Add item + + + Suggestions: + + src/app/components/common/input/select/select.component.html + 29 + + + src/app/components/common/input/tags/tags.component.html + 42 + + Suggestions: + + + Add tag + + src/app/components/common/input/tags/tags.component.html + 11 + + Add tag + + + Select + + src/app/components/common/select-dialog/select-dialog.component.html + 13 + + + src/app/components/common/select-dialog/select-dialog.component.ts + 18 + + + src/app/components/document-list/document-list.component.html + 7 + + Select + + + Please select an object + + src/app/components/common/select-dialog/select-dialog.component.ts + 21 + + Please select an object + + + Hello , welcome to Paperless-ngx! + + src/app/components/dashboard/dashboard.component.ts + 33 + + Hello , welcome to Paperless-ngx! + + + Welcome to Paperless-ngx! + + src/app/components/dashboard/dashboard.component.ts + 35 + + Welcome to Paperless-ngx! + + + Show all + + src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html + 3 + + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 27 + + Show all + + + Created + + src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html + 9 + + + src/app/components/document-list/document-list.component.html + 141 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 41 + + + src/app/services/rest/document.service.ts + 21 + + Created + + + Title + + src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html + 10 + + + src/app/components/document-detail/document-detail.component.html + 55 + + + src/app/components/document-list/document-list.component.html + 129 + + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 88 + + + src/app/services/rest/document.service.ts + 19 + + Title + + + Statistics + + src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html + 1 + + Statistics + + + Documents in inbox: + + src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html + 3 + + Documents in inbox: + + + Total documents: + + src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html + 4 + + Total documents: + + + Upload new documents + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 1 + + Upload new documents + + + Dismiss completed + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 4 + + This button dismisses all status messages about processed documents on the dashboard (failed and successful) + Dismiss completed + + + Drop documents here or + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 13 + + Drop documents here or + + + Browse files + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 13 + + Browse files + + + {VAR_PLURAL, plural, =1 {One more document} other { more documents}} + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 25 + + This is shown as a summary line when there are more than 5 document in the processing pipeline. + {VAR_PLURAL, plural, =1 {One more document} other { more documents}} + + + Processing: + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 32 + + Processing: + + + Failed: + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 35 + + Failed: + + + Added: + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 38 + + Added: + + + , + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 40 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 117 + + this string is used to separate processing, failed and added on the file upload widget + , + + + Connecting... + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 118 + + Connecting... + + + Uploading... + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 123 + + Uploading... + + + Upload complete, waiting... + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 126 + + Upload complete, waiting... + + + HTTP error: + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 136 + + HTTP error: + + + First steps + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 1 + + First steps + + + Paperless is running! :) + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 5 + + Paperless is running! :) + + + You can start uploading documents by dropping them in the file upload box to the right or by dropping them in the configured consumption folder and they'll start showing up in the documents list. After you've added some metadata to your documents, use the filtering mechanisms of paperless to create custom views (such as 'Recently added', 'Tagged TODO') and they will appear on the dashboard instead of this message. + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 6,7 + + You can start uploading documents by dropping them in the file upload box to the right or by dropping them in the configured consumption folder and they'll start showing up in the documents list. After you've added some metadata to your documents, use the filtering mechanisms of paperless to create custom views (such as 'Recently added', 'Tagged TODO') and they will appear on the dashboard instead of this message. + + + Paperless offers some more features that try to make your life easier: + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 8 + + Paperless offers some more features that try to make your life easier: + + + Once you've got a couple documents in paperless and added metadata to them, paperless can assign that metadata to new documents automatically. + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 10 + + Once you've got a couple documents in paperless and added metadata to them, paperless can assign that metadata to new documents automatically. + + + You can configure paperless to read your mails and add documents from attached files. + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 11 + + You can configure paperless to read your mails and add documents from attached files. + + + Consult the documentation on how to use these features. The section on basic usage also has some information on how to use paperless in general. + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 13 + + Consult the documentation on how to use these features. The section on basic usage also has some information on how to use paperless in general. + + + Searching document with asn + + src/app/components/document-asn/document-asn.component.html + 1 + + Searching document with asn + + + Page + + src/app/components/document-detail/document-detail.component.html + 3 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 15 + + Page + + + of + + src/app/components/document-detail/document-detail.component.html + 5 + + of + + + Delete + + src/app/components/document-detail/document-detail.component.html + 11 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 76 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 48 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 46 + + + src/app/components/manage/generic-list/generic-list.component.ts + 106 + + + src/app/components/manage/settings/settings.component.html + 159 + + + src/app/components/manage/tag-list/tag-list.component.html + 49 + + Delete + + + Download + + src/app/components/document-detail/document-detail.component.html + 19 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 63 + + + src/app/components/document-list/document-card-large/document-card-large.component.html + 60 + + + src/app/components/document-list/document-card-small/document-card-small.component.html + 82 + + Download + + + Download original + + src/app/components/document-detail/document-detail.component.html + 25 + + Download original + + + More like this + + src/app/components/document-detail/document-detail.component.html + 34 + + + src/app/components/document-list/document-card-large/document-card-large.component.html + 38 + + More like this + + + Close + + src/app/components/document-detail/document-detail.component.html + 40 + + Close + + + Details + + src/app/components/document-detail/document-detail.component.html + 52 + + Details + + + Archive serial number + + src/app/components/document-detail/document-detail.component.html + 56 + + Archive serial number + + + Date created + + src/app/components/document-detail/document-detail.component.html + 57 + + Date created + + + Correspondent + + src/app/components/document-detail/document-detail.component.html + 58 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 38 + + + src/app/components/document-list/document-list.component.html + 123 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 26 + + + src/app/services/rest/document.service.ts + 18 + + Correspondent + + + Document type + + src/app/components/document-detail/document-detail.component.html + 60 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 47 + + + src/app/components/document-list/document-list.component.html + 135 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 33 + + + src/app/services/rest/document.service.ts + 20 + + Document type + + + Content + + src/app/components/document-detail/document-detail.component.html + 68 + + Content + + + Metadata + + src/app/components/document-detail/document-detail.component.html + 77 + + + src/app/components/document-detail/metadata-collapse/metadata-collapse.component.ts + 18 + + Metadata + + + Date modified + + src/app/components/document-detail/document-detail.component.html + 83 + + Date modified + + + Date added + + src/app/components/document-detail/document-detail.component.html + 87 + + Date added + + + Media filename + + src/app/components/document-detail/document-detail.component.html + 91 + + Media filename + + + Original MD5 checksum + + src/app/components/document-detail/document-detail.component.html + 95 + + Original MD5 checksum + + + Original file size + + src/app/components/document-detail/document-detail.component.html + 99 + + Original file size + + + Original mime type + + src/app/components/document-detail/document-detail.component.html + 103 + + Original mime type + + + Archive MD5 checksum + + src/app/components/document-detail/document-detail.component.html + 107 + + Archive MD5 checksum + + + Archive file size + + src/app/components/document-detail/document-detail.component.html + 111 + + Archive file size + + + Original document metadata + + src/app/components/document-detail/document-detail.component.html + 117 + + Original document metadata + + + Archived document metadata + + src/app/components/document-detail/document-detail.component.html + 118 + + Archived document metadata + + + Discard + + src/app/components/document-detail/document-detail.component.html + 143 + + Discard + + + Save & next + + src/app/components/document-detail/document-detail.component.html + 144 + + Save & next + + + Save + + src/app/components/document-detail/document-detail.component.html + 145 + + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 14 + + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 15 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 17 + + + src/app/components/manage/settings/settings.component.html + 173 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 19 + + Save + + + Confirm delete + + src/app/components/document-detail/document-detail.component.ts + 267 + + + src/app/components/manage/generic-list/generic-list.component.ts + 102 + + Confirm delete + + + Do you really want to delete document ""? + + src/app/components/document-detail/document-detail.component.ts + 268 + + Do you really want to delete document ""? + + + The files for this document will be deleted permanently. This operation cannot be undone. + + src/app/components/document-detail/document-detail.component.ts + 269 + + The files for this document will be deleted permanently. This operation cannot be undone. + + + Delete document + + src/app/components/document-detail/document-detail.component.ts + 271 + + Delete document + + + Error deleting document: + + src/app/components/document-detail/document-detail.component.ts + 281 + + Error deleting document: + + + Select: + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 10 + + Select: + + + All + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 20 + + All + + + Edit: + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 27 + + Edit: + + + Filter tags + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 29 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 19 + + Filter tags + + + Filter correspondents + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 39 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 27 + + Filter correspondents + + + Filter document types + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 48 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 34 + + Filter document types + + + Download originals + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 68 + + Download originals + + + Error executing bulk operation: + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 74 + + Error executing bulk operation: + + + "" + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 113 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 117 + + "" + + + "" and "" + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 115 + + This is for messages like 'modify "tag1" and "tag2"' + "" and "" + + + and "" + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 118 + + this is for messages like 'modify "tag1", "tag2" and "tag3"' + and "" + + + Confirm tags assignment + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 127 + + Confirm tags assignment + + + This operation will add the tag "" to selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 130 + + This operation will add the tag "" to selected document(s). + + + This operation will add the tags to selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 132 + + This operation will add the tags to selected document(s). + + + This operation will remove the tag "" from selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 135 + + This operation will remove the tag "" from selected document(s). + + + This operation will remove the tags from selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 137 + + This operation will remove the tags from selected document(s). + + + This operation will add the tags and remove the tags on selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 139 + + This operation will add the tags and remove the tags on selected document(s). + + + Confirm correspondent assignment + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 159 + + Confirm correspondent assignment + + + This operation will assign the correspondent "" to selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 161 + + This operation will assign the correspondent "" to selected document(s). + + + This operation will remove the correspondent from selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 163 + + This operation will remove the correspondent from selected document(s). + + + Confirm document type assignment + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 182 + + Confirm document type assignment + + + This operation will assign the document type "" to selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 184 + + This operation will assign the document type "" to selected document(s). + + + This operation will remove the document type from selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 186 + + This operation will remove the document type from selected document(s). + + + Delete confirm + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 201 + + Delete confirm + + + This operation will permanently delete selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 202 + + This operation will permanently delete selected document(s). + + + This operation cannot be undone. + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 203 + + This operation cannot be undone. + + + Delete document(s) + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 205 + + Delete document(s) + + + Filter by correspondent + + src/app/components/document-list/document-card-large/document-card-large.component.html + 20 + + + src/app/components/document-list/document-card-small/document-card-small.component.html + 26 + + Filter by correspondent + + + Filter by tag + + src/app/components/document-list/document-card-large/document-card-large.component.html + 24 + + + src/app/components/document-list/document-card-small/document-card-small.component.html + 15 + + Filter by tag + + + Edit + + src/app/components/document-list/document-card-large/document-card-large.component.html + 43 + + + src/app/components/document-list/document-card-small/document-card-small.component.html + 66 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 42 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 40 + + + src/app/components/manage/tag-list/tag-list.component.html + 43 + + Edit + + + View + + src/app/components/document-list/document-card-large/document-card-large.component.html + 51 + + View + + + Score: + + src/app/components/document-list/document-card-large/document-card-large.component.html + 87 + + Score: + + + Created: + + src/app/components/document-list/document-card-small/document-card-small.component.html + 43 + + Created: + + + Added: + + src/app/components/document-list/document-card-small/document-card-small.component.html + 44 + + Added: + + + Modified: + + src/app/components/document-list/document-card-small/document-card-small.component.html + 45 + + Modified: + + + Select none + + src/app/components/document-list/document-list.component.html + 10 + + Select none + + + Select page + + src/app/components/document-list/document-list.component.html + 11 + + Select page + + + Select all + + src/app/components/document-list/document-list.component.html + 12 + + Select all + + + Sort + + src/app/components/document-list/document-list.component.html + 39 + + Sort + + + Views + + src/app/components/document-list/document-list.component.html + 64 + + Views + + + Save "" + + src/app/components/document-list/document-list.component.html + 71 + + Save "" + + + Save as... + + src/app/components/document-list/document-list.component.html + 72 + + Save as... + + + Loading... + + src/app/components/document-list/document-list.component.html + 87 + + Loading... + + + {VAR_PLURAL, plural, =1 {Selected of one document} other {Selected of documents}} + + src/app/components/document-list/document-list.component.html + 89 + + {VAR_PLURAL, plural, =1 {Selected of one document} other {Selected of documents}} + + + {VAR_PLURAL, plural, =1 {One document} other { documents}} + + src/app/components/document-list/document-list.component.html + 91 + + {VAR_PLURAL, plural, =1 {One document} other { documents}} + + + (filtered) + + src/app/components/document-list/document-list.component.html + 91 + + (filtered) + + + ASN + + src/app/components/document-list/document-list.component.html + 117 + + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 90 + + + src/app/services/rest/document.service.ts + 17 + + ASN + + + Added + + src/app/components/document-list/document-list.component.html + 147 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 48 + + + src/app/services/rest/document.service.ts + 22 + + Added + + + View "" saved successfully. + + src/app/components/document-list/document-list.component.ts + 116 + + View "" saved successfully. + + + View "" created successfully. + + src/app/components/document-list/document-list.component.ts + 138 + + View "" created successfully. + + + Reset filters + + src/app/components/document-list/filter-editor/filter-editor.component.html + 57 + + Reset filters + + + Correspondent: + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 37 + + Correspondent: + + + Without correspondent + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 39 + + Without correspondent + + + Type: + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 44 + + Type: + + + Without document type + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 46 + + Without document type + + + Tag: + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 50 + + Tag: + + + Without any tag + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 54 + + Without any tag + + + Title: + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 58 + + Title: + + + ASN: + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 61 + + ASN: + + + Title & content + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 89 + + Title & content + + + Advanced search + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 91 + + Advanced search + + + More like + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 94 + + More like + + + Save current view + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 3 + + Save current view + + + Name + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 8 + + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 8 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 9 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 19 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 9 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 9 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 19 + + + src/app/components/manage/settings/settings.component.html + 141 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 8 + + + src/app/components/manage/tag-list/tag-list.component.html + 9 + + + src/app/components/manage/tag-list/tag-list.component.html + 19 + + Name + + + Show in sidebar + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 9 + + + src/app/components/manage/settings/settings.component.html + 153 + + Show in sidebar + + + Show on dashboard + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 10 + + + src/app/components/manage/settings/settings.component.html + 149 + + Show on dashboard + + + Matching algorithm + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 9 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 10 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 13 + + Matching algorithm + + + Matching pattern + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 10 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 11 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 14 + + Matching pattern + + + Case insensitive + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 11 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 12 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 15 + + Case insensitive + + + Create new correspondent + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.ts + 21 + + Create new correspondent + + + Edit correspondent + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.ts + 25 + + Edit correspondent + + + Create + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 2 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 2 + + + src/app/components/manage/tag-list/tag-list.component.html + 2 + + Create + + + Filter by: + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 8 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 8 + + + src/app/components/manage/tag-list/tag-list.component.html + 8 + + Filter by: + + + Matching + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 20 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 20 + + + src/app/components/manage/tag-list/tag-list.component.html + 21 + + Matching + + + Document count + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 21 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 21 + + + src/app/components/manage/tag-list/tag-list.component.html + 22 + + Document count + + + Last correspondence + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 22 + + Last correspondence + + + Actions + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 23 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 22 + + + src/app/components/manage/settings/settings.component.html + 158 + + + src/app/components/manage/tag-list/tag-list.component.html + 23 + + Actions + + + Do you really want to delete the correspondent ""? + + src/app/components/manage/correspondent-list/correspondent-list.component.ts + 26 + + Do you really want to delete the correspondent ""? + + + Create new document type + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.ts + 21 + + Create new document type + + + Edit document type + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.ts + 25 + + Edit document type + + + Do you really want to delete the document type ""? + + src/app/components/manage/document-type-list/document-type-list.component.ts + 26 + + Do you really want to delete the document type ""? + + + Automatic + + src/app/components/manage/generic-list/generic-list.component.ts + 39 + + + src/app/data/matching-model.ts + 17 + + Automatic + + + Do you really want to delete this element? + + src/app/components/manage/generic-list/generic-list.component.ts + 97 + + Do you really want to delete this element? + + + Associated documents will not be deleted. + + src/app/components/manage/generic-list/generic-list.component.ts + 104 + + Associated documents will not be deleted. + + + Error while deleting element: + + src/app/components/manage/generic-list/generic-list.component.ts + 114 + + Error while deleting element: + + + General settings + + src/app/components/manage/settings/settings.component.html + 10 + + General settings + + + Appearance + + src/app/components/manage/settings/settings.component.html + 13 + + Appearance + + + Display language + + src/app/components/manage/settings/settings.component.html + 17 + + Display language + + + You need to reload the page after applying a new language. + + src/app/components/manage/settings/settings.component.html + 25 + + You need to reload the page after applying a new language. + + + Date display + + src/app/components/manage/settings/settings.component.html + 32 + + Date display + + + Date format + + src/app/components/manage/settings/settings.component.html + 45 + + Date format + + + Short: + + src/app/components/manage/settings/settings.component.html + 51 + + Short: + + + Medium: + + src/app/components/manage/settings/settings.component.html + 55 + + Medium: + + + Long: + + src/app/components/manage/settings/settings.component.html + 59 + + Long: + + + Items per page + + src/app/components/manage/settings/settings.component.html + 67 + + Items per page + + + Document editor + + src/app/components/manage/settings/settings.component.html + 83 + + Document editor + + + Use PDF viewer provided by the browser + + src/app/components/manage/settings/settings.component.html + 87 + + Use PDF viewer provided by the browser + + + This is usually faster for displaying large PDF documents, but it might not work on some browsers. + + src/app/components/manage/settings/settings.component.html + 87 + + This is usually faster for displaying large PDF documents, but it might not work on some browsers. + + + Dark mode + + src/app/components/manage/settings/settings.component.html + 94 + + Dark mode + + + Use system settings + + src/app/components/manage/settings/settings.component.html + 97 + + Use system settings + + + Enable dark mode + + src/app/components/manage/settings/settings.component.html + 98 + + Enable dark mode + + + Invert thumbnails in dark mode + + src/app/components/manage/settings/settings.component.html + 99 + + Invert thumbnails in dark mode + + + Bulk editing + + src/app/components/manage/settings/settings.component.html + 103 + + Bulk editing + + + Show confirmation dialogs + + src/app/components/manage/settings/settings.component.html + 107 + + Show confirmation dialogs + + + Deleting documents will always ask for confirmation. + + src/app/components/manage/settings/settings.component.html + 107 + + Deleting documents will always ask for confirmation. + + + Apply on close + + src/app/components/manage/settings/settings.component.html + 108 + + Apply on close + + + Notifications + + src/app/components/manage/settings/settings.component.html + 116 + + Notifications + + + Document processing + + src/app/components/manage/settings/settings.component.html + 119 + + Document processing + + + Show notifications when new documents are detected + + src/app/components/manage/settings/settings.component.html + 123 + + Show notifications when new documents are detected + + + Show notifications when document processing completes successfully + + src/app/components/manage/settings/settings.component.html + 124 + + Show notifications when document processing completes successfully + + + Show notifications when document processing fails + + src/app/components/manage/settings/settings.component.html + 125 + + Show notifications when document processing fails + + + Suppress notifications on dashboard + + src/app/components/manage/settings/settings.component.html + 126 + + Suppress notifications on dashboard + + + This will suppress all messages about document processing status on the dashboard. + + src/app/components/manage/settings/settings.component.html + 126 + + This will suppress all messages about document processing status on the dashboard. + + + Appears on + + src/app/components/manage/settings/settings.component.html + 146 + + Appears on + + + No saved views defined. + + src/app/components/manage/settings/settings.component.html + 163 + + No saved views defined. + + + Saved view "" deleted. + + src/app/components/manage/settings/settings.component.ts + 111 + + Saved view "" deleted. + + + Settings saved successfully. + + src/app/components/manage/settings/settings.component.ts + 133 + + Settings saved successfully. + + + Use system language + + src/app/components/manage/settings/settings.component.ts + 138 + + Use system language + + + Use date format of display language + + src/app/components/manage/settings/settings.component.ts + 144 + + Use date format of display language + + + Error while storing settings on server: + + src/app/components/manage/settings/settings.component.ts + 161 + + Error while storing settings on server: + + + Color + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 10 + + + src/app/components/manage/tag-list/tag-list.component.html + 20 + + Color + + + Inbox tag + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 12 + + Inbox tag + + + Inbox tags are automatically assigned to all consumed documents. + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 12 + + Inbox tags are automatically assigned to all consumed documents. + + + Create new tag + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.ts + 22 + + Create new tag + + + Edit tag + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.ts + 26 + + Edit tag + + + Do you really want to delete the tag ""? + + src/app/components/manage/tag-list/tag-list.component.ts + 26 + + Do you really want to delete the tag ""? + + + 404 Not Found + + src/app/components/not-found/not-found.component.html + 7 + + 404 Not Found + + + Any word + + src/app/data/matching-model.ts + 12 + + Any word + + + Any: Document contains any of these words (space separated) + + src/app/data/matching-model.ts + 12 + + Any: Document contains any of these words (space separated) + + + All words + + src/app/data/matching-model.ts + 13 + + All words + + + All: Document contains all of these words (space separated) + + src/app/data/matching-model.ts + 13 + + All: Document contains all of these words (space separated) + + + Exact match + + src/app/data/matching-model.ts + 14 + + Exact match + + + Exact: Document contains this string + + src/app/data/matching-model.ts + 14 + + Exact: Document contains this string + + + Regular expression + + src/app/data/matching-model.ts + 15 + + Regular expression + + + Regular expression: Document matches this regular expression + + src/app/data/matching-model.ts + 15 + + Regular expression: Document matches this regular expression + + + Fuzzy word + + src/app/data/matching-model.ts + 16 + + Fuzzy word + + + Fuzzy: Document contains a word similar to this word + + src/app/data/matching-model.ts + 16 + + Fuzzy: Document contains a word similar to this word + + + Auto: Learn matching automatically + + src/app/data/matching-model.ts + 17 + + Auto: Learn matching automatically + + + Unsaved Changes + + src/app/guards/dirty-form.guard.ts + 16 + + + src/app/services/open-documents.service.ts + 75 + + + src/app/services/open-documents.service.ts + 96 + + Unsaved Changes + + + You have unsaved changes. + + src/app/guards/dirty-form.guard.ts + 17 + + + src/app/services/open-documents.service.ts + 76 + + + src/app/services/open-documents.service.ts + 97 + + You have unsaved changes. + + + Are you sure you want to leave? + + src/app/guards/dirty-form.guard.ts + 18 + + Are you sure you want to leave? + + + Leave page + + src/app/guards/dirty-form.guard.ts + 20 + + Leave page + + + (no title) + + src/app/pipes/document-title.pipe.ts + 12 + + (no title) + + + Yes + + src/app/pipes/yes-no.pipe.ts + 9 + + Yes + + + No + + src/app/pipes/yes-no.pipe.ts + 9 + + No + + + Document already exists. + + src/app/services/consumer-status.service.ts + 15 + + Document already exists. + + + File not found. + + src/app/services/consumer-status.service.ts + 16 + + File not found. + + + Pre-consume script does not exist. + + src/app/services/consumer-status.service.ts + 17 + + Pre-Consume is a term that appears like that in the documentation as well and does not need a specific translation + Pre-consume script does not exist. + + + Error while executing pre-consume script. + + src/app/services/consumer-status.service.ts + 18 + + Pre-Consume is a term that appears like that in the documentation as well and does not need a specific translation + Error while executing pre-consume script. + + + Post-consume script does not exist. + + src/app/services/consumer-status.service.ts + 19 + + Post-Consume is a term that appears like that in the documentation as well and does not need a specific translation + Post-consume script does not exist. + + + Error while executing post-consume script. + + src/app/services/consumer-status.service.ts + 20 + + Post-Consume is a term that appears like that in the documentation as well and does not need a specific translation + Error while executing post-consume script. + + + Received new file. + + src/app/services/consumer-status.service.ts + 21 + + Received new file. + + + File type not supported. + + src/app/services/consumer-status.service.ts + 22 + + File type not supported. + + + Processing document... + + src/app/services/consumer-status.service.ts + 23 + + Processing document... + + + Generating thumbnail... + + src/app/services/consumer-status.service.ts + 24 + + Generating thumbnail... + + + Retrieving date from document... + + src/app/services/consumer-status.service.ts + 25 + + Retrieving date from document... + + + Saving document... + + src/app/services/consumer-status.service.ts + 26 + + Saving document... + + + Finished. + + src/app/services/consumer-status.service.ts + 27 + + Finished. + + + Are you sure you want to close this document? + + src/app/services/open-documents.service.ts + 77 + + Are you sure you want to close this document? + + + Close document + + src/app/services/open-documents.service.ts + 79 + + Close document + + + Are you sure you want to close all documents? + + src/app/services/open-documents.service.ts + 98 + + Are you sure you want to close all documents? + + + Close documents + + src/app/services/open-documents.service.ts + 100 + + Close documents + + + Modified + + src/app/services/rest/document.service.ts + 23 + + Modified + + + Search score + + src/app/services/rest/document.service.ts + 28 + + Score is a value returned by the full text search engine and specifies how well a result matches the given query + Search score + + + English (US) + + src/app/services/settings.service.ts + 90 + + English (US) + + + Czech + + src/app/services/settings.service.ts + 91 + + Czech + + + Danish + + src/app/services/settings.service.ts + 92 + + Danish + + + German + + src/app/services/settings.service.ts + 93 + + German + + + English (GB) + + src/app/services/settings.service.ts + 94 + + English (GB) + + + Spanish + + src/app/services/settings.service.ts + 95 + + Spanish + + + French + + src/app/services/settings.service.ts + 96 + + French + + + Italian + + src/app/services/settings.service.ts + 97 + + Italian + + + Luxembourgish + + src/app/services/settings.service.ts + 98 + + Luxembourgish + + + Dutch + + src/app/services/settings.service.ts + 99 + + Dutch + + + Polish + + src/app/services/settings.service.ts + 100 + + Polish + + + Portuguese (Brazil) + + src/app/services/settings.service.ts + 101 + + Portuguese (Brazil) + + + Portuguese + + src/app/services/settings.service.ts + 102 + + Portuguese + + + Romanian + + src/app/services/settings.service.ts + 103 + + Romanian + + + Russian + + src/app/services/settings.service.ts + 104 + + Russian + + + Swedish + + src/app/services/settings.service.ts + 105 + + Swedish + + + ISO 8601 + + src/app/services/settings.service.ts + 115 + + ISO 8601 + + + Error + + src/app/services/toast.service.ts + 35 + + Error + + + Information + + src/app/services/toast.service.ts + 39 + + Information + + + + diff --git a/src-ui/src/locale/messages.fr_FR.xlf b/src-ui/src/locale/messages.fr_FR.xlf index ee4e3abba..f1dbe3dff 100644 --- a/src-ui/src/locale/messages.fr_FR.xlf +++ b/src-ui/src/locale/messages.fr_FR.xlf @@ -511,7 +511,7 @@ src/app/components/dashboard/dashboard.component.ts 33 - Bonjour , bienvenue dans Paperless-ngx! + Bonjour , bienvenue dans Paperless-ngx ! Welcome to Paperless-ngx! @@ -519,7 +519,7 @@ src/app/components/dashboard/dashboard.component.ts 35 - Bienvenue dans Paperless-ngx! + Bienvenue dans Paperless-ngx ! Show all @@ -1304,7 +1304,7 @@ src/app/components/document-list/bulk-editor/bulk-editor.component.ts 161 - Cette action affectera le correspondant "" au(x) document(s) sélectionné(s). + Cette action affectera le correspondant "" au(x) document(s) sélectionné(s). This operation will remove the correspondent from selected document(s). @@ -1520,7 +1520,7 @@ src/app/components/document-list/document-list.component.html 87 - Chargement ... + Chargement… {VAR_PLURAL, plural, =1 {Selected of one document} other {Selected of documents}} @@ -2136,7 +2136,7 @@ src/app/components/manage/settings/settings.component.html 103 - Edition en masse + Édition en masse Show confirmation dialogs diff --git a/src-ui/src/locale/messages.it_IT.xlf b/src-ui/src/locale/messages.it_IT.xlf index 04766556e..af8718f02 100644 --- a/src-ui/src/locale/messages.it_IT.xlf +++ b/src-ui/src/locale/messages.it_IT.xlf @@ -61,7 +61,7 @@ 11 app title - Paperless-ngx + Paperless-ngx Search documents @@ -113,7 +113,7 @@ src/app/components/dashboard/dashboard.component.html 1 - Dashboard + Dashboard Documents @@ -265,7 +265,7 @@ src/app/components/app-frame/app-frame.component.html 175 - GitHub + GitHub Suggest an idea @@ -433,7 +433,7 @@ src/app/components/common/filterable-dropdown/filterable-dropdown.component.html 45 - Click again to exclude items. + Clicca di nuovo per escludere gli elementi. Not assigned @@ -511,7 +511,7 @@ src/app/components/dashboard/dashboard.component.ts 33 - Hello , welcome to Paperless-ngx! + Ciao , benvenuto su Paperless-ngx! Welcome to Paperless-ngx! @@ -519,7 +519,7 @@ src/app/components/dashboard/dashboard.component.ts 35 - Welcome to Paperless-ngx! + Benvenuto su Paperless-ngx! Show all @@ -1222,7 +1222,7 @@ src/app/components/document-list/bulk-editor/bulk-editor.component.ts 117 - "" + "" "" and "" @@ -1520,7 +1520,7 @@ src/app/components/document-list/document-list.component.html 87 - Loading... + Caricamento in corso... {VAR_PLURAL, plural, =1 {Selected of one document} other {Selected of documents}} @@ -1560,7 +1560,7 @@ src/app/services/rest/document.service.ts 17 - ASN + ASN Added @@ -1640,7 +1640,7 @@ src/app/components/document-list/filter-editor/filter-editor.component.ts 50 - Tag: + Tag: Without any tag @@ -1664,7 +1664,7 @@ src/app/components/document-list/filter-editor/filter-editor.component.ts 61 - ASN: + ASN: Title & content @@ -2072,7 +2072,7 @@ src/app/components/manage/settings/settings.component.html 67 - Oggetti per pagina + Elementi per pagina Document editor @@ -2436,7 +2436,7 @@ src/app/services/open-documents.service.ts 96 - Unsaved Changes + Modifiche non salvate You have unsaved changes. @@ -2452,7 +2452,7 @@ src/app/services/open-documents.service.ts 97 - You have unsaved changes. + Hai delle modifiche non salvate. Are you sure you want to leave? @@ -2460,7 +2460,7 @@ src/app/guards/dirty-form.guard.ts 18 - Are you sure you want to leave? + Sei sicuro di voler uscire? Leave page @@ -2468,7 +2468,7 @@ src/app/guards/dirty-form.guard.ts 20 - Leave page + Esci dalla pagina (no title) @@ -2492,7 +2492,7 @@ src/app/pipes/yes-no.pipe.ts 9 - No + No Document already exists. @@ -2608,7 +2608,7 @@ src/app/services/open-documents.service.ts 77 - Are you sure you want to close this document? + Sei sicuro di voler chiudere questo documento? Close document @@ -2616,7 +2616,7 @@ src/app/services/open-documents.service.ts 79 - Close document + Chiudi documento Are you sure you want to close all documents? @@ -2624,7 +2624,7 @@ src/app/services/open-documents.service.ts 98 - Are you sure you want to close all documents? + Sei sicuro di voler chiudere tutti i documenti? Close documents @@ -2632,7 +2632,7 @@ src/app/services/open-documents.service.ts 100 - Close documents + Chiudi documenti Modified @@ -2665,7 +2665,7 @@ src/app/services/settings.service.ts 91 - Czech + Ceco Danish @@ -2673,7 +2673,7 @@ src/app/services/settings.service.ts 92 - Danish + Danese German @@ -2721,7 +2721,7 @@ src/app/services/settings.service.ts 98 - Luxembourgish + Lussemburghese Dutch @@ -2785,7 +2785,7 @@ src/app/services/settings.service.ts 115 - ISO 8601 + ISO 8601 Error diff --git a/src-ui/src/locale/messages.nl_NL.xlf b/src-ui/src/locale/messages.nl_NL.xlf index e9be3b8f4..8a878bd78 100644 --- a/src-ui/src/locale/messages.nl_NL.xlf +++ b/src-ui/src/locale/messages.nl_NL.xlf @@ -61,7 +61,7 @@ 11 app title - Paperless-ngx + Paperless-ngx Search documents @@ -113,7 +113,7 @@ src/app/components/dashboard/dashboard.component.html 1 - Dashboard + Dashboard Documents @@ -265,7 +265,7 @@ src/app/components/app-frame/app-frame.component.html 175 - GitHub + GitHub Suggest an idea @@ -433,7 +433,7 @@ src/app/components/common/filterable-dropdown/filterable-dropdown.component.html 45 - Click again to exclude items. + Klik nogmaals om items uit te sluiten. Not assigned @@ -511,7 +511,7 @@ src/app/components/dashboard/dashboard.component.ts 33 - Hello , welcome to Paperless-ngx! + Hallo , welkom bij Paperless-ngx! Welcome to Paperless-ngx! @@ -519,7 +519,7 @@ src/app/components/dashboard/dashboard.component.ts 35 - Welcome to Paperless-ngx! + Welkom bij Paperless-ngx! Show all @@ -882,7 +882,7 @@ src/app/components/document-detail/document-detail.component.html 52 - Details + Details Archive serial number @@ -1432,7 +1432,7 @@ src/app/components/document-list/document-card-large/document-card-large.component.html 87 - Score: + Score: Created: @@ -1520,7 +1520,7 @@ src/app/components/document-list/document-list.component.html 87 - Loading... + Laden... {VAR_PLURAL, plural, =1 {Selected of one document} other {Selected of documents}} @@ -2056,7 +2056,7 @@ src/app/components/manage/settings/settings.component.html 55 - Medium: + Medium: Long: @@ -2436,7 +2436,7 @@ src/app/services/open-documents.service.ts 96 - Unsaved Changes + Niet-opgeslagen wijzigingen You have unsaved changes. @@ -2452,7 +2452,7 @@ src/app/services/open-documents.service.ts 97 - You have unsaved changes. + U heeft niet-opgeslagen wijzigingen. Are you sure you want to leave? @@ -2460,7 +2460,7 @@ src/app/guards/dirty-form.guard.ts 18 - Are you sure you want to leave? + Weet u zeker dat u dit wilt verlaten? Leave page @@ -2468,7 +2468,7 @@ src/app/guards/dirty-form.guard.ts 20 - Leave page + Pagina verlaten (no title) @@ -2608,7 +2608,7 @@ src/app/services/open-documents.service.ts 77 - Are you sure you want to close this document? + Weet u zeker dat u dit document wilt sluiten? Close document @@ -2616,7 +2616,7 @@ src/app/services/open-documents.service.ts 79 - Close document + Sluit document Are you sure you want to close all documents? @@ -2624,7 +2624,7 @@ src/app/services/open-documents.service.ts 98 - Are you sure you want to close all documents? + Weet u zeker dat u alle documenten wilt sluiten? Close documents @@ -2632,7 +2632,7 @@ src/app/services/open-documents.service.ts 100 - Close documents + Sluit documenten Modified @@ -2665,7 +2665,7 @@ src/app/services/settings.service.ts 91 - Czech + Tsjechisch Danish @@ -2673,7 +2673,7 @@ src/app/services/settings.service.ts 92 - Danish + Deens German @@ -2721,7 +2721,7 @@ src/app/services/settings.service.ts 98 - Luxembourgish + Luxemburgs Dutch diff --git a/src-ui/src/locale/messages.pl_PL.xlf b/src-ui/src/locale/messages.pl_PL.xlf index 18263c1a9..e6af49cfb 100644 --- a/src-ui/src/locale/messages.pl_PL.xlf +++ b/src-ui/src/locale/messages.pl_PL.xlf @@ -61,7 +61,7 @@ 11 app title - Paperless-ngx + Paperless-ngx Search documents @@ -241,7 +241,7 @@ src/app/components/app-frame/app-frame.component.html 154 - Admin + Administracja Info @@ -249,7 +249,7 @@ src/app/components/app-frame/app-frame.component.html 160 - Info + Informacje Documentation @@ -265,7 +265,7 @@ src/app/components/app-frame/app-frame.component.html 175 - GitHub + GitHub Suggest an idea @@ -433,7 +433,7 @@ src/app/components/common/filterable-dropdown/filterable-dropdown.component.html 45 - Click again to exclude items. + Kliknij ponownie, aby wykluczyć elementy. Not assigned @@ -511,7 +511,7 @@ src/app/components/dashboard/dashboard.component.ts 33 - Hello , welcome to Paperless-ngx! + Cześć , witaj w Paperless-ngx! Welcome to Paperless-ngx! @@ -519,7 +519,7 @@ src/app/components/dashboard/dashboard.component.ts 35 - Welcome to Paperless-ngx! + Witaj w Paperless-ngx! Show all @@ -678,7 +678,7 @@ 117 this string is used to separate processing, failed and added on the file upload widget - , + , Connecting... @@ -1222,7 +1222,7 @@ src/app/components/document-list/bulk-editor/bulk-editor.component.ts 117 - "" + "" "" and "" @@ -1520,7 +1520,7 @@ src/app/components/document-list/document-list.component.html 87 - Loading... + Wczytywanie... {VAR_PLURAL, plural, =1 {Selected of one document} other {Selected of documents}} @@ -1560,7 +1560,7 @@ src/app/services/rest/document.service.ts 17 - ASN + Numer archiwum Added @@ -1640,7 +1640,7 @@ src/app/components/document-list/filter-editor/filter-editor.component.ts 50 - Tag: + Znacznik: Without any tag @@ -2436,7 +2436,7 @@ src/app/services/open-documents.service.ts 96 - Unsaved Changes + Niezapisane zmiany You have unsaved changes. @@ -2452,7 +2452,7 @@ src/app/services/open-documents.service.ts 97 - You have unsaved changes. + Masz niezapisane zmiany. Are you sure you want to leave? @@ -2460,7 +2460,7 @@ src/app/guards/dirty-form.guard.ts 18 - Are you sure you want to leave? + Czy na pewno chcesz wyjść? Leave page @@ -2468,7 +2468,7 @@ src/app/guards/dirty-form.guard.ts 20 - Leave page + Opuść stronÄ™ (no title) @@ -2608,7 +2608,7 @@ src/app/services/open-documents.service.ts 77 - Are you sure you want to close this document? + Czy na pewno chcesz zamknąć ten dokument? Close document @@ -2616,7 +2616,7 @@ src/app/services/open-documents.service.ts 79 - Close document + Zamknij dokument Are you sure you want to close all documents? @@ -2624,7 +2624,7 @@ src/app/services/open-documents.service.ts 98 - Are you sure you want to close all documents? + Czy na pewno chcesz zamknąć wszystkie dokumenty? Close documents @@ -2632,7 +2632,7 @@ src/app/services/open-documents.service.ts 100 - Close documents + Zamknij dokumenty Modified @@ -2665,7 +2665,7 @@ src/app/services/settings.service.ts 91 - Czech + Czeski Danish @@ -2673,7 +2673,7 @@ src/app/services/settings.service.ts 92 - Danish + DuÅ„ski German @@ -2721,7 +2721,7 @@ src/app/services/settings.service.ts 98 - Luxembourgish + Luksemburski Dutch @@ -2785,7 +2785,7 @@ src/app/services/settings.service.ts 115 - ISO 8601 + ISO 8601 Error diff --git a/src-ui/src/locale/messages.pt_BR.xlf b/src-ui/src/locale/messages.pt_BR.xlf index 50fe3e407..45ff6dc2e 100644 --- a/src-ui/src/locale/messages.pt_BR.xlf +++ b/src-ui/src/locale/messages.pt_BR.xlf @@ -233,7 +233,7 @@ src/app/components/manage/logs/logs.component.html 1 - Logs + Logs Admin @@ -241,7 +241,7 @@ src/app/components/app-frame/app-frame.component.html 154 - Admin + Admin Info @@ -433,7 +433,7 @@ src/app/components/common/filterable-dropdown/filterable-dropdown.component.html 45 - Click again to exclude items. + Clique novamente para excluir itens. Not assigned @@ -511,7 +511,7 @@ src/app/components/dashboard/dashboard.component.ts 33 - Hello , welcome to Paperless-ngx! + Olá , bem-vindo ao Paperless-ngx! Welcome to Paperless-ngx! @@ -519,7 +519,7 @@ src/app/components/dashboard/dashboard.component.ts 35 - Welcome to Paperless-ngx! + Bem-vindo ao Paperless-ngx! Show all @@ -774,7 +774,7 @@ src/app/components/document-asn/document-asn.component.html 1 - Searching document with asn + Procurando documento com asn Page @@ -1440,7 +1440,7 @@ src/app/components/document-list/document-card-small/document-card-small.component.html 43 - Created: + Criado: Added: @@ -1448,7 +1448,7 @@ src/app/components/document-list/document-card-small/document-card-small.component.html 44 - Added: + Adicionado: Modified: @@ -1456,7 +1456,7 @@ src/app/components/document-list/document-card-small/document-card-small.component.html 45 - Modified: + Modificado: Select none @@ -1664,7 +1664,7 @@ src/app/components/document-list/filter-editor/filter-editor.component.ts 61 - ASN: + NSA: Title & content @@ -1688,7 +1688,7 @@ src/app/components/document-list/filter-editor/filter-editor.component.ts 94 - More like + Mais parecido Save current view @@ -2436,7 +2436,7 @@ src/app/services/open-documents.service.ts 96 - Unsaved Changes + Alterações não salvas You have unsaved changes. @@ -2452,7 +2452,7 @@ src/app/services/open-documents.service.ts 97 - You have unsaved changes. + Você tem alterações não salvas. Are you sure you want to leave? @@ -2460,7 +2460,7 @@ src/app/guards/dirty-form.guard.ts 18 - Are you sure you want to leave? + Tem certeza que deseja sair? Leave page @@ -2468,7 +2468,7 @@ src/app/guards/dirty-form.guard.ts 20 - Leave page + Sair da página (no title) @@ -2608,7 +2608,7 @@ src/app/services/open-documents.service.ts 77 - Are you sure you want to close this document? + Tem certeza de que deseja fechar este documento? Close document @@ -2616,7 +2616,7 @@ src/app/services/open-documents.service.ts 79 - Close document + Fechar documento Are you sure you want to close all documents? @@ -2624,7 +2624,7 @@ src/app/services/open-documents.service.ts 98 - Are you sure you want to close all documents? + Tem certeza de que deseja fechar todos os documentos? Close documents @@ -2632,7 +2632,7 @@ src/app/services/open-documents.service.ts 100 - Close documents + Fechar documentos Modified diff --git a/src-ui/src/locale/messages.pt_PT.xlf b/src-ui/src/locale/messages.pt_PT.xlf index bce1ca1ce..1d1a5eba9 100644 --- a/src-ui/src/locale/messages.pt_PT.xlf +++ b/src-ui/src/locale/messages.pt_PT.xlf @@ -113,7 +113,7 @@ src/app/components/dashboard/dashboard.component.html 1 - Painel de controle + Painel de controlo Documents @@ -826,7 +826,7 @@ src/app/components/manage/tag-list/tag-list.component.html 49 - Excluir + Apagar Download @@ -2452,7 +2452,7 @@ src/app/services/open-documents.service.ts 97 - Você tem alterações não guardadas. + Tem alterações não guardadas. Are you sure you want to leave? @@ -2460,7 +2460,7 @@ src/app/guards/dirty-form.guard.ts 18 - Tem certeza que quer sair? + Tem a certeza de que pretende sair? Leave page @@ -2624,7 +2624,7 @@ src/app/services/open-documents.service.ts 98 - Tem a certeza de que deseja fechar todos os documento? + Tem a certeza de que pretende fechar todos os documentos? Close documents diff --git a/src-ui/src/locale/messages.ro_RO.xlf b/src-ui/src/locale/messages.ro_RO.xlf index b77031a47..0e092dedc 100644 --- a/src-ui/src/locale/messages.ro_RO.xlf +++ b/src-ui/src/locale/messages.ro_RO.xlf @@ -61,7 +61,7 @@ 11 app title - Paperless-ngx + Paperless-ngx Search documents @@ -265,7 +265,7 @@ src/app/components/app-frame/app-frame.component.html 175 - GitHub + GitHub Suggest an idea @@ -433,7 +433,7 @@ src/app/components/common/filterable-dropdown/filterable-dropdown.component.html 45 - Click again to exclude items. + Click din nou pentru a exclude elemente. Not assigned @@ -511,7 +511,7 @@ src/app/components/dashboard/dashboard.component.ts 33 - Hello , welcome to Paperless-ngx! + Salut, , bun venit la Paperless-ngx! Welcome to Paperless-ngx! @@ -519,7 +519,7 @@ src/app/components/dashboard/dashboard.component.ts 35 - Welcome to Paperless-ngx! + Bun venit la Paperless-ngx! Show all @@ -678,7 +678,7 @@ 117 this string is used to separate processing, failed and added on the file upload widget - , + , Connecting... @@ -1222,7 +1222,7 @@ src/app/components/document-list/bulk-editor/bulk-editor.component.ts 117 - "" + "" "" and "" @@ -1520,7 +1520,7 @@ src/app/components/document-list/document-list.component.html 87 - Loading... + Se încarcă... {VAR_PLURAL, plural, =1 {Selected of one document} other {Selected of documents}} @@ -2436,7 +2436,7 @@ src/app/services/open-documents.service.ts 96 - Unsaved Changes + Modificări nesalvate You have unsaved changes. @@ -2452,7 +2452,7 @@ src/app/services/open-documents.service.ts 97 - You have unsaved changes. + AveÈ›i modificări nesalvate. Are you sure you want to leave? @@ -2460,7 +2460,7 @@ src/app/guards/dirty-form.guard.ts 18 - Are you sure you want to leave? + SunteÈ›i sigur că doriÈ›i să ieÈ™iÈ›i? Leave page @@ -2468,7 +2468,7 @@ src/app/guards/dirty-form.guard.ts 20 - Leave page + PărăsiÈ›i pagina (no title) @@ -2608,7 +2608,7 @@ src/app/services/open-documents.service.ts 77 - Are you sure you want to close this document? + Sigur doriÈ›i să închideÈ›i acest document? Close document @@ -2616,7 +2616,7 @@ src/app/services/open-documents.service.ts 79 - Close document + ÃŽnchide document Are you sure you want to close all documents? @@ -2624,7 +2624,7 @@ src/app/services/open-documents.service.ts 98 - Are you sure you want to close all documents? + Sigur doriÈ›i să închideÈ›i toate documentele? Close documents @@ -2632,7 +2632,7 @@ src/app/services/open-documents.service.ts 100 - Close documents + ÃŽnchide documentele Modified @@ -2665,7 +2665,7 @@ src/app/services/settings.service.ts 91 - Czech + Cehă Danish @@ -2673,7 +2673,7 @@ src/app/services/settings.service.ts 92 - Danish + Daneză German @@ -2721,7 +2721,7 @@ src/app/services/settings.service.ts 98 - Luxembourgish + Luxemburgheză Dutch @@ -2785,7 +2785,7 @@ src/app/services/settings.service.ts 115 - ISO 8601 + ISO 8601 Error diff --git a/src-ui/src/locale/messages.ru_RU.xlf b/src-ui/src/locale/messages.ru_RU.xlf index ee3990862..1c562f103 100644 --- a/src-ui/src/locale/messages.ru_RU.xlf +++ b/src-ui/src/locale/messages.ru_RU.xlf @@ -54,14 +54,14 @@ Документ обрабатываетÑÑ paperless - + Paperless-ngx src/app/components/app-frame/app-frame.component.html 11 app title - Paperless-ngx + Paperless-ngx Search documents @@ -265,7 +265,7 @@ src/app/components/app-frame/app-frame.component.html 175 - GitHub + GitHub Suggest an idea @@ -433,7 +433,7 @@ src/app/components/common/filterable-dropdown/filterable-dropdown.component.html 45 - Click again to exclude items. + Ðажмите еще раз, чтобы иÑключить Ñлементы. Not assigned @@ -505,13 +505,13 @@ ПожалуйÑта, выберите объект - + Hello , welcome to Paperless-ngx! src/app/components/dashboard/dashboard.component.ts 33 - Hello , welcome to Paperless-ngx! + Привет, , добро пожаловать в Paperless-ngx! Welcome to Paperless-ngx! @@ -519,7 +519,7 @@ src/app/components/dashboard/dashboard.component.ts 35 - Welcome to Paperless-ngx! + Добро пожаловать в Paperless-ngx! Show all @@ -667,7 +667,7 @@ Добавлено: - + , src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts @@ -678,7 +678,7 @@ 117 this string is used to separate processing, failed and added on the file upload widget - , + , Connecting... @@ -1222,7 +1222,7 @@ src/app/components/document-list/bulk-editor/bulk-editor.component.ts 117 - "" + "" "" and "" @@ -1520,7 +1520,7 @@ src/app/components/document-list/document-list.component.html 87 - Loading... + Загрузка... {VAR_PLURAL, plural, =1 {Selected of one document} other {Selected of documents}} @@ -2184,7 +2184,7 @@ src/app/components/manage/settings/settings.component.html 123 - Показывать уведомлениÑ, когда новый документ удалён + Показывать ÑƒÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸ обнаружении новых документов Show notifications when document processing completes successfully @@ -2436,7 +2436,7 @@ src/app/services/open-documents.service.ts 96 - Unsaved Changes + ÐеÑохранённые Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ You have unsaved changes. @@ -2452,7 +2452,7 @@ src/app/services/open-documents.service.ts 97 - You have unsaved changes. + У Ð²Ð°Ñ ÐµÑÑ‚ÑŒ неÑохраненные изменениÑ. Are you sure you want to leave? @@ -2460,7 +2460,7 @@ src/app/guards/dirty-form.guard.ts 18 - Are you sure you want to leave? + Ð’Ñ‹ уверены, что хотите выйти? Leave page @@ -2468,7 +2468,7 @@ src/app/guards/dirty-form.guard.ts 20 - Leave page + Покинуть Ñтраницу (no title) @@ -2608,7 +2608,7 @@ src/app/services/open-documents.service.ts 77 - Are you sure you want to close this document? + Ð’Ñ‹ уверены, что хотите закрыть Ñтот документ? Close document @@ -2616,7 +2616,7 @@ src/app/services/open-documents.service.ts 79 - Close document + Закрыть документ Are you sure you want to close all documents? @@ -2624,7 +2624,7 @@ src/app/services/open-documents.service.ts 98 - Are you sure you want to close all documents? + Ð’Ñ‹ уверены, что хотите закрыть вÑе документы? Close documents @@ -2632,7 +2632,7 @@ src/app/services/open-documents.service.ts 100 - Close documents + Закрыть документы Modified @@ -2657,7 +2657,7 @@ src/app/services/settings.service.ts 90 - English (US) + ÐнглийÑкий (СШÐ) Czech @@ -2665,7 +2665,7 @@ src/app/services/settings.service.ts 91 - Czech + ЧешÑкий Danish @@ -2673,7 +2673,7 @@ src/app/services/settings.service.ts 92 - Danish + ДатÑкий German @@ -2681,7 +2681,7 @@ src/app/services/settings.service.ts 93 - German + Ðемецкий English (GB) @@ -2689,7 +2689,7 @@ src/app/services/settings.service.ts 94 - English (GB) + ÐнглийÑкий (Великобритании) Spanish @@ -2705,7 +2705,7 @@ src/app/services/settings.service.ts 96 - French + ФранцузÑкий Italian @@ -2713,7 +2713,7 @@ src/app/services/settings.service.ts 97 - Italian + ИтальÑнÑкий Luxembourgish @@ -2721,7 +2721,7 @@ src/app/services/settings.service.ts 98 - Luxembourgish + ЛюкÑембургÑкий Dutch @@ -2745,7 +2745,7 @@ src/app/services/settings.service.ts 101 - Portuguese (Brazil) + ПортугальÑкий (БразилиÑ) Portuguese @@ -2761,7 +2761,7 @@ src/app/services/settings.service.ts 103 - Romanian + РумынÑкий Russian @@ -2785,7 +2785,7 @@ src/app/services/settings.service.ts 115 - ISO 8601 + ISO 8601 Error diff --git a/src-ui/src/locale/messages.sk_SK.xlf b/src-ui/src/locale/messages.sk_SK.xlf new file mode 100644 index 000000000..ef9bd484c --- /dev/null +++ b/src-ui/src/locale/messages.sk_SK.xlf @@ -0,0 +1,2808 @@ + + + + + + Document added + + src/app/app.component.ts + 51 + + Document added + + + Document was added to paperless. + + src/app/app.component.ts + 51 + + Document was added to paperless. + + + Open document + + src/app/app.component.ts + 51 + + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 45 + + Open document + + + Could not add : + + src/app/app.component.ts + 59 + + Could not add : + + + New document detected + + src/app/app.component.ts + 65 + + New document detected + + + Document is being processed by paperless. + + src/app/app.component.ts + 65 + + Document is being processed by paperless. + + + Paperless-ngx + + src/app/components/app-frame/app-frame.component.html + 11 + + app title + Paperless-ngx + + + Search documents + + src/app/components/app-frame/app-frame.component.html + 18 + + Search documents + + + Logged in as + + src/app/components/app-frame/app-frame.component.html + 34 + + Logged in as + + + Settings + + src/app/components/app-frame/app-frame.component.html + 40 + + + src/app/components/app-frame/app-frame.component.html + 147 + + + src/app/components/manage/settings/settings.component.html + 1 + + Settings + + + Logout + + src/app/components/app-frame/app-frame.component.html + 45 + + Logout + + + Dashboard + + src/app/components/app-frame/app-frame.component.html + 61 + + + src/app/components/dashboard/dashboard.component.html + 1 + + Dashboard + + + Documents + + src/app/components/app-frame/app-frame.component.html + 68 + + + src/app/components/document-list/document-list.component.ts + 51 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 37 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 35 + + + src/app/components/manage/tag-list/tag-list.component.html + 38 + + Documents + + + Saved views + + src/app/components/app-frame/app-frame.component.html + 74 + + + src/app/components/manage/settings/settings.component.html + 134 + + Saved views + + + Open documents + + src/app/components/app-frame/app-frame.component.html + 87 + + Open documents + + + Close all + + src/app/components/app-frame/app-frame.component.html + 106 + + Close all + + + Manage + + src/app/components/app-frame/app-frame.component.html + 112 + + Manage + + + Correspondents + + src/app/components/app-frame/app-frame.component.html + 119 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 1 + + Correspondents + + + Tags + + src/app/components/app-frame/app-frame.component.html + 126 + + + src/app/components/common/input/tags/tags.component.html + 2 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 28 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 18 + + + src/app/components/manage/tag-list/tag-list.component.html + 1 + + Tags + + + Document types + + src/app/components/app-frame/app-frame.component.html + 133 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 1 + + Document types + + + Logs + + src/app/components/app-frame/app-frame.component.html + 140 + + + src/app/components/manage/logs/logs.component.html + 1 + + Logs + + + Admin + + src/app/components/app-frame/app-frame.component.html + 154 + + Admin + + + Info + + src/app/components/app-frame/app-frame.component.html + 160 + + Info + + + Documentation + + src/app/components/app-frame/app-frame.component.html + 167 + + Documentation + + + GitHub + + src/app/components/app-frame/app-frame.component.html + 175 + + GitHub + + + Suggest an idea + + src/app/components/app-frame/app-frame.component.html + 181 + + Suggest an idea + + + Cancel + + src/app/components/common/confirm-dialog/confirm-dialog.component.html + 11 + + + src/app/components/common/select-dialog/select-dialog.component.html + 12 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 6 + + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 13 + + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 14 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 16 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 18 + + Cancel + + + Confirmation + + src/app/components/common/confirm-dialog/confirm-dialog.component.ts + 18 + + Confirmation + + + Confirm + + src/app/components/common/confirm-dialog/confirm-dialog.component.ts + 30 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 143 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 166 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 189 + + Confirm + + + After + + src/app/components/common/date-dropdown/date-dropdown.component.html + 13 + + After + + + Clear + + src/app/components/common/date-dropdown/date-dropdown.component.html + 18 + + + src/app/components/common/date-dropdown/date-dropdown.component.html + 41 + + Clear + + + Before + + src/app/components/common/date-dropdown/date-dropdown.component.html + 36 + + Before + + + Last 7 days + + src/app/components/common/date-dropdown/date-dropdown.component.ts + 34 + + Last 7 days + + + Last month + + src/app/components/common/date-dropdown/date-dropdown.component.ts + 35 + + Last month + + + Last 3 months + + src/app/components/common/date-dropdown/date-dropdown.component.ts + 36 + + Last 3 months + + + Last year + + src/app/components/common/date-dropdown/date-dropdown.component.ts + 37 + + Last year + + + Create new item + + src/app/components/common/edit-dialog/edit-dialog.component.ts + 50 + + Create new item + + + Edit item + + src/app/components/common/edit-dialog/edit-dialog.component.ts + 54 + + Edit item + + + Could not save element: + + src/app/components/common/edit-dialog/edit-dialog.component.ts + 58 + + Could not save element: + + + Apply + + src/app/components/common/filterable-dropdown/filterable-dropdown.component.html + 39 + + Apply + + + Click again to exclude items. + + src/app/components/common/filterable-dropdown/filterable-dropdown.component.html + 45 + + Click again to exclude items. + + + Not assigned + + src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts + 209 + + Filter drop down element to filter for documents with no correspondent/type/tag assigned + Not assigned + + + Invalid date. + + src/app/components/common/input/date/date.component.html + 12 + + Invalid date. + + + Add item + + src/app/components/common/input/select/select.component.html + 11 + + Used for both types and correspondents + Add item + + + Suggestions: + + src/app/components/common/input/select/select.component.html + 29 + + + src/app/components/common/input/tags/tags.component.html + 42 + + Suggestions: + + + Add tag + + src/app/components/common/input/tags/tags.component.html + 11 + + Add tag + + + Select + + src/app/components/common/select-dialog/select-dialog.component.html + 13 + + + src/app/components/common/select-dialog/select-dialog.component.ts + 18 + + + src/app/components/document-list/document-list.component.html + 7 + + Select + + + Please select an object + + src/app/components/common/select-dialog/select-dialog.component.ts + 21 + + Please select an object + + + Hello , welcome to Paperless-ngx! + + src/app/components/dashboard/dashboard.component.ts + 33 + + Hello , welcome to Paperless-ngx! + + + Welcome to Paperless-ngx! + + src/app/components/dashboard/dashboard.component.ts + 35 + + Welcome to Paperless-ngx! + + + Show all + + src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html + 3 + + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 27 + + Show all + + + Created + + src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html + 9 + + + src/app/components/document-list/document-list.component.html + 141 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 41 + + + src/app/services/rest/document.service.ts + 21 + + Created + + + Title + + src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html + 10 + + + src/app/components/document-detail/document-detail.component.html + 55 + + + src/app/components/document-list/document-list.component.html + 129 + + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 88 + + + src/app/services/rest/document.service.ts + 19 + + Title + + + Statistics + + src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html + 1 + + Statistics + + + Documents in inbox: + + src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html + 3 + + Documents in inbox: + + + Total documents: + + src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html + 4 + + Total documents: + + + Upload new documents + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 1 + + Upload new documents + + + Dismiss completed + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 4 + + This button dismisses all status messages about processed documents on the dashboard (failed and successful) + Dismiss completed + + + Drop documents here or + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 13 + + Drop documents here or + + + Browse files + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 13 + + Browse files + + + {VAR_PLURAL, plural, =1 {One more document} other { more documents}} + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 25 + + This is shown as a summary line when there are more than 5 document in the processing pipeline. + {VAR_PLURAL, plural, =1 {One more document} other { more documents}} + + + Processing: + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 32 + + Processing: + + + Failed: + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 35 + + Failed: + + + Added: + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 38 + + Added: + + + , + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 40 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 117 + + this string is used to separate processing, failed and added on the file upload widget + , + + + Connecting... + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 118 + + Connecting... + + + Uploading... + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 123 + + Uploading... + + + Upload complete, waiting... + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 126 + + Upload complete, waiting... + + + HTTP error: + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 136 + + HTTP error: + + + First steps + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 1 + + First steps + + + Paperless is running! :) + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 5 + + Paperless is running! :) + + + You can start uploading documents by dropping them in the file upload box to the right or by dropping them in the configured consumption folder and they'll start showing up in the documents list. After you've added some metadata to your documents, use the filtering mechanisms of paperless to create custom views (such as 'Recently added', 'Tagged TODO') and they will appear on the dashboard instead of this message. + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 6,7 + + You can start uploading documents by dropping them in the file upload box to the right or by dropping them in the configured consumption folder and they'll start showing up in the documents list. After you've added some metadata to your documents, use the filtering mechanisms of paperless to create custom views (such as 'Recently added', 'Tagged TODO') and they will appear on the dashboard instead of this message. + + + Paperless offers some more features that try to make your life easier: + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 8 + + Paperless offers some more features that try to make your life easier: + + + Once you've got a couple documents in paperless and added metadata to them, paperless can assign that metadata to new documents automatically. + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 10 + + Once you've got a couple documents in paperless and added metadata to them, paperless can assign that metadata to new documents automatically. + + + You can configure paperless to read your mails and add documents from attached files. + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 11 + + You can configure paperless to read your mails and add documents from attached files. + + + Consult the documentation on how to use these features. The section on basic usage also has some information on how to use paperless in general. + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 13 + + Consult the documentation on how to use these features. The section on basic usage also has some information on how to use paperless in general. + + + Searching document with asn + + src/app/components/document-asn/document-asn.component.html + 1 + + Searching document with asn + + + Page + + src/app/components/document-detail/document-detail.component.html + 3 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 15 + + Page + + + of + + src/app/components/document-detail/document-detail.component.html + 5 + + of + + + Delete + + src/app/components/document-detail/document-detail.component.html + 11 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 76 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 48 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 46 + + + src/app/components/manage/generic-list/generic-list.component.ts + 106 + + + src/app/components/manage/settings/settings.component.html + 159 + + + src/app/components/manage/tag-list/tag-list.component.html + 49 + + Delete + + + Download + + src/app/components/document-detail/document-detail.component.html + 19 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 63 + + + src/app/components/document-list/document-card-large/document-card-large.component.html + 60 + + + src/app/components/document-list/document-card-small/document-card-small.component.html + 82 + + Download + + + Download original + + src/app/components/document-detail/document-detail.component.html + 25 + + Download original + + + More like this + + src/app/components/document-detail/document-detail.component.html + 34 + + + src/app/components/document-list/document-card-large/document-card-large.component.html + 38 + + More like this + + + Close + + src/app/components/document-detail/document-detail.component.html + 40 + + Close + + + Details + + src/app/components/document-detail/document-detail.component.html + 52 + + Details + + + Archive serial number + + src/app/components/document-detail/document-detail.component.html + 56 + + Archive serial number + + + Date created + + src/app/components/document-detail/document-detail.component.html + 57 + + Date created + + + Correspondent + + src/app/components/document-detail/document-detail.component.html + 58 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 38 + + + src/app/components/document-list/document-list.component.html + 123 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 26 + + + src/app/services/rest/document.service.ts + 18 + + Correspondent + + + Document type + + src/app/components/document-detail/document-detail.component.html + 60 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 47 + + + src/app/components/document-list/document-list.component.html + 135 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 33 + + + src/app/services/rest/document.service.ts + 20 + + Document type + + + Content + + src/app/components/document-detail/document-detail.component.html + 68 + + Content + + + Metadata + + src/app/components/document-detail/document-detail.component.html + 77 + + + src/app/components/document-detail/metadata-collapse/metadata-collapse.component.ts + 18 + + Metadata + + + Date modified + + src/app/components/document-detail/document-detail.component.html + 83 + + Date modified + + + Date added + + src/app/components/document-detail/document-detail.component.html + 87 + + Date added + + + Media filename + + src/app/components/document-detail/document-detail.component.html + 91 + + Media filename + + + Original MD5 checksum + + src/app/components/document-detail/document-detail.component.html + 95 + + Original MD5 checksum + + + Original file size + + src/app/components/document-detail/document-detail.component.html + 99 + + Original file size + + + Original mime type + + src/app/components/document-detail/document-detail.component.html + 103 + + Original mime type + + + Archive MD5 checksum + + src/app/components/document-detail/document-detail.component.html + 107 + + Archive MD5 checksum + + + Archive file size + + src/app/components/document-detail/document-detail.component.html + 111 + + Archive file size + + + Original document metadata + + src/app/components/document-detail/document-detail.component.html + 117 + + Original document metadata + + + Archived document metadata + + src/app/components/document-detail/document-detail.component.html + 118 + + Archived document metadata + + + Discard + + src/app/components/document-detail/document-detail.component.html + 143 + + Discard + + + Save & next + + src/app/components/document-detail/document-detail.component.html + 144 + + Save & next + + + Save + + src/app/components/document-detail/document-detail.component.html + 145 + + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 14 + + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 15 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 17 + + + src/app/components/manage/settings/settings.component.html + 173 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 19 + + Save + + + Confirm delete + + src/app/components/document-detail/document-detail.component.ts + 267 + + + src/app/components/manage/generic-list/generic-list.component.ts + 102 + + Confirm delete + + + Do you really want to delete document ""? + + src/app/components/document-detail/document-detail.component.ts + 268 + + Do you really want to delete document ""? + + + The files for this document will be deleted permanently. This operation cannot be undone. + + src/app/components/document-detail/document-detail.component.ts + 269 + + The files for this document will be deleted permanently. This operation cannot be undone. + + + Delete document + + src/app/components/document-detail/document-detail.component.ts + 271 + + Delete document + + + Error deleting document: + + src/app/components/document-detail/document-detail.component.ts + 281 + + Error deleting document: + + + Select: + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 10 + + Select: + + + All + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 20 + + All + + + Edit: + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 27 + + Edit: + + + Filter tags + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 29 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 19 + + Filter tags + + + Filter correspondents + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 39 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 27 + + Filter correspondents + + + Filter document types + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 48 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 34 + + Filter document types + + + Download originals + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 68 + + Download originals + + + Error executing bulk operation: + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 74 + + Error executing bulk operation: + + + "" + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 113 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 117 + + "" + + + "" and "" + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 115 + + This is for messages like 'modify "tag1" and "tag2"' + "" and "" + + + and "" + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 118 + + this is for messages like 'modify "tag1", "tag2" and "tag3"' + and "" + + + Confirm tags assignment + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 127 + + Confirm tags assignment + + + This operation will add the tag "" to selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 130 + + This operation will add the tag "" to selected document(s). + + + This operation will add the tags to selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 132 + + This operation will add the tags to selected document(s). + + + This operation will remove the tag "" from selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 135 + + This operation will remove the tag "" from selected document(s). + + + This operation will remove the tags from selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 137 + + This operation will remove the tags from selected document(s). + + + This operation will add the tags and remove the tags on selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 139 + + This operation will add the tags and remove the tags on selected document(s). + + + Confirm correspondent assignment + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 159 + + Confirm correspondent assignment + + + This operation will assign the correspondent "" to selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 161 + + This operation will assign the correspondent "" to selected document(s). + + + This operation will remove the correspondent from selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 163 + + This operation will remove the correspondent from selected document(s). + + + Confirm document type assignment + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 182 + + Confirm document type assignment + + + This operation will assign the document type "" to selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 184 + + This operation will assign the document type "" to selected document(s). + + + This operation will remove the document type from selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 186 + + This operation will remove the document type from selected document(s). + + + Delete confirm + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 201 + + Delete confirm + + + This operation will permanently delete selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 202 + + This operation will permanently delete selected document(s). + + + This operation cannot be undone. + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 203 + + This operation cannot be undone. + + + Delete document(s) + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 205 + + Delete document(s) + + + Filter by correspondent + + src/app/components/document-list/document-card-large/document-card-large.component.html + 20 + + + src/app/components/document-list/document-card-small/document-card-small.component.html + 26 + + Filter by correspondent + + + Filter by tag + + src/app/components/document-list/document-card-large/document-card-large.component.html + 24 + + + src/app/components/document-list/document-card-small/document-card-small.component.html + 15 + + Filter by tag + + + Edit + + src/app/components/document-list/document-card-large/document-card-large.component.html + 43 + + + src/app/components/document-list/document-card-small/document-card-small.component.html + 66 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 42 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 40 + + + src/app/components/manage/tag-list/tag-list.component.html + 43 + + Edit + + + View + + src/app/components/document-list/document-card-large/document-card-large.component.html + 51 + + View + + + Score: + + src/app/components/document-list/document-card-large/document-card-large.component.html + 87 + + Score: + + + Created: + + src/app/components/document-list/document-card-small/document-card-small.component.html + 43 + + Created: + + + Added: + + src/app/components/document-list/document-card-small/document-card-small.component.html + 44 + + Added: + + + Modified: + + src/app/components/document-list/document-card-small/document-card-small.component.html + 45 + + Modified: + + + Select none + + src/app/components/document-list/document-list.component.html + 10 + + Select none + + + Select page + + src/app/components/document-list/document-list.component.html + 11 + + Select page + + + Select all + + src/app/components/document-list/document-list.component.html + 12 + + Select all + + + Sort + + src/app/components/document-list/document-list.component.html + 39 + + Sort + + + Views + + src/app/components/document-list/document-list.component.html + 64 + + Views + + + Save "" + + src/app/components/document-list/document-list.component.html + 71 + + Save "" + + + Save as... + + src/app/components/document-list/document-list.component.html + 72 + + Save as... + + + Loading... + + src/app/components/document-list/document-list.component.html + 87 + + Loading... + + + {VAR_PLURAL, plural, =1 {Selected of one document} other {Selected of documents}} + + src/app/components/document-list/document-list.component.html + 89 + + {VAR_PLURAL, plural, =1 {Selected of one document} other {Selected of documents}} + + + {VAR_PLURAL, plural, =1 {One document} other { documents}} + + src/app/components/document-list/document-list.component.html + 91 + + {VAR_PLURAL, plural, =1 {One document} other { documents}} + + + (filtered) + + src/app/components/document-list/document-list.component.html + 91 + + (filtered) + + + ASN + + src/app/components/document-list/document-list.component.html + 117 + + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 90 + + + src/app/services/rest/document.service.ts + 17 + + ASN + + + Added + + src/app/components/document-list/document-list.component.html + 147 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 48 + + + src/app/services/rest/document.service.ts + 22 + + Added + + + View "" saved successfully. + + src/app/components/document-list/document-list.component.ts + 116 + + View "" saved successfully. + + + View "" created successfully. + + src/app/components/document-list/document-list.component.ts + 138 + + View "" created successfully. + + + Reset filters + + src/app/components/document-list/filter-editor/filter-editor.component.html + 57 + + Reset filters + + + Correspondent: + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 37 + + Correspondent: + + + Without correspondent + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 39 + + Without correspondent + + + Type: + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 44 + + Type: + + + Without document type + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 46 + + Without document type + + + Tag: + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 50 + + Tag: + + + Without any tag + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 54 + + Without any tag + + + Title: + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 58 + + Title: + + + ASN: + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 61 + + ASN: + + + Title & content + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 89 + + Title & content + + + Advanced search + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 91 + + Advanced search + + + More like + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 94 + + More like + + + Save current view + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 3 + + Save current view + + + Name + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 8 + + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 8 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 9 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 19 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 9 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 9 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 19 + + + src/app/components/manage/settings/settings.component.html + 141 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 8 + + + src/app/components/manage/tag-list/tag-list.component.html + 9 + + + src/app/components/manage/tag-list/tag-list.component.html + 19 + + Name + + + Show in sidebar + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 9 + + + src/app/components/manage/settings/settings.component.html + 153 + + Show in sidebar + + + Show on dashboard + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 10 + + + src/app/components/manage/settings/settings.component.html + 149 + + Show on dashboard + + + Matching algorithm + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 9 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 10 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 13 + + Matching algorithm + + + Matching pattern + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 10 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 11 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 14 + + Matching pattern + + + Case insensitive + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 11 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 12 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 15 + + Case insensitive + + + Create new correspondent + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.ts + 21 + + Create new correspondent + + + Edit correspondent + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.ts + 25 + + Edit correspondent + + + Create + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 2 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 2 + + + src/app/components/manage/tag-list/tag-list.component.html + 2 + + Create + + + Filter by: + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 8 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 8 + + + src/app/components/manage/tag-list/tag-list.component.html + 8 + + Filter by: + + + Matching + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 20 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 20 + + + src/app/components/manage/tag-list/tag-list.component.html + 21 + + Matching + + + Document count + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 21 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 21 + + + src/app/components/manage/tag-list/tag-list.component.html + 22 + + Document count + + + Last correspondence + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 22 + + Last correspondence + + + Actions + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 23 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 22 + + + src/app/components/manage/settings/settings.component.html + 158 + + + src/app/components/manage/tag-list/tag-list.component.html + 23 + + Actions + + + Do you really want to delete the correspondent ""? + + src/app/components/manage/correspondent-list/correspondent-list.component.ts + 26 + + Do you really want to delete the correspondent ""? + + + Create new document type + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.ts + 21 + + Create new document type + + + Edit document type + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.ts + 25 + + Edit document type + + + Do you really want to delete the document type ""? + + src/app/components/manage/document-type-list/document-type-list.component.ts + 26 + + Do you really want to delete the document type ""? + + + Automatic + + src/app/components/manage/generic-list/generic-list.component.ts + 39 + + + src/app/data/matching-model.ts + 17 + + Automatic + + + Do you really want to delete this element? + + src/app/components/manage/generic-list/generic-list.component.ts + 97 + + Do you really want to delete this element? + + + Associated documents will not be deleted. + + src/app/components/manage/generic-list/generic-list.component.ts + 104 + + Associated documents will not be deleted. + + + Error while deleting element: + + src/app/components/manage/generic-list/generic-list.component.ts + 114 + + Error while deleting element: + + + General settings + + src/app/components/manage/settings/settings.component.html + 10 + + General settings + + + Appearance + + src/app/components/manage/settings/settings.component.html + 13 + + Appearance + + + Display language + + src/app/components/manage/settings/settings.component.html + 17 + + Display language + + + You need to reload the page after applying a new language. + + src/app/components/manage/settings/settings.component.html + 25 + + You need to reload the page after applying a new language. + + + Date display + + src/app/components/manage/settings/settings.component.html + 32 + + Date display + + + Date format + + src/app/components/manage/settings/settings.component.html + 45 + + Date format + + + Short: + + src/app/components/manage/settings/settings.component.html + 51 + + Short: + + + Medium: + + src/app/components/manage/settings/settings.component.html + 55 + + Medium: + + + Long: + + src/app/components/manage/settings/settings.component.html + 59 + + Long: + + + Items per page + + src/app/components/manage/settings/settings.component.html + 67 + + Items per page + + + Document editor + + src/app/components/manage/settings/settings.component.html + 83 + + Document editor + + + Use PDF viewer provided by the browser + + src/app/components/manage/settings/settings.component.html + 87 + + Use PDF viewer provided by the browser + + + This is usually faster for displaying large PDF documents, but it might not work on some browsers. + + src/app/components/manage/settings/settings.component.html + 87 + + This is usually faster for displaying large PDF documents, but it might not work on some browsers. + + + Dark mode + + src/app/components/manage/settings/settings.component.html + 94 + + Dark mode + + + Use system settings + + src/app/components/manage/settings/settings.component.html + 97 + + Use system settings + + + Enable dark mode + + src/app/components/manage/settings/settings.component.html + 98 + + Enable dark mode + + + Invert thumbnails in dark mode + + src/app/components/manage/settings/settings.component.html + 99 + + Invert thumbnails in dark mode + + + Bulk editing + + src/app/components/manage/settings/settings.component.html + 103 + + Bulk editing + + + Show confirmation dialogs + + src/app/components/manage/settings/settings.component.html + 107 + + Show confirmation dialogs + + + Deleting documents will always ask for confirmation. + + src/app/components/manage/settings/settings.component.html + 107 + + Deleting documents will always ask for confirmation. + + + Apply on close + + src/app/components/manage/settings/settings.component.html + 108 + + Apply on close + + + Notifications + + src/app/components/manage/settings/settings.component.html + 116 + + Notifications + + + Document processing + + src/app/components/manage/settings/settings.component.html + 119 + + Document processing + + + Show notifications when new documents are detected + + src/app/components/manage/settings/settings.component.html + 123 + + Show notifications when new documents are detected + + + Show notifications when document processing completes successfully + + src/app/components/manage/settings/settings.component.html + 124 + + Show notifications when document processing completes successfully + + + Show notifications when document processing fails + + src/app/components/manage/settings/settings.component.html + 125 + + Show notifications when document processing fails + + + Suppress notifications on dashboard + + src/app/components/manage/settings/settings.component.html + 126 + + Suppress notifications on dashboard + + + This will suppress all messages about document processing status on the dashboard. + + src/app/components/manage/settings/settings.component.html + 126 + + This will suppress all messages about document processing status on the dashboard. + + + Appears on + + src/app/components/manage/settings/settings.component.html + 146 + + Appears on + + + No saved views defined. + + src/app/components/manage/settings/settings.component.html + 163 + + No saved views defined. + + + Saved view "" deleted. + + src/app/components/manage/settings/settings.component.ts + 111 + + Saved view "" deleted. + + + Settings saved successfully. + + src/app/components/manage/settings/settings.component.ts + 133 + + Settings saved successfully. + + + Use system language + + src/app/components/manage/settings/settings.component.ts + 138 + + Use system language + + + Use date format of display language + + src/app/components/manage/settings/settings.component.ts + 144 + + Use date format of display language + + + Error while storing settings on server: + + src/app/components/manage/settings/settings.component.ts + 161 + + Error while storing settings on server: + + + Color + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 10 + + + src/app/components/manage/tag-list/tag-list.component.html + 20 + + Color + + + Inbox tag + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 12 + + Inbox tag + + + Inbox tags are automatically assigned to all consumed documents. + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 12 + + Inbox tags are automatically assigned to all consumed documents. + + + Create new tag + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.ts + 22 + + Create new tag + + + Edit tag + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.ts + 26 + + Edit tag + + + Do you really want to delete the tag ""? + + src/app/components/manage/tag-list/tag-list.component.ts + 26 + + Do you really want to delete the tag ""? + + + 404 Not Found + + src/app/components/not-found/not-found.component.html + 7 + + 404 Not Found + + + Any word + + src/app/data/matching-model.ts + 12 + + Any word + + + Any: Document contains any of these words (space separated) + + src/app/data/matching-model.ts + 12 + + Any: Document contains any of these words (space separated) + + + All words + + src/app/data/matching-model.ts + 13 + + All words + + + All: Document contains all of these words (space separated) + + src/app/data/matching-model.ts + 13 + + All: Document contains all of these words (space separated) + + + Exact match + + src/app/data/matching-model.ts + 14 + + Exact match + + + Exact: Document contains this string + + src/app/data/matching-model.ts + 14 + + Exact: Document contains this string + + + Regular expression + + src/app/data/matching-model.ts + 15 + + Regular expression + + + Regular expression: Document matches this regular expression + + src/app/data/matching-model.ts + 15 + + Regular expression: Document matches this regular expression + + + Fuzzy word + + src/app/data/matching-model.ts + 16 + + Fuzzy word + + + Fuzzy: Document contains a word similar to this word + + src/app/data/matching-model.ts + 16 + + Fuzzy: Document contains a word similar to this word + + + Auto: Learn matching automatically + + src/app/data/matching-model.ts + 17 + + Auto: Learn matching automatically + + + Unsaved Changes + + src/app/guards/dirty-form.guard.ts + 16 + + + src/app/services/open-documents.service.ts + 75 + + + src/app/services/open-documents.service.ts + 96 + + Unsaved Changes + + + You have unsaved changes. + + src/app/guards/dirty-form.guard.ts + 17 + + + src/app/services/open-documents.service.ts + 76 + + + src/app/services/open-documents.service.ts + 97 + + You have unsaved changes. + + + Are you sure you want to leave? + + src/app/guards/dirty-form.guard.ts + 18 + + Are you sure you want to leave? + + + Leave page + + src/app/guards/dirty-form.guard.ts + 20 + + Leave page + + + (no title) + + src/app/pipes/document-title.pipe.ts + 12 + + (no title) + + + Yes + + src/app/pipes/yes-no.pipe.ts + 9 + + Yes + + + No + + src/app/pipes/yes-no.pipe.ts + 9 + + No + + + Document already exists. + + src/app/services/consumer-status.service.ts + 15 + + Document already exists. + + + File not found. + + src/app/services/consumer-status.service.ts + 16 + + File not found. + + + Pre-consume script does not exist. + + src/app/services/consumer-status.service.ts + 17 + + Pre-Consume is a term that appears like that in the documentation as well and does not need a specific translation + Pre-consume script does not exist. + + + Error while executing pre-consume script. + + src/app/services/consumer-status.service.ts + 18 + + Pre-Consume is a term that appears like that in the documentation as well and does not need a specific translation + Error while executing pre-consume script. + + + Post-consume script does not exist. + + src/app/services/consumer-status.service.ts + 19 + + Post-Consume is a term that appears like that in the documentation as well and does not need a specific translation + Post-consume script does not exist. + + + Error while executing post-consume script. + + src/app/services/consumer-status.service.ts + 20 + + Post-Consume is a term that appears like that in the documentation as well and does not need a specific translation + Error while executing post-consume script. + + + Received new file. + + src/app/services/consumer-status.service.ts + 21 + + Received new file. + + + File type not supported. + + src/app/services/consumer-status.service.ts + 22 + + File type not supported. + + + Processing document... + + src/app/services/consumer-status.service.ts + 23 + + Processing document... + + + Generating thumbnail... + + src/app/services/consumer-status.service.ts + 24 + + Generating thumbnail... + + + Retrieving date from document... + + src/app/services/consumer-status.service.ts + 25 + + Retrieving date from document... + + + Saving document... + + src/app/services/consumer-status.service.ts + 26 + + Saving document... + + + Finished. + + src/app/services/consumer-status.service.ts + 27 + + Finished. + + + Are you sure you want to close this document? + + src/app/services/open-documents.service.ts + 77 + + Are you sure you want to close this document? + + + Close document + + src/app/services/open-documents.service.ts + 79 + + Close document + + + Are you sure you want to close all documents? + + src/app/services/open-documents.service.ts + 98 + + Are you sure you want to close all documents? + + + Close documents + + src/app/services/open-documents.service.ts + 100 + + Close documents + + + Modified + + src/app/services/rest/document.service.ts + 23 + + Modified + + + Search score + + src/app/services/rest/document.service.ts + 28 + + Score is a value returned by the full text search engine and specifies how well a result matches the given query + Search score + + + English (US) + + src/app/services/settings.service.ts + 90 + + English (US) + + + Czech + + src/app/services/settings.service.ts + 91 + + Czech + + + Danish + + src/app/services/settings.service.ts + 92 + + Danish + + + German + + src/app/services/settings.service.ts + 93 + + German + + + English (GB) + + src/app/services/settings.service.ts + 94 + + English (GB) + + + Spanish + + src/app/services/settings.service.ts + 95 + + Spanish + + + French + + src/app/services/settings.service.ts + 96 + + French + + + Italian + + src/app/services/settings.service.ts + 97 + + Italian + + + Luxembourgish + + src/app/services/settings.service.ts + 98 + + Luxembourgish + + + Dutch + + src/app/services/settings.service.ts + 99 + + Dutch + + + Polish + + src/app/services/settings.service.ts + 100 + + Polish + + + Portuguese (Brazil) + + src/app/services/settings.service.ts + 101 + + Portuguese (Brazil) + + + Portuguese + + src/app/services/settings.service.ts + 102 + + Portuguese + + + Romanian + + src/app/services/settings.service.ts + 103 + + Romanian + + + Russian + + src/app/services/settings.service.ts + 104 + + Russian + + + Swedish + + src/app/services/settings.service.ts + 105 + + Swedish + + + ISO 8601 + + src/app/services/settings.service.ts + 115 + + ISO 8601 + + + Error + + src/app/services/toast.service.ts + 35 + + Error + + + Information + + src/app/services/toast.service.ts + 39 + + Information + + + + diff --git a/src-ui/src/locale/messages.sl_SI.xlf b/src-ui/src/locale/messages.sl_SI.xlf index 403dd38dc..260bcdb3a 100644 --- a/src-ui/src/locale/messages.sl_SI.xlf +++ b/src-ui/src/locale/messages.sl_SI.xlf @@ -8,7 +8,7 @@ src/app/app.component.ts 51 - Document added + Dokument dodan Document was added to paperless. @@ -16,7 +16,7 @@ src/app/app.component.ts 51 - Document was added to paperless. + Dokument je bil dodan v paperless. Open document @@ -28,7 +28,7 @@ src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html 45 - Open document + Odpri dokument Could not add : @@ -36,7 +36,7 @@ src/app/app.component.ts 59 - Could not add : + Ni bilo mogoÄe dodati : New document detected @@ -44,7 +44,7 @@ src/app/app.component.ts 65 - New document detected + Nov dokument zaznan Document is being processed by paperless. @@ -52,7 +52,7 @@ src/app/app.component.ts 65 - Document is being processed by paperless. + Dokument je v postopku obdelave. Paperless-ngx @@ -61,7 +61,7 @@ 11 app title - Paperless-ngx + Paperless-ngx Search documents @@ -69,7 +69,7 @@ src/app/components/app-frame/app-frame.component.html 18 - Search documents + IÅ¡Äi dokumente Logged in as @@ -77,7 +77,7 @@ src/app/components/app-frame/app-frame.component.html 34 - Logged in as + Prijavljen kot Settings @@ -93,7 +93,7 @@ src/app/components/manage/settings/settings.component.html 1 - Settings + Nastavitve Logout @@ -101,7 +101,7 @@ src/app/components/app-frame/app-frame.component.html 45 - Logout + Odjavi se Dashboard @@ -113,7 +113,7 @@ src/app/components/dashboard/dashboard.component.html 1 - Dashboard + Pregledna ploÅ¡Äa Documents @@ -149,7 +149,7 @@ src/app/components/manage/settings/settings.component.html 134 - Saved views + Shranjeni pogledi Open documents @@ -157,7 +157,7 @@ src/app/components/app-frame/app-frame.component.html 87 - Open documents + Odpri dokumente Close all @@ -165,7 +165,7 @@ src/app/components/app-frame/app-frame.component.html 106 - Close all + Zapri vse Manage @@ -173,7 +173,7 @@ src/app/components/app-frame/app-frame.component.html 112 - Manage + Upravljaj Correspondents @@ -185,7 +185,7 @@ src/app/components/manage/correspondent-list/correspondent-list.component.html 1 - Correspondents + Dopisniki Tags @@ -209,7 +209,7 @@ src/app/components/manage/tag-list/tag-list.component.html 1 - Tags + Oznake Document types @@ -221,7 +221,7 @@ src/app/components/manage/document-type-list/document-type-list.component.html 1 - Document types + Vrste dokumentov Logs @@ -233,7 +233,7 @@ src/app/components/manage/logs/logs.component.html 1 - Logs + Dnevniki Admin @@ -241,7 +241,7 @@ src/app/components/app-frame/app-frame.component.html 154 - Admin + Skrbnik Info @@ -249,7 +249,7 @@ src/app/components/app-frame/app-frame.component.html 160 - Info + Informacije Documentation @@ -257,7 +257,7 @@ src/app/components/app-frame/app-frame.component.html 167 - Documentation + Dokumentacija GitHub @@ -265,7 +265,7 @@ src/app/components/app-frame/app-frame.component.html 175 - GitHub + GitHub Suggest an idea @@ -273,7 +273,7 @@ src/app/components/app-frame/app-frame.component.html 181 - Suggest an idea + Podaj predlog Cancel @@ -305,7 +305,7 @@ src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html 18 - Cancel + PrekliÄi Confirmation @@ -313,7 +313,7 @@ src/app/components/common/confirm-dialog/confirm-dialog.component.ts 18 - Confirmation + Potrditev Confirm @@ -333,7 +333,7 @@ src/app/components/document-list/bulk-editor/bulk-editor.component.ts 189 - Confirm + Potrdi After @@ -341,7 +341,7 @@ src/app/components/common/date-dropdown/date-dropdown.component.html 13 - After + Po Clear @@ -353,7 +353,7 @@ src/app/components/common/date-dropdown/date-dropdown.component.html 41 - Clear + PoÄisti Before @@ -361,7 +361,7 @@ src/app/components/common/date-dropdown/date-dropdown.component.html 36 - Before + Pred Last 7 days @@ -369,7 +369,7 @@ src/app/components/common/date-dropdown/date-dropdown.component.ts 34 - Last 7 days + Zadnjih 7 dni Last month @@ -377,7 +377,7 @@ src/app/components/common/date-dropdown/date-dropdown.component.ts 35 - Last month + Zadnji mesec Last 3 months @@ -385,7 +385,7 @@ src/app/components/common/date-dropdown/date-dropdown.component.ts 36 - Last 3 months + Zadnje 3 mesece Last year @@ -393,7 +393,7 @@ src/app/components/common/date-dropdown/date-dropdown.component.ts 37 - Last year + PrejÅ¡nje leto Create new item @@ -401,7 +401,7 @@ src/app/components/common/edit-dialog/edit-dialog.component.ts 50 - Create new item + Ustvari nov element Edit item @@ -409,7 +409,7 @@ src/app/components/common/edit-dialog/edit-dialog.component.ts 54 - Edit item + Uredi vnos Could not save element: @@ -417,7 +417,7 @@ src/app/components/common/edit-dialog/edit-dialog.component.ts 58 - Could not save element: + Elementa ni bilo mogoÄe shraniti: Apply @@ -425,7 +425,7 @@ src/app/components/common/filterable-dropdown/filterable-dropdown.component.html 39 - Apply + Uporabi Click again to exclude items. @@ -433,7 +433,7 @@ src/app/components/common/filterable-dropdown/filterable-dropdown.component.html 45 - Click again to exclude items. + Kliknite znova, da izkljuÄite elemente. Not assigned @@ -442,7 +442,7 @@ 209 Filter drop down element to filter for documents with no correspondent/type/tag assigned - Not assigned + Ni dodeljeno Invalid date. @@ -450,7 +450,7 @@ src/app/components/common/input/date/date.component.html 12 - Invalid date. + Neveljaven datum. Add item @@ -459,7 +459,7 @@ 11 Used for both types and correspondents - Add item + Dodaj vnos Suggestions: @@ -471,7 +471,7 @@ src/app/components/common/input/tags/tags.component.html 42 - Suggestions: + Predlogi: Add tag @@ -479,7 +479,7 @@ src/app/components/common/input/tags/tags.component.html 11 - Add tag + Dodaj oznako Select @@ -495,7 +495,7 @@ src/app/components/document-list/document-list.component.html 7 - Select + Izberi Please select an object @@ -503,7 +503,7 @@ src/app/components/common/select-dialog/select-dialog.component.ts 21 - Please select an object + Prosimo, izberite vrednost Hello , welcome to Paperless-ngx! @@ -511,7 +511,7 @@ src/app/components/dashboard/dashboard.component.ts 33 - Hello , welcome to Paperless-ngx! + Pozdravljen , dobrodoÅ¡el v Paperless-ngx! Welcome to Paperless-ngx! @@ -519,7 +519,7 @@ src/app/components/dashboard/dashboard.component.ts 35 - Welcome to Paperless-ngx! + DobrodoÅ¡li v Paperless-ngx! Show all @@ -531,7 +531,7 @@ src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html 27 - Show all + Prikaži vse Created @@ -551,7 +551,7 @@ src/app/services/rest/document.service.ts 21 - Created + Ustvarjeno Title @@ -575,7 +575,7 @@ src/app/services/rest/document.service.ts 19 - Title + Naslov Statistics @@ -583,7 +583,7 @@ src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html 1 - Statistics + Statistika Documents in inbox: @@ -591,7 +591,7 @@ src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html 3 - Documents in inbox: + Dokumenti v nabiralniku: Total documents: @@ -599,7 +599,7 @@ src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html 4 - Total documents: + Skupaj dokumentov: Upload new documents @@ -607,7 +607,7 @@ src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html 1 - Upload new documents + Naložite nove dokumente Dismiss completed @@ -616,7 +616,7 @@ 4 This button dismisses all status messages about processed documents on the dashboard (failed and successful) - Dismiss completed + Odstrani konÄane Drop documents here or @@ -624,7 +624,7 @@ src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html 13 - Drop documents here or + Dokumente spustite sem oz. Browse files @@ -632,7 +632,7 @@ src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html 13 - Browse files + Prebrskaj datoteke {VAR_PLURAL, plural, =1 {One more document} other { more documents}} @@ -641,7 +641,7 @@ 25 This is shown as a summary line when there are more than 5 document in the processing pipeline. - {VAR_PLURAL, plural, =1 {One more document} other { more documents}} + {VAR_PLURAL, plural, =1 {Å e en dokument} other { veÄ dokumentov}} Processing: @@ -649,7 +649,7 @@ src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts 32 - Processing: + Obravnavanje: Failed: @@ -657,7 +657,7 @@ src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts 35 - Failed: + NeuspeÅ¡no: Added: @@ -665,7 +665,7 @@ src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts 38 - Added: + Dodani: , @@ -678,7 +678,7 @@ 117 this string is used to separate processing, failed and added on the file upload widget - , + , Connecting... @@ -686,7 +686,7 @@ src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts 118 - Connecting... + Povezovanje... Uploading... @@ -694,7 +694,7 @@ src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts 123 - Uploading... + Nalaganje... Upload complete, waiting... @@ -702,7 +702,7 @@ src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts 126 - Upload complete, waiting... + Nalaganje je konÄano, Äakam... HTTP error: @@ -710,7 +710,7 @@ src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts 136 - HTTP error: + Napaka HTTP: First steps @@ -718,7 +718,7 @@ src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html 1 - First steps + Prvi koraki Paperless is running! :) @@ -726,7 +726,7 @@ src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html 5 - Paperless is running! :) + Paperless je zagnan! :) You can start uploading documents by dropping them in the file upload box to the right or by dropping them in the configured consumption folder and they'll start showing up in the documents list. After you've added some metadata to your documents, use the filtering mechanisms of paperless to create custom views (such as 'Recently added', 'Tagged TODO') and they will appear on the dashboard instead of this message. @@ -734,7 +734,7 @@ src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html 6,7 - You can start uploading documents by dropping them in the file upload box to the right or by dropping them in the configured consumption folder and they'll start showing up in the documents list. After you've added some metadata to your documents, use the filtering mechanisms of paperless to create custom views (such as 'Recently added', 'Tagged TODO') and they will appear on the dashboard instead of this message. + Dokumente lahko zaÄnete nalagati tako, da jih spustite v polje za nalaganje datotek na desni ali tako, da jih spustite v nastavljeno mapo in zaÄeli se bodo prikazovati na seznamu dokumentov. Ko v svoje dokumente dodate nekaj metapodatkov, uporabite mehanizme filtriranja Paperless, da ustvarite poglede po meri (na primer »Nedavno dodano«, »OznaÄeno TODO«) in prikazani bodo na pregledni ploÅ¡Äi namesto tega sporoÄila. Paperless offers some more features that try to make your life easier: @@ -742,7 +742,7 @@ src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html 8 - Paperless offers some more features that try to make your life easier: + Paperless ponuja Å¡e nekaj funkcij, ki vam poskuÅ¡ajo olajÅ¡ati življenje: Once you've got a couple documents in paperless and added metadata to them, paperless can assign that metadata to new documents automatically. @@ -750,7 +750,7 @@ src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html 10 - Once you've got a couple documents in paperless and added metadata to them, paperless can assign that metadata to new documents automatically. + Ko imate nekaj dokumentov v paperless in jim dodate metapodatke, lahko paperless samodejno dodeli te metapodatke novim dokumentom. You can configure paperless to read your mails and add documents from attached files. @@ -758,7 +758,7 @@ src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html 11 - You can configure paperless to read your mails and add documents from attached files. + Paperless lahko konfigurirate za branje e-poÅ¡te in dodajanje dokumentov iz priloženih datotek. Consult the documentation on how to use these features. The section on basic usage also has some information on how to use paperless in general. @@ -766,7 +766,7 @@ src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html 13 - Consult the documentation on how to use these features. The section on basic usage also has some information on how to use paperless in general. + Oglejte si dokumentacijo o uporabi teh funkcij. Razdelek o osnovni uporabi vsebuje tudi nekaj informacij o uporabi paperless tudi na sploÅ¡no. Searching document with asn @@ -774,7 +774,7 @@ src/app/components/document-asn/document-asn.component.html 1 - Searching document with asn + Iskanje dokumenta z asn Page @@ -786,7 +786,7 @@ src/app/components/document-list/bulk-editor/bulk-editor.component.html 15 - Page + Stran of @@ -794,7 +794,7 @@ src/app/components/document-detail/document-detail.component.html 5 - of + od Delete @@ -826,7 +826,7 @@ src/app/components/manage/tag-list/tag-list.component.html 49 - Delete + IzbriÅ¡i Download @@ -846,7 +846,7 @@ src/app/components/document-list/document-card-small/document-card-small.component.html 82 - Download + Prenesi Download original @@ -854,7 +854,7 @@ src/app/components/document-detail/document-detail.component.html 25 - Download original + Prenesi izvirnik More like this @@ -866,7 +866,7 @@ src/app/components/document-list/document-card-large/document-card-large.component.html 38 - More like this + VeÄ takih Close @@ -874,7 +874,7 @@ src/app/components/document-detail/document-detail.component.html 40 - Close + Zapri Details @@ -882,7 +882,7 @@ src/app/components/document-detail/document-detail.component.html 52 - Details + Podrobnosti Archive serial number @@ -890,7 +890,7 @@ src/app/components/document-detail/document-detail.component.html 56 - Archive serial number + Arhivska serijska Å¡tevilka Date created @@ -898,7 +898,7 @@ src/app/components/document-detail/document-detail.component.html 57 - Date created + Datum nastanka Correspondent @@ -922,7 +922,7 @@ src/app/services/rest/document.service.ts 18 - Correspondent + Dopisnik Document type @@ -946,7 +946,7 @@ src/app/services/rest/document.service.ts 20 - Document type + Vrsta dokumenta Content @@ -954,7 +954,7 @@ src/app/components/document-detail/document-detail.component.html 68 - Content + Vsebina Metadata @@ -966,7 +966,7 @@ src/app/components/document-detail/metadata-collapse/metadata-collapse.component.ts 18 - Metadata + Metapodatki Date modified @@ -974,7 +974,7 @@ src/app/components/document-detail/document-detail.component.html 83 - Date modified + Datum spremembe Date added @@ -982,7 +982,7 @@ src/app/components/document-detail/document-detail.component.html 87 - Date added + Datum vnosa Media filename @@ -990,7 +990,7 @@ src/app/components/document-detail/document-detail.component.html 91 - Media filename + Ime medijske datoteke Original MD5 checksum @@ -998,7 +998,7 @@ src/app/components/document-detail/document-detail.component.html 95 - Original MD5 checksum + Izvirni MD5 checksum Original file size @@ -1006,7 +1006,7 @@ src/app/components/document-detail/document-detail.component.html 99 - Original file size + Izvirna velikost datoteke Original mime type @@ -1014,7 +1014,7 @@ src/app/components/document-detail/document-detail.component.html 103 - Original mime type + Izvirna mime vrsta Archive MD5 checksum @@ -1022,7 +1022,7 @@ src/app/components/document-detail/document-detail.component.html 107 - Archive MD5 checksum + Arhiviran MD5 checksum Archive file size @@ -1030,7 +1030,7 @@ src/app/components/document-detail/document-detail.component.html 111 - Archive file size + Velikost arhivske datoteke Original document metadata @@ -1038,7 +1038,7 @@ src/app/components/document-detail/document-detail.component.html 117 - Original document metadata + Izvirni metapodatki dokumenta Archived document metadata @@ -1046,7 +1046,7 @@ src/app/components/document-detail/document-detail.component.html 118 - Archived document metadata + Arhivirani metapodatki dokumenta Discard @@ -1054,7 +1054,7 @@ src/app/components/document-detail/document-detail.component.html 143 - Discard + Zavrzi Save & next @@ -1062,7 +1062,7 @@ src/app/components/document-detail/document-detail.component.html 144 - Save & next + Shrani & naslednjo Save @@ -1090,7 +1090,7 @@ src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html 19 - Save + Shrani Confirm delete @@ -1102,7 +1102,7 @@ src/app/components/manage/generic-list/generic-list.component.ts 102 - Confirm delete + Potrdi brisanje Do you really want to delete document ""? @@ -1110,7 +1110,7 @@ src/app/components/document-detail/document-detail.component.ts 268 - Do you really want to delete document ""? + Ali res želite izbrisati dokument ""? The files for this document will be deleted permanently. This operation cannot be undone. @@ -1118,7 +1118,7 @@ src/app/components/document-detail/document-detail.component.ts 269 - The files for this document will be deleted permanently. This operation cannot be undone. + Datoteke za ta dokument bodo trajno izbrisane. Te operacije ni mogoÄe razveljaviti. Delete document @@ -1126,7 +1126,7 @@ src/app/components/document-detail/document-detail.component.ts 271 - Delete document + IzbriÅ¡i dokument Error deleting document: @@ -1134,7 +1134,7 @@ src/app/components/document-detail/document-detail.component.ts 281 - Error deleting document: + Napaka pri brisanju dokumenta: Select: @@ -1142,7 +1142,7 @@ src/app/components/document-list/bulk-editor/bulk-editor.component.html 10 - Select: + Izberi: All @@ -1150,7 +1150,7 @@ src/app/components/document-list/bulk-editor/bulk-editor.component.html 20 - All + Vse Edit: @@ -1158,7 +1158,7 @@ src/app/components/document-list/bulk-editor/bulk-editor.component.html 27 - Edit: + Uredi: Filter tags @@ -1170,7 +1170,7 @@ src/app/components/document-list/filter-editor/filter-editor.component.html 19 - Filter tags + Filtriraj oznake Filter correspondents @@ -1182,7 +1182,7 @@ src/app/components/document-list/filter-editor/filter-editor.component.html 27 - Filter correspondents + Filtrirajte dopisnike Filter document types @@ -1194,7 +1194,7 @@ src/app/components/document-list/filter-editor/filter-editor.component.html 34 - Filter document types + Filtrirajte vrste dokumentov Download originals @@ -1202,7 +1202,7 @@ src/app/components/document-list/bulk-editor/bulk-editor.component.html 68 - Download originals + Prenesi izvirnik Error executing bulk operation: @@ -1210,7 +1210,7 @@ src/app/components/document-list/bulk-editor/bulk-editor.component.ts 74 - Error executing bulk operation: + Napaka pri izvajanju operacije v velikem obsegu: "" @@ -1222,7 +1222,7 @@ src/app/components/document-list/bulk-editor/bulk-editor.component.ts 117 - "" + "" "" and "" @@ -1231,7 +1231,7 @@ 115 This is for messages like 'modify "tag1" and "tag2"' - "" and "" + "" in "" and "" @@ -1240,7 +1240,7 @@ 118 this is for messages like 'modify "tag1", "tag2" and "tag3"' - and "" + in "" Confirm tags assignment @@ -1248,7 +1248,7 @@ src/app/components/document-list/bulk-editor/bulk-editor.component.ts 127 - Confirm tags assignment + Potrdite dodelitev oznak This operation will add the tag "" to selected document(s). @@ -1256,7 +1256,7 @@ src/app/components/document-list/bulk-editor/bulk-editor.component.ts 130 - This operation will add the tag "" to selected document(s). + Ta operacija bo dodala oznako "" izbranemu dokumentu . This operation will add the tags to selected document(s). @@ -1264,7 +1264,7 @@ src/app/components/document-list/bulk-editor/bulk-editor.component.ts 132 - This operation will add the tags to selected document(s). + Ta operacija bo dodala oznake na izbrane dokumente. This operation will remove the tag "" from selected document(s). @@ -1272,7 +1272,7 @@ src/app/components/document-list/bulk-editor/bulk-editor.component.ts 135 - This operation will remove the tag "" from selected document(s). + Ta operacija bo odstranila oznako "" iz izbranega dokumenta(ov). This operation will remove the tags from selected document(s). @@ -1280,7 +1280,7 @@ src/app/components/document-list/bulk-editor/bulk-editor.component.ts 137 - This operation will remove the tags from selected document(s). + Ta operacija bo odstranila oznake iz izbranih dokumentov. This operation will add the tags and remove the tags on selected document(s). @@ -1288,7 +1288,7 @@ src/app/components/document-list/bulk-editor/bulk-editor.component.ts 139 - This operation will add the tags and remove the tags on selected document(s). + Ta operacija bo dodala oznake in odstranila oznake na izbranih dokumentih. Confirm correspondent assignment @@ -1296,7 +1296,7 @@ src/app/components/document-list/bulk-editor/bulk-editor.component.ts 159 - Confirm correspondent assignment + Potrdite dopisnika This operation will assign the correspondent "" to selected document(s). @@ -1304,7 +1304,7 @@ src/app/components/document-list/bulk-editor/bulk-editor.component.ts 161 - This operation will assign the correspondent "" to selected document(s). + Ta operacija bo dodelila ustrezniega dopisnika "" izbranemu dokumentu(om). This operation will remove the correspondent from selected document(s). @@ -1312,7 +1312,7 @@ src/app/components/document-list/bulk-editor/bulk-editor.component.ts 163 - This operation will remove the correspondent from selected document(s). + Ta operacija bo odstranila dopisnika iz izbranih dokumentov. Confirm document type assignment @@ -1320,7 +1320,7 @@ src/app/components/document-list/bulk-editor/bulk-editor.component.ts 182 - Confirm document type assignment + Potrdite dodelitev vrste dokumenta This operation will assign the document type "" to selected document(s). @@ -1328,7 +1328,7 @@ src/app/components/document-list/bulk-editor/bulk-editor.component.ts 184 - This operation will assign the document type "" to selected document(s). + Ta operacija bo dodelila vrsto dokumenta "" izbranim dokumentom. This operation will remove the document type from selected document(s). @@ -1336,7 +1336,7 @@ src/app/components/document-list/bulk-editor/bulk-editor.component.ts 186 - This operation will remove the document type from selected document(s). + Ta operacija bo odstranila vrsto dokumenta iz izbranih dokumentov. Delete confirm @@ -1344,7 +1344,7 @@ src/app/components/document-list/bulk-editor/bulk-editor.component.ts 201 - Delete confirm + Potrdi izbris This operation will permanently delete selected document(s). @@ -1352,7 +1352,7 @@ src/app/components/document-list/bulk-editor/bulk-editor.component.ts 202 - This operation will permanently delete selected document(s). + Ta operacija bo trajno izbrisala izbrane dokumente. This operation cannot be undone. @@ -1360,7 +1360,7 @@ src/app/components/document-list/bulk-editor/bulk-editor.component.ts 203 - This operation cannot be undone. + Te operacije ni mogoÄe razveljaviti. Delete document(s) @@ -1368,7 +1368,7 @@ src/app/components/document-list/bulk-editor/bulk-editor.component.ts 205 - Delete document(s) + IzbriÅ¡i dokument(e) Filter by correspondent @@ -1380,7 +1380,7 @@ src/app/components/document-list/document-card-small/document-card-small.component.html 26 - Filter by correspondent + Filtriraj po dopisnikih Filter by tag @@ -1392,7 +1392,7 @@ src/app/components/document-list/document-card-small/document-card-small.component.html 15 - Filter by tag + Filtriraj po oznakah Edit @@ -1416,7 +1416,7 @@ src/app/components/manage/tag-list/tag-list.component.html 43 - Edit + Uredi View @@ -1424,7 +1424,7 @@ src/app/components/document-list/document-card-large/document-card-large.component.html 51 - View + Poglej Score: @@ -1432,7 +1432,7 @@ src/app/components/document-list/document-card-large/document-card-large.component.html 87 - Score: + Rezultat: Created: @@ -1440,7 +1440,7 @@ src/app/components/document-list/document-card-small/document-card-small.component.html 43 - Created: + Ustvarjeno: Added: @@ -1448,7 +1448,7 @@ src/app/components/document-list/document-card-small/document-card-small.component.html 44 - Added: + Dodano: Modified: @@ -1456,7 +1456,7 @@ src/app/components/document-list/document-card-small/document-card-small.component.html 45 - Modified: + Spremenjeno: Select none @@ -1464,7 +1464,7 @@ src/app/components/document-list/document-list.component.html 10 - Select none + NiÄ ne izberite Select page @@ -1472,7 +1472,7 @@ src/app/components/document-list/document-list.component.html 11 - Select page + Izberite stran Select all @@ -1480,7 +1480,7 @@ src/app/components/document-list/document-list.component.html 12 - Select all + Izberite vse Sort @@ -1488,7 +1488,7 @@ src/app/components/document-list/document-list.component.html 39 - Sort + Razvrsti Views @@ -1496,7 +1496,7 @@ src/app/components/document-list/document-list.component.html 64 - Views + Pogledi Save "" @@ -1504,7 +1504,7 @@ src/app/components/document-list/document-list.component.html 71 - Save "" + Shrani "" Save as... @@ -1512,7 +1512,7 @@ src/app/components/document-list/document-list.component.html 72 - Save as... + Shrani kot... Loading... @@ -1520,7 +1520,7 @@ src/app/components/document-list/document-list.component.html 87 - Loading... + Nalaganje... {VAR_PLURAL, plural, =1 {Selected of one document} other {Selected of documents}} @@ -1528,7 +1528,7 @@ src/app/components/document-list/document-list.component.html 89 - {VAR_PLURAL, plural, =1 {Selected of one document} other {Selected of documents}} + {VAR_PLURAL, plural, =1 {Izbrano enega dokumenta} other {Izbrano od dokumentov}} {VAR_PLURAL, plural, =1 {One document} other { documents}} @@ -1536,7 +1536,7 @@ src/app/components/document-list/document-list.component.html 91 - {VAR_PLURAL, plural, =1 {One document} other { documents}} + {VAR_PLURAL, plural, =1 {Dokument} other { dokumentov}} (filtered) @@ -1544,7 +1544,7 @@ src/app/components/document-list/document-list.component.html 91 - (filtered) + (filtrirano) ASN @@ -1560,7 +1560,7 @@ src/app/services/rest/document.service.ts 17 - ASN + ASN Added @@ -1576,7 +1576,7 @@ src/app/services/rest/document.service.ts 22 - Added + Dodano View "" saved successfully. @@ -1584,7 +1584,7 @@ src/app/components/document-list/document-list.component.ts 116 - View "" saved successfully. + Pogled »" je uspeÅ¡no shranjen. View "" created successfully. @@ -1592,7 +1592,7 @@ src/app/components/document-list/document-list.component.ts 138 - View "" created successfully. + Pogled »" je bil uspeÅ¡no ustvarjen. Reset filters @@ -1600,7 +1600,7 @@ src/app/components/document-list/filter-editor/filter-editor.component.html 57 - Reset filters + Ponastavi filtre Correspondent: @@ -1608,7 +1608,7 @@ src/app/components/document-list/filter-editor/filter-editor.component.ts 37 - Correspondent: + Dopisnik: Without correspondent @@ -1616,7 +1616,7 @@ src/app/components/document-list/filter-editor/filter-editor.component.ts 39 - Without correspondent + Brez dopisnika Type: @@ -1624,7 +1624,7 @@ src/app/components/document-list/filter-editor/filter-editor.component.ts 44 - Type: + Vrsta: Without document type @@ -1632,7 +1632,7 @@ src/app/components/document-list/filter-editor/filter-editor.component.ts 46 - Without document type + Brez vrste dokumenta Tag: @@ -1640,7 +1640,7 @@ src/app/components/document-list/filter-editor/filter-editor.component.ts 50 - Tag: + Oznaka: Without any tag @@ -1648,7 +1648,7 @@ src/app/components/document-list/filter-editor/filter-editor.component.ts 54 - Without any tag + Brez kakrÅ¡ne koli oznake Title: @@ -1656,7 +1656,7 @@ src/app/components/document-list/filter-editor/filter-editor.component.ts 58 - Title: + Naslov: ASN: @@ -1664,7 +1664,7 @@ src/app/components/document-list/filter-editor/filter-editor.component.ts 61 - ASN: + ASN: Title & content @@ -1672,7 +1672,7 @@ src/app/components/document-list/filter-editor/filter-editor.component.ts 89 - Title & content + Naslov & vsebina Advanced search @@ -1680,7 +1680,7 @@ src/app/components/document-list/filter-editor/filter-editor.component.ts 91 - Advanced search + Napredno iskanje More like @@ -1688,7 +1688,7 @@ src/app/components/document-list/filter-editor/filter-editor.component.ts 94 - More like + Bolj podobno Save current view @@ -1696,7 +1696,7 @@ src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html 3 - Save current view + Shrani trenutni pogled Name @@ -1744,7 +1744,7 @@ src/app/components/manage/tag-list/tag-list.component.html 19 - Name + Ime Show in sidebar @@ -1756,7 +1756,7 @@ src/app/components/manage/settings/settings.component.html 153 - Show in sidebar + Prikaži v stranski vrstici Show on dashboard @@ -1768,7 +1768,7 @@ src/app/components/manage/settings/settings.component.html 149 - Show on dashboard + Prikaži na pregledni ploÅ¡Äi Matching algorithm @@ -1784,7 +1784,7 @@ src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html 13 - Matching algorithm + Algoritem ujemanja Matching pattern @@ -1800,7 +1800,7 @@ src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html 14 - Matching pattern + Vzorec ujemanja Case insensitive @@ -1816,7 +1816,7 @@ src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html 15 - Case insensitive + Brez razlikovanje velikosti Ärk Create new correspondent @@ -1824,7 +1824,7 @@ src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.ts 21 - Create new correspondent + Ustvarite novega dopisnika Edit correspondent @@ -1832,7 +1832,7 @@ src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.ts 25 - Edit correspondent + Uredi dopisnika Create @@ -1848,7 +1848,7 @@ src/app/components/manage/tag-list/tag-list.component.html 2 - Create + Ustvari Filter by: @@ -1864,7 +1864,7 @@ src/app/components/manage/tag-list/tag-list.component.html 8 - Filter by: + Filtriraj po: Matching @@ -1880,7 +1880,7 @@ src/app/components/manage/tag-list/tag-list.component.html 21 - Matching + Ujemanje Document count @@ -1896,7 +1896,7 @@ src/app/components/manage/tag-list/tag-list.component.html 22 - Document count + Å tevilo dokumentov Last correspondence @@ -1904,7 +1904,7 @@ src/app/components/manage/correspondent-list/correspondent-list.component.html 22 - Last correspondence + Zadnja korespondenca Actions @@ -1924,7 +1924,7 @@ src/app/components/manage/tag-list/tag-list.component.html 23 - Actions + Dejanja Do you really want to delete the correspondent ""? @@ -1932,7 +1932,7 @@ src/app/components/manage/correspondent-list/correspondent-list.component.ts 26 - Do you really want to delete the correspondent ""? + Ali res želite izbrisati dopisnika ""? Create new document type @@ -1940,7 +1940,7 @@ src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.ts 21 - Create new document type + Ustvarite novo vrsto dokumenta Edit document type @@ -1948,7 +1948,7 @@ src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.ts 25 - Edit document type + Uredite vrsto dokumenta Do you really want to delete the document type ""? @@ -1956,7 +1956,7 @@ src/app/components/manage/document-type-list/document-type-list.component.ts 26 - Do you really want to delete the document type ""? + Ali res želite izbrisati vrsto dokumenta ""? Automatic @@ -1968,7 +1968,7 @@ src/app/data/matching-model.ts 17 - Automatic + Samodejno Do you really want to delete this element? @@ -1976,7 +1976,7 @@ src/app/components/manage/generic-list/generic-list.component.ts 97 - Do you really want to delete this element? + Ali res želite izbrisati ta element? Associated documents will not be deleted. @@ -1984,7 +1984,7 @@ src/app/components/manage/generic-list/generic-list.component.ts 104 - Associated documents will not be deleted. + Povezani dokumenti ne bodo izbrisani. Error while deleting element: @@ -1992,7 +1992,7 @@ src/app/components/manage/generic-list/generic-list.component.ts 114 - Error while deleting element: + Napaka pri brisanju elementa: General settings @@ -2000,7 +2000,7 @@ src/app/components/manage/settings/settings.component.html 10 - General settings + SploÅ¡ne nastavitve Appearance @@ -2008,7 +2008,7 @@ src/app/components/manage/settings/settings.component.html 13 - Appearance + Izgled Display language @@ -2016,7 +2016,7 @@ src/app/components/manage/settings/settings.component.html 17 - Display language + Jezik prikaza You need to reload the page after applying a new language. @@ -2024,7 +2024,7 @@ src/app/components/manage/settings/settings.component.html 25 - You need to reload the page after applying a new language. + Po uporabi novega jezika morate osvežiti stran. Date display @@ -2032,7 +2032,7 @@ src/app/components/manage/settings/settings.component.html 32 - Date display + Prikaz datuma Date format @@ -2040,7 +2040,7 @@ src/app/components/manage/settings/settings.component.html 45 - Date format + Oblika datuma Short: @@ -2048,7 +2048,7 @@ src/app/components/manage/settings/settings.component.html 51 - Short: + Kratka: Medium: @@ -2056,7 +2056,7 @@ src/app/components/manage/settings/settings.component.html 55 - Medium: + Srednja: Long: @@ -2064,7 +2064,7 @@ src/app/components/manage/settings/settings.component.html 59 - Long: + Dolga: Items per page @@ -2072,7 +2072,7 @@ src/app/components/manage/settings/settings.component.html 67 - Items per page + Elementov na stran Document editor @@ -2080,7 +2080,7 @@ src/app/components/manage/settings/settings.component.html 83 - Document editor + Urejevalnik dokumentov Use PDF viewer provided by the browser @@ -2088,7 +2088,7 @@ src/app/components/manage/settings/settings.component.html 87 - Use PDF viewer provided by the browser + Uporabite pregledovalnik PDF, ki ga ponuja brskalnik This is usually faster for displaying large PDF documents, but it might not work on some browsers. @@ -2096,7 +2096,7 @@ src/app/components/manage/settings/settings.component.html 87 - This is usually faster for displaying large PDF documents, but it might not work on some browsers. + To je obiÄajno hitrejÅ¡e za prikazovanje velikih dokumentov PDF, vendar morda ne bo delovalo v nekaterih brskalnikih. Dark mode @@ -2104,7 +2104,7 @@ src/app/components/manage/settings/settings.component.html 94 - Dark mode + Temni naÄin Use system settings @@ -2112,7 +2112,7 @@ src/app/components/manage/settings/settings.component.html 97 - Use system settings + Uporabite sistemske nastavitve Enable dark mode @@ -2120,7 +2120,7 @@ src/app/components/manage/settings/settings.component.html 98 - Enable dark mode + OmogoÄi temni naÄin Invert thumbnails in dark mode @@ -2128,7 +2128,7 @@ src/app/components/manage/settings/settings.component.html 99 - Invert thumbnails in dark mode + Invertirajte sliÄice v temnem naÄinu Bulk editing @@ -2136,7 +2136,7 @@ src/app/components/manage/settings/settings.component.html 103 - Bulk editing + MnožiÄno urejanje Show confirmation dialogs @@ -2144,7 +2144,7 @@ src/app/components/manage/settings/settings.component.html 107 - Show confirmation dialogs + Pokaži potrditvena okna Deleting documents will always ask for confirmation. @@ -2152,7 +2152,7 @@ src/app/components/manage/settings/settings.component.html 107 - Deleting documents will always ask for confirmation. + Brisanje dokumentov bo vedno zahtevalo potrditev. Apply on close @@ -2160,7 +2160,7 @@ src/app/components/manage/settings/settings.component.html 108 - Apply on close + Potrdite ob zaprtju Notifications @@ -2168,7 +2168,7 @@ src/app/components/manage/settings/settings.component.html 116 - Notifications + Obvestila Document processing @@ -2176,7 +2176,7 @@ src/app/components/manage/settings/settings.component.html 119 - Document processing + Obdelava dokumentov Show notifications when new documents are detected @@ -2184,7 +2184,7 @@ src/app/components/manage/settings/settings.component.html 123 - Show notifications when new documents are detected + Pokaži obvestila, ko so zaznani novi dokumenti Show notifications when document processing completes successfully @@ -2192,7 +2192,7 @@ src/app/components/manage/settings/settings.component.html 124 - Show notifications when document processing completes successfully + Pokaži obvestila, ko se obdelava dokumenta uspeÅ¡no zakljuÄi Show notifications when document processing fails @@ -2200,7 +2200,7 @@ src/app/components/manage/settings/settings.component.html 125 - Show notifications when document processing fails + Pokaži obvestila, ko obdelava dokumenta ne uspe Suppress notifications on dashboard @@ -2208,7 +2208,7 @@ src/app/components/manage/settings/settings.component.html 126 - Suppress notifications on dashboard + PrepreÄite obvestila na pregledni strani This will suppress all messages about document processing status on the dashboard. @@ -2216,7 +2216,7 @@ src/app/components/manage/settings/settings.component.html 126 - This will suppress all messages about document processing status on the dashboard. + S tem bodo na ploÅ¡Äi prekinjena vsa sporoÄila o stanju obdelave dokumentov. Appears on @@ -2224,7 +2224,7 @@ src/app/components/manage/settings/settings.component.html 146 - Appears on + Pojavi se na No saved views defined. @@ -2232,7 +2232,7 @@ src/app/components/manage/settings/settings.component.html 163 - No saved views defined. + Ni doloÄenih shranjenih pogledov. Saved view "" deleted. @@ -2240,7 +2240,7 @@ src/app/components/manage/settings/settings.component.ts 111 - Saved view "" deleted. + Shranjen pogled "" je izbrisan. Settings saved successfully. @@ -2248,7 +2248,7 @@ src/app/components/manage/settings/settings.component.ts 133 - Settings saved successfully. + Nastavitve uspeÅ¡no shranjene. Use system language @@ -2256,7 +2256,7 @@ src/app/components/manage/settings/settings.component.ts 138 - Use system language + Uporabi sistemski jezik Use date format of display language @@ -2264,7 +2264,7 @@ src/app/components/manage/settings/settings.component.ts 144 - Use date format of display language + Uporabite obliko datuma prikaznega jezika Error while storing settings on server: @@ -2272,7 +2272,7 @@ src/app/components/manage/settings/settings.component.ts 161 - Error while storing settings on server: + Napaka pri shranjevanju nastavitev na strežnik: Color @@ -2284,7 +2284,7 @@ src/app/components/manage/tag-list/tag-list.component.html 20 - Color + Barva Inbox tag @@ -2292,7 +2292,7 @@ src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html 12 - Inbox tag + Vhodna oznaka Inbox tags are automatically assigned to all consumed documents. @@ -2300,7 +2300,7 @@ src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html 12 - Inbox tags are automatically assigned to all consumed documents. + Vhodne oznake se samodejno dodelijo vsem vloženim dokumentom. Create new tag @@ -2308,7 +2308,7 @@ src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.ts 22 - Create new tag + Ustvari novo oznako Edit tag @@ -2316,7 +2316,7 @@ src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.ts 26 - Edit tag + Uredi oznako Do you really want to delete the tag ""? @@ -2324,7 +2324,7 @@ src/app/components/manage/tag-list/tag-list.component.ts 26 - Do you really want to delete the tag ""? + Ali res želite izbrisati oznako ""? 404 Not Found @@ -2332,7 +2332,7 @@ src/app/components/not-found/not-found.component.html 7 - 404 Not Found + 404 ni mogoÄe najti Any word @@ -2348,7 +2348,7 @@ src/app/data/matching-model.ts 12 - Any: Document contains any of these words (space separated) + Karkoli: dokument vsebuje katero koli od teh besed (loÄeno s presledkom) All words @@ -2364,7 +2364,7 @@ src/app/data/matching-model.ts 13 - All: Document contains all of these words (space separated) + Vse: dokument vsebuje vse te besede (loÄene s presledkom) Exact match @@ -2380,7 +2380,7 @@ src/app/data/matching-model.ts 14 - Exact: Document contains this string + ToÄno: dokument vsebuje ta niz Regular expression @@ -2388,7 +2388,7 @@ src/app/data/matching-model.ts 15 - Regular expression + Regularni izraz Regular expression: Document matches this regular expression @@ -2396,7 +2396,7 @@ src/app/data/matching-model.ts 15 - Regular expression: Document matches this regular expression + Regularni izraz: dokument se ujema s tem regularnim izrazom Fuzzy word @@ -2404,7 +2404,7 @@ src/app/data/matching-model.ts 16 - Fuzzy word + Fuzzy beseda Fuzzy: Document contains a word similar to this word @@ -2412,7 +2412,7 @@ src/app/data/matching-model.ts 16 - Fuzzy: Document contains a word similar to this word + Fuzzy: dokument vsebuje besedo, podobno tej besedi Auto: Learn matching automatically @@ -2420,7 +2420,7 @@ src/app/data/matching-model.ts 17 - Auto: Learn matching automatically + Samodejno: NauÄi se samodejnega ujemanja Unsaved Changes @@ -2436,7 +2436,7 @@ src/app/services/open-documents.service.ts 96 - Unsaved Changes + Neshranjene spremembe You have unsaved changes. @@ -2452,7 +2452,7 @@ src/app/services/open-documents.service.ts 97 - You have unsaved changes. + Imate neshranjene spremembe. Are you sure you want to leave? @@ -2460,7 +2460,7 @@ src/app/guards/dirty-form.guard.ts 18 - Are you sure you want to leave? + Ste prepriÄani, da želite oditi? Leave page @@ -2468,7 +2468,7 @@ src/app/guards/dirty-form.guard.ts 20 - Leave page + Zapusti stran (no title) @@ -2476,7 +2476,7 @@ src/app/pipes/document-title.pipe.ts 12 - (no title) + (brez naslova) Yes @@ -2484,7 +2484,7 @@ src/app/pipes/yes-no.pipe.ts 9 - Yes + Da No @@ -2492,7 +2492,7 @@ src/app/pipes/yes-no.pipe.ts 9 - No + Ne Document already exists. @@ -2500,7 +2500,7 @@ src/app/services/consumer-status.service.ts 15 - Document already exists. + Dokument že obstaja. File not found. @@ -2508,7 +2508,7 @@ src/app/services/consumer-status.service.ts 16 - File not found. + Datoteke ni mogoÄe najti. Pre-consume script does not exist. @@ -2517,7 +2517,7 @@ 17 Pre-Consume is a term that appears like that in the documentation as well and does not need a specific translation - Pre-consume script does not exist. + Skripta pre-consume ne obstaja. Error while executing pre-consume script. @@ -2526,7 +2526,7 @@ 18 Pre-Consume is a term that appears like that in the documentation as well and does not need a specific translation - Error while executing pre-consume script. + Napaka pri izvajanju skripte pre-consume. Post-consume script does not exist. @@ -2535,7 +2535,7 @@ 19 Post-Consume is a term that appears like that in the documentation as well and does not need a specific translation - Post-consume script does not exist. + Post-consume skripta ne obstaja. Error while executing post-consume script. @@ -2544,7 +2544,7 @@ 20 Post-Consume is a term that appears like that in the documentation as well and does not need a specific translation - Error while executing post-consume script. + Napaka pri izvajanju skripte post-consume. Received new file. @@ -2552,7 +2552,7 @@ src/app/services/consumer-status.service.ts 21 - Received new file. + Prejeta nova datoteka. File type not supported. @@ -2560,7 +2560,7 @@ src/app/services/consumer-status.service.ts 22 - File type not supported. + Vrsta datoteke ni podprta. Processing document... @@ -2568,7 +2568,7 @@ src/app/services/consumer-status.service.ts 23 - Processing document... + Obdelava dokumenta... Generating thumbnail... @@ -2576,7 +2576,7 @@ src/app/services/consumer-status.service.ts 24 - Generating thumbnail... + Generiranje sliÄice... Retrieving date from document... @@ -2584,7 +2584,7 @@ src/app/services/consumer-status.service.ts 25 - Retrieving date from document... + Pridobivanje datuma iz dokumenta... Saving document... @@ -2592,7 +2592,7 @@ src/app/services/consumer-status.service.ts 26 - Saving document... + Shranjevanje dokumenta... Finished. @@ -2600,7 +2600,7 @@ src/app/services/consumer-status.service.ts 27 - Finished. + KonÄano. Are you sure you want to close this document? @@ -2608,7 +2608,7 @@ src/app/services/open-documents.service.ts 77 - Are you sure you want to close this document? + Ali ste prepriÄani, da želite zapreti ta dokument? Close document @@ -2616,7 +2616,7 @@ src/app/services/open-documents.service.ts 79 - Close document + Zapri dokument Are you sure you want to close all documents? @@ -2624,7 +2624,7 @@ src/app/services/open-documents.service.ts 98 - Are you sure you want to close all documents? + Ali ste prepriÄani, da želite zapreti vse dokumente? Close documents @@ -2632,7 +2632,7 @@ src/app/services/open-documents.service.ts 100 - Close documents + Zapri dokumente Modified @@ -2640,7 +2640,7 @@ src/app/services/rest/document.service.ts 23 - Modified + Spremenjeno Search score @@ -2649,7 +2649,7 @@ 28 Score is a value returned by the full text search engine and specifies how well a result matches the given query - Search score + Rezultat iskanja English (US) @@ -2657,7 +2657,7 @@ src/app/services/settings.service.ts 90 - English (US) + AngleÅ¡Äina (ZDA) Czech @@ -2665,7 +2665,7 @@ src/app/services/settings.service.ts 91 - Czech + ÄŒeÅ¡Äina Danish @@ -2673,7 +2673,7 @@ src/app/services/settings.service.ts 92 - Danish + DanÅ¡Äina German @@ -2681,7 +2681,7 @@ src/app/services/settings.service.ts 93 - German + NemÅ¡Äina English (GB) @@ -2689,7 +2689,7 @@ src/app/services/settings.service.ts 94 - English (GB) + AngleÅ¡Äina (GB) Spanish @@ -2697,7 +2697,7 @@ src/app/services/settings.service.ts 95 - Spanish + Å panÅ¡Äina French @@ -2705,7 +2705,7 @@ src/app/services/settings.service.ts 96 - French + FrancoÅ¡Äina Italian @@ -2713,7 +2713,7 @@ src/app/services/settings.service.ts 97 - Italian + ItalijanÅ¡Äina Luxembourgish @@ -2721,7 +2721,7 @@ src/app/services/settings.service.ts 98 - Luxembourgish + LuksemburÅ¡ki Dutch @@ -2729,7 +2729,7 @@ src/app/services/settings.service.ts 99 - Dutch + NizozemÅ¡Äina Polish @@ -2737,7 +2737,7 @@ src/app/services/settings.service.ts 100 - Polish + PoljÅ¡Äina Portuguese (Brazil) @@ -2745,7 +2745,7 @@ src/app/services/settings.service.ts 101 - Portuguese (Brazil) + PortugalÅ¡Äina (Brazilija) Portuguese @@ -2753,7 +2753,7 @@ src/app/services/settings.service.ts 102 - Portuguese + PortugalÅ¡Äina Romanian @@ -2761,7 +2761,7 @@ src/app/services/settings.service.ts 103 - Romanian + RomunÅ¡Äina Russian @@ -2769,7 +2769,7 @@ src/app/services/settings.service.ts 104 - Russian + RuÅ¡Äina Swedish @@ -2777,7 +2777,7 @@ src/app/services/settings.service.ts 105 - Swedish + Å vedÅ¡Äina ISO 8601 @@ -2785,7 +2785,7 @@ src/app/services/settings.service.ts 115 - ISO 8601 + ISO 8601 Error @@ -2793,7 +2793,7 @@ src/app/services/toast.service.ts 35 - Error + Napaka Information @@ -2801,7 +2801,7 @@ src/app/services/toast.service.ts 39 - Information + Informacija diff --git a/src-ui/src/locale/messages.sr_CS.xlf b/src-ui/src/locale/messages.sr_CS.xlf new file mode 100644 index 000000000..648c007f7 --- /dev/null +++ b/src-ui/src/locale/messages.sr_CS.xlf @@ -0,0 +1,2808 @@ + + + + + + Document added + + src/app/app.component.ts + 51 + + Dokument je dodat + + + Document was added to paperless. + + src/app/app.component.ts + 51 + + Dokument je dodat u Paperless. + + + Open document + + src/app/app.component.ts + 51 + + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 45 + + Otvoreni dokument + + + Could not add : + + src/app/app.component.ts + 59 + + Nije moguće dodati : + + + New document detected + + src/app/app.component.ts + 65 + + Novi dokument je otkriven + + + Document is being processed by paperless. + + src/app/app.component.ts + 65 + + Dokument obraÄ‘uje Paperless. + + + Paperless-ngx + + src/app/components/app-frame/app-frame.component.html + 11 + + app title + Paperless-ngx + + + Search documents + + src/app/components/app-frame/app-frame.component.html + 18 + + Pretraga dokumenata + + + Logged in as + + src/app/components/app-frame/app-frame.component.html + 34 + + Ulogovan kao + + + Settings + + src/app/components/app-frame/app-frame.component.html + 40 + + + src/app/components/app-frame/app-frame.component.html + 147 + + + src/app/components/manage/settings/settings.component.html + 1 + + PodeÅ¡avanja + + + Logout + + src/app/components/app-frame/app-frame.component.html + 45 + + Odjavi se + + + Dashboard + + src/app/components/app-frame/app-frame.component.html + 61 + + + src/app/components/dashboard/dashboard.component.html + 1 + + Komandna tabla + + + Documents + + src/app/components/app-frame/app-frame.component.html + 68 + + + src/app/components/document-list/document-list.component.ts + 51 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 37 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 35 + + + src/app/components/manage/tag-list/tag-list.component.html + 38 + + Dokumenta + + + Saved views + + src/app/components/app-frame/app-frame.component.html + 74 + + + src/app/components/manage/settings/settings.component.html + 134 + + SaÄuvani prikaz + + + Open documents + + src/app/components/app-frame/app-frame.component.html + 87 + + Otvorena dokumenta + + + Close all + + src/app/components/app-frame/app-frame.component.html + 106 + + Zatvori svе + + + Manage + + src/app/components/app-frame/app-frame.component.html + 112 + + Upravljanje + + + Correspondents + + src/app/components/app-frame/app-frame.component.html + 119 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 1 + + Dopisnici + + + Tags + + src/app/components/app-frame/app-frame.component.html + 126 + + + src/app/components/common/input/tags/tags.component.html + 2 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 28 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 18 + + + src/app/components/manage/tag-list/tag-list.component.html + 1 + + Oznake + + + Document types + + src/app/components/app-frame/app-frame.component.html + 133 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 1 + + Tipovi dokumenta + + + Logs + + src/app/components/app-frame/app-frame.component.html + 140 + + + src/app/components/manage/logs/logs.component.html + 1 + + Logovi + + + Admin + + src/app/components/app-frame/app-frame.component.html + 154 + + Administracija + + + Info + + src/app/components/app-frame/app-frame.component.html + 160 + + Informacije + + + Documentation + + src/app/components/app-frame/app-frame.component.html + 167 + + Dokumentacija + + + GitHub + + src/app/components/app-frame/app-frame.component.html + 175 + + GitHub + + + Suggest an idea + + src/app/components/app-frame/app-frame.component.html + 181 + + Predložite ideju + + + Cancel + + src/app/components/common/confirm-dialog/confirm-dialog.component.html + 11 + + + src/app/components/common/select-dialog/select-dialog.component.html + 12 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 6 + + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 13 + + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 14 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 16 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 18 + + Otkaži + + + Confirmation + + src/app/components/common/confirm-dialog/confirm-dialog.component.ts + 18 + + Potvrda + + + Confirm + + src/app/components/common/confirm-dialog/confirm-dialog.component.ts + 30 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 143 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 166 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 189 + + Potvrdi + + + After + + src/app/components/common/date-dropdown/date-dropdown.component.html + 13 + + Posle + + + Clear + + src/app/components/common/date-dropdown/date-dropdown.component.html + 18 + + + src/app/components/common/date-dropdown/date-dropdown.component.html + 41 + + OÄisti + + + Before + + src/app/components/common/date-dropdown/date-dropdown.component.html + 36 + + Pre + + + Last 7 days + + src/app/components/common/date-dropdown/date-dropdown.component.ts + 34 + + Poslednjih 7 dana + + + Last month + + src/app/components/common/date-dropdown/date-dropdown.component.ts + 35 + + Prethodni mesec + + + Last 3 months + + src/app/components/common/date-dropdown/date-dropdown.component.ts + 36 + + Prethodna 3 meseca + + + Last year + + src/app/components/common/date-dropdown/date-dropdown.component.ts + 37 + + Prethodna godina + + + Create new item + + src/app/components/common/edit-dialog/edit-dialog.component.ts + 50 + + Kreiraj novu stavku + + + Edit item + + src/app/components/common/edit-dialog/edit-dialog.component.ts + 54 + + Izmeni stavku + + + Could not save element: + + src/app/components/common/edit-dialog/edit-dialog.component.ts + 58 + + Nije moguće saÄuvati elelement: + + + Apply + + src/app/components/common/filterable-dropdown/filterable-dropdown.component.html + 39 + + Primeni + + + Click again to exclude items. + + src/app/components/common/filterable-dropdown/filterable-dropdown.component.html + 45 + + Kliknite ponovo da biste iskljuÄili stavke. + + + Not assigned + + src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts + 209 + + Filter drop down element to filter for documents with no correspondent/type/tag assigned + Nije dodeljeno + + + Invalid date. + + src/app/components/common/input/date/date.component.html + 12 + + Nevažeći datum. + + + Add item + + src/app/components/common/input/select/select.component.html + 11 + + Used for both types and correspondents + Dodaj stavku + + + Suggestions: + + src/app/components/common/input/select/select.component.html + 29 + + + src/app/components/common/input/tags/tags.component.html + 42 + + Sugestije: + + + Add tag + + src/app/components/common/input/tags/tags.component.html + 11 + + Dodaj oznaku + + + Select + + src/app/components/common/select-dialog/select-dialog.component.html + 13 + + + src/app/components/common/select-dialog/select-dialog.component.ts + 18 + + + src/app/components/document-list/document-list.component.html + 7 + + Izaberi + + + Please select an object + + src/app/components/common/select-dialog/select-dialog.component.ts + 21 + + Molimo odaberete objekat + + + Hello , welcome to Paperless-ngx! + + src/app/components/dashboard/dashboard.component.ts + 33 + + Pozdrav , dobro doÅ¡ao u Paperless-ngx! + + + Welcome to Paperless-ngx! + + src/app/components/dashboard/dashboard.component.ts + 35 + + Dobro doÅ¡li u Paperless-ngx! + + + Show all + + src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html + 3 + + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 27 + + Prikaži sve + + + Created + + src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html + 9 + + + src/app/components/document-list/document-list.component.html + 141 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 41 + + + src/app/services/rest/document.service.ts + 21 + + Kreirano + + + Title + + src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html + 10 + + + src/app/components/document-detail/document-detail.component.html + 55 + + + src/app/components/document-list/document-list.component.html + 129 + + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 88 + + + src/app/services/rest/document.service.ts + 19 + + Naslov + + + Statistics + + src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html + 1 + + Statistika + + + Documents in inbox: + + src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html + 3 + + Dokumenata u prijemnom sanduÄetu: + + + Total documents: + + src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html + 4 + + Ukupno dokumenata: + + + Upload new documents + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 1 + + Otpremanje novih dokumenata + + + Dismiss completed + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 4 + + This button dismisses all status messages about processed documents on the dashboard (failed and successful) + Odbaci zavrÅ¡eno + + + Drop documents here or + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 13 + + Prevuci dokumenta ovde ili + + + Browse files + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 13 + + Istražite fajlove + + + {VAR_PLURAL, plural, =1 {One more document} other { more documents}} + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 25 + + This is shown as a summary line when there are more than 5 document in the processing pipeline. + {VAR_PLURAL, plural, =1 {Jedan dokument} other { viÅ¡e dokumenata}} + + + Processing: + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 32 + + Obrada: + + + Failed: + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 35 + + NeuspeÅ¡no: + + + Added: + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 38 + + Dodato: + + + , + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 40 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 117 + + this string is used to separate processing, failed and added on the file upload widget + , + + + Connecting... + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 118 + + Povezivanje... + + + Uploading... + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 123 + + Otpremanje... + + + Upload complete, waiting... + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 126 + + Otpremanje je zavrÅ¡eno, Äeka se... + + + HTTP error: + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 136 + + HTTP greÅ¡ka: + + + First steps + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 1 + + Prvi koraci + + + Paperless is running! :) + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 5 + + Paperless je pokrenut! :) + + + You can start uploading documents by dropping them in the file upload box to the right or by dropping them in the configured consumption folder and they'll start showing up in the documents list. After you've added some metadata to your documents, use the filtering mechanisms of paperless to create custom views (such as 'Recently added', 'Tagged TODO') and they will appear on the dashboard instead of this message. + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 6,7 + + Možete poÄeti da otpremate dokumente tako Å¡to cÌete ih ispustiti u polje za otpremanje datoteka sa desne strane ili tako Å¡to cÌete ih ispustiti u konfigurisani folder potroÅ¡nje i oni cÌe poÄeti da se pojavljuju na listi dokumenata. Nakon Å¡to dodate neke metapodatke u svoje dokumente, koristite mehanizme filtriranja Paperlessa da biste kreirali prilagoÄ‘ene prikaze (kao Å¡to su „Nedavno dodato“, „OznaÄeni TODO“) i oni cÌe se pojaviti na kontrolnoj tabli umesto ove poruke. + + + Paperless offers some more features that try to make your life easier: + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 8 + + Paperless nudi joÅ¡ neke funkcije koje pokuÅ¡avaju da vam olakÅ¡aju život: + + + Once you've got a couple documents in paperless and added metadata to them, paperless can assign that metadata to new documents automatically. + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 10 + + Kada imate nekoliko dokumenata u Paperlessu i dodate metapodatke u njih, Paperless možete automatski dodeliti te metapodatke novim dokumentima. + + + You can configure paperless to read your mails and add documents from attached files. + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 11 + + Možete da konfiguriÅ¡ete Paperless da Äitate svoju poÅ¡tu i dodajete dokumente iz priloženih fajlova. + + + Consult the documentation on how to use these features. The section on basic usage also has some information on how to use paperless in general. + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 13 + + Pogledajte dokumentaciju o tome kako da koristite ove funkcije. Odeljak o osnovnoj upotrebi takoÄ‘e sadrži neke informacije o tome kako se Paperless uopÅ¡te koristi. + + + Searching document with asn + + src/app/components/document-asn/document-asn.component.html + 1 + + Pretraži dokument sa ASN + + + Page + + src/app/components/document-detail/document-detail.component.html + 3 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 15 + + Strana + + + of + + src/app/components/document-detail/document-detail.component.html + 5 + + od + + + Delete + + src/app/components/document-detail/document-detail.component.html + 11 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 76 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 48 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 46 + + + src/app/components/manage/generic-list/generic-list.component.ts + 106 + + + src/app/components/manage/settings/settings.component.html + 159 + + + src/app/components/manage/tag-list/tag-list.component.html + 49 + + ObriÅ¡i + + + Download + + src/app/components/document-detail/document-detail.component.html + 19 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 63 + + + src/app/components/document-list/document-card-large/document-card-large.component.html + 60 + + + src/app/components/document-list/document-card-small/document-card-small.component.html + 82 + + Preuzmi + + + Download original + + src/app/components/document-detail/document-detail.component.html + 25 + + Preuzmi original + + + More like this + + src/app/components/document-detail/document-detail.component.html + 34 + + + src/app/components/document-list/document-card-large/document-card-large.component.html + 38 + + ViÅ¡e ovakvih + + + Close + + src/app/components/document-detail/document-detail.component.html + 40 + + Zatvori + + + Details + + src/app/components/document-detail/document-detail.component.html + 52 + + Detalji + + + Archive serial number + + src/app/components/document-detail/document-detail.component.html + 56 + + Arhivski serijski broj + + + Date created + + src/app/components/document-detail/document-detail.component.html + 57 + + Datum kreiranja + + + Correspondent + + src/app/components/document-detail/document-detail.component.html + 58 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 38 + + + src/app/components/document-list/document-list.component.html + 123 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 26 + + + src/app/services/rest/document.service.ts + 18 + + Dopisnik + + + Document type + + src/app/components/document-detail/document-detail.component.html + 60 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 47 + + + src/app/components/document-list/document-list.component.html + 135 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 33 + + + src/app/services/rest/document.service.ts + 20 + + Tip dokumenta + + + Content + + src/app/components/document-detail/document-detail.component.html + 68 + + Sadržaj + + + Metadata + + src/app/components/document-detail/document-detail.component.html + 77 + + + src/app/components/document-detail/metadata-collapse/metadata-collapse.component.ts + 18 + + Metapodaci + + + Date modified + + src/app/components/document-detail/document-detail.component.html + 83 + + Datum izmene + + + Date added + + src/app/components/document-detail/document-detail.component.html + 87 + + Datum dodavanja + + + Media filename + + src/app/components/document-detail/document-detail.component.html + 91 + + Naziv fajla + + + Original MD5 checksum + + src/app/components/document-detail/document-detail.component.html + 95 + + Originalni MD5 checksum + + + Original file size + + src/app/components/document-detail/document-detail.component.html + 99 + + Originalna veliÄina fajla + + + Original mime type + + src/app/components/document-detail/document-detail.component.html + 103 + + Originalni MIME tip + + + Archive MD5 checksum + + src/app/components/document-detail/document-detail.component.html + 107 + + Arhivni MD5 checksum + + + Archive file size + + src/app/components/document-detail/document-detail.component.html + 111 + + Arhivna veliÄina fajla + + + Original document metadata + + src/app/components/document-detail/document-detail.component.html + 117 + + Metapodaci originalnog dokumenta + + + Archived document metadata + + src/app/components/document-detail/document-detail.component.html + 118 + + Metapodaci arhivnog dokumenta + + + Discard + + src/app/components/document-detail/document-detail.component.html + 143 + + Odbaci + + + Save & next + + src/app/components/document-detail/document-detail.component.html + 144 + + SaÄuvaj & sledeći + + + Save + + src/app/components/document-detail/document-detail.component.html + 145 + + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 14 + + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 15 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 17 + + + src/app/components/manage/settings/settings.component.html + 173 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 19 + + SaÄuvaj + + + Confirm delete + + src/app/components/document-detail/document-detail.component.ts + 267 + + + src/app/components/manage/generic-list/generic-list.component.ts + 102 + + Potvrdi brisanje + + + Do you really want to delete document ""? + + src/app/components/document-detail/document-detail.component.ts + 268 + + Da li stvarno želite da obriÅ¡ite dokument ""? + + + The files for this document will be deleted permanently. This operation cannot be undone. + + src/app/components/document-detail/document-detail.component.ts + 269 + + Fajlovi za ovaj dokument cÌe biti trajno obrisani. Ova operacija se ne može opozvati. + + + Delete document + + src/app/components/document-detail/document-detail.component.ts + 271 + + ObriÅ¡i dokument + + + Error deleting document: + + src/app/components/document-detail/document-detail.component.ts + 281 + + GreÅ¡ka prilikom brisanja dokumenta: + + + Select: + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 10 + + Izaberi: + + + All + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 20 + + Sve + + + Edit: + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 27 + + Izmeni: + + + Filter tags + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 29 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 19 + + Filtriraj oznake + + + Filter correspondents + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 39 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 27 + + Filtriraj dopisnike + + + Filter document types + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 48 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 34 + + Filtriraj tipove dokumenata + + + Download originals + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 68 + + Preuzmi original + + + Error executing bulk operation: + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 74 + + GreÅ¡ka pri izvrÅ¡avanju grupne operacije: + + + "" + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 113 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 117 + + "" + + + "" and "" + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 115 + + This is for messages like 'modify "tag1" and "tag2"' + "" i "" + + + and "" + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 118 + + this is for messages like 'modify "tag1", "tag2" and "tag3"' + i "" + + + Confirm tags assignment + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 127 + + Potvrdi dodelu oznaka + + + This operation will add the tag "" to selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 130 + + Ova operacija će dodati oznaku "" to na selektovan(e) dokument(e). + + + This operation will add the tags to selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 132 + + Ova operacija će dodati oznake na selektovan(e) dokument(e). + + + This operation will remove the tag "" from selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 135 + + Ova radnja će obrisati oznaku "" iz selektovanih dokumenata. + + + This operation will remove the tags from selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 137 + + Ova radnja će obrisati oznake iz selektovanih dokumenata. + + + This operation will add the tags and remove the tags on selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 139 + + Ova radnja će dodati oznake i ukloniti oznake na selektovanim dokumentima. + + + Confirm correspondent assignment + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 159 + + Potvrdi dodelu dopisnika + + + This operation will assign the correspondent "" to selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 161 + + Ova radnja će dodati dopisnika "" na selektovane dokumente. + + + This operation will remove the correspondent from selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 163 + + Ova radnja će obrisati dopisnike sa selektovanih dokumenata. + + + Confirm document type assignment + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 182 + + Potvrdi dodelu tipa dokumenta + + + This operation will assign the document type "" to selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 184 + + Ova radnja će dodati tip dokumenta "" na selektovane dokumente. + + + This operation will remove the document type from selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 186 + + Ova radnja će obrisati tip dokumenta sa selektovanih dokumenata. + + + Delete confirm + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 201 + + Potvrdi brisanje + + + This operation will permanently delete selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 202 + + Ova radnja će trajno obrisati selektovan(a) dokument(a). + + + This operation cannot be undone. + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 203 + + Ovu radnju nije moguće opozvati. + + + Delete document(s) + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 205 + + ObriÅ¡i dokument(e) + + + Filter by correspondent + + src/app/components/document-list/document-card-large/document-card-large.component.html + 20 + + + src/app/components/document-list/document-card-small/document-card-small.component.html + 26 + + Filtriraj po dopisniku + + + Filter by tag + + src/app/components/document-list/document-card-large/document-card-large.component.html + 24 + + + src/app/components/document-list/document-card-small/document-card-small.component.html + 15 + + Filtriraj po oznaci + + + Edit + + src/app/components/document-list/document-card-large/document-card-large.component.html + 43 + + + src/app/components/document-list/document-card-small/document-card-small.component.html + 66 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 42 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 40 + + + src/app/components/manage/tag-list/tag-list.component.html + 43 + + Izmeni + + + View + + src/app/components/document-list/document-card-large/document-card-large.component.html + 51 + + Prikaz + + + Score: + + src/app/components/document-list/document-card-large/document-card-large.component.html + 87 + + Rezultat: + + + Created: + + src/app/components/document-list/document-card-small/document-card-small.component.html + 43 + + Kreirano: + + + Added: + + src/app/components/document-list/document-card-small/document-card-small.component.html + 44 + + Dodato: + + + Modified: + + src/app/components/document-list/document-card-small/document-card-small.component.html + 45 + + Izmenjeno: + + + Select none + + src/app/components/document-list/document-list.component.html + 10 + + PoniÅ¡ti sve + + + Select page + + src/app/components/document-list/document-list.component.html + 11 + + Izaberi stranu + + + Select all + + src/app/components/document-list/document-list.component.html + 12 + + Odaberi sve + + + Sort + + src/app/components/document-list/document-list.component.html + 39 + + Sortiraj + + + Views + + src/app/components/document-list/document-list.component.html + 64 + + Prikazi + + + Save "" + + src/app/components/document-list/document-list.component.html + 71 + + SaÄuvaj "" + + + Save as... + + src/app/components/document-list/document-list.component.html + 72 + + SaÄuvaj kao... + + + Loading... + + src/app/components/document-list/document-list.component.html + 87 + + UÄitavanje... + + + {VAR_PLURAL, plural, =1 {Selected of one document} other {Selected of documents}} + + src/app/components/document-list/document-list.component.html + 89 + + {VAR_PLURAL, plural, =1 {Selektovan od jednog dokumenta} other {Selektovano od dokumenata}} + + + {VAR_PLURAL, plural, =1 {One document} other { documents}} + + src/app/components/document-list/document-list.component.html + 91 + + {VAR_PLURAL, plural, =1 {Jedan dokument} other { dokumenata}} + + + (filtered) + + src/app/components/document-list/document-list.component.html + 91 + + (filtrirano) + + + ASN + + src/app/components/document-list/document-list.component.html + 117 + + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 90 + + + src/app/services/rest/document.service.ts + 17 + + ASN + + + Added + + src/app/components/document-list/document-list.component.html + 147 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 48 + + + src/app/services/rest/document.service.ts + 22 + + Dodato + + + View "" saved successfully. + + src/app/components/document-list/document-list.component.ts + 116 + + Prikaz "" je uspeÅ¡no saÄuvan. + + + View "" created successfully. + + src/app/components/document-list/document-list.component.ts + 138 + + Prikaz "" je uspeÅ¡no kreiran. + + + Reset filters + + src/app/components/document-list/filter-editor/filter-editor.component.html + 57 + + PoniÅ¡tavanje filtera + + + Correspondent: + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 37 + + Dopisnik: + + + Without correspondent + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 39 + + Bez dopisnika + + + Type: + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 44 + + Tip: + + + Without document type + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 46 + + Bez tipa dokumenta + + + Tag: + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 50 + + Oznake: + + + Without any tag + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 54 + + Bez oznake + + + Title: + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 58 + + Naslov: + + + ASN: + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 61 + + ASN: + + + Title & content + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 89 + + Naslov & sadržaj + + + Advanced search + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 91 + + Napredna pretraga + + + More like + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 94 + + ViÅ¡e sliÄnog + + + Save current view + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 3 + + SaÄuvaj trenutni prikaz + + + Name + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 8 + + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 8 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 9 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 19 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 9 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 9 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 19 + + + src/app/components/manage/settings/settings.component.html + 141 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 8 + + + src/app/components/manage/tag-list/tag-list.component.html + 9 + + + src/app/components/manage/tag-list/tag-list.component.html + 19 + + Naziv + + + Show in sidebar + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 9 + + + src/app/components/manage/settings/settings.component.html + 153 + + Prikaži u boÄnoj traci + + + Show on dashboard + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 10 + + + src/app/components/manage/settings/settings.component.html + 149 + + Prikaži na kontrolnoj tabli + + + Matching algorithm + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 9 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 10 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 13 + + Algoritam podudaranja + + + Matching pattern + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 10 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 11 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 14 + + Obrzac podudaranja + + + Case insensitive + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 11 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 12 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 15 + + Bez razlike veliko/malo slovo + + + Create new correspondent + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.ts + 21 + + Krairaj novog dopisnika + + + Edit correspondent + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.ts + 25 + + Izmeni dopisnika + + + Create + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 2 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 2 + + + src/app/components/manage/tag-list/tag-list.component.html + 2 + + Kreiraj + + + Filter by: + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 8 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 8 + + + src/app/components/manage/tag-list/tag-list.component.html + 8 + + Filtriraj po: + + + Matching + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 20 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 20 + + + src/app/components/manage/tag-list/tag-list.component.html + 21 + + Podudaranje + + + Document count + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 21 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 21 + + + src/app/components/manage/tag-list/tag-list.component.html + 22 + + Broj dokumenata + + + Last correspondence + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 22 + + Poslednja prepiska + + + Actions + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 23 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 22 + + + src/app/components/manage/settings/settings.component.html + 158 + + + src/app/components/manage/tag-list/tag-list.component.html + 23 + + Akcije + + + Do you really want to delete the correspondent ""? + + src/app/components/manage/correspondent-list/correspondent-list.component.ts + 26 + + Da li stvarno želite da obriÅ¡ete ovog dopisnika ""? + + + Create new document type + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.ts + 21 + + Kreiraj novi tip dokumenta + + + Edit document type + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.ts + 25 + + Uredi tip dokumenta + + + Do you really want to delete the document type ""? + + src/app/components/manage/document-type-list/document-type-list.component.ts + 26 + + Da li stvarno želite da obriÅ¡ite ovaj tip dokumenta ""? + + + Automatic + + src/app/components/manage/generic-list/generic-list.component.ts + 39 + + + src/app/data/matching-model.ts + 17 + + Automatski + + + Do you really want to delete this element? + + src/app/components/manage/generic-list/generic-list.component.ts + 97 + + Da li ste sigurni da želite da obriÅ¡ete ovaj element? + + + Associated documents will not be deleted. + + src/app/components/manage/generic-list/generic-list.component.ts + 104 + + Povezani dokumenti necÌe biti obrisani. + + + Error while deleting element: + + src/app/components/manage/generic-list/generic-list.component.ts + 114 + + GreÅ¡ka prilikom brisanja elementa: + + + General settings + + src/app/components/manage/settings/settings.component.html + 10 + + OpÅ¡ta podeÅ¡avanja + + + Appearance + + src/app/components/manage/settings/settings.component.html + 13 + + Izglеd + + + Display language + + src/app/components/manage/settings/settings.component.html + 17 + + Jezik prikaza + + + You need to reload the page after applying a new language. + + src/app/components/manage/settings/settings.component.html + 25 + + Morate ponovo da uÄitati stranicu nakon Å¡to primenite novi jezik. + + + Date display + + src/app/components/manage/settings/settings.component.html + 32 + + Prikaz datuma + + + Date format + + src/app/components/manage/settings/settings.component.html + 45 + + Format datuma + + + Short: + + src/app/components/manage/settings/settings.component.html + 51 + + Kratak: + + + Medium: + + src/app/components/manage/settings/settings.component.html + 55 + + Srednji: + + + Long: + + src/app/components/manage/settings/settings.component.html + 59 + + DugaÄak: + + + Items per page + + src/app/components/manage/settings/settings.component.html + 67 + + Stavki po stranici + + + Document editor + + src/app/components/manage/settings/settings.component.html + 83 + + Dokument editor + + + Use PDF viewer provided by the browser + + src/app/components/manage/settings/settings.component.html + 87 + + Koristite PDF pregledaÄ koji obezbeÄ‘uje brauzer + + + This is usually faster for displaying large PDF documents, but it might not work on some browsers. + + src/app/components/manage/settings/settings.component.html + 87 + + Ovo je obiÄno brže za prikazivanje velikih PDF dokumenata, ali možda necÌe raditi u nekim pretraživaÄima. + + + Dark mode + + src/app/components/manage/settings/settings.component.html + 94 + + Tamni režim + + + Use system settings + + src/app/components/manage/settings/settings.component.html + 97 + + Koristi sistemska podeÅ¡avanja + + + Enable dark mode + + src/app/components/manage/settings/settings.component.html + 98 + + Omogući tamni režim + + + Invert thumbnails in dark mode + + src/app/components/manage/settings/settings.component.html + 99 + + Okrenite sliÄice u tamnom režimu + + + Bulk editing + + src/app/components/manage/settings/settings.component.html + 103 + + Grupno ureÄ‘ivanje + + + Show confirmation dialogs + + src/app/components/manage/settings/settings.component.html + 107 + + Prikaži dijaloge za potvrdu + + + Deleting documents will always ask for confirmation. + + src/app/components/manage/settings/settings.component.html + 107 + + Brisanje dokumenata cÌe uvek tražiti potvrdu. + + + Apply on close + + src/app/components/manage/settings/settings.component.html + 108 + + Primeni pri zatvaranju + + + Notifications + + src/app/components/manage/settings/settings.component.html + 116 + + ObaveÅ¡tenja + + + Document processing + + src/app/components/manage/settings/settings.component.html + 119 + + Obrada dokumenata + + + Show notifications when new documents are detected + + src/app/components/manage/settings/settings.component.html + 123 + + Prikaži obaveÅ¡tenja kada se otkriju novi dokumenti + + + Show notifications when document processing completes successfully + + src/app/components/manage/settings/settings.component.html + 124 + + Prikaži obaveÅ¡tenja kada se obrada dokumenta uspeÅ¡no zavrÅ¡i + + + Show notifications when document processing fails + + src/app/components/manage/settings/settings.component.html + 125 + + Prikaži obaveÅ¡tenja kada obrada dokumenta ne uspe + + + Suppress notifications on dashboard + + src/app/components/manage/settings/settings.component.html + 126 + + PoniÅ¡ti obaveÅ¡tenja na kontrolnoj tabli + + + This will suppress all messages about document processing status on the dashboard. + + src/app/components/manage/settings/settings.component.html + 126 + + Ovo cÌe potisnuti sve poruke o statusu obrade dokumenta na kontrolnoj tabli. + + + Appears on + + src/app/components/manage/settings/settings.component.html + 146 + + Pojavljuje se na + + + No saved views defined. + + src/app/components/manage/settings/settings.component.html + 163 + + Nema definisanih saÄuvanih prikaza. + + + Saved view "" deleted. + + src/app/components/manage/settings/settings.component.ts + 111 + + SaÄuvani prikaz "" je obrisan. + + + Settings saved successfully. + + src/app/components/manage/settings/settings.component.ts + 133 + + PodeÅ¡avanja su uspeÅ¡no saÄuvana. + + + Use system language + + src/app/components/manage/settings/settings.component.ts + 138 + + Koristi sistemski jezik + + + Use date format of display language + + src/app/components/manage/settings/settings.component.ts + 144 + + Koristi format datuma jezika prikaza + + + Error while storing settings on server: + + src/app/components/manage/settings/settings.component.ts + 161 + + GreÅ¡ka pri Äuvanju podeÅ¡avanja na serveru: + + + Color + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 10 + + + src/app/components/manage/tag-list/tag-list.component.html + 20 + + Boja + + + Inbox tag + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 12 + + Oznaka prijemnog sanduÄeta + + + Inbox tags are automatically assigned to all consumed documents. + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 12 + + Oznake prijemnog sanduÄeta se automatski dodeljuju svim obraÄ‘enim dokumentima. + + + Create new tag + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.ts + 22 + + Kreiraj novu oznaku + + + Edit tag + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.ts + 26 + + Izmeni oznaku + + + Do you really want to delete the tag ""? + + src/app/components/manage/tag-list/tag-list.component.ts + 26 + + Da li stvarno želite da obriÅ¡ete oznaku ""? + + + 404 Not Found + + src/app/components/not-found/not-found.component.html + 7 + + 404 Nije pronaÄ‘eno + + + Any word + + src/app/data/matching-model.ts + 12 + + Bilo koja reÄ + + + Any: Document contains any of these words (space separated) + + src/app/data/matching-model.ts + 12 + + Bilo koji: dokument sadrži bilo koju od ovih reÄi (razdvojenih razmacima) + + + All words + + src/app/data/matching-model.ts + 13 + + Sve reÄi + + + All: Document contains all of these words (space separated) + + src/app/data/matching-model.ts + 13 + + Sve: Dokument sadrži sve ove reÄi (razdvojene razmakom) + + + Exact match + + src/app/data/matching-model.ts + 14 + + TaÄno podudaranje + + + Exact: Document contains this string + + src/app/data/matching-model.ts + 14 + + TaÄno: dokument sadrži ovaj niz + + + Regular expression + + src/app/data/matching-model.ts + 15 + + Regularni izraz + + + Regular expression: Document matches this regular expression + + src/app/data/matching-model.ts + 15 + + Regularni izraz: Dokument odgovara ovom regularnom izrazu + + + Fuzzy word + + src/app/data/matching-model.ts + 16 + + Fuzzy reÄ + + + Fuzzy: Document contains a word similar to this word + + src/app/data/matching-model.ts + 16 + + Fuzzy: Dokument sadrži reÄ sliÄnu ovoj reÄi + + + Auto: Learn matching automatically + + src/app/data/matching-model.ts + 17 + + Automatski: nauÄi automatsko podudaranje + + + Unsaved Changes + + src/app/guards/dirty-form.guard.ts + 16 + + + src/app/services/open-documents.service.ts + 75 + + + src/app/services/open-documents.service.ts + 96 + + NesaÄuvane izmene + + + You have unsaved changes. + + src/app/guards/dirty-form.guard.ts + 17 + + + src/app/services/open-documents.service.ts + 76 + + + src/app/services/open-documents.service.ts + 97 + + Imate nesaÄuvanih izmena. + + + Are you sure you want to leave? + + src/app/guards/dirty-form.guard.ts + 18 + + Da li ste sigurni da želite da napustite? + + + Leave page + + src/app/guards/dirty-form.guard.ts + 20 + + Napusti stranicu + + + (no title) + + src/app/pipes/document-title.pipe.ts + 12 + + (bеz naslova) + + + Yes + + src/app/pipes/yes-no.pipe.ts + 9 + + Da + + + No + + src/app/pipes/yes-no.pipe.ts + 9 + + Ne + + + Document already exists. + + src/app/services/consumer-status.service.ts + 15 + + Dokument već postoji. + + + File not found. + + src/app/services/consumer-status.service.ts + 16 + + Fajl nije pronaÄ‘en. + + + Pre-consume script does not exist. + + src/app/services/consumer-status.service.ts + 17 + + Pre-Consume is a term that appears like that in the documentation as well and does not need a specific translation + Pre-consume skripta ne postoji. + + + Error while executing pre-consume script. + + src/app/services/consumer-status.service.ts + 18 + + Pre-Consume is a term that appears like that in the documentation as well and does not need a specific translation + GreÅ¡ka prilikom izvrÅ¡avanja pre-consume skripte. + + + Post-consume script does not exist. + + src/app/services/consumer-status.service.ts + 19 + + Post-Consume is a term that appears like that in the documentation as well and does not need a specific translation + Post-consume skripta ne postoji. + + + Error while executing post-consume script. + + src/app/services/consumer-status.service.ts + 20 + + Post-Consume is a term that appears like that in the documentation as well and does not need a specific translation + GreÅ¡ka prilikom izvrÅ¡avanja post-consume skripte. + + + Received new file. + + src/app/services/consumer-status.service.ts + 21 + + Primljen novi fajl. + + + File type not supported. + + src/app/services/consumer-status.service.ts + 22 + + Tip fajla nije podržan. + + + Processing document... + + src/app/services/consumer-status.service.ts + 23 + + ObraÄ‘ivanje dokumenta... + + + Generating thumbnail... + + src/app/services/consumer-status.service.ts + 24 + + Generisanje sliÄice... + + + Retrieving date from document... + + src/app/services/consumer-status.service.ts + 25 + + Preuzimanje datuma iz dokumenta... + + + Saving document... + + src/app/services/consumer-status.service.ts + 26 + + ÄŒuvanje dokumenta... + + + Finished. + + src/app/services/consumer-status.service.ts + 27 + + ZavrÅ¡eno. + + + Are you sure you want to close this document? + + src/app/services/open-documents.service.ts + 77 + + Da li ste sigurni da želite da zatvorite ovaj dokument? + + + Close document + + src/app/services/open-documents.service.ts + 79 + + Zatvori dokument + + + Are you sure you want to close all documents? + + src/app/services/open-documents.service.ts + 98 + + Da li ste sigurni da želite da zatvorite sve dokumente? + + + Close documents + + src/app/services/open-documents.service.ts + 100 + + Zatvori dokumenta + + + Modified + + src/app/services/rest/document.service.ts + 23 + + Izmenjeno + + + Search score + + src/app/services/rest/document.service.ts + 28 + + Score is a value returned by the full text search engine and specifies how well a result matches the given query + Rezultate pretrage + + + English (US) + + src/app/services/settings.service.ts + 90 + + Engleski (USA) + + + Czech + + src/app/services/settings.service.ts + 91 + + ÄŒeÅ¡ki + + + Danish + + src/app/services/settings.service.ts + 92 + + Danski + + + German + + src/app/services/settings.service.ts + 93 + + NemaÄki + + + English (GB) + + src/app/services/settings.service.ts + 94 + + Engleski (UK) + + + Spanish + + src/app/services/settings.service.ts + 95 + + Å panski + + + French + + src/app/services/settings.service.ts + 96 + + Francuski + + + Italian + + src/app/services/settings.service.ts + 97 + + Italijanski + + + Luxembourgish + + src/app/services/settings.service.ts + 98 + + LuksemburÅ¡ki + + + Dutch + + src/app/services/settings.service.ts + 99 + + Holandski + + + Polish + + src/app/services/settings.service.ts + 100 + + Poljski + + + Portuguese (Brazil) + + src/app/services/settings.service.ts + 101 + + Portugalski (Brazil) + + + Portuguese + + src/app/services/settings.service.ts + 102 + + Portugalski + + + Romanian + + src/app/services/settings.service.ts + 103 + + Rumunski + + + Russian + + src/app/services/settings.service.ts + 104 + + Ruski + + + Swedish + + src/app/services/settings.service.ts + 105 + + Å vedski + + + ISO 8601 + + src/app/services/settings.service.ts + 115 + + ISO 8601 + + + Error + + src/app/services/toast.service.ts + 35 + + Grеška + + + Information + + src/app/services/toast.service.ts + 39 + + Informacija + + + + diff --git a/src-ui/src/locale/messages.tr_TR.xlf b/src-ui/src/locale/messages.tr_TR.xlf new file mode 100644 index 000000000..ada92b569 --- /dev/null +++ b/src-ui/src/locale/messages.tr_TR.xlf @@ -0,0 +1,2808 @@ + + + + + + Document added + + src/app/app.component.ts + 51 + + Belge eklendi + + + Document was added to paperless. + + src/app/app.component.ts + 51 + + Belge paperless'e eklendi. + + + Open document + + src/app/app.component.ts + 51 + + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 45 + + Belgeyi aç + + + Could not add : + + src/app/app.component.ts + 59 + + : 'i ekliyemiyorum + + + New document detected + + src/app/app.component.ts + 65 + + Yeni belge algılandı + + + Document is being processed by paperless. + + src/app/app.component.ts + 65 + + adlı belge paperless tarafından iÅŸleniyor. + + + Paperless-ngx + + src/app/components/app-frame/app-frame.component.html + 11 + + app title + Paperless-ngx + + + Search documents + + src/app/components/app-frame/app-frame.component.html + 18 + + Belgeleri Ara + + + Logged in as + + src/app/components/app-frame/app-frame.component.html + 34 + + olarak oturum açıldı + + + Settings + + src/app/components/app-frame/app-frame.component.html + 40 + + + src/app/components/app-frame/app-frame.component.html + 147 + + + src/app/components/manage/settings/settings.component.html + 1 + + Ayarlar + + + Logout + + src/app/components/app-frame/app-frame.component.html + 45 + + Oturumu kapat + + + Dashboard + + src/app/components/app-frame/app-frame.component.html + 61 + + + src/app/components/dashboard/dashboard.component.html + 1 + + Kontrol Paneli + + + Documents + + src/app/components/app-frame/app-frame.component.html + 68 + + + src/app/components/document-list/document-list.component.ts + 51 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 37 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 35 + + + src/app/components/manage/tag-list/tag-list.component.html + 38 + + Belgeler + + + Saved views + + src/app/components/app-frame/app-frame.component.html + 74 + + + src/app/components/manage/settings/settings.component.html + 134 + + Kaydedilen görünümler + + + Open documents + + src/app/components/app-frame/app-frame.component.html + 87 + + Belgeleri aç + + + Close all + + src/app/components/app-frame/app-frame.component.html + 106 + + Tümünü kapat + + + Manage + + src/app/components/app-frame/app-frame.component.html + 112 + + Yönet + + + Correspondents + + src/app/components/app-frame/app-frame.component.html + 119 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 1 + + Muhabirler + + + Tags + + src/app/components/app-frame/app-frame.component.html + 126 + + + src/app/components/common/input/tags/tags.component.html + 2 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 28 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 18 + + + src/app/components/manage/tag-list/tag-list.component.html + 1 + + Etiketler + + + Document types + + src/app/components/app-frame/app-frame.component.html + 133 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 1 + + Belge türleri + + + Logs + + src/app/components/app-frame/app-frame.component.html + 140 + + + src/app/components/manage/logs/logs.component.html + 1 + + Günlükler + + + Admin + + src/app/components/app-frame/app-frame.component.html + 154 + + Yönetici + + + Info + + src/app/components/app-frame/app-frame.component.html + 160 + + Bilgi + + + Documentation + + src/app/components/app-frame/app-frame.component.html + 167 + + Dökümantasyon + + + GitHub + + src/app/components/app-frame/app-frame.component.html + 175 + + Github + + + Suggest an idea + + src/app/components/app-frame/app-frame.component.html + 181 + + Bir fikir öner + + + Cancel + + src/app/components/common/confirm-dialog/confirm-dialog.component.html + 11 + + + src/app/components/common/select-dialog/select-dialog.component.html + 12 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 6 + + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 13 + + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 14 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 16 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 18 + + Vazgeç + + + Confirmation + + src/app/components/common/confirm-dialog/confirm-dialog.component.ts + 18 + + Onayla + + + Confirm + + src/app/components/common/confirm-dialog/confirm-dialog.component.ts + 30 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 143 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 166 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 189 + + Onayla + + + After + + src/app/components/common/date-dropdown/date-dropdown.component.html + 13 + + Sonrası + + + Clear + + src/app/components/common/date-dropdown/date-dropdown.component.html + 18 + + + src/app/components/common/date-dropdown/date-dropdown.component.html + 41 + + Temizle + + + Before + + src/app/components/common/date-dropdown/date-dropdown.component.html + 36 + + Öncesinde + + + Last 7 days + + src/app/components/common/date-dropdown/date-dropdown.component.ts + 34 + + Son 7 gün + + + Last month + + src/app/components/common/date-dropdown/date-dropdown.component.ts + 35 + + Geçen ay + + + Last 3 months + + src/app/components/common/date-dropdown/date-dropdown.component.ts + 36 + + Son 3 ay + + + Last year + + src/app/components/common/date-dropdown/date-dropdown.component.ts + 37 + + Geçen yıl + + + Create new item + + src/app/components/common/edit-dialog/edit-dialog.component.ts + 50 + + Yeni Öğe OluÅŸtur + + + Edit item + + src/app/components/common/edit-dialog/edit-dialog.component.ts + 54 + + Öğeyi Düzenle + + + Could not save element: + + src/app/components/common/edit-dialog/edit-dialog.component.ts + 58 + + olan öğeyi kayıt edemiyorum + + + Apply + + src/app/components/common/filterable-dropdown/filterable-dropdown.component.html + 39 + + Uygula + + + Click again to exclude items. + + src/app/components/common/filterable-dropdown/filterable-dropdown.component.html + 45 + + Öğeleri hariç tutmak için yeniden tıklatın. + + + Not assigned + + src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts + 209 + + Filter drop down element to filter for documents with no correspondent/type/tag assigned + Atanmadı + + + Invalid date. + + src/app/components/common/input/date/date.component.html + 12 + + Geçersiz tarih. + + + Add item + + src/app/components/common/input/select/select.component.html + 11 + + Used for both types and correspondents + Öge ekle + + + Suggestions: + + src/app/components/common/input/select/select.component.html + 29 + + + src/app/components/common/input/tags/tags.component.html + 42 + + Öneriler: + + + Add tag + + src/app/components/common/input/tags/tags.component.html + 11 + + Etiket ekle + + + Select + + src/app/components/common/select-dialog/select-dialog.component.html + 13 + + + src/app/components/common/select-dialog/select-dialog.component.ts + 18 + + + src/app/components/document-list/document-list.component.html + 7 + + Seç + + + Please select an object + + src/app/components/common/select-dialog/select-dialog.component.ts + 21 + + Lütfen bir öğe seçin + + + Hello , welcome to Paperless-ngx! + + src/app/components/dashboard/dashboard.component.ts + 33 + + merhaba, Paperless-ngx'e hoÅŸgeldiniz! + + + Welcome to Paperless-ngx! + + src/app/components/dashboard/dashboard.component.ts + 35 + + Paperless-ngx'e hoÅŸgeldiniz! + + + Show all + + src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html + 3 + + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 27 + + Tümünü göster + + + Created + + src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html + 9 + + + src/app/components/document-list/document-list.component.html + 141 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 41 + + + src/app/services/rest/document.service.ts + 21 + + OluÅŸturuldu + + + Title + + src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html + 10 + + + src/app/components/document-detail/document-detail.component.html + 55 + + + src/app/components/document-list/document-list.component.html + 129 + + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 88 + + + src/app/services/rest/document.service.ts + 19 + + BaÅŸlık + + + Statistics + + src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html + 1 + + Ä°statistikler + + + Documents in inbox: + + src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html + 3 + + Gelen kutusundaki belgeler: + + + Total documents: + + src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html + 4 + + Toplam belgeler: + + + Upload new documents + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 1 + + Yeni belge yükle + + + Dismiss completed + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 4 + + This button dismisses all status messages about processed documents on the dashboard (failed and successful) + BitmiÅŸ olanları gizle + + + Drop documents here or + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 13 + + Belgeleri buraya bırak + + + Browse files + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 13 + + Dosyalara göz atın + + + {VAR_PLURAL, plural, =1 {One more document} other { more documents}} + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 25 + + This is shown as a summary line when there are more than 5 document in the processing pipeline. + {VAR_PLURAL, plural, =1 {Bir belge daha} other { daha fazla belgel}} + + + Processing: + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 32 + + IÅŸleniyor: + + + Failed: + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 35 + + BaÅŸarısız: + + + Added: + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 38 + + Eklenen: + + + , + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 40 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 117 + + this string is used to separate processing, failed and added on the file upload widget + , + + + Connecting... + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 118 + + BaÄŸlaniyor... + + + Uploading... + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 123 + + Yükleniyor... + + + Upload complete, waiting... + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 126 + + Yükleme tamamlanmıştır, bekliyor... + + + HTTP error: + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 136 + + HTTP hatası: + + + First steps + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 1 + + Ä°lk adımlar + + + Paperless is running! :) + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 5 + + Paperless çalışıyor! :) + + + You can start uploading documents by dropping them in the file upload box to the right or by dropping them in the configured consumption folder and they'll start showing up in the documents list. After you've added some metadata to your documents, use the filtering mechanisms of paperless to create custom views (such as 'Recently added', 'Tagged TODO') and they will appear on the dashboard instead of this message. + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 6,7 + + Belgeleri, saÄŸada bulunan dosya karşıya yükleme kutusuna bırakarak veya yapılandırılmış tüketim klasörüne bırakarak karşıya yüklemeye baÅŸlayabilirsiniz ve böylece belgeler listesinde görünmeye baÅŸlarlar. Belgelerinize bazı meta veriler ekledikten sonra, özel görünümler oluÅŸturmak için paperless filtreleme mekanizmalarını kullanın ('Son eklenen', 'YAPILACAKLAR olarak etiketli' gibi) ve bunlar bu ileti yerine kontrol panosunda görünür. + + + Paperless offers some more features that try to make your life easier: + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 8 + + Paperless, hayatınızı kolaylaÅŸtırmaya çalışan bazı özellikler daha sunar: + + + Once you've got a couple documents in paperless and added metadata to them, paperless can assign that metadata to new documents automatically. + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 10 + + Paperless'e birkaç belge ve sonra bunlara da meta veriler ekledikten sonra, paperless bu meta verileri otomatik olarak yeni belgelere atayabilir. + + + You can configure paperless to read your mails and add documents from attached files. + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 11 + + Paperless'i e-postalarınızı okuması için ve ekli dosyalardan belge ekleyecek ÅŸekilde yapılandırabilirsiniz. + + + Consult the documentation on how to use these features. The section on basic usage also has some information on how to use paperless in general. + + src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html + 13 + + Bu özelliklerin nasıl kullanılacağına iliÅŸkin dökümentasyona bakın. Temel kullanım bölümünde, paperless'in genel kullanımın hakkında da ayrıntılı bilgiler vardır. + + + Searching document with asn + + src/app/components/document-asn/document-asn.component.html + 1 + + Belgeyi asn ile arama + + + Page + + src/app/components/document-detail/document-detail.component.html + 3 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 15 + + Sayfa + + + of + + src/app/components/document-detail/document-detail.component.html + 5 + + / + + + Delete + + src/app/components/document-detail/document-detail.component.html + 11 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 76 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 48 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 46 + + + src/app/components/manage/generic-list/generic-list.component.ts + 106 + + + src/app/components/manage/settings/settings.component.html + 159 + + + src/app/components/manage/tag-list/tag-list.component.html + 49 + + Sil + + + Download + + src/app/components/document-detail/document-detail.component.html + 19 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 63 + + + src/app/components/document-list/document-card-large/document-card-large.component.html + 60 + + + src/app/components/document-list/document-card-small/document-card-small.component.html + 82 + + Ä°ndir + + + Download original + + src/app/components/document-detail/document-detail.component.html + 25 + + Orijinal Dosyayı Ä°ndir + + + More like this + + src/app/components/document-detail/document-detail.component.html + 34 + + + src/app/components/document-list/document-card-large/document-card-large.component.html + 38 + + Buna benzer daha + + + Close + + src/app/components/document-detail/document-detail.component.html + 40 + + Kapat + + + Details + + src/app/components/document-detail/document-detail.component.html + 52 + + Ayrıntılar + + + Archive serial number + + src/app/components/document-detail/document-detail.component.html + 56 + + ArÅŸiv seri numarası + + + Date created + + src/app/components/document-detail/document-detail.component.html + 57 + + OluÅŸturma tarihi + + + Correspondent + + src/app/components/document-detail/document-detail.component.html + 58 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 38 + + + src/app/components/document-list/document-list.component.html + 123 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 26 + + + src/app/services/rest/document.service.ts + 18 + + Muhabir + + + Document type + + src/app/components/document-detail/document-detail.component.html + 60 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 47 + + + src/app/components/document-list/document-list.component.html + 135 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 33 + + + src/app/services/rest/document.service.ts + 20 + + Belge türü + + + Content + + src/app/components/document-detail/document-detail.component.html + 68 + + Içerik + + + Metadata + + src/app/components/document-detail/document-detail.component.html + 77 + + + src/app/components/document-detail/metadata-collapse/metadata-collapse.component.ts + 18 + + Metaveri + + + Date modified + + src/app/components/document-detail/document-detail.component.html + 83 + + DeÄŸiÅŸtirilme tarihi + + + Date added + + src/app/components/document-detail/document-detail.component.html + 87 + + Ekleme tarihi + + + Media filename + + src/app/components/document-detail/document-detail.component.html + 91 + + Medya dosya ismi + + + Original MD5 checksum + + src/app/components/document-detail/document-detail.component.html + 95 + + Orijinal MD5 saÄŸlama toplamı + + + Original file size + + src/app/components/document-detail/document-detail.component.html + 99 + + Orijinal dosya boyutu + + + Original mime type + + src/app/components/document-detail/document-detail.component.html + 103 + + Orijinal mime türü + + + Archive MD5 checksum + + src/app/components/document-detail/document-detail.component.html + 107 + + ArÅŸiv MD5 saÄŸlama toplamı + + + Archive file size + + src/app/components/document-detail/document-detail.component.html + 111 + + ArÅŸiv dosya boyutu + + + Original document metadata + + src/app/components/document-detail/document-detail.component.html + 117 + + Orijinal belge meta verisi + + + Archived document metadata + + src/app/components/document-detail/document-detail.component.html + 118 + + ArÅŸivlenen belge meta verileri + + + Discard + + src/app/components/document-detail/document-detail.component.html + 143 + + Gözardı et + + + Save & next + + src/app/components/document-detail/document-detail.component.html + 144 + + Kaydet & sonraki + + + Save + + src/app/components/document-detail/document-detail.component.html + 145 + + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 14 + + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 15 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 17 + + + src/app/components/manage/settings/settings.component.html + 173 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 19 + + Kaydet + + + Confirm delete + + src/app/components/document-detail/document-detail.component.ts + 267 + + + src/app/components/manage/generic-list/generic-list.component.ts + 102 + + Silmeyi onayla + + + Do you really want to delete document ""? + + src/app/components/document-detail/document-detail.component.ts + 268 + + "" olan belgeyi gerçekten silmek istiyormusunuz? + + + The files for this document will be deleted permanently. This operation cannot be undone. + + src/app/components/document-detail/document-detail.component.ts + 269 + + Bu belgeye ait dosyalar kalıcı olarak siliniecektir. Bu iÅŸlem geri alınamaz. + + + Delete document + + src/app/components/document-detail/document-detail.component.ts + 271 + + Belgeyi sil + + + Error deleting document: + + src/app/components/document-detail/document-detail.component.ts + 281 + + belgeyi silerken hata + + + Select: + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 10 + + Seç: + + + All + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 20 + + Tümü + + + Edit: + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 27 + + Düzenle: + + + Filter tags + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 29 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 19 + + Etiketlere göre filtrele + + + Filter correspondents + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 39 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 27 + + Muhabire göre filtrele + + + Filter document types + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 48 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 34 + + Belge türlerini göre filtrele + + + Download originals + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 68 + + Orijinaleri indir + + + Error executing bulk operation: + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 74 + + yığın iÅŸlem sırasında hata + + + "" + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 113 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 117 + + "" + + + "" and "" + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 115 + + This is for messages like 'modify "tag1" and "tag2"' + "" ve "" + + + and "" + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 118 + + this is for messages like 'modify "tag1", "tag2" and "tag3"' + ve "" + + + Confirm tags assignment + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 127 + + Etiket atanmayi doÄŸrulayın + + + This operation will add the tag "" to selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 130 + + Bu iÅŸlem "" etiketini seçili belge(ye/lere) ekliyecektir. + + + This operation will add the tags to selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 132 + + Bu iÅŸlem "" etiketlerini seçili belge(ye/lere) ekliyecektir. + + + This operation will remove the tag "" from selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 135 + + Bu iÅŸlem "" etiketini seçili belge(den/lerden) kaldıracaktır. + + + This operation will remove the tags from selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 137 + + Bu iÅŸlem "" etiketlerini seçili belge(den/lerden) kaldıracaktır. + + + This operation will add the tags and remove the tags on selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 139 + + Bu iÅŸlem olan secili belge(ye/lere) etiketlerini ekliyecektir ve olan etiketlerini çıkartacaktır. + + + Confirm correspondent assignment + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 159 + + Muhabir atanmayı onaylayın + + + This operation will assign the correspondent "" to selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 161 + + Bu iÅŸlem "" muhabirini seçili belge(ye/lere) atıyacaktır. + + + This operation will remove the correspondent from selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 163 + + Bu iÅŸlem, muhabiri "" seçili belge(den/lerden) kaldıracaktır. + + + Confirm document type assignment + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 182 + + Belge türü atanmayı onaylayın + + + This operation will assign the document type "" to selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 184 + + Bu iÅŸlem "" belge türünü seçili belge(ye/lere) atıyacaktır. + + + This operation will remove the document type from selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 186 + + Bu iÅŸlem, belge türünü "" seçili belge(den/lerden) kaldıracaktır. + + + Delete confirm + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 201 + + Silmeyi onaylayın + + + This operation will permanently delete selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 202 + + Bu iÅŸlem, "" seçili belge(leri) kalıcı olarak silecektir. + + + This operation cannot be undone. + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 203 + + Bu iÅŸlem geri alınamaz. + + + Delete document(s) + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 205 + + Belge(yi/leri) sil + + + Filter by correspondent + + src/app/components/document-list/document-card-large/document-card-large.component.html + 20 + + + src/app/components/document-list/document-card-small/document-card-small.component.html + 26 + + Muhabire göre filtrele + + + Filter by tag + + src/app/components/document-list/document-card-large/document-card-large.component.html + 24 + + + src/app/components/document-list/document-card-small/document-card-small.component.html + 15 + + Etikete göre filtrele + + + Edit + + src/app/components/document-list/document-card-large/document-card-large.component.html + 43 + + + src/app/components/document-list/document-card-small/document-card-small.component.html + 66 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 42 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 40 + + + src/app/components/manage/tag-list/tag-list.component.html + 43 + + Düzenle + + + View + + src/app/components/document-list/document-card-large/document-card-large.component.html + 51 + + Görüntüle + + + Score: + + src/app/components/document-list/document-card-large/document-card-large.component.html + 87 + + Puan: + + + Created: + + src/app/components/document-list/document-card-small/document-card-small.component.html + 43 + + OluÅŸturulan: + + + Added: + + src/app/components/document-list/document-card-small/document-card-small.component.html + 44 + + Eklenen: + + + Modified: + + src/app/components/document-list/document-card-small/document-card-small.component.html + 45 + + DeÄŸiÅŸtirilen: + + + Select none + + src/app/components/document-list/document-list.component.html + 10 + + Seçimi kaldır + + + Select page + + src/app/components/document-list/document-list.component.html + 11 + + Sayfayı seç + + + Select all + + src/app/components/document-list/document-list.component.html + 12 + + Tümünü seç + + + Sort + + src/app/components/document-list/document-list.component.html + 39 + + Sırala + + + Views + + src/app/components/document-list/document-list.component.html + 64 + + Görünümler + + + Save "" + + src/app/components/document-list/document-list.component.html + 71 + + Kayıt et + + + Save as... + + src/app/components/document-list/document-list.component.html + 72 + + Farklı kaydet... + + + Loading... + + src/app/components/document-list/document-list.component.html + 87 + + Yükleniyor... + + + {VAR_PLURAL, plural, =1 {Selected of one document} other {Selected of documents}} + + src/app/components/document-list/document-list.component.html + 89 + + {VAR_PLURAL, plural, =1 {Seçili bir belgeden} other {Seçili , belgeden}} + + + {VAR_PLURAL, plural, =1 {One document} other { documents}} + + src/app/components/document-list/document-list.component.html + 91 + + {VAR_PLURAL, plural, =1 {Bir belge} other { belgeler}} + + + (filtered) + + src/app/components/document-list/document-list.component.html + 91 + + (filtrelenmiÅŸ) + + + ASN + + src/app/components/document-list/document-list.component.html + 117 + + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 90 + + + src/app/services/rest/document.service.ts + 17 + + ASN + + + Added + + src/app/components/document-list/document-list.component.html + 147 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 48 + + + src/app/services/rest/document.service.ts + 22 + + Eklendi + + + View "" saved successfully. + + src/app/components/document-list/document-list.component.ts + 116 + + "" adlı görünüm baÅŸarı ile kayıt edildi. + + + View "" created successfully. + + src/app/components/document-list/document-list.component.ts + 138 + + adlı görünüm baÅŸarı ile oluÅŸturuldu. + + + Reset filters + + src/app/components/document-list/filter-editor/filter-editor.component.html + 57 + + Filtreleri sıfırla + + + Correspondent: + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 37 + + Muhabir: + + + Without correspondent + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 39 + + Muhabiri olmayan + + + Type: + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 44 + + Tür: + + + Without document type + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 46 + + Belge türü olmayan + + + Tag: + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 50 + + Etiket: + + + Without any tag + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 54 + + Herhangi bir etiket olmayan + + + Title: + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 58 + + BaÅŸlık: + + + ASN: + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 61 + + ASN: + + + Title & content + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 89 + + BaÅŸlık & İçerik + + + Advanced search + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 91 + + GeliÅŸmiÅŸ arama + + + More like + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 94 + + Benzeri gibi + + + Save current view + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 3 + + Geçerli görünümü kaydet + + + Name + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 8 + + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 8 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 9 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 19 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 9 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 9 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 19 + + + src/app/components/manage/settings/settings.component.html + 141 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 8 + + + src/app/components/manage/tag-list/tag-list.component.html + 9 + + + src/app/components/manage/tag-list/tag-list.component.html + 19 + + Ä°sim + + + Show in sidebar + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 9 + + + src/app/components/manage/settings/settings.component.html + 153 + + Kenar çubuÄŸunda göster + + + Show on dashboard + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 10 + + + src/app/components/manage/settings/settings.component.html + 149 + + Kontrol paneli'nde göster + + + Matching algorithm + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 9 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 10 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 13 + + EÅŸleÅŸtirme algoritması + + + Matching pattern + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 10 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 11 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 14 + + EÅŸleÅŸme düzeni + + + Case insensitive + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 11 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 12 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 15 + + Büyük / küçük harf duyarsız + + + Create new correspondent + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.ts + 21 + + Yeni bir muhabir oluÅŸturun + + + Edit correspondent + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.ts + 25 + + Muhabiri düzenleyin + + + Create + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 2 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 2 + + + src/app/components/manage/tag-list/tag-list.component.html + 2 + + OluÅŸtur + + + Filter by: + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 8 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 8 + + + src/app/components/manage/tag-list/tag-list.component.html + 8 + + Filtreleme kriteri: + + + Matching + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 20 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 20 + + + src/app/components/manage/tag-list/tag-list.component.html + 21 + + EÅŸleÅŸtirme + + + Document count + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 21 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 21 + + + src/app/components/manage/tag-list/tag-list.component.html + 22 + + Belge sayısı + + + Last correspondence + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 22 + + Son yazışma + + + Actions + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 23 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 22 + + + src/app/components/manage/settings/settings.component.html + 158 + + + src/app/components/manage/tag-list/tag-list.component.html + 23 + + Eylemler + + + Do you really want to delete the correspondent ""? + + src/app/components/manage/correspondent-list/correspondent-list.component.ts + 26 + + "" muhabirini gerçekten silmek istiyor musunuz? + + + Create new document type + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.ts + 21 + + Yeni belge türü oluÅŸtur + + + Edit document type + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.ts + 25 + + Belge türünü düzenle + + + Do you really want to delete the document type ""? + + src/app/components/manage/document-type-list/document-type-list.component.ts + 26 + + "" belge türünü gerçekten silmek istiyor musunuz? + + + Automatic + + src/app/components/manage/generic-list/generic-list.component.ts + 39 + + + src/app/data/matching-model.ts + 17 + + Otomatik + + + Do you really want to delete this element? + + src/app/components/manage/generic-list/generic-list.component.ts + 97 + + Bu öğeyi gerçekten silmek istiyor musunuz? + + + Associated documents will not be deleted. + + src/app/components/manage/generic-list/generic-list.component.ts + 104 + + Ä°liÅŸkilendirilmiÅŸ belgeler silinmeyecektir. + + + Error while deleting element: + + src/app/components/manage/generic-list/generic-list.component.ts + 114 + + öge silerken hata oluÅŸtu + + + General settings + + src/app/components/manage/settings/settings.component.html + 10 + + Genel ayarlar + + + Appearance + + src/app/components/manage/settings/settings.component.html + 13 + + Görünüm + + + Display language + + src/app/components/manage/settings/settings.component.html + 17 + + Uygulama dili + + + You need to reload the page after applying a new language. + + src/app/components/manage/settings/settings.component.html + 25 + + Yeni bir dil uyguladıktan sonra sayfayı yeniden yüklemeniz gerekir. + + + Date display + + src/app/components/manage/settings/settings.component.html + 32 + + Tarih Gösterimi + + + Date format + + src/app/components/manage/settings/settings.component.html + 45 + + Tarih formatı + + + Short: + + src/app/components/manage/settings/settings.component.html + 51 + + Kısa: + + + Medium: + + src/app/components/manage/settings/settings.component.html + 55 + + Orta: + + + Long: + + src/app/components/manage/settings/settings.component.html + 59 + + Uzun: + + + Items per page + + src/app/components/manage/settings/settings.component.html + 67 + + Sayfa başına öğe + + + Document editor + + src/app/components/manage/settings/settings.component.html + 83 + + Belge düzenleyici + + + Use PDF viewer provided by the browser + + src/app/components/manage/settings/settings.component.html + 87 + + Tarayıcı tarafından saÄŸlanan PDF görüntüleyiciyi kullan + + + This is usually faster for displaying large PDF documents, but it might not work on some browsers. + + src/app/components/manage/settings/settings.component.html + 87 + + Bu genellikle büyük PDF belgelerini görüntülemek için daha hızlıdır, ancak bazı tarayıcılarda çalışmayabilir. + + + Dark mode + + src/app/components/manage/settings/settings.component.html + 94 + + Karanlık modu + + + Use system settings + + src/app/components/manage/settings/settings.component.html + 97 + + Sistem ayarlarını kullan + + + Enable dark mode + + src/app/components/manage/settings/settings.component.html + 98 + + Karanlık modu etkinleÅŸtir + + + Invert thumbnails in dark mode + + src/app/components/manage/settings/settings.component.html + 99 + + Karanlık modunda küçük resimleri tersine çevir + + + Bulk editing + + src/app/components/manage/settings/settings.component.html + 103 + + Toplu düzenlemec + + + Show confirmation dialogs + + src/app/components/manage/settings/settings.component.html + 107 + + Onaylama iletiÅŸim kutuları göster + + + Deleting documents will always ask for confirmation. + + src/app/components/manage/settings/settings.component.html + 107 + + Belgeleri silmek her zaman onay ister. + + + Apply on close + + src/app/components/manage/settings/settings.component.html + 108 + + Kapanışta uygula + + + Notifications + + src/app/components/manage/settings/settings.component.html + 116 + + Bildirimler + + + Document processing + + src/app/components/manage/settings/settings.component.html + 119 + + Belge iÅŸleme + + + Show notifications when new documents are detected + + src/app/components/manage/settings/settings.component.html + 123 + + Yeni belge bulunduÄŸunda bildirimi göster + + + Show notifications when document processing completes successfully + + src/app/components/manage/settings/settings.component.html + 124 + + Belge iÅŸleme baÅŸarıyla tamamlandığında bildirimleri göster + + + Show notifications when document processing fails + + src/app/components/manage/settings/settings.component.html + 125 + + Belge iÅŸleme baÅŸarız tamamlandığında bildirimleri göster + + + Suppress notifications on dashboard + + src/app/components/manage/settings/settings.component.html + 126 + + Kontrol panodaki bildirimleri bastır + + + This will suppress all messages about document processing status on the dashboard. + + src/app/components/manage/settings/settings.component.html + 126 + + Bu, kontrol panodaki belge iÅŸleme durumuyla ilgili tüm iletileri bastırır. + + + Appears on + + src/app/components/manage/settings/settings.component.html + 146 + + Görünür + + + No saved views defined. + + src/app/components/manage/settings/settings.component.html + 163 + + KaydedilmiÅŸ görünüm tanımlanmadı. + + + Saved view "" deleted. + + src/app/components/manage/settings/settings.component.ts + 111 + + adlı görünüm silindi. + + + Settings saved successfully. + + src/app/components/manage/settings/settings.component.ts + 133 + + Ayarlar baÅŸarıyla kaydedildi. + + + Use system language + + src/app/components/manage/settings/settings.component.ts + 138 + + Sistem dilini kullan + + + Use date format of display language + + src/app/components/manage/settings/settings.component.ts + 144 + + Görüntüleme dilinin tarih formatını kullan + + + Error while storing settings on server: + + src/app/components/manage/settings/settings.component.ts + 161 + + Ayarları servere kayıt edilirken hata oluÅŸtu: + + + Color + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 10 + + + src/app/components/manage/tag-list/tag-list.component.html + 20 + + Renk + + + Inbox tag + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 12 + + Gelen kutusu etiketi + + + Inbox tags are automatically assigned to all consumed documents. + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 12 + + Gelen kutusu etiketleri, otomatik olarak tüketilen bütin belgelere atanmaktadır. + + + Create new tag + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.ts + 22 + + Yeni etiket oluÅŸtur + + + Edit tag + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.ts + 26 + + Etiketi düzenle + + + Do you really want to delete the tag ""? + + src/app/components/manage/tag-list/tag-list.component.ts + 26 + + "" olan etiketi gerçekten silmek istiyormusunuz? + + + 404 Not Found + + src/app/components/not-found/not-found.component.html + 7 + + 404 Sayfa Bulunamadı + + + Any word + + src/app/data/matching-model.ts + 12 + + Herhangi bir kelime + + + Any: Document contains any of these words (space separated) + + src/app/data/matching-model.ts + 12 + + Herhangi biri: Belge bu sözcüklerden herhangi birini içerir (boÅŸlukla ayrılmış olarak) + + + All words + + src/app/data/matching-model.ts + 13 + + Tüm Kelimeler + + + All: Document contains all of these words (space separated) + + src/app/data/matching-model.ts + 13 + + Tümü: Belge bu sözcüklerin tümünü içerir (boÅŸlukla ayrılmış olarak) + + + Exact match + + src/app/data/matching-model.ts + 14 + + Tam eÅŸleÅŸme + + + Exact: Document contains this string + + src/app/data/matching-model.ts + 14 + + Tam: Belge bu ifadeyi içerir + + + Regular expression + + src/app/data/matching-model.ts + 15 + + Düzenli ifade + + + Regular expression: Document matches this regular expression + + src/app/data/matching-model.ts + 15 + + Düzenli ifade: Belge bu düzenli ifade ile eÅŸleÅŸir + + + Fuzzy word + + src/app/data/matching-model.ts + 16 + + Fuzzy Kelime + + + Fuzzy: Document contains a word similar to this word + + src/app/data/matching-model.ts + 16 + + Fuzzy: Belge bu kelimeye benzer bir ifade içerir + + + Auto: Learn matching automatically + + src/app/data/matching-model.ts + 17 + + Otomatik mod: EÅŸleÅŸmeyi otomatik olarak öğrenir + + + Unsaved Changes + + src/app/guards/dirty-form.guard.ts + 16 + + + src/app/services/open-documents.service.ts + 75 + + + src/app/services/open-documents.service.ts + 96 + + KaydedilmemiÅŸ deÄŸiÅŸiklikler + + + You have unsaved changes. + + src/app/guards/dirty-form.guard.ts + 17 + + + src/app/services/open-documents.service.ts + 76 + + + src/app/services/open-documents.service.ts + 97 + + KaydedilmemiÅŸ deÄŸiÅŸiklikleriniz var. + + + Are you sure you want to leave? + + src/app/guards/dirty-form.guard.ts + 18 + + Ayrılmak istediÄŸinizden emin misiniz? + + + Leave page + + src/app/guards/dirty-form.guard.ts + 20 + + Sayfadan ayrıl + + + (no title) + + src/app/pipes/document-title.pipe.ts + 12 + + (baÅŸlıksız) + + + Yes + + src/app/pipes/yes-no.pipe.ts + 9 + + Evet + + + No + + src/app/pipes/yes-no.pipe.ts + 9 + + Hayır + + + Document already exists. + + src/app/services/consumer-status.service.ts + 15 + + Belge zaten var. + + + File not found. + + src/app/services/consumer-status.service.ts + 16 + + Dosya bulunamadı. + + + Pre-consume script does not exist. + + src/app/services/consumer-status.service.ts + 17 + + Pre-Consume is a term that appears like that in the documentation as well and does not need a specific translation + Tüketim öncesi komut dosyası yok. + + + Error while executing pre-consume script. + + src/app/services/consumer-status.service.ts + 18 + + Pre-Consume is a term that appears like that in the documentation as well and does not need a specific translation + Tüketim öncesi komut dosyasını iÅŸlerken hata oluÅŸtu. + + + Post-consume script does not exist. + + src/app/services/consumer-status.service.ts + 19 + + Post-Consume is a term that appears like that in the documentation as well and does not need a specific translation + Tüketim sonrası komut dosyası yok. + + + Error while executing post-consume script. + + src/app/services/consumer-status.service.ts + 20 + + Post-Consume is a term that appears like that in the documentation as well and does not need a specific translation + Tüketim sonrası komut dosyasını iÅŸlerken hata oluÅŸtu. + + + Received new file. + + src/app/services/consumer-status.service.ts + 21 + + Yeni dosya alındı. + + + File type not supported. + + src/app/services/consumer-status.service.ts + 22 + + Dosya türü desteklenmiyor. + + + Processing document... + + src/app/services/consumer-status.service.ts + 23 + + Belge iÅŸleniyor... + + + Generating thumbnail... + + src/app/services/consumer-status.service.ts + 24 + + Küçük resimler oluÅŸturuluyor... + + + Retrieving date from document... + + src/app/services/consumer-status.service.ts + 25 + + Belgeden tarih alınıyor... + + + Saving document... + + src/app/services/consumer-status.service.ts + 26 + + Belge kayıt ediliyor... + + + Finished. + + src/app/services/consumer-status.service.ts + 27 + + Tamamlandı. + + + Are you sure you want to close this document? + + src/app/services/open-documents.service.ts + 77 + + Bu belgeyi kapatmak istediÄŸinizden emin misin? + + + Close document + + src/app/services/open-documents.service.ts + 79 + + Belgeyi kapat + + + Are you sure you want to close all documents? + + src/app/services/open-documents.service.ts + 98 + + Tüm belgeleri kapatmak istediÄŸinizden emin misiniz? + + + Close documents + + src/app/services/open-documents.service.ts + 100 + + Belgeleri kapat + + + Modified + + src/app/services/rest/document.service.ts + 23 + + DeÄŸiÅŸtirilmiÅŸ + + + Search score + + src/app/services/rest/document.service.ts + 28 + + Score is a value returned by the full text search engine and specifies how well a result matches the given query + Puanı ara + + + English (US) + + src/app/services/settings.service.ts + 90 + + Ä°ngilizce (BirleÅŸik Devletler) + + + Czech + + src/app/services/settings.service.ts + 91 + + Çekçe + + + Danish + + src/app/services/settings.service.ts + 92 + + Danca + + + German + + src/app/services/settings.service.ts + 93 + + Almanca + + + English (GB) + + src/app/services/settings.service.ts + 94 + + Ä°ngilizce (GB) + + + Spanish + + src/app/services/settings.service.ts + 95 + + Ä°spanyolca + + + French + + src/app/services/settings.service.ts + 96 + + Fransızca + + + Italian + + src/app/services/settings.service.ts + 97 + + Ä°talyanca + + + Luxembourgish + + src/app/services/settings.service.ts + 98 + + Lüksemburgca + + + Dutch + + src/app/services/settings.service.ts + 99 + + Hollandaca + + + Polish + + src/app/services/settings.service.ts + 100 + + Polonyaca + + + Portuguese (Brazil) + + src/app/services/settings.service.ts + 101 + + Portekizce (Brezilya) + + + Portuguese + + src/app/services/settings.service.ts + 102 + + Portekizce + + + Romanian + + src/app/services/settings.service.ts + 103 + + Romence + + + Russian + + src/app/services/settings.service.ts + 104 + + Rusça + + + Swedish + + src/app/services/settings.service.ts + 105 + + Ä°sveççe + + + ISO 8601 + + src/app/services/settings.service.ts + 115 + + ISO 8601 + + + Error + + src/app/services/toast.service.ts + 35 + + Hata + + + Information + + src/app/services/toast.service.ts + 39 + + Bilgi + + + + diff --git a/src-ui/src/locale/messages.zh_CN.xlf b/src-ui/src/locale/messages.zh_CN.xlf index 3d6883a27..8c60f4e0a 100644 --- a/src-ui/src/locale/messages.zh_CN.xlf +++ b/src-ui/src/locale/messages.zh_CN.xlf @@ -8,7 +8,7 @@ src/app/app.component.ts 51 - Document added + 文档已添加 Document was added to paperless. @@ -16,7 +16,7 @@ src/app/app.component.ts 51 - Document was added to paperless. + 文档 已添加到 paperless-ngx。 Open document @@ -24,7 +24,11 @@ src/app/app.component.ts 51 - Open document + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 45 + + 打开文档 Could not add : @@ -32,7 +36,7 @@ src/app/app.component.ts 59 - Could not add : + 无法添加 : New document detected @@ -40,7 +44,7 @@ src/app/app.component.ts 65 - New document detected + 检测到新文档 Document is being processed by paperless. @@ -48,1072 +52,24 @@ src/app/app.component.ts 65 - Document is being processed by paperless. + 文档 正在被 paperless 处ç†ä¸­ã€‚ - - Documents - - src/app/components/document-list/document-list.component.ts - 51 - - Documents - - - View "" saved successfully. - - src/app/components/document-list/document-list.component.ts - 116 - - View "" saved successfully. - - - View "" created successfully. - - src/app/components/document-list/document-list.component.ts - 138 - - View "" created successfully. - - - Select - - src/app/components/document-list/document-list.component.html - 7 - - Select - - - Select none - - src/app/components/document-list/document-list.component.html - 10 - - Select none - - - Select page - - src/app/components/document-list/document-list.component.html - 11 - - Select page - - - Select all - - src/app/components/document-list/document-list.component.html - 12 - - Select all - - - Sort - - src/app/components/document-list/document-list.component.html - 39 - - Sort - - - Views - - src/app/components/document-list/document-list.component.html - 64 - - Views - - - Save as... - - src/app/components/document-list/document-list.component.html - 72 - - Save as... - - - Save "" - - src/app/components/document-list/document-list.component.html - 71 - - Save "" - - - {VAR_PLURAL, plural, =1 {Selected of one document} other {Selected of documents}} - - src/app/components/document-list/document-list.component.html - 85 - - {VAR_PLURAL, plural, =1 {Selected of one document} other {Selected of documents}} - - - {VAR_PLURAL, plural, =1 {One document} other { documents}} - - src/app/components/document-list/document-list.component.html - 86 - - {VAR_PLURAL, plural, =1 {One document} other { documents}} - - - (filtered) - - src/app/components/document-list/document-list.component.html - 86 - - (filtered) - - - ASN - - src/app/components/document-list/document-list.component.html - 111 - - ASN - - - Correspondent - - src/app/components/document-list/document-list.component.html - 117 - - Correspondent - - - Title - - src/app/components/document-list/document-list.component.html - 123 - - Title - - - Document type - - src/app/components/document-list/document-list.component.html - 129 - - Document type - - - Created - - src/app/components/document-list/document-list.component.html - 135 - - Created - - - Added - - src/app/components/document-list/document-list.component.html - 141 - - Added - - - Confirm delete - - src/app/components/document-detail/document-detail.component.ts - 206 - - Confirm delete - - - Do you really want to delete document ""? - - src/app/components/document-detail/document-detail.component.ts - 207 - - Do you really want to delete document ""? - - - The files for this document will be deleted permanently. This operation cannot be undone. - - src/app/components/document-detail/document-detail.component.ts - 208 - - The files for this document will be deleted permanently. This operation cannot be undone. - - - Delete document - - src/app/components/document-detail/document-detail.component.ts - 210 - - Delete document - - - Error deleting document: - - src/app/components/document-detail/document-detail.component.ts - 217 - - Error deleting document: - - - Delete - - src/app/components/document-detail/document-detail.component.html - 15 - - Delete - - - Download - - src/app/components/document-detail/document-detail.component.html - 23 - - Download - - - More like this - - src/app/components/document-detail/document-detail.component.html - 38 - - More like this - - - Close - - src/app/components/document-detail/document-detail.component.html - 44 - - Close - - - Details - - src/app/components/document-detail/document-detail.component.html - 56 - - Details - - - Content - - src/app/components/document-detail/document-detail.component.html - 72 - - Content - - - Metadata - - src/app/components/document-detail/document-detail.component.html - 81 - - Metadata - - - Discard - - src/app/components/document-detail/document-detail.component.html - 130 - - Discard - - - Save - - src/app/components/document-detail/document-detail.component.html - 132 - - Save - - - Page - - src/app/components/document-detail/document-detail.component.html - 4 - - Page - - - of - - src/app/components/document-detail/document-detail.component.html - 8 - - of - - - Download original - - src/app/components/document-detail/document-detail.component.html - 29 - - Download original - - - Archive serial number - - src/app/components/document-detail/document-detail.component.html - 60 - - Archive serial number - - - Date created - - src/app/components/document-detail/document-detail.component.html - 61 - - Date created - - - Date modified - - src/app/components/document-detail/document-detail.component.html - 87 - - Date modified - - - Date added - - src/app/components/document-detail/document-detail.component.html - 91 - - Date added - - - Media filename - - src/app/components/document-detail/document-detail.component.html - 95 - - Media filename - - - Original MD5 checksum - - src/app/components/document-detail/document-detail.component.html - 99 - - Original MD5 checksum - - - Original file size - - src/app/components/document-detail/document-detail.component.html - 103 - - Original file size - - - Original mime type - - src/app/components/document-detail/document-detail.component.html - 107 - - Original mime type - - - Archive MD5 checksum - - src/app/components/document-detail/document-detail.component.html - 111 - - Archive MD5 checksum - - - Archive file size - - src/app/components/document-detail/document-detail.component.html - 115 - - Archive file size - - - Original document metadata - - src/app/components/document-detail/document-detail.component.html - 121 - - Original document metadata - - - Archived document metadata - - src/app/components/document-detail/document-detail.component.html - 122 - - Archived document metadata - - - Save & next - - src/app/components/document-detail/document-detail.component.html - 131 - - Save & next - - - Hello , welcome to Paperless-ngx! - - src/app/components/dashboard/dashboard.component.ts - 33 - - Hello , welcome to Paperless-ngx! - - - Welcome to Paperless-ngx! - - src/app/components/dashboard/dashboard.component.ts - 35 - - Welcome to Paperless-ngx! - - - Dashboard - - src/app/components/dashboard/dashboard.component.html - 1 - - Dashboard - - - Do you really want to delete the tag ""? - - src/app/components/manage/tag-list/tag-list.component.ts - 26 - - Do you really want to delete the tag ""? - - - Tags - - src/app/components/manage/tag-list/tag-list.component.html - 1 - - Tags - - - Create - - src/app/components/manage/tag-list/tag-list.component.html - 2 - - Create - - - Filter by: - - src/app/components/manage/tag-list/tag-list.component.html - 8 - - Filter by: - - - Name - - src/app/components/manage/tag-list/tag-list.component.html - 9 - - Name - - - Color - - src/app/components/manage/tag-list/tag-list.component.html - 20 - - Color - - - Matching - - src/app/components/manage/tag-list/tag-list.component.html - 21 - - Matching - - - Document count - - src/app/components/manage/tag-list/tag-list.component.html - 22 - - Document count - - - Actions - - src/app/components/manage/tag-list/tag-list.component.html - 23 - - Actions - - - Documents - - src/app/components/manage/tag-list/tag-list.component.html - 38 - - Documents - - - Edit - - src/app/components/manage/tag-list/tag-list.component.html - 43 - - Edit - - - Do you really want to delete the document type ""? - - src/app/components/manage/document-type-list/document-type-list.component.ts - 26 - - Do you really want to delete the document type ""? - - - Document types - - src/app/components/manage/document-type-list/document-type-list.component.html - 1 - - Document types - - - Logs - - src/app/components/manage/logs/logs.component.html - 1 - - Logs - - - Saved view "" deleted. - - src/app/components/manage/settings/settings.component.ts - 68 - - Saved view "" deleted. - - - Settings saved successfully. - - src/app/components/manage/settings/settings.component.ts - 89 - - Settings saved successfully. - - - Use system language - - src/app/components/manage/settings/settings.component.ts - 94 - - Use system language - - - Use date format of display language - - src/app/components/manage/settings/settings.component.ts - 100 - - Use date format of display language - - - Error while storing settings on server: - - src/app/components/manage/settings/settings.component.ts - 117 - - Error while storing settings on server: - - - Settings - - src/app/components/manage/settings/settings.component.html - 1 - - Settings - - - General settings - - src/app/components/manage/settings/settings.component.html - 10 - - General settings - - - Notifications - - src/app/components/manage/settings/settings.component.html - 116 - - Notifications - - - Saved views - - src/app/components/manage/settings/settings.component.html - 134 - - Saved views - - - Appearance - - src/app/components/manage/settings/settings.component.html - 13 - - Appearance - - - Display language - - src/app/components/manage/settings/settings.component.html - 17 - - Display language - - - You need to reload the page after applying a new language. - - src/app/components/manage/settings/settings.component.html - 25 - - You need to reload the page after applying a new language. - - - Date display - - src/app/components/manage/settings/settings.component.html - 32 - - Date display - - - Date format - - src/app/components/manage/settings/settings.component.html - 45 - - Date format - - - Short: - - src/app/components/manage/settings/settings.component.html - 51 - - Short: - - - Medium: - - src/app/components/manage/settings/settings.component.html - 55 - - Medium: - - - Long: - - src/app/components/manage/settings/settings.component.html - 59 - - Long: - - - Items per page - - src/app/components/manage/settings/settings.component.html - 67 - - Items per page - - - Document editor - - src/app/components/manage/settings/settings.component.html - 83 - - Document editor - - - Use PDF viewer provided by the browser - - src/app/components/manage/settings/settings.component.html - 87 - - Use PDF viewer provided by the browser - - - This is usually faster for displaying large PDF documents, but it might not work on some browsers. - - src/app/components/manage/settings/settings.component.html - 87 - - This is usually faster for displaying large PDF documents, but it might not work on some browsers. - - - Dark mode - - src/app/components/manage/settings/settings.component.html - 94 - - Dark mode - - - Use system settings - - src/app/components/manage/settings/settings.component.html - 97 - - Use system settings - - - Enable dark mode - - src/app/components/manage/settings/settings.component.html - 98 - - Enable dark mode - - - Invert thumbnails in dark mode - - src/app/components/manage/settings/settings.component.html - 99 - - Invert thumbnails in dark mode - - - Bulk editing - - src/app/components/manage/settings/settings.component.html - 103 - - Bulk editing - - - Show confirmation dialogs - - src/app/components/manage/settings/settings.component.html - 107 - - Show confirmation dialogs - - - Deleting documents will always ask for confirmation. - - src/app/components/manage/settings/settings.component.html - 107 - - Deleting documents will always ask for confirmation. - - - Apply on close - - src/app/components/manage/settings/settings.component.html - 108 - - Apply on close - - - Document processing - - src/app/components/manage/settings/settings.component.html - 119 - - Document processing - - - Show notifications when new documents are detected - - src/app/components/manage/settings/settings.component.html - 123 - - Show notifications when new documents are detected - - - Show notifications when document processing completes successfully - - src/app/components/manage/settings/settings.component.html - 124 - - Show notifications when document processing completes successfully - - - Show notifications when document processing fails - - src/app/components/manage/settings/settings.component.html - 125 - - Show notifications when document processing fails - - - Suppress notifications on dashboard - - src/app/components/manage/settings/settings.component.html - 126 - - Suppress notifications on dashboard - - - This will suppress all messages about document processing status on the dashboard. - - src/app/components/manage/settings/settings.component.html - 126 - - This will suppress all messages about document processing status on the dashboard. - - - Appears on - - src/app/components/manage/settings/settings.component.html - 146 - - Appears on - - - Show on dashboard - - src/app/components/manage/settings/settings.component.html - 149 - - Show on dashboard - - - Show in sidebar - - src/app/components/manage/settings/settings.component.html - 153 - - Show in sidebar - - - No saved views defined. - - src/app/components/manage/settings/settings.component.html - 163 - - No saved views defined. - - - 404 Not Found - - src/app/components/not-found/not-found.component.html - 7 - - 404 Not Found - - - Do you really want to delete the correspondent ""? - - src/app/components/manage/correspondent-list/correspondent-list.component.ts - 26 - - Do you really want to delete the correspondent ""? - - - Correspondents - - src/app/components/manage/correspondent-list/correspondent-list.component.html - 1 - - Correspondents - - - Last correspondence - - src/app/components/manage/correspondent-list/correspondent-list.component.html - 22 - - Last correspondence - - - Confirmation - - src/app/components/common/confirm-dialog/confirm-dialog.component.ts - 17 - - Confirmation - - - Confirm - - src/app/components/common/confirm-dialog/confirm-dialog.component.ts - 29 - - Confirm - - - Cancel - - src/app/components/common/confirm-dialog/confirm-dialog.component.html - 12 - - Cancel - - - Create new correspondent - - src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.ts - 21 - - Create new correspondent - - - Edit correspondent - - src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.ts - 25 - - Edit correspondent - - - Matching algorithm - - src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html - 10 - - Matching algorithm - - - Matching pattern - - src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html - 11 - - Matching pattern - - - Case insensitive - - src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html - 12 - - Case insensitive - - - Create new tag - - src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.ts - 22 - - Create new tag - - - Edit tag - - src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.ts - 26 - - Edit tag - - - Inbox tag - - src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html - 13 - - Inbox tag - - - Inbox tags are automatically assigned to all consumed documents. - - src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html - 13 - - Inbox tags are automatically assigned to all consumed documents. - - - Create new document type - - src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.ts - 21 - - Create new document type - - - Edit document type - - src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.ts - 25 - - Edit document type - - + Paperless-ngx src/app/components/app-frame/app-frame.component.html 11 app title - Paperless-ngx + Paperless-ngx Search documents src/app/components/app-frame/app-frame.component.html - 15 + 18 - Search documents - - - Logout - - src/app/components/app-frame/app-frame.component.html - 45 - - Logout - - - Manage - - src/app/components/app-frame/app-frame.component.html - 112 - - Manage - - - Admin - - src/app/components/app-frame/app-frame.component.html - 154 - - Admin - - - Info - - src/app/components/app-frame/app-frame.component.html - 160 - - Info - - - Documentation - - src/app/components/app-frame/app-frame.component.html - 167 - - Documentation - - - GitHub - - src/app/components/app-frame/app-frame.component.html - 175 - - GitHub - - - Suggest an idea - - src/app/components/app-frame/app-frame.component.html - 181 - - Suggest an idea + æœç´¢æ–‡æ¡£ Logged in as @@ -1121,7 +77,79 @@ src/app/components/app-frame/app-frame.component.html 34 - Logged in as + 登录为 + + + Settings + + src/app/components/app-frame/app-frame.component.html + 40 + + + src/app/components/app-frame/app-frame.component.html + 147 + + + src/app/components/manage/settings/settings.component.html + 1 + + 设置 + + + Logout + + src/app/components/app-frame/app-frame.component.html + 45 + + 退出 + + + Dashboard + + src/app/components/app-frame/app-frame.component.html + 61 + + + src/app/components/dashboard/dashboard.component.html + 1 + + 仪表盘 + + + Documents + + src/app/components/app-frame/app-frame.component.html + 68 + + + src/app/components/document-list/document-list.component.ts + 51 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 37 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 35 + + + src/app/components/manage/tag-list/tag-list.component.html + 38 + + 文档 + + + Saved views + + src/app/components/app-frame/app-frame.component.html + 74 + + + src/app/components/manage/settings/settings.component.html + 134 + + ä¿å­˜è§†å›¾ Open documents @@ -1129,7 +157,7 @@ src/app/components/app-frame/app-frame.component.html 87 - Open documents + 打开文档 Close all @@ -1137,192 +165,175 @@ src/app/components/app-frame/app-frame.component.html 106 - Close all + 全部关闭 - - Correspondent: + + Manage - src/app/components/document-list/filter-editor/filter-editor.component.ts - 37 + src/app/components/app-frame/app-frame.component.html + 112 - Correspondent: + ç®¡ç† - - Without correspondent + + Correspondents - src/app/components/document-list/filter-editor/filter-editor.component.ts - 39 + src/app/components/app-frame/app-frame.component.html + 119 - Without correspondent - - - Type: - src/app/components/document-list/filter-editor/filter-editor.component.ts - 44 + src/app/components/manage/correspondent-list/correspondent-list.component.html + 1 - Type: + è”系人 - - Without document type + + Tags - src/app/components/document-list/filter-editor/filter-editor.component.ts - 46 + src/app/components/app-frame/app-frame.component.html + 126 - Without document type - - - Tag: - src/app/components/document-list/filter-editor/filter-editor.component.ts - 50 + src/app/components/common/input/tags/tags.component.html + 2 - Tag: - - - Without any tag - src/app/components/document-list/filter-editor/filter-editor.component.ts - 54 + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 28 - Without any tag - - - Title: - - src/app/components/document-list/filter-editor/filter-editor.component.ts - 58 - - Title: - - - ASN: - - src/app/components/document-list/filter-editor/filter-editor.component.ts - 61 - - ASN: - - - Title - - src/app/components/document-list/filter-editor/filter-editor.component.ts - 88 - - Title - - - Title & content - - src/app/components/document-list/filter-editor/filter-editor.component.ts - 89 - - Title & content - - - ASN - - src/app/components/document-list/filter-editor/filter-editor.component.ts - 90 - - ASN - - - Advanced search - - src/app/components/document-list/filter-editor/filter-editor.component.ts - 91 - - Advanced search - - - More like - - src/app/components/document-list/filter-editor/filter-editor.component.ts - 94 - - More like - - - Filter tags src/app/components/document-list/filter-editor/filter-editor.component.html - 19 + 18 - Filter tags - - - Filter correspondents - src/app/components/document-list/filter-editor/filter-editor.component.html - 27 + src/app/components/manage/tag-list/tag-list.component.html + 1 - Filter correspondents + 标签 - - Filter document types + + Document types - src/app/components/document-list/filter-editor/filter-editor.component.html - 34 + src/app/components/app-frame/app-frame.component.html + 133 - Filter document types - - - Reset filters - src/app/components/document-list/filter-editor/filter-editor.component.html - 57 + src/app/components/manage/document-type-list/document-type-list.component.html + 1 - Reset filters + 文档类型 - - Not assigned + + Logs - src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts + src/app/components/app-frame/app-frame.component.html + 140 + + + src/app/components/manage/logs/logs.component.html + 1 + + 日志 + + + Admin + + src/app/components/app-frame/app-frame.component.html + 154 + + åŽå°ç®¡ç† + + + Info + + src/app/components/app-frame/app-frame.component.html + 160 + + ä¿¡æ¯ + + + Documentation + + src/app/components/app-frame/app-frame.component.html + 167 + + 帮助文档 + + + GitHub + + src/app/components/app-frame/app-frame.component.html + 175 + + GitHub + + + Suggest an idea + + src/app/components/app-frame/app-frame.component.html + 181 + + æ出建议 + + + Cancel + + src/app/components/common/confirm-dialog/confirm-dialog.component.html + 11 + + + src/app/components/common/select-dialog/select-dialog.component.html + 12 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 6 + + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 13 + + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 14 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 16 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 18 + + å–消 + + + Confirmation + + src/app/components/common/confirm-dialog/confirm-dialog.component.ts + 18 + + 确认 + + + Confirm + + src/app/components/common/confirm-dialog/confirm-dialog.component.ts + 30 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 143 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts 166 - Filter drop down element to filter for documents with no correspondent/type/tag assigned - Not assigned - - - Apply - src/app/components/common/filterable-dropdown/filterable-dropdown.component.html - 26 + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 189 - Apply - - - Last 7 days - - src/app/components/common/date-dropdown/date-dropdown.component.ts - 34 - - Last 7 days - - - Last month - - src/app/components/common/date-dropdown/date-dropdown.component.ts - 35 - - Last month - - - Last 3 months - - src/app/components/common/date-dropdown/date-dropdown.component.ts - 36 - - Last 3 months - - - Last year - - src/app/components/common/date-dropdown/date-dropdown.component.ts - 37 - - Last year + 确认 After @@ -1330,15 +341,7 @@ src/app/components/common/date-dropdown/date-dropdown.component.html 13 - After - - - Before - - src/app/components/common/date-dropdown/date-dropdown.component.html - 38 - - Before + ä¹‹åŽ Clear @@ -1346,266 +349,108 @@ src/app/components/common/date-dropdown/date-dropdown.component.html 18 - Clear - - - View - src/app/components/document-list/document-card-large/document-card-large.component.html - 51 + src/app/components/common/date-dropdown/date-dropdown.component.html + 41 - View + 清除 - - Filter by correspondent + + Before - src/app/components/document-list/document-card-large/document-card-large.component.html - 20 + src/app/components/common/date-dropdown/date-dropdown.component.html + 36 - Filter by correspondent + ä¹‹å‰ - - Filter by tag + + Last 7 days - src/app/components/document-list/document-card-large/document-card-large.component.html - 24 + src/app/components/common/date-dropdown/date-dropdown.component.ts + 34 - Filter by tag + 过去7天 - - Score: + + Last month - src/app/components/document-list/document-card-large/document-card-large.component.html - 87 + src/app/components/common/date-dropdown/date-dropdown.component.ts + 35 - Score: + 上个月 - - Created: + + Last 3 months - src/app/components/document-list/document-card-small/document-card-small.component.html - 43 + src/app/components/common/date-dropdown/date-dropdown.component.ts + 36 - Created: + 过去3个月 - - Added: + + Last year - src/app/components/document-list/document-card-small/document-card-small.component.html - 44 + src/app/components/common/date-dropdown/date-dropdown.component.ts + 37 - Added: + 去年 - - Modified: + + Create new item - src/app/components/document-list/document-card-small/document-card-small.component.html + src/app/components/common/edit-dialog/edit-dialog.component.ts + 50 + + 创建新项目 + + + Edit item + + src/app/components/common/edit-dialog/edit-dialog.component.ts + 54 + + 编辑项目 + + + Could not save element: + + src/app/components/common/edit-dialog/edit-dialog.component.ts + 58 + + 无法ä¿å­˜å…ƒç´ : + + + Apply + + src/app/components/common/filterable-dropdown/filterable-dropdown.component.html + 39 + + 应用 + + + Click again to exclude items. + + src/app/components/common/filterable-dropdown/filterable-dropdown.component.html 45 - Modified: + å†æ¬¡å•å‡»ä»¥æŽ’除项目。 - - Error executing bulk operation: + + Not assigned - src/app/components/document-list/bulk-editor/bulk-editor.component.ts - 74 + src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts + 209 - Error executing bulk operation: + Filter drop down element to filter for documents with no correspondent/type/tag assigned + æœªåˆ†é… - - "" + + Invalid date. - src/app/components/document-list/bulk-editor/bulk-editor.component.ts - 113 + src/app/components/common/input/date/date.component.html + 12 - "" - - - "" and "" - - src/app/components/document-list/bulk-editor/bulk-editor.component.ts - 115 - - This is for messages like 'modify "tag1" and "tag2"' - "" and "" - - - , - - src/app/components/document-list/bulk-editor/bulk-editor.component.ts - 117 - - this is used to separate enumerations and should probably be a comma and a whitespace in most languages - , - - - and "" - - src/app/components/document-list/bulk-editor/bulk-editor.component.ts - 118 - - this is for messages like 'modify "tag1", "tag2" and "tag3"' - and "" - - - Confirm tags assignment - - src/app/components/document-list/bulk-editor/bulk-editor.component.ts - 127 - - Confirm tags assignment - - - This operation will add the tag "" to selected document(s). - - src/app/components/document-list/bulk-editor/bulk-editor.component.ts - 130 - - This operation will add the tag "" to selected document(s). - - - This operation will add the tags to selected document(s). - - src/app/components/document-list/bulk-editor/bulk-editor.component.ts - 132 - - This operation will add the tags to selected document(s). - - - This operation will remove the tag "" from selected document(s). - - src/app/components/document-list/bulk-editor/bulk-editor.component.ts - 135 - - This operation will remove the tag "" from selected document(s). - - - This operation will remove the tags from selected document(s). - - src/app/components/document-list/bulk-editor/bulk-editor.component.ts - 137 - - This operation will remove the tags from selected document(s). - - - This operation will add the tags and remove the tags on selected document(s). - - src/app/components/document-list/bulk-editor/bulk-editor.component.ts - 139 - - This operation will add the tags and remove the tags on selected document(s). - - - Confirm correspondent assignment - - src/app/components/document-list/bulk-editor/bulk-editor.component.ts - 159 - - Confirm correspondent assignment - - - This operation will assign the correspondent "" to selected document(s). - - src/app/components/document-list/bulk-editor/bulk-editor.component.ts - 161 - - This operation will assign the correspondent "" to selected document(s). - - - This operation will remove the correspondent from selected document(s). - - src/app/components/document-list/bulk-editor/bulk-editor.component.ts - 163 - - This operation will remove the correspondent from selected document(s). - - - Confirm document type assignment - - src/app/components/document-list/bulk-editor/bulk-editor.component.ts - 182 - - Confirm document type assignment - - - This operation will assign the document type "" to selected document(s). - - src/app/components/document-list/bulk-editor/bulk-editor.component.ts - 184 - - This operation will assign the document type "" to selected document(s). - - - This operation will remove the document type from selected document(s). - - src/app/components/document-list/bulk-editor/bulk-editor.component.ts - 186 - - This operation will remove the document type from selected document(s). - - - Delete confirm - - src/app/components/document-list/bulk-editor/bulk-editor.component.ts - 201 - - Delete confirm - - - This operation will permanently delete selected document(s). - - src/app/components/document-list/bulk-editor/bulk-editor.component.ts - 202 - - This operation will permanently delete selected document(s). - - - This operation cannot be undone. - - src/app/components/document-list/bulk-editor/bulk-editor.component.ts - 203 - - This operation cannot be undone. - - - Delete document(s) - - src/app/components/document-list/bulk-editor/bulk-editor.component.ts - 205 - - Delete document(s) - - - Select: - - src/app/components/document-list/bulk-editor/bulk-editor.component.html - 10 - - Select: - - - All - - src/app/components/document-list/bulk-editor/bulk-editor.component.html - 20 - - All - - - Edit: - - src/app/components/document-list/bulk-editor/bulk-editor.component.html - 27 - - Edit: - - - Download originals - - src/app/components/document-list/bulk-editor/bulk-editor.component.html - 68 - - Download originals + 无效的日期。 Add item @@ -1614,23 +459,19 @@ 11 Used for both types and correspondents - Add item + 添加项 Suggestions: src/app/components/common/input/select/select.component.html - 31 + 29 - Suggestions: - - - Save current view - src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html - 3 + src/app/components/common/input/tags/tags.component.html + 42 - Save current view + 建议: Add tag @@ -1638,7 +479,47 @@ src/app/components/common/input/tags/tags.component.html 11 - Add tag + 添加标签 + + + Select + + src/app/components/common/select-dialog/select-dialog.component.html + 13 + + + src/app/components/common/select-dialog/select-dialog.component.ts + 18 + + + src/app/components/document-list/document-list.component.html + 7 + + 选择 + + + Please select an object + + src/app/components/common/select-dialog/select-dialog.component.ts + 21 + + 请选择一个对象 + + + Hello , welcome to Paperless-ngx! + + src/app/components/dashboard/dashboard.component.ts + 33 + + 您好 ,欢迎使用 Paperless-ngxï¼ + + + Welcome to Paperless-ngx! + + src/app/components/dashboard/dashboard.component.ts + 35 + + 欢迎使用 Paperless-ngxï¼ Show all @@ -1646,7 +527,55 @@ src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html 3 - Show all + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 27 + + 显示全部 + + + Created + + src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html + 9 + + + src/app/components/document-list/document-list.component.html + 141 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 41 + + + src/app/services/rest/document.service.ts + 21 + + 已创建 + + + Title + + src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html + 10 + + + src/app/components/document-detail/document-detail.component.html + 55 + + + src/app/components/document-list/document-list.component.html + 129 + + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 88 + + + src/app/services/rest/document.service.ts + 19 + + 标题 Statistics @@ -1654,15 +583,7 @@ src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html 1 - Statistics - - - Total documents: - - src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html - 4 - - Total documents: + 统计 Documents in inbox: @@ -1670,63 +591,15 @@ src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html 3 - Documents in inbox: + 收件箱中的文档: - - Processing: + + Total documents: - src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts - 32 + src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.html + 4 - Processing: - - - Failed: - - src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts - 35 - - Failed: - - - Added: - - src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts - 38 - - Added: - - - Connecting... - - src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts - 118 - - Connecting... - - - Uploading... - - src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts - 123 - - Uploading... - - - Upload complete, waiting... - - src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts - 126 - - Upload complete, waiting... - - - HTTP error: - - src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts - 136 - - HTTP error: + 文档总数: Upload new documents @@ -1734,23 +607,7 @@ src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html 1 - Upload new documents - - - Drop documents here or - - src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html - 13 - - Drop documents here or - - - Browse files - - src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html - 13 - - Browse files + 上传新文档 Dismiss completed @@ -1759,7 +616,23 @@ 4 This button dismisses all status messages about processed documents on the dashboard (failed and successful) - Dismiss completed + æ¸…é™¤å·²å®Œæˆ + + + Drop documents here or + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 13 + + 拖放文档到此处或 + + + Browse files + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html + 13 + + æµè§ˆæ–‡ä»¶ {VAR_PLURAL, plural, =1 {One more document} other { more documents}} @@ -1768,15 +641,76 @@ 25 This is shown as a summary line when there are more than 5 document in the processing pipeline. - {VAR_PLURAL, plural, =1 {One more document} other { more documents}} + {VAR_PLURAL, plural, =1 {还有一个文档} other { 个更多文档}} - - Open document + + Processing: - src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html - 45 + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 32 - Open document + 正在处ç†ï¼š + + + Failed: + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 35 + + 失败: + + + Added: + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 38 + + 已添加: + + + , + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 40 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 117 + + this string is used to separate processing, failed and added on the file upload widget + , + + + Connecting... + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 118 + + 正在连接… + + + Uploading... + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 123 + + 正在上传... + + + Upload complete, waiting... + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 126 + + 上传完æˆï¼Œç­‰å¾…... + + + HTTP error: + + src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts + 136 + + HTTP 错误: First steps @@ -1784,7 +718,7 @@ src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html 1 - First steps + 第一步 Paperless is running! :) @@ -1792,7 +726,7 @@ src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html 5 - Paperless is running! :) + Paperless-ngx 正在è¿è¡Œï¼:) You can start uploading documents by dropping them in the file upload box to the right or by dropping them in the configured consumption folder and they'll start showing up in the documents list. After you've added some metadata to your documents, use the filtering mechanisms of paperless to create custom views (such as 'Recently added', 'Tagged TODO') and they will appear on the dashboard instead of this message. @@ -1800,7 +734,7 @@ src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html 6,7 - You can start uploading documents by dropping them in the file upload box to the right or by dropping them in the configured consumption folder and they'll start showing up in the documents list. After you've added some metadata to your documents, use the filtering mechanisms of paperless to create custom views (such as 'Recently added', 'Tagged TODO') and they will appear on the dashboard instead of this message. + ä½ å¯ä»¥é€šè¿‡æŠŠæ–‡ä»¶æ‹–拽到å³è¾¹çš„文件上传框中,或者把它们放到é…置好的处ç†æ–‡ä»¶å¤¹ä¸­ä¸Šä¼ æ–‡ä»¶ï¼Œå®ƒä»¬å°±ä¼šå¼€å§‹æ˜¾ç¤ºåœ¨æ–‡ä»¶åˆ—表中。在你给文件添加了一些元数æ®åŽï¼Œä½¿ç”¨ paperless-ngx 的过滤机制æ¥åˆ›å»ºè‡ªå®šä¹‰è§†å›¾ï¼ˆå¦‚ "最近添加"ã€"标签TODO"),它们就会出现在仪表盘上,而ä¸æ˜¯æ­¤ä¿¡æ¯ã€‚ Paperless offers some more features that try to make your life easier: @@ -1808,7 +742,7 @@ src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html 8 - Paperless offers some more features that try to make your life easier: + Paperless-ngx æ供了更多的功能以便于让您的生活更加容易: Once you've got a couple documents in paperless and added metadata to them, paperless can assign that metadata to new documents automatically. @@ -1816,7 +750,7 @@ src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html 10 - Once you've got a couple documents in paperless and added metadata to them, paperless can assign that metadata to new documents automatically. + 一旦你在 paperless-ngx 中上传了几个文件,并为它们添加了元数æ®ï¼Œpaperless-ngx 就能自动将这些元数æ®åˆ†é…给新的文件。 You can configure paperless to read your mails and add documents from attached files. @@ -1824,7 +758,7 @@ src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html 11 - You can configure paperless to read your mails and add documents from attached files. + ä½ å¯ä»¥é…ç½® paperless-ngx æ¥è¯»å–你的邮件并从附件中添加文档。 Consult the documentation on how to use these features. The section on basic usage also has some information on how to use paperless in general. @@ -1832,39 +766,7 @@ src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html 13 - Consult the documentation on how to use these features. The section on basic usage also has some information on how to use paperless in general. - - - Metadata - - src/app/components/document-detail/metadata-collapse/metadata-collapse.component.ts - 18 - - Metadata - - - Select - - src/app/components/common/select-dialog/select-dialog.component.ts - 18 - - Select - - - Please select an object - - src/app/components/common/select-dialog/select-dialog.component.ts - 21 - - Please select an object - - - Invalid date. - - src/app/components/common/input/date/date.component.html - 14 - - Invalid date. + 请å‚阅有关如何使用这些功能的文档。基本使用的部分也有一些关于如何使用 paperless-ngx 的一般信æ¯ã€‚ Searching document with asn @@ -1872,23 +774,1701 @@ src/app/components/document-asn/document-asn.component.html 1 - Searching document with asn + 正在以ASNæœç´¢æ–‡æ¡£ - - Yes + + Page - src/app/pipes/yes-no.pipe.ts + src/app/components/document-detail/document-detail.component.html + 3 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 15 + + é¡µç  + + + of + + src/app/components/document-detail/document-detail.component.html + 5 + + å…± + + + Delete + + src/app/components/document-detail/document-detail.component.html + 11 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 76 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 48 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 46 + + + src/app/components/manage/generic-list/generic-list.component.ts + 106 + + + src/app/components/manage/settings/settings.component.html + 159 + + + src/app/components/manage/tag-list/tag-list.component.html + 49 + + 删除 + + + Download + + src/app/components/document-detail/document-detail.component.html + 19 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 63 + + + src/app/components/document-list/document-card-large/document-card-large.component.html + 60 + + + src/app/components/document-list/document-card-small/document-card-small.component.html + 82 + + 下载 + + + Download original + + src/app/components/document-detail/document-detail.component.html + 25 + + 下载原始文件 + + + More like this + + src/app/components/document-detail/document-detail.component.html + 34 + + + src/app/components/document-list/document-card-large/document-card-large.component.html + 38 + + 更多类似内容 + + + Close + + src/app/components/document-detail/document-detail.component.html + 40 + + 关闭 + + + Details + + src/app/components/document-detail/document-detail.component.html + 52 + + è¯¦ç»†ä¿¡æ¯ + + + Archive serial number + + src/app/components/document-detail/document-detail.component.html + 56 + + å½’æ¡£åºåˆ—å· + + + Date created + + src/app/components/document-detail/document-detail.component.html + 57 + + 创建日期 + + + Correspondent + + src/app/components/document-detail/document-detail.component.html + 58 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 38 + + + src/app/components/document-list/document-list.component.html + 123 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 26 + + + src/app/services/rest/document.service.ts + 18 + + è”系人 + + + Document type + + src/app/components/document-detail/document-detail.component.html + 60 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 47 + + + src/app/components/document-list/document-list.component.html + 135 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 33 + + + src/app/services/rest/document.service.ts + 20 + + 文档类型 + + + Content + + src/app/components/document-detail/document-detail.component.html + 68 + + 内容 + + + Metadata + + src/app/components/document-detail/document-detail.component.html + 77 + + + src/app/components/document-detail/metadata-collapse/metadata-collapse.component.ts + 18 + + å…ƒæ•°æ® + + + Date modified + + src/app/components/document-detail/document-detail.component.html + 83 + + 修改日期 + + + Date added + + src/app/components/document-detail/document-detail.component.html + 87 + + 日期已添加 + + + Media filename + + src/app/components/document-detail/document-detail.component.html + 91 + + 媒体文件å + + + Original MD5 checksum + + src/app/components/document-detail/document-detail.component.html + 95 + + 原始 MD5 校验和 + + + Original file size + + src/app/components/document-detail/document-detail.component.html + 99 + + åŽŸå§‹æ–‡ä»¶å¤§å° + + + Original mime type + + src/app/components/document-detail/document-detail.component.html + 103 + + 原始 mime 类型 + + + Archive MD5 checksum + + src/app/components/document-detail/document-detail.component.html + 107 + + å½’æ¡£ MD5 校验和 + + + Archive file size + + src/app/components/document-detail/document-detail.component.html + 111 + + å½’æ¡£æ–‡ä»¶å¤§å° + + + Original document metadata + + src/app/components/document-detail/document-detail.component.html + 117 + + åŽŸå§‹æ–‡æ¡£å…ƒæ•°æ® + + + Archived document metadata + + src/app/components/document-detail/document-detail.component.html + 118 + + å½’æ¡£æ–‡æ¡£å…ƒæ•°æ® + + + Discard + + src/app/components/document-detail/document-detail.component.html + 143 + + 放弃 + + + Save & next + + src/app/components/document-detail/document-detail.component.html + 144 + + ä¿å­˜ & 下一个 + + + Save + + src/app/components/document-detail/document-detail.component.html + 145 + + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 14 + + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 15 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 17 + + + src/app/components/manage/settings/settings.component.html + 173 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 19 + + ä¿å­˜ + + + Confirm delete + + src/app/components/document-detail/document-detail.component.ts + 267 + + + src/app/components/manage/generic-list/generic-list.component.ts + 102 + + 确认删除 + + + Do you really want to delete document ""? + + src/app/components/document-detail/document-detail.component.ts + 268 + + 您真的想è¦åˆ é™¤æ–‡æ¡£ Ҡå—? + + + The files for this document will be deleted permanently. This operation cannot be undone. + + src/app/components/document-detail/document-detail.component.ts + 269 + + 此文档的文件将被永久删除。此æ“作无法撤消。 + + + Delete document + + src/app/components/document-detail/document-detail.component.ts + 271 + + 删除文档 + + + Error deleting document: + + src/app/components/document-detail/document-detail.component.ts + 281 + + 删除文档时出错: + + + Select: + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 10 + + 选择: + + + All + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 20 + + 全部 + + + Edit: + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 27 + + 编辑: + + + Filter tags + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 29 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 19 + + 过滤器标签 + + + Filter correspondents + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 39 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 27 + + 过滤è”系人 + + + Filter document types + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 48 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 34 + + 过滤文档类型 + + + Download originals + + src/app/components/document-list/bulk-editor/bulk-editor.component.html + 68 + + 下载原始文件 + + + Error executing bulk operation: + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 74 + + 执行批é‡æ“作时出错: + + + "" + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 113 + + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 117 + + + + + "" and "" + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 115 + + This is for messages like 'modify "tag1" and "tag2"' + å’Œ + + + and "" + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 118 + + this is for messages like 'modify "tag1", "tag2" and "tag3"' + å’Œ + + + Confirm tags assignment + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 127 + + ç¡®è®¤æ ‡ç­¾åˆ†é… + + + This operation will add the tag "" to selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 130 + + æ­¤æ“作将把标签“â€æ·»åŠ åˆ° 个选定的文档。 + + + This operation will add the tags to selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 132 + + æ­¤æ“作将添加标签 到 个选定的文档。 + + + This operation will remove the tag "" from selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 135 + + æ­¤æ“作将从 个选定的文档中移除标签“â€ã€‚ + + + This operation will remove the tags from selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 137 + + æ­¤æ“作将从 个选定的文档中删除标签 。 + + + This operation will add the tags and remove the tags on selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 139 + + æ­¤æ“作将在 个指定的文档添加标签 并删除标签 。 + + + Confirm correspondent assignment + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 159 + + 确认è”ç³»äººåˆ†é… + + + This operation will assign the correspondent "" to selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 161 + + æ­¤æ“作将分é…è”系人 "" 到 个选定的文档。 + + + This operation will remove the correspondent from selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 163 + + æ­¤æ“作将从 个选定文档中移除è”系人。 + + + Confirm document type assignment + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 182 + + ç¡®è®¤æ–‡ä»¶ç±»åž‹åˆ†é… + + + This operation will assign the document type "" to selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 184 + + æ­¤æ“作将把文档类型 " 分é…到 个选定的文档。 + + + This operation will remove the document type from selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 186 + + æ­¤æ“作将从 个选定文档中删除文档类型。 + + + Delete confirm + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 201 + + 删除确认 + + + This operation will permanently delete selected document(s). + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 202 + + æ­¤æ“作将永久删除 个选定的文档。 + + + This operation cannot be undone. + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 203 + + æ­¤æ“作无法撤消。 + + + Delete document(s) + + src/app/components/document-list/bulk-editor/bulk-editor.component.ts + 205 + + 删除文档 + + + Filter by correspondent + + src/app/components/document-list/document-card-large/document-card-large.component.html + 20 + + + src/app/components/document-list/document-card-small/document-card-small.component.html + 26 + + 按è”系人过滤 + + + Filter by tag + + src/app/components/document-list/document-card-large/document-card-large.component.html + 24 + + + src/app/components/document-list/document-card-small/document-card-small.component.html + 15 + + 按标签过滤 + + + Edit + + src/app/components/document-list/document-card-large/document-card-large.component.html + 43 + + + src/app/components/document-list/document-card-small/document-card-small.component.html + 66 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 42 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 40 + + + src/app/components/manage/tag-list/tag-list.component.html + 43 + + 编辑 + + + View + + src/app/components/document-list/document-card-large/document-card-large.component.html + 51 + + 查看 + + + Score: + + src/app/components/document-list/document-card-large/document-card-large.component.html + 87 + + 分数: + + + Created: + + src/app/components/document-list/document-card-small/document-card-small.component.html + 43 + + 创建于: + + + Added: + + src/app/components/document-list/document-card-small/document-card-small.component.html + 44 + + 添加于: + + + Modified: + + src/app/components/document-list/document-card-small/document-card-small.component.html + 45 + + 修改于: + + + Select none + + src/app/components/document-list/document-list.component.html + 10 + + 选择“无†+ + + Select page + + src/app/components/document-list/document-list.component.html + 11 + + é€‰æ‹©é¡µé¢ + + + Select all + + src/app/components/document-list/document-list.component.html + 12 + + 全选 + + + Sort + + src/app/components/document-list/document-list.component.html + 39 + + æŽ’åº + + + Views + + src/app/components/document-list/document-list.component.html + 64 + + 视图 + + + Save "" + + src/app/components/document-list/document-list.component.html + 71 + + ä¿å­˜ + + + Save as... + + src/app/components/document-list/document-list.component.html + 72 + + å¦å­˜ä¸º... + + + Loading... + + src/app/components/document-list/document-list.component.html + 87 + + 加载中... + + + {VAR_PLURAL, plural, =1 {Selected of one document} other {Selected of documents}} + + src/app/components/document-list/document-list.component.html + 89 + + {VAR_PLURAL, plural, =1 {已选择 一个文档} other {已选择 å…± 文档}} + + + {VAR_PLURAL, plural, =1 {One document} other { documents}} + + src/app/components/document-list/document-list.component.html + 91 + + {VAR_PLURAL, plural, =1 {一个文档} other { 文档}} + + + (filtered) + + src/app/components/document-list/document-list.component.html + 91 + + (已过滤) + + + ASN + + src/app/components/document-list/document-list.component.html + 117 + + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 90 + + + src/app/services/rest/document.service.ts + 17 + + ASN + + + Added + + src/app/components/document-list/document-list.component.html + 147 + + + src/app/components/document-list/filter-editor/filter-editor.component.html + 48 + + + src/app/services/rest/document.service.ts + 22 + + 已添加 + + + View "" saved successfully. + + src/app/components/document-list/document-list.component.ts + 116 + + 视图ä¿å­˜æˆåŠŸã€‚ + + + View "" created successfully. + + src/app/components/document-list/document-list.component.ts + 138 + + 视图:创建æˆåŠŸã€‚ + + + Reset filters + + src/app/components/document-list/filter-editor/filter-editor.component.html + 57 + + é‡ç½®è¿‡æ»¤å™¨ + + + Correspondent: + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 37 + + è”系人: + + + Without correspondent + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 39 + + 没有è”系人 + + + Type: + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 44 + + 类型: + + + Without document type + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 46 + + 没有文档类型 + + + Tag: + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 50 + + 标签: + + + Without any tag + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 54 + + 没有任何标签 + + + Title: + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 58 + + 标题: + + + ASN: + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 61 + + ASN: + + + Title & content + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 89 + + 标题 & 内容 + + + Advanced search + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 91 + + 高级æœç´¢ + + + More like + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 94 + + 更多 + + + Save current view + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 3 + + ä¿å­˜å½“å‰è§†å›¾ + + + Name + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 8 + + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 8 + + + src/app/components/manage/correspondent-list/correspondent-list.component.html 9 - Yes - - - No - src/app/pipes/yes-no.pipe.ts + src/app/components/manage/correspondent-list/correspondent-list.component.html + 19 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html 9 - No + + src/app/components/manage/document-type-list/document-type-list.component.html + 9 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 19 + + + src/app/components/manage/settings/settings.component.html + 141 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 8 + + + src/app/components/manage/tag-list/tag-list.component.html + 9 + + + src/app/components/manage/tag-list/tag-list.component.html + 19 + + å称 + + + Show in sidebar + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 9 + + + src/app/components/manage/settings/settings.component.html + 153 + + 在侧边æ æ˜¾ç¤º + + + Show on dashboard + + src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html + 10 + + + src/app/components/manage/settings/settings.component.html + 149 + + 在仪表æ¿ä¸Šæ˜¾ç¤º + + + Matching algorithm + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 9 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 10 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 13 + + 匹é…算法 + + + Matching pattern + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 10 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 11 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 14 + + 匹é…æ¨¡å¼ + + + Case insensitive + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.html + 11 + + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.html + 12 + + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 15 + + 忽略大å°å†™ + + + Create new correspondent + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.ts + 21 + + 创建新的è”系人 + + + Edit correspondent + + src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.ts + 25 + + 编辑è”系人 + + + Create + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 2 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 2 + + + src/app/components/manage/tag-list/tag-list.component.html + 2 + + 创建 + + + Filter by: + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 8 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 8 + + + src/app/components/manage/tag-list/tag-list.component.html + 8 + + 过滤æ¡ä»¶: + + + Matching + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 20 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 20 + + + src/app/components/manage/tag-list/tag-list.component.html + 21 + + åŒ¹é… + + + Document count + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 21 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 21 + + + src/app/components/manage/tag-list/tag-list.component.html + 22 + + æ–‡æ¡£æ•°é‡ + + + Last correspondence + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 22 + + 上一å°ä¿¡ä»¶ + + + Actions + + src/app/components/manage/correspondent-list/correspondent-list.component.html + 23 + + + src/app/components/manage/document-type-list/document-type-list.component.html + 22 + + + src/app/components/manage/settings/settings.component.html + 158 + + + src/app/components/manage/tag-list/tag-list.component.html + 23 + + æ“作 + + + Do you really want to delete the correspondent ""? + + src/app/components/manage/correspondent-list/correspondent-list.component.ts + 26 + + 您真的想è¦åˆ é™¤è”系人" "å—? + + + Create new document type + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.ts + 21 + + 创建新文档类型 + + + Edit document type + + src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.ts + 25 + + 编辑文档类型 + + + Do you really want to delete the document type ""? + + src/app/components/manage/document-type-list/document-type-list.component.ts + 26 + + 您真的想è¦åˆ é™¤æ–‡æ¡£ç±»åž‹" "å—? + + + Automatic + + src/app/components/manage/generic-list/generic-list.component.ts + 39 + + + src/app/data/matching-model.ts + 17 + + 自动 + + + Do you really want to delete this element? + + src/app/components/manage/generic-list/generic-list.component.ts + 97 + + 您真的想è¦åˆ é™¤æ­¤å…ƒç´ å—? + + + Associated documents will not be deleted. + + src/app/components/manage/generic-list/generic-list.component.ts + 104 + + 已关è”的文档将ä¸ä¼šè¢«åˆ é™¤ã€‚ + + + Error while deleting element: + + src/app/components/manage/generic-list/generic-list.component.ts + 114 + + 删除元素时出错: + + + General settings + + src/app/components/manage/settings/settings.component.html + 10 + + 常规设置 + + + Appearance + + src/app/components/manage/settings/settings.component.html + 13 + + 外观 + + + Display language + + src/app/components/manage/settings/settings.component.html + 17 + + 显示语言 + + + You need to reload the page after applying a new language. + + src/app/components/manage/settings/settings.component.html + 25 + + 您需è¦åœ¨åº”用新语言åŽé‡æ–°åŠ è½½é¡µé¢ã€‚ + + + Date display + + src/app/components/manage/settings/settings.component.html + 32 + + 日期显示 + + + Date format + + src/app/components/manage/settings/settings.component.html + 45 + + æ—¥æœŸæ ¼å¼ + + + Short: + + src/app/components/manage/settings/settings.component.html + 51 + + 短: + + + Medium: + + src/app/components/manage/settings/settings.component.html + 55 + + 中: + + + Long: + + src/app/components/manage/settings/settings.component.html + 59 + + 长: + + + Items per page + + src/app/components/manage/settings/settings.component.html + 67 + + æ¯é¡µæ˜¾ç¤º + + + Document editor + + src/app/components/manage/settings/settings.component.html + 83 + + 文档编辑器 + + + Use PDF viewer provided by the browser + + src/app/components/manage/settings/settings.component.html + 87 + + 使用æµè§ˆå™¨æ供的 PDF 查看器 + + + This is usually faster for displaying large PDF documents, but it might not work on some browsers. + + src/app/components/manage/settings/settings.component.html + 87 + + 显示大型的 PDF 文档通常更快,但在æŸäº›æµè§ˆå™¨ä¸Šå¯èƒ½æ— æ³•ä½¿ç”¨ã€‚ + + + Dark mode + + src/app/components/manage/settings/settings.component.html + 94 + + æ·±è‰²æ¨¡å¼ + + + Use system settings + + src/app/components/manage/settings/settings.component.html + 97 + + 使用系统设置 + + + Enable dark mode + + src/app/components/manage/settings/settings.component.html + 98 + + å¯ç”¨æ·±è‰²æ¨¡å¼ + + + Invert thumbnails in dark mode + + src/app/components/manage/settings/settings.component.html + 99 + + 在深色模å¼ä¸‹å转缩略图 + + + Bulk editing + + src/app/components/manage/settings/settings.component.html + 103 + + 批é‡ç¼–辑 + + + Show confirmation dialogs + + src/app/components/manage/settings/settings.component.html + 107 + + 显示确认对è¯æ¡† + + + Deleting documents will always ask for confirmation. + + src/app/components/manage/settings/settings.component.html + 107 + + 删除文档时总是需è¦ç¡®è®¤ã€‚ + + + Apply on close + + src/app/components/manage/settings/settings.component.html + 108 + + 关闭时应用 + + + Notifications + + src/app/components/manage/settings/settings.component.html + 116 + + 通知 + + + Document processing + + src/app/components/manage/settings/settings.component.html + 119 + + æ–‡æ¡£å¤„ç† + + + Show notifications when new documents are detected + + src/app/components/manage/settings/settings.component.html + 123 + + 检测到新文档时显示通知 + + + Show notifications when document processing completes successfully + + src/app/components/manage/settings/settings.component.html + 124 + + 文件处ç†æˆåŠŸå®Œæˆæ—¶æ˜¾ç¤ºé€šçŸ¥ + + + Show notifications when document processing fails + + src/app/components/manage/settings/settings.component.html + 125 + + 文件处ç†å¤±è´¥æ—¶æ˜¾ç¤ºé€šçŸ¥ + + + Suppress notifications on dashboard + + src/app/components/manage/settings/settings.component.html + 126 + + ç¦ç”¨åœ¨ä»ªè¡¨ç›˜ä¸Šçš„通知 + + + This will suppress all messages about document processing status on the dashboard. + + src/app/components/manage/settings/settings.component.html + 126 + + 这将ç¦æ­¢ä»ªè¡¨ç›˜ä¸Šæ‰€æœ‰æœ‰å…³æ–‡ä»¶å¤„ç†çŠ¶æ€çš„消æ¯ã€‚ + + + Appears on + + src/app/components/manage/settings/settings.component.html + 146 + + 出现于 + + + No saved views defined. + + src/app/components/manage/settings/settings.component.html + 163 + + 未定义ä¿å­˜çš„视图。 + + + Saved view "" deleted. + + src/app/components/manage/settings/settings.component.ts + 111 + + ä¿å­˜çš„视图已删除。 + + + Settings saved successfully. + + src/app/components/manage/settings/settings.component.ts + 133 + + 设置ä¿å­˜æˆåŠŸã€‚ + + + Use system language + + src/app/components/manage/settings/settings.component.ts + 138 + + 使用系统语言 + + + Use date format of display language + + src/app/components/manage/settings/settings.component.ts + 144 + + ä½¿ç”¨æ˜¾ç¤ºè¯­è¨€çš„æ—¥æœŸæ ¼å¼ + + + Error while storing settings on server: + + src/app/components/manage/settings/settings.component.ts + 161 + + 在æœåŠ¡å™¨ä¸Šå­˜å‚¨è®¾ç½®æ—¶å‡ºé”™ï¼š + + + Color + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 10 + + + src/app/components/manage/tag-list/tag-list.component.html + 20 + + 颜色 + + + Inbox tag + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 12 + + 收件箱标签 + + + Inbox tags are automatically assigned to all consumed documents. + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.html + 12 + + 收件箱标签自动分é…给所有已处ç†çš„文档。 + + + Create new tag + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.ts + 22 + + 创建新标签 + + + Edit tag + + src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.ts + 26 + + 编辑标签 + + + Do you really want to delete the tag ""? + + src/app/components/manage/tag-list/tag-list.component.ts + 26 + + 您真的想è¦åˆ é™¤æ ‡ç­¾â€œ â€å—? + + + 404 Not Found + + src/app/components/not-found/not-found.component.html + 7 + + 404 页é¢æœªæ‰¾åˆ° + + + Any word + + src/app/data/matching-model.ts + 12 + + ä»»æ„å•è¯ + + + Any: Document contains any of these words (space separated) + + src/app/data/matching-model.ts + 12 + + ä»»æ„:文档包å«å…¶ä¸­ä»»ä½•ä¸€ä¸ªå•è¯(空格分隔) + + + All words + + src/app/data/matching-model.ts + 13 + + 所有å•è¯ + + + All: Document contains all of these words (space separated) + + src/app/data/matching-model.ts + 13 + + 全部: 文档包å«æ‰€æœ‰è¿™äº›å•è¯(空格分隔) + + + Exact match + + src/app/data/matching-model.ts + 14 + + ç²¾ç¡®åŒ¹é… + + + Exact: Document contains this string + + src/app/data/matching-model.ts + 14 + + 精确:文档中包å«æ­¤å­—符串 + + + Regular expression + + src/app/data/matching-model.ts + 15 + + æ­£åˆ™è¡¨è¾¾å¼ + + + Regular expression: Document matches this regular expression + + src/app/data/matching-model.ts + 15 + + 正则表达å¼ï¼šæ–‡æ¡£åŒ¹é…æ­¤æ­£åˆ™è¡¨è¾¾å¼ + + + Fuzzy word + + src/app/data/matching-model.ts + 16 + + 模糊å•è¯ + + + Fuzzy: Document contains a word similar to this word + + src/app/data/matching-model.ts + 16 + + 模糊:文档包å«ä¸€ä¸ªç±»ä¼¼äºŽæ­¤å•è¯çš„å•è¯ + + + Auto: Learn matching automatically + + src/app/data/matching-model.ts + 17 + + è‡ªåŠ¨ï¼šè‡ªåŠ¨å­¦ä¹ åŒ¹é… + + + Unsaved Changes + + src/app/guards/dirty-form.guard.ts + 16 + + + src/app/services/open-documents.service.ts + 75 + + + src/app/services/open-documents.service.ts + 96 + + 未ä¿å­˜çš„更改 + + + You have unsaved changes. + + src/app/guards/dirty-form.guard.ts + 17 + + + src/app/services/open-documents.service.ts + 76 + + + src/app/services/open-documents.service.ts + 97 + + 您有尚未ä¿å­˜çš„更改。 + + + Are you sure you want to leave? + + src/app/guards/dirty-form.guard.ts + 18 + + 你确定è¦ç¦»å¼€å—? + + + Leave page + + src/app/guards/dirty-form.guard.ts + 20 + + ç¦»å¼€é¡µé¢ (no title) @@ -1896,119 +2476,23 @@ src/app/pipes/document-title.pipe.ts 12 - (no title) + (无标题) - - English (US) + + Yes - src/app/services/settings.service.ts - 90 + src/app/pipes/yes-no.pipe.ts + 9 - English (US) + 是 - - English (GB) + + No - src/app/services/settings.service.ts - 91 + src/app/pipes/yes-no.pipe.ts + 9 - English (GB) - - - German - - src/app/services/settings.service.ts - 92 - - German - - - Dutch - - src/app/services/settings.service.ts - 93 - - Dutch - - - French - - src/app/services/settings.service.ts - 94 - - French - - - Portuguese - - src/app/services/settings.service.ts - 95 - - Portuguese - - - Portuguese (Brazil) - - src/app/services/settings.service.ts - 96 - - Portuguese (Brazil) - - - Italian - - src/app/services/settings.service.ts - 97 - - Italian - - - Romanian - - src/app/services/settings.service.ts - 98 - - Romanian - - - Russian - - src/app/services/settings.service.ts - 99 - - Russian - - - Spanish - - src/app/services/settings.service.ts - 100 - - Spanish - - - Polish - - src/app/services/settings.service.ts - 101 - - Polish - - - Swedish - - src/app/services/settings.service.ts - 102 - - Swedish - - - ISO 8601 - - src/app/services/settings.service.ts - 107 - - ISO 8601 + å¦ Document already exists. @@ -2016,7 +2500,7 @@ src/app/services/consumer-status.service.ts 15 - Document already exists. + 文档已存在。 File not found. @@ -2024,7 +2508,7 @@ src/app/services/consumer-status.service.ts 16 - File not found. + 找ä¸åˆ°æ–‡ä»¶ã€‚ Pre-consume script does not exist. @@ -2033,7 +2517,7 @@ 17 Pre-Consume is a term that appears like that in the documentation as well and does not need a specific translation - Pre-consume script does not exist. + 预处ç†è„šæœ¬ä¸å­˜åœ¨ã€‚ Error while executing pre-consume script. @@ -2042,7 +2526,7 @@ 18 Pre-Consume is a term that appears like that in the documentation as well and does not need a specific translation - Error while executing pre-consume script. + 执行å‰ç½®å‘½ä»¤æ—¶å‡ºé”™ã€‚ Post-consume script does not exist. @@ -2051,7 +2535,7 @@ 19 Post-Consume is a term that appears like that in the documentation as well and does not need a specific translation - Post-consume script does not exist. + åŽå¤„ç†è„šæœ¬ä¸å­˜åœ¨ã€‚ Error while executing post-consume script. @@ -2060,7 +2544,7 @@ 20 Post-Consume is a term that appears like that in the documentation as well and does not need a specific translation - Error while executing post-consume script. + 执行åŽå¤„ç†è„šæœ¬æ—¶å‡ºé”™ã€‚ Received new file. @@ -2068,7 +2552,7 @@ src/app/services/consumer-status.service.ts 21 - Received new file. + 收到新文件。 File type not supported. @@ -2076,7 +2560,7 @@ src/app/services/consumer-status.service.ts 22 - File type not supported. + ä¸æ”¯æŒçš„文件类型。 Processing document... @@ -2084,7 +2568,7 @@ src/app/services/consumer-status.service.ts 23 - Processing document... + 正在处ç†æ–‡æ¡£... Generating thumbnail... @@ -2092,7 +2576,7 @@ src/app/services/consumer-status.service.ts 24 - Generating thumbnail... + 正在生æˆç¼©ç•¥å›¾... Retrieving date from document... @@ -2100,7 +2584,7 @@ src/app/services/consumer-status.service.ts 25 - Retrieving date from document... + 正在从文档中获å–日期... Saving document... @@ -2108,7 +2592,7 @@ src/app/services/consumer-status.service.ts 26 - Saving document... + 正在ä¿å­˜æ–‡æ¡£â€¦ Finished. @@ -2116,55 +2600,39 @@ src/app/services/consumer-status.service.ts 27 - Finished. + 已完æˆã€‚ - - Error + + Are you sure you want to close this document? - src/app/services/toast.service.ts - 35 + src/app/services/open-documents.service.ts + 77 - Error + 您确定è¦å…³é—­æ­¤æ–‡æ¡£å—? - - Information + + Close document - src/app/services/toast.service.ts - 39 + src/app/services/open-documents.service.ts + 79 - Information + 关闭文档 - - Correspondent + + Are you sure you want to close all documents? - src/app/services/rest/document.service.ts - 18 + src/app/services/open-documents.service.ts + 98 - Correspondent + 您确定è¦å…³é—­æ‰€æœ‰æ–‡æ¡£å—? - - Document type + + Close documents - src/app/services/rest/document.service.ts - 20 + src/app/services/open-documents.service.ts + 100 - Document type - - - Created - - src/app/services/rest/document.service.ts - 21 - - Created - - - Added - - src/app/services/rest/document.service.ts - 22 - - Added + 关闭文档 Modified @@ -2172,7 +2640,7 @@ src/app/services/rest/document.service.ts 23 - Modified + 已修改 Search score @@ -2181,159 +2649,159 @@ 28 Score is a value returned by the full text search engine and specifies how well a result matches the given query - Search score + æœç´¢åˆ†æ•° - - Create new item + + English (US) - src/app/components/common/edit-dialog/edit-dialog.component.ts - 50 + src/app/services/settings.service.ts + 90 - Create new item + 英语(美国) - - Edit item + + Czech - src/app/components/common/edit-dialog/edit-dialog.component.ts - 54 + src/app/services/settings.service.ts + 91 - Edit item + æ·å…‹è¯­ - - Could not save element: + + Danish - src/app/components/common/edit-dialog/edit-dialog.component.ts - 58 + src/app/services/settings.service.ts + 92 - Could not save element: + 丹麦语 - - Automatic + + German - src/app/components/manage/generic-list/generic-list.component.ts - 39 + src/app/services/settings.service.ts + 93 - Automatic + 德语 - - Do you really want to delete this element? + + English (GB) - src/app/components/manage/generic-list/generic-list.component.ts + src/app/services/settings.service.ts + 94 + + 英语(英国) + + + Spanish + + src/app/services/settings.service.ts + 95 + + 西ç­ç‰™è¯­ + + + French + + src/app/services/settings.service.ts + 96 + + 法语 + + + Italian + + src/app/services/settings.service.ts 97 - Do you really want to delete this element? + æ„大利语 - - Associated documents will not be deleted. + + Luxembourgish - src/app/components/manage/generic-list/generic-list.component.ts + src/app/services/settings.service.ts + 98 + + å¢æ£®å ¡è¯­ + + + Dutch + + src/app/services/settings.service.ts + 99 + + è·å…°è¯­ + + + Polish + + src/app/services/settings.service.ts + 100 + + 波兰语 + + + Portuguese (Brazil) + + src/app/services/settings.service.ts + 101 + + è‘¡è„牙语 (巴西) + + + Portuguese + + src/app/services/settings.service.ts + 102 + + è‘¡è„牙语 + + + Romanian + + src/app/services/settings.service.ts + 103 + + 罗马尼亚语 + + + Russian + + src/app/services/settings.service.ts 104 - Associated documents will not be deleted. + 俄语 - - Delete + + Swedish - src/app/components/manage/generic-list/generic-list.component.ts - 106 + src/app/services/settings.service.ts + 105 - Delete + 瑞典语 - - Error while deleting element: + + ISO 8601 - src/app/components/manage/generic-list/generic-list.component.ts - 114 + src/app/services/settings.service.ts + 115 - Error while deleting element: + ISO 8601 - - Any word + + Error - src/app/data/matching-model.ts - 12 + src/app/services/toast.service.ts + 35 - Any word + 错误 - - Any: Document contains any of these words (space separated) + + Information - src/app/data/matching-model.ts - 12 + src/app/services/toast.service.ts + 39 - Any: Document contains any of these words (space separated) - - - All words - - src/app/data/matching-model.ts - 13 - - All words - - - All: Document contains all of these words (space separated) - - src/app/data/matching-model.ts - 13 - - All: Document contains all of these words (space separated) - - - Exact match - - src/app/data/matching-model.ts - 14 - - Exact match - - - Exact: Document contains this string - - src/app/data/matching-model.ts - 14 - - Exact: Document contains this string - - - Regular expression - - src/app/data/matching-model.ts - 15 - - Regular expression - - - Regular expression: Document matches this regular expression - - src/app/data/matching-model.ts - 15 - - Regular expression: Document matches this regular expression - - - Fuzzy word - - src/app/data/matching-model.ts - 16 - - Fuzzy word - - - Fuzzy: Document contains a word similar to this word - - src/app/data/matching-model.ts - 16 - - Fuzzy: Document contains a word similar to this word - - - Auto: Learn matching automatically - - src/app/data/matching-model.ts - 17 - - Auto: Learn matching automatically + ä¿¡æ¯ diff --git a/src-ui/src/main.ts b/src-ui/src/main.ts index c7b673cf4..274537fe8 100644 --- a/src-ui/src/main.ts +++ b/src-ui/src/main.ts @@ -1,12 +1,13 @@ -import { enableProdMode } from '@angular/core'; -import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { enableProdMode } from '@angular/core' +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic' -import { AppModule } from './app/app.module'; -import { environment } from './environments/environment'; +import { AppModule } from './app/app.module' +import { environment } from './environments/environment' if (environment.production) { - enableProdMode(); + enableProdMode() } -platformBrowserDynamic().bootstrapModule(AppModule) - .catch(err => console.error(err)); +platformBrowserDynamic() + .bootstrapModule(AppModule) + .catch((err) => console.error(err)) diff --git a/src-ui/src/polyfills.ts b/src-ui/src/polyfills.ts index 4eef33bb7..ac9c93e4a 100644 --- a/src-ui/src/polyfills.ts +++ b/src-ui/src/polyfills.ts @@ -1,7 +1,7 @@ /*************************************************************************************************** * Load `$localize` onto the global scope - used if i18n tags appear in Angular templates. */ -import '@angular/localize/init'; +import '@angular/localize/init' /** * This file includes polyfills needed by Angular and is loaded before the app. * You can add your own extra polyfills to this file. @@ -49,8 +49,7 @@ import '@angular/localize/init'; /*************************************************************************************************** * Zone JS is required by default for Angular itself. */ -import 'zone.js'; // Included with Angular CLI. - +import 'zone.js' // Included with Angular CLI. /*************************************************************************************************** * APPLICATION IMPORTS diff --git a/src-ui/src/styles.scss b/src-ui/src/styles.scss index 7073d4c23..06fe95f94 100644 --- a/src-ui/src/styles.scss +++ b/src-ui/src/styles.scss @@ -1,27 +1,149 @@ -@import "theme"; -@import "theme_dark"; -@import "print"; +// bs options +$enable-negative-margins: true; + @import "node_modules/bootstrap/scss/bootstrap"; @import "~@ng-select/ng-select/themes/default.theme.css"; +@import "theme"; +@import "print"; -.toolbaricon { - width: 1.2em; - height: 1.2em; -} - -.buttonicon { - width: 1.2em; - height: 1.2em; -} - -.sidebaricon { - width: 16px; - height: 16px; - vertical-align: text-bottom; -} - +// Paperless-ngx styles body { font-size: 0.875rem; + height: 100vh; +} + +* { + transition: background-color 0.3s ease, border-color 0.3s ease; +} + +svg.logo { + .leaf { + fill: var(--bs-primary) !important; + } + .text { + fill: var(--bs-body-color) !important; + } +} + +.navbar.bg-primary { + --bs-primary: hsl(var(--pngx-primary),var(--pngx-primary-lightness)); + --bs-primary-rgb: var(--bs-primary); +} + +.border { + border-color: var(--bs-border-color) !important; +} + +.border-end { + border-right: 1px solid var(--bs-border-color) !important; +} + +.border-start { + border-left: 1px solid var(--bs-border-color) !important; +} + +.border-bottom { + border-bottom: 1px solid var(--bs-border-color) !important; +} + +.nav-link, .list-group-item { + color: var(--bs-body-color); +} + +.bg-body { + background-color: var(--bs-body-bg); +} + +.bg-primary { + background-color: var(--bs-primary) !important; + color: var(--pngx-primary-text-contrast); +} + +.navbar-brand { + color: var(--pngx-primary-text-contrast) !important; +} + +.navbar .dropdown .btn { + color: var(--pngx-primary-text-contrast) !important; +} + +.btn-primary { + color: var(--pngx-primary-text-contrast); + background-color: var(--bs-primary); + border-color: var(--bs-primary); + + &:hover, &:focus { + background-color: var(--pngx-primary-darken-5); + border-color: var(--pngx-primary-darken-5); + } + + &:disabled, &.disabled { + color: var(--pngx-primary-text-contrast); + background-color: var(--pngx-primary-darken-5) !important; + border-color: var(--pngx-primary-darken-5) !important; + } +} + +.btn-outline-primary { + border-color: var(--bs-primary) !important; + color: var(--bs-primary) !important; + + &:hover, &:focus, &.active, &:active { + background-color: var(--bs-primary) !important; + color: var(--bs-light) !important; + } +} + +.btn-outline-secondary { + color: var(--bs-secondary); + + &:hover { + color: var(--bs-light); + } +} + +.nav-item .sidebaricon { + color: var(--bs-secondary); +} + +.btn:focus, +.btn:active:focus, +.dropdown-item:focus, +.btn-check:focus + .btn, +.form-control:focus, +.form-check-input:focus, +.form-check-radio:focus, +.form-select:focus { + box-shadow: 0 0 0 0.25rem hsla(var(--pngx-primary), var(--pngx-primary-lightness), var(--pngx-focus-alpha)); +} + +.form-switch .form-check-input:focus { + background-image: escape-svg(url("data:image/svg+xml,")); +} + +.nav-item a:focus-visible { + outline: none; + background-color: var(--bs-body-bg); +} + +a.navbar-brand:focus-visible { + outline: none; + color: var(--pngx-primary-darken-5); +} + +.dropdown.show { + > .btn-primary { + background-color: var(--bs-primary); + border-color: var(--bs-primary); + } + + > .btn-outline-primary { + color: var(--pngx-primary-text-contrast) !important; + } +} + +a, a:hover, .btn-link, .btn-link:hover { + color: var(--bs-primary); } .form-control-dark { @@ -113,8 +235,249 @@ body { } } -.ngx-file-drop__drop-zone--over { - background-color: $primaryFaded !important; +.form-control:not(.btn), +input, +select, +textarea, +.form-select:not(.is-invalid):not(:disabled), +.form-check-input, +.ng-select .ng-select-container .ng-value-container .ng-input > input { + color: var(--bs-body-color); + background-color: var(--bs-body-bg); + border-color: var(--bs-border-color); + + &:focus { + background-color: var(--pngx-bg-darker); + color: var(--bs-body-color); + } +} + +.form-check-input:checked { + background-color: var(--bs-primary); + border-color: var(--bs-primary); +} + +.form-check-input:focus { + border-color: var(--bs-primary); +} + +.page-link { + color: var(--bs-secondary); + background-color: var(--bs-body-bg); + border-color: var(--bs-border-color) !important; + + &:hover, &:focus { + background-color: var(--bs-primary) !important; + color: var(--bs-light) !important; + } +} + +.page-item.active .page-link { + background-color: var(--bs-primary); + border-color: var(--bs-primary) !important; + color: var(--bs-light); +} + +.page-item.disabled .page-link { + background-color: var(--pngx-bg-darker); +} + +.nav-tabs { + border-bottom: 1px solid var(--bs-border-color); + + .nav-link { + color: var(--bs-primary); + + &.active, &:hover { + border-color: var(--bs-border-color); + background-color: var(--bs-body-bg); + color: var(--bs-body-color); + border-bottom: 1px solid transparent; + } + + &:focus { + border-color: var(--bs-border-color); + } + + &.active:focus, &:active { + border-bottom: 1px solid transparent; + } + } +} + +.ng-select-container, +.ng-select.ng-select-opened > .ng-select-container, +.ng-dropdown-panel, +.ng-dropdown-panel .ng-dropdown-panel-items .ng-option { + background-color: var(--bs-body-bg) !important; + color: var(--bs-body-color) !important; + border-color: var(--bs-border-color) !important; + + input:focus { + background-color: transparent !important; + } +} + +.input-group-text { + color: var(--bs-body-color); + background-color: var(--bs-body-bg); + border-color: var(--bs-border-color); +} + +.list-group-item { + color: var(--bs-body-color); + background-color: var(--bs-body-bg); + border-color: var(--bs-border-color); + + &:hover, &:focus { + background-color: var(--bs-body-bg); + } +} + +.dropdown-menu { + background-color: var(--bs-body-bg); + + .dropdown-divider { + border-color: var(--bs-border-color); + } + + .dropdown-item { + color: var(--bs-body-color); + + &:hover, &:focus { + background-color: var(--pngx-bg-darker); + color: var(--bs-body-color); + } + + &.active { + background-color: var(--bs-primary); + color: var(--pngx-primary-text-contrast); + } + } +} + +.doc-img-container { + border: none !important; + border-top-left-radius: .25rem; + border-top-right-radius: .25rem; + overflow: hidden; +} + +// icons +.toolbaricon { + width: 1.2em; + height: 1.2em; +} + +.buttonicon { + width: 1.2em; + height: 1.2em; +} + +.sidebaricon { + width: 16px; + height: 16px; + vertical-align: text-bottom; +} + +table.table { + color: var(--bs-body-color); + + .des,.asc { + background-color: var(--bs-body-bg) !important; + } +} + +.close { + color: var(--bs-body-color); +} + +.modal .btn-close { + color: var(--bs-body-color); +} + +.main-dropzone { + height: 100%; + width: 100%; + + &.ngx-file-drop__drop-zone--over { + background-color: transparent !important; + } +} + +.global-dropzone-overlay { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + background-color: rgba(23, 84, 31, .8); + z-index: 1055; // $zindex-modal + pointer-events: none !important; + user-select: none !important; + text-align: center; + padding-top: 25%; + + &.show { + opacity: 1 !important; + } + + &.hide { + display: none; + } +} + +.ngx-file-drop__drop-zone--over .global-dropzone-overlay { + opacity: 0; +} + +.inert { + pointer-events: none !important; + user-select: none !important; +} + +.alert-danger { + color: var(--bs-body-color); + background-color: var(--bs-danger); + border-color: var(--bs-danger); +} + +.progress { + background-color: var(--bs-body-bg); +} + +.ngb-dp-header, +.ngb-dp-weekdays, +.ngb-dp-month { + background-color: var(--bs-body-bg); +} + +.popover { + .popover-header, + .popover-body { + background-color: var(--pngx-bg-alt); + border-color: var(--bs-border-color); + color: var(--bs-body-color); + } +} + +// fix popover carat colors +.bs-popover-start > .popover-arrow::after, .bs-popover-auto[data-popper-placement^="left"] { + border-left-color: var(--pngx-bg-alt); +} +.bs-popover-end > .popover-arrow::after, .bs-popover-auto[data-popper-placement^="right"] { + border-right-color: var(--pngx-bg-alt); +} +.bs-popover-top > .popover-arrow::after, .bs-popover-auto[data-popper-placement^="top"] { + border-top-color: var(--pngx-bg-alt); +} +.bs-popover-bottom > .popover-arrow::after, .bs-popover-auto[data-popper-placement^="bottom"] { + border-bottom-color: var(--pngx-bg-alt); +} + +.bs-popover-bottom .popover-header::before, +.bs-popover-auto[x-placement^=bottom] .popover-header::before { + border-bottom-color: var(--pngx-bg-alt); } // Bootstrap 5 tweaks @@ -130,6 +493,6 @@ a.badge { } .btn-outline-primary:not(:disabled):not(.disabled).active,.btn-outline-primary:not(:disabled):not(.disabled):active,.show>.btn-outline-primary.dropdown-toggle { - background-color: $paperless-green; - border-color: $paperless-green; + background-color: var(--bs-primary); + border-color: var(--bs-primary); } diff --git a/src-ui/src/test.ts b/src-ui/src/test.ts deleted file mode 100644 index 4bf4afba6..000000000 --- a/src-ui/src/test.ts +++ /dev/null @@ -1,27 +0,0 @@ -// This file is required by karma.conf.js and loads recursively all the .spec and framework files - -import 'zone.js/testing'; -import { getTestBed } from '@angular/core/testing'; -import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting -} from '@angular/platform-browser-dynamic/testing'; - -declare const require: { - context(path: string, deep?: boolean, filter?: RegExp): { - keys(): string[]; - (id: string): T; - }; -}; - -// First, initialize the Angular testing environment. -getTestBed().initTestEnvironment( - BrowserDynamicTestingModule, - platformBrowserDynamicTesting(), { - teardown: { destroyAfterEach: false } -} -); -// Then we find all the tests. -const context = require.context('./', true, /\.spec\.ts$/); -// And load the modules. -context.keys().map(context); diff --git a/src-ui/src/theme.scss b/src-ui/src/theme.scss index e01e3cdc3..a18ce1358 100644 --- a/src-ui/src/theme.scss +++ b/src-ui/src/theme.scss @@ -1,8 +1,222 @@ -$paperless-green: #17541f; -$primary: #17541f; -$primaryFaded: #d1ddd2; -$enable-negative-margins: true; - -.bg-body { - background-color: #fff; +@mixin paperless-green { + // base color e.g. #17541f = hsl(128, 57%, 21%) + --pngx-primary: 128, 57%; + --pngx-primary-lightness: 21%; +} + +body { + @include paperless-green; + --pngx-primary-text-contrast: var(--bs-light); + + --bs-primary: hsl(var(--pngx-primary), var(--pngx-primary-lightness)); + --bs-border-color: var(--bs-gray-400); + --pngx-primary-faded: hsl(var(--pngx-primary), calc(var(--pngx-primary-lightness) + 72%)); + --pngx-primary-lighten-30: hsl(var(--pngx-primary), calc(var(--pngx-primary-lightness) + 30%)); + --pngx-primary-darken-5: hsl(var(--pngx-primary), calc(var(--pngx-primary-lightness) - 5%)); + --pngx-primary-darken-15: hsl(var(--pngx-primary), calc(var(--pngx-primary-lightness) - 15%)); + --pngx-primary-darken-18: hsl(var(--pngx-primary), calc(var(--pngx-primary-lightness) - 18%)); + --pngx-bg-alt: #fff; + --pngx-bg-darker: var(--bs-gray-100); + --pngx-focus-alpha: 0.3; +} + +// Dark text colors allow for maintain contrast with theme color changes +$text-color-light-bg: #212529; +$text-color-dark-bg: #abb2bf; +$text-color-dark-bg-accent: lighten($text-color-dark-bg, 10%); +// Taken from bootstrap +$form-check-input-checked-bg-image-dark: url("data:image/svg+xml,"); +$form-check-radio-checked-bg-image-dark: url("data:image/svg+xml,"); + +.primary-light { + --pngx-primary-text-contrast: #{$text-color-light-bg} !important; + + .form-check-input:checked[type=checkbox] { + background-image: escape-svg($form-check-input-checked-bg-image-dark); + } + + .form-check-input:checked[type=radio] { + background-image: escape-svg($form-check-radio-checked-bg-image-dark); + } + + .btn-close { + filter: none !important; + } +} + +.primary-dark { + --pngx-primary-text-contrast: #{$text-color-dark-bg} !important; +} + +// Dark mode +@mixin paperless-green-dark-mode { + --pngx-primary-lightness: 31%; +} + +@mixin dark-mode { + --bs-body-color: #{$text-color-dark-bg}; + --pngx-body-color-accent: #{$text-color-dark-bg-accent}; + --bs-danger: #b71631; + --bs-danger-rgb: 183, 22, 49; + --bs-body-bg: #161618; + --bs-body-bg-rgb: 22, 22, 24; + --bs-light: #1c1c1f; + --bs-light-rgb: 28, 28, 31; + --bs-border-color: #47494f; + --pngx-bg-darker: #101216; + --pngx-bg-alt: #242529; + --pngx-focus-alpha: 0.6; + --pngx-primary-faded: var(--pngx-primary-darken-15); + --pngx-primary-text-contrast: var(--bs-body-color); + + .text-dark, .text-light { + color: var(--bs-body-color) !important; + } + + .btn-primary { + &:hover, &:focus, &.active, &:active { + color: var(--bs-body-color) !important; + } + } + + .btn-outline-primary { + &:hover, &:focus, &.active, &:active { + color: var(--bs-light) !important; + } + } + + .btn-outline-secondary { + &:hover, &:focus, &.active, &:active { + background-color: var(--pngx-bg-darker); + color: var(--bs-primary); + } + } + + .btn-light { + color: var(--bs-body-color); + } + + .btn .progress { + background-color: var(--pngx-body-color-accent); + } + + .search-form-container { + input, input:focus { + color: var(--bs-body-color) !important; + } + } + + .card { + background-color: var(--bs-body-bg); + + .card-header { + background-color: rgba(0, 0, 0, 0.12); + } + } + + .modal-content, .modal-header, .modal-body, .modal-footer { + background-color: var(--bs-body-bg); + border-color: var(--bs-border-color); + } + + app-tag .badge { + filter: brightness(.8); + } + + .doc-img { + mix-blend-mode: normal; + border-radius: 0; + border-color: var(--bs-border-color); + filter: invert(10%); + + &.border-end { + border-right: none !important; + } + } + + .doc-img.inverted { + filter: invert(95%) hue-rotate(180deg); + } + + .card-selected .doc-img { + mix-blend-mode: luminosity; + } + + .ng-dropdown-panel .ng-dropdown-panel-items .ng-option:hover, + .ng-dropdown-panel .ng-dropdown-panel-items .ng-option.ng-option-marked { + background-color: var(--bs-light); + } + + table { + .des, + .asc { + &::after { + filter: invert(0.8); /* arrow is a black inline png bkgd image (!) so use filter */ + } + } + + &.table-hover > tbody > tr:hover > * { + background-color: var(--bs-light); + color: var(--pngx-body-color-accent); + } + + } + + .alert-secondary { + background-color: var(--bs-light); + border-color: var(--pngx-bg-darker); + color: var(--bs-body-color); + } + + .table-striped > tbody > tr:nth-of-type(odd) > * { + color: var(--pngx-body-color-accent); + } + + .close, .modal .btn-close, .alert .btn-close { + text-shadow: 0 1px 0 #666; + } + + .modal .btn-close, .alert .btn-close, .toast .btn-close { + filter: invert(1) grayscale(100%) brightness(200%); + } + + .toast, .toast-header { + background-color: hsla(var(--pngx-primary), calc(var(--pngx-primary-lightness) - 15%), 0.8); + } + + .toast, + .toast .toast-header, + .toast .btn-close { + color: var(--pngx-primary-text-contrast); + } +} + +body.color-scheme-dark { + // no custom theme color + &:not(.primary-light):not(.primary-dark) { + @include paperless-green-dark-mode; + + .navbar.bg-primary { + // navbar is og green in dark mode + @include paperless-green; + } + } + + @include dark-mode; +} + +@media (prefers-color-scheme: dark) { + body.color-scheme-system { + // no custom theme color + &:not(.primary-light):not(.primary-dark) { + @include paperless-green-dark-mode; + + .navbar.bg-primary { + // navbar is og green in dark mode + @include paperless-green; + } + } + + @include dark-mode; + } } diff --git a/src-ui/src/theme_dark.scss b/src-ui/src/theme_dark.scss deleted file mode 100644 index b7355ade9..000000000 --- a/src-ui/src/theme_dark.scss +++ /dev/null @@ -1,454 +0,0 @@ -$primary-dark-mode: #45973a; -$danger-dark-mode: #b71631; -$bg-dark-mode: #161618; -$bg-dark-mode-accent: #21262d; -$bg-light-dark-mode: #1c1c1f; -$text-color-dark-mode: #abb2bf; -$text-color-dark-mode-accent: lighten($text-color-dark-mode, 10%); -$border-color-dark-mode: #47494f; - -* { - transition: background-color 0.3s ease, border-color 0.3s ease; -} - -@mixin dark-mode { - background-color: $bg-dark-mode !important; - color: $text-color-dark-mode; - - .navbar-brand { - color: $text-color-dark-mode; - } - - svg.logo { - .leaf { - color: $primary-dark-mode !important; - } - .text { - fill: $text-color-dark-mode !important; - } - } - - .bg-light { - background-color: $bg-light-dark-mode !important; - - a, - div { - color: $text-color-dark-mode; - } - } - - .bg-body { - background-color: $bg-dark-mode !important; - } - - .text-light { - color: $text-color-dark-mode !important; - } - - .border { - border-color: $border-color-dark-mode !important; - } - - .border-end { - border-right: 1px solid $border-color-dark-mode !important; - } - - .border-start { - border-left: 1px solid $border-color-dark-mode !important; - } - - .border-bottom { - border-bottom: 1px solid $border-color-dark-mode !important; - } - - .nav-link { - color: $text-color-dark-mode !important; - - &.active { - background-color: $bg-dark-mode; - color: $text-color-dark-mode; - border-color: $border-color-dark-mode $border-color-dark-mode $bg-dark-mode; - - .close { - background-color: inherit !important; - } - } - - &:hover { - color: $text-color-dark-mode-accent !important; - border-color: $border-color-dark-mode $border-color-dark-mode $bg-dark-mode; - } - } - - .page-item.active .page-link { - background-color: darken($primary-dark-mode, 10%); - } - - .nav-tabs { - border-color: $border-color-dark-mode; - - .nav-link { - color: $primary-dark-mode !important; - - &.active { - color: $text-color-dark-mode !important; - } - } - } - - .dropdown-menu { - background-color: $bg-light-dark-mode; - - .dropdown-divider { - border-color: $border-color-dark-mode; - } - - .dropdown-item { - color: $text-color-dark-mode; - - &:hover { - background-color: $bg-light-dark-mode; - color: $text-color-dark-mode; - } - } - - .dropdown-item.disabled { - color: darken($text-color-dark-mode, 20%); - } - } - - .card { - background-color: $bg-light-dark-mode; - - .card-text { - color: $text-color-dark-mode; - } - } - - .text-dark { - color: $text-color-dark-mode !important; - } - - .modal-content, .modal-header, .modal-body, .modal-footer { - background-color: $bg-light-dark-mode; - border-color: $border-color-dark-mode; - } - - app-tag .badge { - filter: brightness(.8); - } - - .badge-light { - background-color: darken($bg-dark-mode, 20%); - color: $text-color-dark-mode-accent; - } - - .badge.border-light { - border-color: $bg-dark-mode !important; - } - - .doc-img-container { - border: none !important; - border-top-left-radius: .25rem; - border-top-right-radius: .25rem; - overflow: hidden; - } - - .doc-img { - mix-blend-mode: normal; - border-radius: 0; - border-color: $bg-dark-mode; - filter: invert(10%); - &.border-end { - border-right: none !important; - } - } - - .doc-img.inverted { - filter: invert(95%) hue-rotate(180deg); - } - - .card-selected .doc-img { - mix-blend-mode: luminosity; - } - - .toast { - background-color: opacify($bg-light-dark-mode, .85); - } - - .toast-header { - background-color: opacify($bg-dark-mode, .85); - } - - a, - .card-title a { - color: $primary-dark-mode; - - &:hover { - color: lighten($primary, 10%); - } - } - - table { - background-color: $bg-dark-mode; - color: $text-color-dark-mode; - border-color: $border-color-dark-mode; - - .des, - .asc { - background-color: transparent !important; - color: $text-color-dark-mode; - border-color: $border-color-dark-mode; - - &::after { - filter: invert(0.8); /* arrow is a black inline png bkgd image (!) so use filter */ - } - } - - &.table-hover > tbody > tr:hover > * { - background-color: $bg-light-dark-mode; - color: $text-color-dark-mode-accent; - } - } - - .table td, - .table th { - border-color: $border-color-dark-mode; - } - - .table-row-selected { - background-color: $bg-light-dark-mode; - } - - .table-striped > tbody > tr:nth-of-type(odd) > * { - color: $text-color-dark-mode-accent; - } - - .close { - color: $text-color-dark-mode; - text-shadow: 0 1px 0 #666; - } - - .modal .btn-close { - color: $text-color-dark-mode; - text-shadow: 0 1px 0 #666; - filter: invert(1) grayscale(100%) brightness(200%); - } - - .btn-outline-primary { - border-color: $primary-dark-mode; - color: $primary-dark-mode; - - &:not(:disabled):not(.disabled).active, - &:not(:disabled):not(.disabled):hover { - background-color: darken($primary-dark-mode, 10%); - border-color: darken($primary-dark-mode, 10%); - color: $text-color-dark-mode-accent; - } - - &.disabled.active { - background-color: darken($primary-dark-mode, 10%); - } - } - - .btn-outline-secondary { - border-color: darken($text-color-dark-mode, 30%); - color: $text-color-dark-mode; - - &:not(:disabled):not(.disabled):hover { - background-color: $bg-dark-mode; - } - } - - .btn-outline-danger { - border-color: $danger-dark-mode; - color: $danger-dark-mode; - - &:not(:disabled):not(.disabled):hover { - background-color: darken($danger-dark-mode, 10%); - border-color: darken($danger-dark-mode, 10%); - color: $text-color-dark-mode-accent; - } - } - - .btn-outline-dark { - border-color: $border-color-dark-mode; - color: $text-color-dark-mode; - - &:not(:disabled):not(.disabled):hover { - color: $text-color-dark-mode-accent; - } - } - - .btn-light:not(:disabled):not(.disabled) { - background-color: $bg-dark-mode; - color: $text-color-dark-mode-accent; - - &:hover { - background-color: $text-color-dark-mode; - color: $bg-dark-mode; - } - } - - .btn-link:not(:disabled):not(.disabled) { - color: $primary-dark-mode; - } - - .btn-link:hover, - .btn-outline-primary:not(:disabled):not(.disabled).active, - .btn-outline-primary:not(:disabled):not(.disabled):active, - .show > .btn-outline-primary.dropdown-toggle { - color: $text-color-dark-mode-accent; - } - - button.bg-light:hover { - background-color: $bg-dark-mode !important; - } - - .card-footer button:hover { - color: $primary-dark-mode !important; - } - - .form-control:not(.is-invalid):not(.btn), - input:not(.is-invalid), - textarea:not(.is-invalid) { - border-color: $border-color-dark-mode; /* we dont want to override controls that get highlighting for errors */ - } - - .form-control:not(.btn), - input, - select, - textarea { - background-color: $bg-dark-mode; - color: $text-color-dark-mode; - - &::placeholder { - color: $text-color-dark-mode; - } - - &:focus { - background-color: $bg-light-dark-mode !important; - color: darken($text-color-dark-mode, 10%) !important; - } - } - - .form-select:not(.is-invalid):not(:disabled) { - border-color: $border-color-dark-mode; - } - - .ng-select-container, - .ng-select.ng-select-opened > .ng-select-container, - .ng-dropdown-panel, - .ng-dropdown-panel .ng-dropdown-panel-items .ng-option { - background-color: $bg-dark-mode; - color: $text-color-dark-mode; - border-color: $border-color-dark-mode; - - input:focus { - background-color: transparent !important; - } - } - - .ng-dropdown-panel .ng-dropdown-panel-items .ng-option:hover, - .ng-dropdown-panel .ng-dropdown-panel-items .ng-option.ng-option-marked { - background-color: $bg-light-dark-mode; - } - - .input-group-text { - color: $text-color-dark-mode; - background-color: $bg-light-dark-mode; - border-color: $border-color-dark-mode; - } - - .list-group-item { - color: $text-color-dark-mode; - background-color: $bg-light-dark-mode; - border-color: $border-color-dark-mode; - } - - .page-item.disabled .page-link { - background-color: $bg-dark-mode; - border-color: $border-color-dark-mode; - } - - .list-group-item, - .page-link { - background-color: $bg-light-dark-mode; - border-color: $border-color-dark-mode; - } - - .page-item.active .page-link { - border-color: $border-color-dark-mode; - color: $text-color-dark-mode-accent; - } - - .progress { - background-color: $border-color-dark-mode; - } - - .alert-danger { - color: $text-color-dark-mode-accent; - background-color: darken($danger-dark-mode, 20%); - border-color: darken($danger-dark-mode, 20%); - } - - .bg-dark { - background-color: $bg-light-dark-mode !important; - } - - .ngx-file-drop__drop-zone--over { - background-color: darken($primary-dark-mode, 35%) !important; - } - - .alert-secondary { - background-color: $bg-light-dark-mode; - border-color: darken($bg-light-dark-mode, 10%); - color: $text-color-dark-mode-accent; - } - - .progress-bar.bg-primary { - background-color: darken($primary-dark-mode, 5%) !important; - } - - .popover { - .popover-header, - .popover-body { - background-color: $bg-dark-mode-accent; - border-color: $border-color-dark-mode; - } - } - - // fix popover carat colors - .bs-popover-start > .popover-arrow::after, .bs-popover-auto[data-popper-placement^="left"] { - border-left-color: $bg-dark-mode-accent; - } - .bs-popover-end > .popover-arrow::after, .bs-popover-auto[data-popper-placement^="right"] { - border-right-color: $bg-dark-mode-accent; - } - .bs-popover-top > .popover-arrow::after, .bs-popover-auto[data-popper-placement^="top"] { - border-top-color: $bg-dark-mode-accent; - } - .bs-popover-bottom > .popover-arrow::after, .bs-popover-auto[data-popper-placement^="bottom"] { - border-bottom-color: $bg-dark-mode-accent; - } - - .bs-popover-bottom .popover-header::before, - .bs-popover-auto[x-placement^=bottom] .popover-header::before { - border-bottom-color: $bg-dark-mode-accent; - } - - .ngb-dp-header, - .ngb-dp-weekdays, - .ngb-dp-month { - background-color: $bg-light-dark-mode; - } -} - -body.color-scheme-dark { - @include dark-mode; -} -body.color-scheme-system { - @media (prefers-color-scheme: dark) { - @include dark-mode; - } -} diff --git a/src-ui/test-config.helper.ts b/src-ui/test-config.helper.ts new file mode 100644 index 000000000..f38cdfb26 --- /dev/null +++ b/src-ui/test-config.helper.ts @@ -0,0 +1,24 @@ +import { TestBed } from '@angular/core/testing' + +type CompilerOptions = Partial<{ + providers: any[] + useJit: boolean + preserveWhitespaces: boolean +}> +export type ConfigureFn = (testBed: typeof TestBed) => void + +export const configureTests = ( + configure: ConfigureFn, + compilerOptions: CompilerOptions = {} +) => { + const compilerConfig: CompilerOptions = { + preserveWhitespaces: false, + ...compilerOptions, + } + + const configuredTestBed = TestBed.configureCompiler(compilerConfig) + + configure(configuredTestBed) + + return configuredTestBed.compileComponents().then(() => configuredTestBed) +} diff --git a/src-ui/tsconfig.spec.json b/src-ui/tsconfig.spec.json index 092345b02..58c6bb3a6 100644 --- a/src-ui/tsconfig.spec.json +++ b/src-ui/tsconfig.spec.json @@ -1,14 +1,15 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ { "extends": "./tsconfig.json", "compilerOptions": { "outDir": "./out-tsc/spec", "types": [ - "jasmine" - ] + "jest" + ], + "module": "commonjs", + "emitDecoratorMetadata": true, + "allowJs": true }, "files": [ - "src/test.ts", "src/polyfills.ts" ], "include": [ diff --git a/src/documents/__init__.py b/src/documents/__init__.py index 5c9f358c3..dc94f2bdd 100644 --- a/src/documents/__init__.py +++ b/src/documents/__init__.py @@ -1,2 +1,5 @@ # this is here so that django finds the checks. -from .checks import * +from .checks import changed_password_check +from .checks import parser_check + +__all__ = ["changed_password_check", "parser_check"] diff --git a/src/documents/admin.py b/src/documents/admin.py index 88e2da50e..0551278ef 100644 --- a/src/documents/admin.py +++ b/src/documents/admin.py @@ -1,13 +1,11 @@ from django.contrib import admin -from .models import ( - Correspondent, - Document, - DocumentType, - Tag, - SavedView, - SavedViewFilterRule, -) +from .models import Correspondent +from .models import Document +from .models import DocumentType +from .models import SavedView +from .models import SavedViewFilterRule +from .models import Tag class CorrespondentAdmin(admin.ModelAdmin): diff --git a/src/documents/apps.py b/src/documents/apps.py index 0a59fef51..f4802532e 100644 --- a/src/documents/apps.py +++ b/src/documents/apps.py @@ -1,5 +1,4 @@ from django.apps import AppConfig - from django.utils.translation import gettext_lazy as _ diff --git a/src/documents/bulk_download.py b/src/documents/bulk_download.py index 11770968d..cf0b8949f 100644 --- a/src/documents/bulk_download.py +++ b/src/documents/bulk_download.py @@ -8,7 +8,10 @@ class BulkArchiveStrategy: self.zipf = zipf def make_unique_filename( - self, doc: Document, archive: bool = False, folder: str = "" + self, + doc: Document, + archive: bool = False, + folder: str = "", ): counter = 0 while True: @@ -34,7 +37,8 @@ class ArchiveOnlyStrategy(BulkArchiveStrategy): def add_document(self, doc: Document): if doc.has_archive_version: self.zipf.write( - doc.archive_path, self.make_unique_filename(doc, archive=True) + doc.archive_path, + self.make_unique_filename(doc, archive=True), ) else: self.zipf.write(doc.source_path, self.make_unique_filename(doc)) @@ -49,5 +53,6 @@ class OriginalAndArchiveStrategy(BulkArchiveStrategy): ) self.zipf.write( - doc.source_path, self.make_unique_filename(doc, folder="originals/") + doc.source_path, + self.make_unique_filename(doc, folder="originals/"), ) diff --git a/src/documents/bulk_edit.py b/src/documents/bulk_edit.py index 18ad04f2d..650138f1e 100644 --- a/src/documents/bulk_edit.py +++ b/src/documents/bulk_edit.py @@ -2,8 +2,9 @@ import itertools from django.db.models import Q from django_q.tasks import async_task - -from documents.models import Document, Correspondent, DocumentType +from documents.models import Correspondent +from documents.models import Document +from documents.models import DocumentType def set_correspondent(doc_ids, correspondent): @@ -40,7 +41,7 @@ def add_tag(doc_ids, tag): DocumentTagRelationship = Document.tags.through DocumentTagRelationship.objects.bulk_create( - [DocumentTagRelationship(document_id=doc, tag_id=tag) for doc in affected_docs] + [DocumentTagRelationship(document_id=doc, tag_id=tag) for doc in affected_docs], ) async_task("documents.tasks.bulk_update_documents", document_ids=affected_docs) @@ -56,7 +57,7 @@ def remove_tag(doc_ids, tag): DocumentTagRelationship = Document.tags.through DocumentTagRelationship.objects.filter( - Q(document_id__in=affected_docs) & Q(tag_id=tag) + Q(document_id__in=affected_docs) & Q(tag_id=tag), ).delete() async_task("documents.tasks.bulk_update_documents", document_ids=affected_docs) diff --git a/src/documents/checks.py b/src/documents/checks.py index fe3d89b12..4ac49a2c2 100644 --- a/src/documents/checks.py +++ b/src/documents/checks.py @@ -1,10 +1,11 @@ import textwrap from django.conf import settings -from django.core.checks import Error, register +from django.core.checks import Error +from django.core.checks import register from django.core.exceptions import FieldError -from django.db.utils import OperationalError, ProgrammingError - +from django.db.utils import OperationalError +from django.db.utils import ProgrammingError from documents.signals import document_consumer_declaration @@ -16,7 +17,7 @@ def changed_password_check(app_configs, **kwargs): try: encrypted_doc = Document.objects.filter( - storage_type=Document.STORAGE_TYPE_GPG + storage_type=Document.STORAGE_TYPE_GPG, ).first() except (OperationalError, ProgrammingError, FieldError): return [] # No documents table yet @@ -27,8 +28,8 @@ def changed_password_check(app_configs, **kwargs): return [ Error( "The database contains encrypted documents but no password " - "is set." - ) + "is set.", + ), ] if not GnuPG.decrypted(encrypted_doc.source_file): @@ -42,9 +43,9 @@ def changed_password_check(app_configs, **kwargs): If you intend to change your password, you must first export all of the old documents, start fresh with the new password and then re-import them." - """ - ) - ) + """, + ), + ), ] return [] @@ -61,8 +62,8 @@ def parser_check(app_configs, **kwargs): return [ Error( "No parsers found. This is a bug. The consumer won't be " - "able to consume any documents without parsers." - ) + "able to consume any documents without parsers.", + ), ] else: return [] diff --git a/src/documents/classifier.py b/src/documents/classifier.py index 195c934a9..be2256297 100644 --- a/src/documents/classifier.py +++ b/src/documents/classifier.py @@ -6,8 +6,8 @@ import re import shutil from django.conf import settings - -from documents.models import Document, MatchingModel +from documents.models import Document +from documents.models import MatchingModel class IncompatibleClassifierVersionError(Exception): @@ -30,8 +30,8 @@ def preprocess_content(content): def load_classifier(): if not os.path.isfile(settings.MODEL_FILE): logger.debug( - f"Document classification model does not exist (yet), not " - f"performing automatic matching." + "Document classification model does not exist (yet), not " + "performing automatic matching.", ) return None @@ -42,16 +42,16 @@ def load_classifier(): except (ClassifierModelCorruptError, IncompatibleClassifierVersionError): # there's something wrong with the model file. logger.exception( - f"Unrecoverable error while loading document " - f"classification model, deleting model file." + "Unrecoverable error while loading document " + "classification model, deleting model file.", ) os.unlink(settings.MODEL_FILE) classifier = None except OSError: - logger.exception(f"IO error while loading document classification model") + logger.exception("IO error while loading document classification model") classifier = None except Exception: - logger.exception(f"Unknown error while loading document classification model") + logger.exception("Unknown error while loading document classification model") classifier = None return classifier @@ -59,7 +59,8 @@ def load_classifier(): class DocumentClassifier(object): - FORMAT_VERSION = 6 + # v7 - Updated scikit-learn package version + FORMAT_VERSION = 7 def __init__(self): # hash of the training data. used to prevent re-training when the @@ -78,7 +79,7 @@ class DocumentClassifier(object): if schema_version != self.FORMAT_VERSION: raise IncompatibleClassifierVersionError( - "Cannor load classifier, incompatible versions." + "Cannot load classifier, incompatible versions.", ) else: try: @@ -122,8 +123,8 @@ class DocumentClassifier(object): logger.debug("Gathering data from database...") m = hashlib.sha1() for doc in Document.objects.order_by("pk").exclude( - tags__is_inbox_tag=True - ): # NOQA: E501 + tags__is_inbox_tag=True, + ): preprocessed_content = preprocess_content(doc.content) m.update(preprocessed_content.encode("utf-8")) data.append(preprocessed_content) @@ -146,9 +147,9 @@ class DocumentClassifier(object): [ tag.pk for tag in doc.tags.filter( - matching_algorithm=MatchingModel.MATCH_AUTO + matching_algorithm=MatchingModel.MATCH_AUTO, ) - ] + ], ) for tag in tags: m.update(tag.to_bytes(4, "little", signed=True)) @@ -177,8 +178,11 @@ class DocumentClassifier(object): logger.debug( "{} documents, {} tag(s), {} correspondent(s), " "{} document type(s).".format( - len(data), num_tags, num_correspondents, num_document_types - ) + len(data), + num_tags, + num_correspondents, + num_document_types, + ), ) from sklearn.feature_extraction.text import CountVectorizer @@ -188,7 +192,9 @@ class DocumentClassifier(object): # Step 2: vectorize data logger.debug("Vectorizing data...") self.data_vectorizer = CountVectorizer( - analyzer="word", ngram_range=(1, 2), min_df=0.01 + analyzer="word", + ngram_range=(1, 2), + min_df=0.01, ) data_vectorized = self.data_vectorizer.fit_transform(data) @@ -204,7 +210,7 @@ class DocumentClassifier(object): ] self.tags_binarizer = LabelBinarizer() labels_tags_vectorized = self.tags_binarizer.fit_transform( - labels_tags + labels_tags, ).ravel() else: self.tags_binarizer = MultiLabelBinarizer() @@ -223,7 +229,8 @@ class DocumentClassifier(object): else: self.correspondent_classifier = None logger.debug( - "There are no correspondents. Not training correspondent " "classifier." + "There are no correspondents. Not training correspondent " + "classifier.", ) if num_document_types > 0: @@ -233,7 +240,8 @@ class DocumentClassifier(object): else: self.document_type_classifier = None logger.debug( - "There are no document types. Not training document type " "classifier." + "There are no document types. Not training document type " + "classifier.", ) self.data_hash = new_data_hash diff --git a/src/documents/consumer.py b/src/documents/consumer.py index 0d246de26..4fe6b02ed 100644 --- a/src/documents/consumer.py +++ b/src/documents/consumer.py @@ -15,11 +15,19 @@ from filelock import FileLock from rest_framework.reverse import reverse from .classifier import load_classifier -from .file_handling import create_source_path_directory, generate_unique_filename +from .file_handling import create_source_path_directory +from .file_handling import generate_unique_filename from .loggers import LoggingMixin -from .models import Document, FileInfo, Correspondent, DocumentType, Tag -from .parsers import ParseError, get_parser_class_for_mime_type, parse_date -from .signals import document_consumption_finished, document_consumption_started +from .models import Correspondent +from .models import Document +from .models import DocumentType +from .models import FileInfo +from .models import Tag +from .parsers import get_parser_class_for_mime_type +from .parsers import parse_date +from .parsers import ParseError +from .signals import document_consumption_finished +from .signals import document_consumption_started class ConsumerError(Exception): @@ -46,12 +54,15 @@ class Consumer(LoggingMixin): logging_name = "paperless.consumer" def _send_progress( - self, current_progress, max_progress, status, message=None, document_id=None + self, + current_progress, + max_progress, + status, + message=None, + document_id=None, ): payload = { - "filename": os.path.basename(self.filename) - if self.filename - else None, # NOQA: E501 + "filename": os.path.basename(self.filename) if self.filename else None, "task_id": self.task_id, "current_progress": current_progress, "max_progress": max_progress, @@ -60,7 +71,8 @@ class Consumer(LoggingMixin): "document_id": document_id, } async_to_sync(self.channel_layer.group_send)( - "status_updates", {"type": "status_update", "data": payload} + "status_updates", + {"type": "status_update", "data": payload}, ) def _fail(self, message, log_message=None, exc_info=None): @@ -83,15 +95,16 @@ class Consumer(LoggingMixin): def pre_check_file_exists(self): if not os.path.isfile(self.path): self._fail( - MESSAGE_FILE_NOT_FOUND, f"Cannot consume {self.path}: File not found." + MESSAGE_FILE_NOT_FOUND, + f"Cannot consume {self.path}: File not found.", ) def pre_check_duplicate(self): with open(self.path, "rb") as f: checksum = hashlib.md5(f.read()).hexdigest() if Document.objects.filter( - Q(checksum=checksum) | Q(archive_checksum=checksum) - ).exists(): # NOQA: E501 + Q(checksum=checksum) | Q(archive_checksum=checksum), + ).exists(): if settings.CONSUMER_DELETE_DUPLICATES: os.unlink(self.path) self._fail( @@ -139,7 +152,8 @@ class Consumer(LoggingMixin): ) self.log( - "info", f"Executing post-consume script {settings.POST_CONSUME_SCRIPT}" + "info", + f"Executing post-consume script {settings.POST_CONSUME_SCRIPT}", ) try: @@ -154,7 +168,7 @@ class Consumer(LoggingMixin): reverse("document-thumb", kwargs={"pk": document.pk}), str(document.correspondent), str(",".join(document.tags.all().values_list("name", flat=True))), - ) + ), ).wait() except Exception as e: self._fail( @@ -213,7 +227,9 @@ class Consumer(LoggingMixin): # Notify all listeners that we're going to do some work. document_consumption_started.send( - sender=self.__class__, filename=self.path, logging_group=self.logging_group + sender=self.__class__, + filename=self.path, + logging_group=self.logging_group, ) self.run_pre_consume_script() @@ -247,7 +263,9 @@ class Consumer(LoggingMixin): self.log("debug", f"Generating thumbnail for {self.filename}...") self._send_progress(70, 100, "WORKING", MESSAGE_GENERATING_THUMBNAIL) thumbnail = document_parser.get_optimised_thumbnail( - self.path, mime_type, self.filename + self.path, + mime_type, + self.filename, ) text = document_parser.get_text() @@ -301,21 +319,26 @@ class Consumer(LoggingMixin): self._write(document.storage_type, self.path, document.source_path) self._write( - document.storage_type, thumbnail, document.thumbnail_path + document.storage_type, + thumbnail, + document.thumbnail_path, ) if archive_path and os.path.isfile(archive_path): document.archive_filename = generate_unique_filename( - document, archive_filename=True + document, + archive_filename=True, ) create_source_path_directory(document.archive_path) self._write( - document.storage_type, archive_path, document.archive_path + document.storage_type, + archive_path, + document.archive_path, ) with open(archive_path, "rb") as f: document.archive_checksum = hashlib.md5( - f.read() + f.read(), ).hexdigest() # Don't save with the lock active. Saving will cause the file @@ -328,7 +351,8 @@ class Consumer(LoggingMixin): # https://github.com/jonaswinkler/paperless-ng/discussions/1037 shadow_file = os.path.join( - os.path.dirname(self.path), "._" + os.path.basename(self.path) + os.path.dirname(self.path), + "._" + os.path.basename(self.path), ) if os.path.isfile(shadow_file): @@ -390,12 +414,12 @@ class Consumer(LoggingMixin): def apply_overrides(self, document): if self.override_correspondent_id: document.correspondent = Correspondent.objects.get( - pk=self.override_correspondent_id + pk=self.override_correspondent_id, ) if self.override_document_type_id: document.document_type = DocumentType.objects.get( - pk=self.override_document_type_id + pk=self.override_document_type_id, ) if self.override_tag_ids: diff --git a/src/documents/file_handling.py b/src/documents/file_handling.py index 390643357..132825e0e 100644 --- a/src/documents/file_handling.py +++ b/src/documents/file_handling.py @@ -103,15 +103,17 @@ def generate_unique_filename(doc, archive_filename=False): if archive_filename and doc.filename: new_filename = os.path.splitext(doc.filename)[0] + ".pdf" if new_filename == old_filename or not os.path.exists( - os.path.join(root, new_filename) - ): # NOQA: E501 + os.path.join(root, new_filename), + ): return new_filename counter = 0 while True: new_filename = generate_filename( - doc, counter, archive_filename=archive_filename + doc, + counter, + archive_filename=archive_filename, ) if new_filename == old_filename: # still the same as before. @@ -137,14 +139,16 @@ def generate_filename(doc, counter=0, append_gpg=True, archive_filename=False): if doc.correspondent: correspondent = pathvalidate.sanitize_filename( - doc.correspondent.name, replacement_text="-" + doc.correspondent.name, + replacement_text="-", ) else: correspondent = "none" if doc.document_type: document_type = pathvalidate.sanitize_filename( - doc.document_type.name, replacement_text="-" + doc.document_type.name, + replacement_text="-", ) else: document_type = "none" @@ -160,9 +164,7 @@ def generate_filename(doc, counter=0, append_gpg=True, archive_filename=False): document_type=document_type, created=datetime.date.isoformat(doc.created), created_year=doc.created.year if doc.created else "none", - created_month=f"{doc.created.month:02}" - if doc.created - else "none", # NOQA: E501 + created_month=f"{doc.created.month:02}" if doc.created else "none", created_day=f"{doc.created.day:02}" if doc.created else "none", added=datetime.date.isoformat(doc.added), added_year=doc.added.year if doc.added else "none", @@ -178,7 +180,7 @@ def generate_filename(doc, counter=0, append_gpg=True, archive_filename=False): except (ValueError, KeyError, IndexError): logger.warning( f"Invalid PAPERLESS_FILENAME_FORMAT: " - f"{settings.PAPERLESS_FILENAME_FORMAT}, falling back to default" + f"{settings.PAPERLESS_FILENAME_FORMAT}, falling back to default", ) counter_str = f"_{counter:02}" if counter else "" diff --git a/src/documents/filters.py b/src/documents/filters.py index 7075eb3d0..6451bea35 100644 --- a/src/documents/filters.py +++ b/src/documents/filters.py @@ -1,7 +1,13 @@ from django.db.models import Q -from django_filters.rest_framework import BooleanFilter, FilterSet, Filter +from django_filters.rest_framework import BooleanFilter +from django_filters.rest_framework import Filter +from django_filters.rest_framework import FilterSet -from .models import Correspondent, Document, Tag, DocumentType, Log +from .models import Correspondent +from .models import Document +from .models import DocumentType +from .models import Log +from .models import Tag CHAR_KWARGS = ["istartswith", "iendswith", "icontains", "iexact"] ID_KWARGS = ["in", "exact"] @@ -75,7 +81,10 @@ class TitleContentFilter(Filter): class DocumentFilterSet(FilterSet): is_tagged = BooleanFilter( - label="Is tagged", field_name="tags", lookup_expr="isnull", exclude=True + label="Is tagged", + field_name="tags", + lookup_expr="isnull", + exclude=True, ) tags__id__all = TagsFilter() diff --git a/src/documents/index.py b/src/documents/index.py index 2c708105c..cc95f2a96 100644 --- a/src/documents/index.py +++ b/src/documents/index.py @@ -1,21 +1,30 @@ import logging +import math import os from contextlib import contextmanager -import math from dateutil.parser import isoparse from django.conf import settings -from whoosh import highlight, classify, query -from whoosh.fields import Schema, TEXT, NUMERIC, KEYWORD, DATETIME, BOOLEAN +from documents.models import Document +from whoosh import classify +from whoosh import highlight +from whoosh import query +from whoosh.fields import BOOLEAN +from whoosh.fields import DATETIME +from whoosh.fields import KEYWORD +from whoosh.fields import NUMERIC +from whoosh.fields import Schema +from whoosh.fields import TEXT from whoosh.highlight import HtmlFormatter -from whoosh.index import create_in, exists_in, open_dir +from whoosh.index import create_in +from whoosh.index import exists_in +from whoosh.index import open_dir from whoosh.qparser import MultifieldParser from whoosh.qparser.dateparse import DateParserPlugin -from whoosh.searching import ResultsPage, Searcher +from whoosh.searching import ResultsPage +from whoosh.searching import Searcher from whoosh.writing import AsyncWriter -from documents.models import Document - logger = logging.getLogger("paperless.index") @@ -45,7 +54,7 @@ def open_index(recreate=False): if exists_in(settings.INDEX_DIR) and not recreate: return open_dir(settings.INDEX_DIR, schema=get_schema()) except Exception: - logger.exception(f"Error while opening the index, recreating.") + logger.exception("Error while opening the index, recreating.") if not os.path.isdir(settings.INDEX_DIR): os.makedirs(settings.INDEX_DIR, exist_ok=True) @@ -138,11 +147,11 @@ class DelayedQuery: criterias.append(query.Term("has_type", v == "false")) elif k == "created__date__lt": criterias.append( - query.DateRange("created", start=None, end=isoparse(v)) + query.DateRange("created", start=None, end=isoparse(v)), ) elif k == "created__date__gt": criterias.append( - query.DateRange("created", start=isoparse(v), end=None) + query.DateRange("created", start=isoparse(v), end=None), ) elif k == "added__date__gt": criterias.append(query.DateRange("added", start=isoparse(v), end=None)) @@ -220,7 +229,7 @@ class DelayedQuery: hit[1], ), page.results.top_n, - ) + ), ) self.saved_results[item.start] = page @@ -240,7 +249,7 @@ class DelayedFullTextQuery(DelayedQuery): corrected = self.searcher.correct_query(q, q_str) if corrected.query != q: - corrected_query = corrected.string + corrected.query = corrected.string return q, None @@ -252,10 +261,14 @@ class DelayedMoreLikeThisQuery(DelayedQuery): docnum = self.searcher.document_number(id=more_like_doc_id) kts = self.searcher.key_terms_from_text( - "content", content, numterms=20, model=classify.Bo1Model, normalize=False + "content", + content, + numterms=20, + model=classify.Bo1Model, + normalize=False, ) q = query.Or( - [query.Term("content", word, boost=weight) for word, weight in kts] + [query.Term("content", word, boost=weight) for word, weight in kts], ) mask = {docnum} @@ -266,7 +279,9 @@ def autocomplete(ix, term, limit=10): with ix.reader() as reader: terms = [] for (score, t) in reader.most_distinctive_terms( - "content", number=limit, prefix=term.lower() + "content", + number=limit, + prefix=term.lower(), ): terms.append(t) return terms diff --git a/src/documents/loggers.py b/src/documents/loggers.py index 78a2f3692..0dd109277 100644 --- a/src/documents/loggers.py +++ b/src/documents/loggers.py @@ -1,8 +1,6 @@ import logging import uuid -from django.conf import settings - class LoggingMixin: diff --git a/src/documents/management/commands/decrypt_documents.py b/src/documents/management/commands/decrypt_documents.py index 38b49b489..861bfa2cc 100644 --- a/src/documents/management/commands/decrypt_documents.py +++ b/src/documents/management/commands/decrypt_documents.py @@ -1,8 +1,8 @@ import os from django.conf import settings -from django.core.management.base import BaseCommand, CommandError - +from django.core.management.base import BaseCommand +from django.core.management.base import CommandError from documents.models import Document from paperless.db import GnuPG @@ -31,9 +31,9 @@ class Command(BaseCommand): "this unless you've got a recent backup\nWARNING: handy. It " "*should* work without a hitch, but be safe and backup your\n" "WARNING: stuff first.\n\nHit Ctrl+C to exit now, or Enter to " - "continue.\n\n" + "continue.\n\n", ) - __ = input() + _ = input() except KeyboardInterrupt: return @@ -41,7 +41,7 @@ class Command(BaseCommand): if not passphrase: raise CommandError( "Passphrase not defined. Please set it with --passphrase or " - "by declaring it in your environment or your config." + "by declaring it in your environment or your config.", ) self.__gpg_to_unencrypted(passphrase) @@ -50,7 +50,7 @@ class Command(BaseCommand): def __gpg_to_unencrypted(passphrase): encrypted_files = Document.objects.filter( - storage_type=Document.STORAGE_TYPE_GPG + storage_type=Document.STORAGE_TYPE_GPG, ) for document in encrypted_files: @@ -59,8 +59,10 @@ class Command(BaseCommand): old_paths = [document.source_path, document.thumbnail_path] - raw_document = GnuPG.decrypted(document.source_file, passphrase) - raw_thumb = GnuPG.decrypted(document.thumbnail_file, passphrase) + with document.source_file as file_handle: + raw_document = GnuPG.decrypted(file_handle, passphrase) + with document.thumbnail_file as file_handle: + raw_thumb = GnuPG.decrypted(file_handle, passphrase) document.storage_type = Document.STORAGE_TYPE_UNENCRYPTED @@ -69,7 +71,7 @@ class Command(BaseCommand): if not ext == ".gpg": raise CommandError( f"Abort: encrypted file {document.source_path} does not " - f"end with .gpg" + f"end with .gpg", ) document.filename = os.path.splitext(document.filename)[0] @@ -81,7 +83,8 @@ class Command(BaseCommand): f.write(raw_thumb) Document.objects.filter(id=document.id).update( - storage_type=document.storage_type, filename=document.filename + storage_type=document.storage_type, + filename=document.filename, ) for path in old_paths: diff --git a/src/documents/management/commands/document_archiver.py b/src/documents/management/commands/document_archiver.py index 7b1f989f8..f33ccd7ce 100644 --- a/src/documents/management/commands/document_archiver.py +++ b/src/documents/management/commands/document_archiver.py @@ -1,7 +1,6 @@ import hashlib -import multiprocessing - import logging +import multiprocessing import os import shutil import uuid @@ -11,12 +10,12 @@ from django import db from django.conf import settings from django.core.management.base import BaseCommand from django.db import transaction -from filelock import FileLock -from whoosh.writing import AsyncWriter - from documents.models import Document +from filelock import FileLock + from ... import index -from ...file_handling import create_source_path_directory, generate_unique_filename +from ...file_handling import create_source_path_directory +from ...file_handling import generate_unique_filename from ...parsers import get_parser_class_for_mime_type @@ -33,7 +32,7 @@ def handle_document(document_id): if not parser_class: logger.error( f"No parser found for mime type {mime_type}, cannot " - f"archive document {document} (ID: {document_id})" + f"archive document {document} (ID: {document_id})", ) return @@ -43,7 +42,9 @@ def handle_document(document_id): parser.parse(document.source_path, mime_type, document.get_public_filename()) thumbnail = parser.get_optimised_thumbnail( - document.source_path, mime_type, document.get_public_filename() + document.source_path, + mime_type, + document.get_public_filename(), ) if parser.get_archive_path(): @@ -55,7 +56,8 @@ def handle_document(document_id): # We also don't use save() since that triggers the filehandling # logic, and we don't want that yet (file not yet in place) document.archive_filename = generate_unique_filename( - document, archive_filename=True + document, + archive_filename=True, ) Document.objects.filter(pk=document.pk).update( archive_checksum=checksum, @@ -70,9 +72,9 @@ def handle_document(document_id): with index.open_index_writer() as writer: index.update_document(writer, document) - except Exception as e: + except Exception: logger.exception( - f"Error while parsing document {document} " f"(ID: {document_id})" + f"Error while parsing document {document} " f"(ID: {document_id})", ) finally: parser.cleanup() @@ -86,7 +88,8 @@ class Command(BaseCommand): back-tag all previously indexed documents with metadata created (or modified) after their initial import. """.replace( - " ", "" + " ", + "", ) def add_arguments(self, parser): @@ -129,7 +132,7 @@ class Command(BaseCommand): map( lambda doc: doc.id, filter(lambda d: overwrite or not d.has_archive_version, documents), - ) + ), ) # Note to future self: this prevents django from reusing database @@ -146,7 +149,7 @@ class Command(BaseCommand): pool.imap_unordered(handle_document, document_ids), total=len(document_ids), disable=options["no_progress_bar"], - ) + ), ) except KeyboardInterrupt: print("Aborting...") diff --git a/src/documents/management/commands/document_consumer.py b/src/documents/management/commands/document_consumer.py index c35594b8c..eb6f0a405 100644 --- a/src/documents/management/commands/document_consumer.py +++ b/src/documents/management/commands/document_consumer.py @@ -1,17 +1,20 @@ import logging import os -from pathlib import Path, PurePath +from pathlib import Path +from pathlib import PurePath from threading import Thread +from time import monotonic from time import sleep +from typing import Final from django.conf import settings -from django.core.management.base import BaseCommand, CommandError +from django.core.management.base import BaseCommand +from django.core.management.base import CommandError from django_q.tasks import async_task -from watchdog.events import FileSystemEventHandler -from watchdog.observers.polling import PollingObserver - from documents.models import Tag from documents.parsers import is_file_ext_supported +from watchdog.events import FileSystemEventHandler +from watchdog.observers.polling import PollingObserver try: from inotifyrecursive import INotify, flags @@ -29,7 +32,7 @@ def _tags_from_path(filepath): path_parts = Path(filepath).relative_to(settings.CONSUMPTION_DIR).parent.parts for part in path_parts: tag_ids.add( - Tag.objects.get_or_create(name__iexact=part, defaults={"name": part})[0].pk + Tag.objects.get_or_create(name__iexact=part, defaults={"name": part})[0].pk, ) return tag_ids @@ -52,11 +55,30 @@ def _consume(filepath): logger.warning(f"Not consuming file {filepath}: Unknown file extension.") return + # Total wait time: up to 500ms + os_error_retry_count: Final[int] = 50 + os_error_retry_wait: Final[float] = 0.01 + + read_try_count = 0 + file_open_ok = False + + while (read_try_count < os_error_retry_count) and not file_open_ok: + try: + with open(filepath, "rb"): + file_open_ok = True + except OSError: + read_try_count += 1 + sleep(os_error_retry_wait) + + if read_try_count >= os_error_retry_count: + logger.warning(f"Not consuming file {filepath}: OS reports file as busy still") + return + tag_ids = None try: if settings.CONSUMER_SUBDIRS_AS_TAGS: tag_ids = _tags_from_path(filepath) - except Exception as e: + except Exception: logger.exception("Error creating tags from path") try: @@ -67,7 +89,7 @@ def _consume(filepath): override_tag_ids=tag_ids if tag_ids else None, task_name=os.path.basename(filepath)[:100], ) - except Exception as e: + except Exception: # Catch all so that the consumer won't crash. # This is also what the test case is listening for to check for # errors. @@ -80,19 +102,23 @@ def _consume_wait_unmodified(file): logger.debug(f"Waiting for file {file} to remain unmodified") mtime = -1 + size = -1 current_try = 0 while current_try < settings.CONSUMER_POLLING_RETRY_COUNT: try: - new_mtime = os.stat(file).st_mtime + stat_data = os.stat(file) + new_mtime = stat_data.st_mtime + new_size = stat_data.st_size except FileNotFoundError: logger.debug( - f"File {file} moved while waiting for it to remain " f"unmodified." + f"File {file} moved while waiting for it to remain " f"unmodified.", ) return - if new_mtime == mtime: + if new_mtime == mtime and new_size == size: _consume(file) return mtime = new_mtime + size = new_size sleep(settings.CONSUMER_POLLING_DELAY) current_try += 1 @@ -181,14 +207,32 @@ class Command(BaseCommand): descriptor = inotify.add_watch(directory, inotify_flags) try: + + inotify_debounce: Final[float] = 0.5 + notified_files = {} + while not self.stop_flag: + for event in inotify.read(timeout=1000): if recursive: path = inotify.get_path(event.wd) else: path = directory filepath = os.path.join(path, event.name) - _consume(filepath) + notified_files[filepath] = monotonic() + + # Check the files against the timeout + still_waiting = {} + for filepath in notified_files: + # Time of the last inotify event for this file + last_event_time = notified_files[filepath] + if (monotonic() - last_event_time) > inotify_debounce: + _consume(filepath) + else: + still_waiting[filepath] = last_event_time + # These files are still waiting to hit the timeout + notified_files = still_waiting + except KeyboardInterrupt: pass diff --git a/src/documents/management/commands/document_create_classifier.py b/src/documents/management/commands/document_create_classifier.py index 6ad3ee9f5..9610d50a0 100644 --- a/src/documents/management/commands/document_create_classifier.py +++ b/src/documents/management/commands/document_create_classifier.py @@ -9,7 +9,8 @@ class Command(BaseCommand): Trains the classifier on your data and saves the resulting models to a file. The document consumer will then automatically use this new model. """.replace( - " ", "" + " ", + "", ) def __init__(self, *args, **kwargs): diff --git a/src/documents/management/commands/document_exporter.py b/src/documents/management/commands/document_exporter.py index d2b6f8e32..b110475a5 100644 --- a/src/documents/management/commands/document_exporter.py +++ b/src/documents/management/commands/document_exporter.py @@ -6,28 +6,28 @@ import time import tqdm from django.conf import settings -from django.contrib.auth.models import User, Group +from django.contrib.auth.models import Group +from django.contrib.auth.models import User from django.core import serializers -from django.core.management.base import BaseCommand, CommandError +from django.core.management.base import BaseCommand +from django.core.management.base import CommandError from django.db import transaction +from documents.models import Correspondent +from documents.models import Document +from documents.models import DocumentType +from documents.models import SavedView +from documents.models import SavedViewFilterRule +from documents.models import Tag +from documents.settings import EXPORTER_ARCHIVE_NAME +from documents.settings import EXPORTER_FILE_NAME +from documents.settings import EXPORTER_THUMBNAIL_NAME from filelock import FileLock - -from documents.models import ( - Document, - Correspondent, - Tag, - DocumentType, - SavedView, - SavedViewFilterRule, -) -from documents.settings import ( - EXPORTER_FILE_NAME, - EXPORTER_THUMBNAIL_NAME, - EXPORTER_ARCHIVE_NAME, -) from paperless.db import GnuPG -from paperless_mail.models import MailAccount, MailRule -from ...file_handling import generate_filename, delete_empty_directories +from paperless_mail.models import MailAccount +from paperless_mail.models import MailRule + +from ...file_handling import delete_empty_directories +from ...file_handling import generate_filename class Command(BaseCommand): @@ -37,7 +37,8 @@ class Command(BaseCommand): directory. And include a manifest file containing document data for easy import. """.replace( - " ", "" + " ", + "", ) def add_arguments(self, parser): @@ -107,20 +108,20 @@ class Command(BaseCommand): # 1. Take a snapshot of what files exist in the current export folder for root, dirs, files in os.walk(self.target): self.files_in_export_dir.extend( - map(lambda f: os.path.abspath(os.path.join(root, f)), files) + map(lambda f: os.path.abspath(os.path.join(root, f)), files), ) # 2. Create manifest, containing all correspondents, types, tags and # documents with transaction.atomic(): manifest = json.loads( - serializers.serialize("json", Correspondent.objects.all()) + serializers.serialize("json", Correspondent.objects.all()), ) manifest += json.loads(serializers.serialize("json", Tag.objects.all())) manifest += json.loads( - serializers.serialize("json", DocumentType.objects.all()) + serializers.serialize("json", DocumentType.objects.all()), ) documents = Document.objects.order_by("id") @@ -129,19 +130,19 @@ class Command(BaseCommand): manifest += document_manifest manifest += json.loads( - serializers.serialize("json", MailAccount.objects.all()) + serializers.serialize("json", MailAccount.objects.all()), ) manifest += json.loads( - serializers.serialize("json", MailRule.objects.all()) + serializers.serialize("json", MailRule.objects.all()), ) manifest += json.loads( - serializers.serialize("json", SavedView.objects.all()) + serializers.serialize("json", SavedView.objects.all()), ) manifest += json.loads( - serializers.serialize("json", SavedViewFilterRule.objects.all()) + serializers.serialize("json", SavedViewFilterRule.objects.all()), ) manifest += json.loads(serializers.serialize("json", Group.objects.all())) @@ -155,9 +156,7 @@ class Command(BaseCommand): disable=progress_bar_disable, ): # 3.1. store files unencrypted - document_dict["fields"][ - "storage_type" - ] = Document.STORAGE_TYPE_UNENCRYPTED # NOQA: E501 + document_dict["fields"]["storage_type"] = Document.STORAGE_TYPE_UNENCRYPTED document = document_map[document_dict["pk"]] @@ -166,7 +165,9 @@ class Command(BaseCommand): while True: if self.use_filename_format: base_name = generate_filename( - document, counter=filename_counter, append_gpg=False + document, + counter=filename_counter, + append_gpg=False, ) else: base_name = document.get_public_filename(counter=filename_counter) @@ -199,29 +200,36 @@ class Command(BaseCommand): os.makedirs(os.path.dirname(original_target), exist_ok=True) with open(original_target, "wb") as f: - f.write(GnuPG.decrypted(document.source_file)) - os.utime(original_target, times=(t, t)) + with document.source_file as out_file: + f.write(GnuPG.decrypted(out_file)) + os.utime(original_target, times=(t, t)) os.makedirs(os.path.dirname(thumbnail_target), exist_ok=True) with open(thumbnail_target, "wb") as f: - f.write(GnuPG.decrypted(document.thumbnail_file)) - os.utime(thumbnail_target, times=(t, t)) + with document.thumbnail_file as out_file: + f.write(GnuPG.decrypted(out_file)) + os.utime(thumbnail_target, times=(t, t)) if archive_target: os.makedirs(os.path.dirname(archive_target), exist_ok=True) with open(archive_target, "wb") as f: - f.write(GnuPG.decrypted(document.archive_path)) - os.utime(archive_target, times=(t, t)) + with document.archive_path as out_file: + f.write(GnuPG.decrypted(out_file)) + os.utime(archive_target, times=(t, t)) else: self.check_and_copy( - document.source_path, document.checksum, original_target + document.source_path, + document.checksum, + original_target, ) self.check_and_copy(document.thumbnail_path, None, thumbnail_target) if archive_target: self.check_and_copy( - document.archive_path, document.archive_checksum, archive_target + document.archive_path, + document.archive_checksum, + archive_target, ) # 4. write manifest to target forlder @@ -240,7 +248,8 @@ class Command(BaseCommand): os.remove(f) delete_empty_directories( - os.path.abspath(os.path.dirname(f)), os.path.abspath(self.target) + os.path.abspath(os.path.dirname(f)), + os.path.abspath(self.target), ) def check_and_copy(self, source, source_checksum, target): diff --git a/src/documents/management/commands/document_importer.py b/src/documents/management/commands/document_importer.py index 9d77c1033..d1ae33afb 100644 --- a/src/documents/management/commands/document_importer.py +++ b/src/documents/management/commands/document_importer.py @@ -7,16 +7,16 @@ from contextlib import contextmanager import tqdm from django.conf import settings from django.core.management import call_command -from django.core.management.base import BaseCommand, CommandError -from django.db.models.signals import post_save, m2m_changed +from django.core.management.base import BaseCommand +from django.core.management.base import CommandError +from django.db.models.signals import m2m_changed +from django.db.models.signals import post_save +from documents.models import Document +from documents.settings import EXPORTER_ARCHIVE_NAME +from documents.settings import EXPORTER_FILE_NAME +from documents.settings import EXPORTER_THUMBNAIL_NAME from filelock import FileLock -from documents.models import Document -from documents.settings import ( - EXPORTER_FILE_NAME, - EXPORTER_THUMBNAIL_NAME, - EXPORTER_ARCHIVE_NAME, -) from ...file_handling import create_source_path_directory from ...signals.handlers import update_filename_and_move_files @@ -36,7 +36,8 @@ class Command(BaseCommand): Using a manifest.json file, load the data from there, and import the documents it refers to. """.replace( - " ", "" + " ", + "", ) def add_arguments(self, parser): @@ -73,7 +74,9 @@ class Command(BaseCommand): self._check_manifest() with disable_signal( - post_save, receiver=update_filename_and_move_files, sender=Document + post_save, + receiver=update_filename_and_move_files, + sender=Document, ): with disable_signal( m2m_changed, @@ -92,7 +95,7 @@ class Command(BaseCommand): def _check_manifest_exists(path): if not os.path.exists(path): raise CommandError( - "That directory doesn't appear to contain a manifest.json " "file." + "That directory doesn't appear to contain a manifest.json " "file.", ) def _check_manifest(self): @@ -105,14 +108,14 @@ class Command(BaseCommand): if EXPORTER_FILE_NAME not in record: raise CommandError( "The manifest file contains a record which does not " - "refer to an actual document file." + "refer to an actual document file.", ) doc_file = record[EXPORTER_FILE_NAME] if not os.path.exists(os.path.join(self.source, doc_file)): raise CommandError( 'The manifest file refers to "{}" which does not ' - "appear to be in the source directory.".format(doc_file) + "appear to be in the source directory.".format(doc_file), ) if EXPORTER_ARCHIVE_NAME in record: @@ -120,7 +123,7 @@ class Command(BaseCommand): if not os.path.exists(os.path.join(self.source, archive_file)): raise CommandError( f"The manifest file refers to {archive_file} which " - f"does not appear to be in the source directory." + f"does not appear to be in the source directory.", ) def _import_files_from_manifest(self, progress_bar_disable): @@ -132,7 +135,7 @@ class Command(BaseCommand): print("Copy files into paperless...") manifest_documents = list( - filter(lambda r: r["model"] == "documents.document", self.manifest) + filter(lambda r: r["model"] == "documents.document", self.manifest), ) for record in tqdm.tqdm(manifest_documents, disable=progress_bar_disable): diff --git a/src/documents/management/commands/document_index.py b/src/documents/management/commands/document_index.py index 3dd4d84ff..cf7eb65e5 100644 --- a/src/documents/management/commands/document_index.py +++ b/src/documents/management/commands/document_index.py @@ -1,7 +1,7 @@ from django.core.management import BaseCommand from django.db import transaction - -from documents.tasks import index_reindex, index_optimize +from documents.tasks import index_optimize +from documents.tasks import index_reindex class Command(BaseCommand): diff --git a/src/documents/management/commands/document_renamer.py b/src/documents/management/commands/document_renamer.py index 221fb4208..79c46f905 100644 --- a/src/documents/management/commands/document_renamer.py +++ b/src/documents/management/commands/document_renamer.py @@ -3,7 +3,6 @@ import logging import tqdm from django.core.management.base import BaseCommand from django.db.models.signals import post_save - from documents.models import Document @@ -12,7 +11,8 @@ class Command(BaseCommand): help = """ This will rename all documents to match the latest filename format. """.replace( - " ", "" + " ", + "", ) def add_arguments(self, parser): @@ -28,6 +28,7 @@ class Command(BaseCommand): logging.getLogger().handlers[0].level = logging.ERROR for document in tqdm.tqdm( - Document.objects.all(), disable=options["no_progress_bar"] + Document.objects.all(), + disable=options["no_progress_bar"], ): post_save.send(Document, instance=document) diff --git a/src/documents/management/commands/document_retagger.py b/src/documents/management/commands/document_retagger.py index fcf9e3478..5ecf7f8ce 100644 --- a/src/documents/management/commands/document_retagger.py +++ b/src/documents/management/commands/document_retagger.py @@ -2,10 +2,12 @@ import logging import tqdm from django.core.management.base import BaseCommand - from documents.classifier import load_classifier from documents.models import Document -from ...signals.handlers import set_correspondent, set_document_type, set_tags + +from ...signals.handlers import set_correspondent +from ...signals.handlers import set_document_type +from ...signals.handlers import set_tags logger = logging.getLogger("paperless.management.retagger") @@ -19,7 +21,8 @@ class Command(BaseCommand): back-tag all previously indexed documents with metadata created (or modified) after their initial import. """.replace( - " ", "" + " ", + "", ) def add_arguments(self, parser): @@ -57,7 +60,8 @@ class Command(BaseCommand): help="Return the suggestion, don't change anything.", ) parser.add_argument( - "--base-url", help="The base URL to use to build the link to the documents." + "--base-url", + help="The base URL to use to build the link to the documents.", ) def handle(self, *args, **options): diff --git a/src/documents/management/commands/document_sanity_checker.py b/src/documents/management/commands/document_sanity_checker.py index 54691fefe..27c119863 100644 --- a/src/documents/management/commands/document_sanity_checker.py +++ b/src/documents/management/commands/document_sanity_checker.py @@ -7,7 +7,8 @@ class Command(BaseCommand): help = """ This command checks your document archive for issues. """.replace( - " ", "" + " ", + "", ) def add_arguments(self, parser): diff --git a/src/documents/management/commands/document_thumbnails.py b/src/documents/management/commands/document_thumbnails.py index 9e2893b5f..c9928c7cc 100644 --- a/src/documents/management/commands/document_thumbnails.py +++ b/src/documents/management/commands/document_thumbnails.py @@ -5,8 +5,8 @@ import shutil import tqdm from django import db from django.core.management.base import BaseCommand - from documents.models import Document + from ...parsers import get_parser_class_for_mime_type @@ -22,7 +22,9 @@ def _process_document(doc_in): try: thumb = parser.get_optimised_thumbnail( - document.source_path, document.mime_type, document.get_public_filename() + document.source_path, + document.mime_type, + document.get_public_filename(), ) shutil.move(thumb, document.thumbnail_path) @@ -35,7 +37,8 @@ class Command(BaseCommand): help = """ This will regenerate the thumbnails for all documents. """.replace( - " ", "" + " ", + "", ) def add_arguments(self, parser): @@ -76,5 +79,5 @@ class Command(BaseCommand): pool.imap_unordered(_process_document, ids), total=len(ids), disable=options["no_progress_bar"], - ) + ), ) diff --git a/src/documents/management/commands/manage_superuser.py b/src/documents/management/commands/manage_superuser.py index f8cefb0d9..e892f7d22 100644 --- a/src/documents/management/commands/manage_superuser.py +++ b/src/documents/management/commands/manage_superuser.py @@ -2,7 +2,7 @@ import logging import os from django.contrib.auth.models import User -from django.core.management.base import BaseCommand, CommandError +from django.core.management.base import BaseCommand logger = logging.getLogger("paperless.management.superuser") @@ -13,7 +13,8 @@ class Command(BaseCommand): help = """ Creates a Django superuser based on env variables. """.replace( - " ", "" + " ", + "", ) def handle(self, *args, **options): @@ -39,5 +40,5 @@ class Command(BaseCommand): self.stdout.write(f'Did not create superuser "{username}".') self.stdout.write( 'Make sure you specified "PAPERLESS_ADMIN_PASSWORD" in your ' - '"docker-compose.env" file.' + '"docker-compose.env" file.', ) diff --git a/src/documents/matching.py b/src/documents/matching.py index 2acd5b7f6..b87fa0461 100644 --- a/src/documents/matching.py +++ b/src/documents/matching.py @@ -1,8 +1,10 @@ import logging import re - -from documents.models import MatchingModel, Correspondent, DocumentType, Tag +from documents.models import Correspondent +from documents.models import DocumentType +from documents.models import MatchingModel +from documents.models import Tag logger = logging.getLogger("paperless.matching") @@ -12,7 +14,7 @@ def log_reason(matching_model, document, reason): class_name = type(matching_model).__name__ logger.debug( f"{class_name} {matching_model.name} matched on document " - f"{document} because {reason}" + f"{document} because {reason}", ) @@ -25,7 +27,7 @@ def match_correspondents(document, classifier): correspondents = Correspondent.objects.all() return list( - filter(lambda o: matches(o, document) or o.pk == pred_id, correspondents) + filter(lambda o: matches(o, document) or o.pk == pred_id, correspondents), ) @@ -38,7 +40,7 @@ def match_document_types(document, classifier): document_types = DocumentType.objects.all() return list( - filter(lambda o: matches(o, document) or o.pk == pred_id, document_types) + filter(lambda o: matches(o, document) or o.pk == pred_id, document_types), ) @@ -51,14 +53,14 @@ def match_tags(document, classifier): tags = Tag.objects.all() return list( - filter(lambda o: matches(o, document) or o.pk in predicted_tag_ids, tags) + filter(lambda o: matches(o, document) or o.pk in predicted_tag_ids, tags), ) def matches(matching_model, document): search_kwargs = {} - document_content = document.content.lower() + document_content = document.content # Check that match is not empty if matching_model.match.strip() == "": @@ -92,7 +94,7 @@ def matches(matching_model, document): rf"\b{re.escape(matching_model.match)}\b", document_content, **search_kwargs, - ) + ), ) if result: log_reason( @@ -105,11 +107,12 @@ def matches(matching_model, document): elif matching_model.matching_algorithm == MatchingModel.MATCH_REGEX: try: match = re.search( - re.compile(matching_model.match, **search_kwargs), document_content + re.compile(matching_model.match, **search_kwargs), + document_content, ) except re.error: logger.error( - f"Error while processing regular expression " f"{matching_model.match}" + f"Error while processing regular expression " f"{matching_model.match}", ) return False if match: diff --git a/src/documents/migrations/1017_alter_savedviewfilterrule_rule_type.py b/src/documents/migrations/1017_alter_savedviewfilterrule_rule_type.py new file mode 100644 index 000000000..52db95138 --- /dev/null +++ b/src/documents/migrations/1017_alter_savedviewfilterrule_rule_type.py @@ -0,0 +1,45 @@ +# Generated by Django 3.2.12 on 2022-03-17 11:59 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("documents", "1016_auto_20210317_1351"), + ] + + operations = [ + migrations.AlterField( + model_name="savedviewfilterrule", + name="rule_type", + field=models.PositiveIntegerField( + choices=[ + (0, "title contains"), + (1, "content contains"), + (2, "ASN is"), + (3, "correspondent is"), + (4, "document type is"), + (5, "is in inbox"), + (6, "has tag"), + (7, "has any tag"), + (8, "created before"), + (9, "created after"), + (10, "created year is"), + (11, "created month is"), + (12, "created day is"), + (13, "added before"), + (14, "added after"), + (15, "modified before"), + (16, "modified after"), + (17, "does not have tag"), + (18, "does not have ASN"), + (19, "title or content contains"), + (20, "fulltext query"), + (21, "more like this"), + (22, "has tags in"), + ], + verbose_name="rule type", + ), + ), + ] diff --git a/src/documents/migrations/1018_alter_savedviewfilterrule_value.py b/src/documents/migrations/1018_alter_savedviewfilterrule_value.py new file mode 100644 index 000000000..aa32c9c5c --- /dev/null +++ b/src/documents/migrations/1018_alter_savedviewfilterrule_value.py @@ -0,0 +1,20 @@ +# Generated by Django 4.0.3 on 2022-04-01 22:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("documents", "1017_alter_savedviewfilterrule_rule_type"), + ] + + operations = [ + migrations.AlterField( + model_name="savedviewfilterrule", + name="value", + field=models.CharField( + blank=True, max_length=255, null=True, verbose_name="value" + ), + ), + ] diff --git a/src/documents/models.py b/src/documents/models.py index 02a6b56dc..a1a787325 100644 --- a/src/documents/models.py +++ b/src/documents/models.py @@ -5,17 +5,14 @@ import os import re from collections import OrderedDict -import pathvalidate - import dateutil.parser +import pathvalidate from django.conf import settings from django.contrib.auth.models import User from django.db import models from django.utils import timezone from django.utils.timezone import is_aware - from django.utils.translation import gettext_lazy as _ - from documents.parsers import get_default_file_extension @@ -42,7 +39,9 @@ class MatchingModel(models.Model): match = models.CharField(_("match"), max_length=256, blank=True) matching_algorithm = models.PositiveIntegerField( - _("matching algorithm"), choices=MATCHING_ALGORITHMS, default=MATCH_ANY + _("matching algorithm"), + choices=MATCHING_ALGORITHMS, + default=MATCH_ANY, ) is_insensitive = models.BooleanField(_("is insensitive"), default=True) @@ -71,7 +70,7 @@ class Tag(MatchingModel): default=False, help_text=_( "Marks this tag as an inbox tag: All newly consumed " - "documents will be tagged with inbox tags." + "documents will be tagged with inbox tags.", ), ) @@ -120,14 +119,17 @@ class Document(models.Model): blank=True, help_text=_( "The raw, text-only data of the document. This field is " - "primarily used for searching." + "primarily used for searching.", ), ) mime_type = models.CharField(_("mime type"), max_length=256, editable=False) tags = models.ManyToManyField( - Tag, related_name="documents", blank=True, verbose_name=_("tags") + Tag, + related_name="documents", + blank=True, + verbose_name=_("tags"), ) checksum = models.CharField( @@ -150,7 +152,10 @@ class Document(models.Model): created = models.DateTimeField(_("created"), default=timezone.now, db_index=True) modified = models.DateTimeField( - _("modified"), auto_now=True, editable=False, db_index=True + _("modified"), + auto_now=True, + editable=False, + db_index=True, ) storage_type = models.CharField( @@ -162,7 +167,10 @@ class Document(models.Model): ) added = models.DateTimeField( - _("added"), default=timezone.now, editable=False, db_index=True + _("added"), + default=timezone.now, + editable=False, + db_index=True, ) filename = models.FilePathField( @@ -192,7 +200,7 @@ class Document(models.Model): unique=True, db_index=True, help_text=_( - "The position of this document in your physical document " "archive." + "The position of this document in your physical document " "archive.", ), ) @@ -289,7 +297,9 @@ class Log(models.Model): message = models.TextField(_("message")) level = models.PositiveIntegerField( - _("level"), choices=LEVELS, default=logging.INFO + _("level"), + choices=LEVELS, + default=logging.INFO, ) created = models.DateTimeField(_("created"), auto_now_add=True) @@ -321,7 +331,10 @@ class SavedView(models.Model): ) sort_field = models.CharField( - _("sort field"), max_length=128, null=True, blank=True + _("sort field"), + max_length=128, + null=True, + blank=True, ) sort_reverse = models.BooleanField(_("sort reverse"), default=False) @@ -362,7 +375,7 @@ class SavedViewFilterRule(models.Model): rule_type = models.PositiveIntegerField(_("rule type"), choices=RULE_TYPES) - value = models.CharField(_("value"), max_length=128, blank=True, null=True) + value = models.CharField(_("value"), max_length=255, blank=True, null=True) class Meta: verbose_name = _("filter rule") @@ -383,11 +396,16 @@ class FileInfo: ), ), ("title", re.compile(r"(?P.*)$", flags=re.IGNORECASE)), - ] + ], ) def __init__( - self, created=None, correspondent=None, title=None, tags=(), extension=None + self, + created=None, + correspondent=None, + title=None, + tags=(), + extension=None, ): self.created = created diff --git a/src/documents/parsers.py b/src/documents/parsers.py index f179337a4..269fddbb4 100644 --- a/src/documents/parsers.py +++ b/src/documents/parsers.py @@ -9,6 +9,8 @@ import tempfile import magic from django.conf import settings from django.utils import timezone +from documents.loggers import LoggingMixin +from documents.signals import document_consumer_declaration # This regular expression will try to find dates in the document at # hand and will match the following formats: @@ -21,17 +23,17 @@ from django.utils import timezone # - XX. MONTH ZZZZ with XX being 1 or 2 and ZZZZ being 2 or 4 digits # - MONTH ZZZZ, with ZZZZ being 4 digits # - MONTH XX, ZZZZ with XX being 1 or 2 and ZZZZ being 4 digits -from documents.loggers import LoggingMixin -from documents.signals import document_consumer_declaration +# - XX MON ZZZZ with XX being 1 or 2 and ZZZZ being 4 digits. MONTH is 3 letters # TODO: isnt there a date parsing library for this? DATE_REGEX = re.compile( - r"(\b|(?!=([_-])))([0-9]{1,2})[\.\/-]([0-9]{1,2})[\.\/-]([0-9]{4}|[0-9]{2})(\b|(?=([_-])))|" # NOQA: E501 - r"(\b|(?!=([_-])))([0-9]{4}|[0-9]{2})[\.\/-]([0-9]{1,2})[\.\/-]([0-9]{1,2})(\b|(?=([_-])))|" # NOQA: E501 - r"(\b|(?!=([_-])))([0-9]{1,2}[\. ]+[^ ]{3,9} ([0-9]{4}|[0-9]{2}))(\b|(?=([_-])))|" # NOQA: E501 + r"(\b|(?!=([_-])))([0-9]{1,2})[\.\/-]([0-9]{1,2})[\.\/-]([0-9]{4}|[0-9]{2})(\b|(?=([_-])))|" # noqa: E501 + r"(\b|(?!=([_-])))([0-9]{4}|[0-9]{2})[\.\/-]([0-9]{1,2})[\.\/-]([0-9]{1,2})(\b|(?=([_-])))|" # noqa: E501 + r"(\b|(?!=([_-])))([0-9]{1,2}[\. ]+[^ ]{3,9} ([0-9]{4}|[0-9]{2}))(\b|(?=([_-])))|" # noqa: E501 r"(\b|(?!=([_-])))([^\W\d_]{3,9} [0-9]{1,2}, ([0-9]{4}))(\b|(?=([_-])))|" - r"(\b|(?!=([_-])))([^\W\d_]{3,9} [0-9]{4})(\b|(?=([_-])))" + r"(\b|(?!=([_-])))([^\W\d_]{3,9} [0-9]{4})(\b|(?=([_-])))|" + r"(\b|(?!=([_-])))(\b[0-9]{1,2}[ \.\/-][A-Z]{3}[ \.\/-][0-9]{4})(\b|(?=([_-])))", # noqa: E501 ) @@ -224,6 +226,7 @@ def parse_date(filename, text): "DATE_ORDER": date_order, "PREFER_DAY_OF_MONTH": "first", "RETURN_AS_TIMEZONE_AWARE": True, + "TIMEZONE": settings.TIME_ZONE, }, ) diff --git a/src/documents/sanity_checker.py b/src/documents/sanity_checker.py index 5dee84258..de3995eb7 100644 --- a/src/documents/sanity_checker.py +++ b/src/documents/sanity_checker.py @@ -3,9 +3,8 @@ import logging import os from django.conf import settings -from tqdm import tqdm - from documents.models import Document +from tqdm import tqdm class SanityCheckMessages: @@ -88,19 +87,19 @@ def check_sanity(progress=False): if not checksum == doc.checksum: messages.error( f"Checksum mismatch of document {doc.pk}. " - f"Stored: {doc.checksum}, actual: {checksum}." + f"Stored: {doc.checksum}, actual: {checksum}.", ) # Check sanity of the archive file. if doc.archive_checksum and not doc.archive_filename: messages.error( f"Document {doc.pk} has an archive file checksum, but no " - f"archive filename." + f"archive filename.", ) elif not doc.archive_checksum and doc.archive_filename: messages.error( f"Document {doc.pk} has an archive file, but its checksum is " - f"missing." + f"missing.", ) elif doc.has_archive_version: if not os.path.isfile(doc.archive_path): @@ -113,7 +112,7 @@ def check_sanity(progress=False): checksum = hashlib.md5(f.read()).hexdigest() except OSError as e: messages.error( - f"Cannot read archive file of document {doc.pk}: {e}" + f"Cannot read archive file of document {doc.pk}: {e}", ) else: if not checksum == doc.archive_checksum: @@ -121,7 +120,7 @@ def check_sanity(progress=False): f"Checksum mismatch of archived document " f"{doc.pk}. " f"Stored: {doc.archive_checksum}, " - f"actual: {checksum}." + f"actual: {checksum}.", ) # other document checks diff --git a/src/documents/serialisers.py b/src/documents/serialisers.py index 0206eb2ae..5e295f537 100644 --- a/src/documents/serialisers.py +++ b/src/documents/serialisers.py @@ -1,25 +1,22 @@ +import math import re import magic -import math from django.utils.text import slugify +from django.utils.translation import gettext as _ from rest_framework import serializers from rest_framework.fields import SerializerMethodField from . import bulk_edit -from .models import ( - Correspondent, - Tag, - Document, - DocumentType, - SavedView, - SavedViewFilterRule, - MatchingModel, -) +from .models import Correspondent +from .models import Document +from .models import DocumentType +from .models import MatchingModel +from .models import SavedView +from .models import SavedViewFilterRule +from .models import Tag from .parsers import is_mime_type_supported -from django.utils.translation import gettext as _ - # https://www.django-rest-framework.org/api-guide/serializers/#example class DynamicFieldsModelSerializer(serializers.ModelSerializer): @@ -56,12 +53,12 @@ class MatchingModelSerializer(serializers.ModelSerializer): if ( "matching_algorithm" in self.initial_data and self.initial_data["matching_algorithm"] == MatchingModel.MATCH_REGEX - ): # NOQA: E501 + ): try: re.compile(match) - except Exception as e: + except re.error as e: raise serializers.ValidationError( - _("Invalid regular expression: %(error)s") % {"error": str(e)} + _("Invalid regular expression: %(error)s") % {"error": str(e.msg)}, ) return match @@ -156,7 +153,7 @@ class TagSerializer(MatchingModelSerializer): luminance = math.sqrt( 0.299 * math.pow(rgb[0], 2) + 0.587 * math.pow(rgb[1], 2) - + 0.114 * math.pow(rgb[2], 2) + + 0.114 * math.pow(rgb[2], 2), ) return "#ffffff" if luminance < 0.53 else "#000000" except ValueError: @@ -298,7 +295,7 @@ class DocumentListSerializer(serializers.Serializer): count = Document.objects.filter(id__in=documents).count() if not count == len(documents): raise serializers.ValidationError( - f"Some documents in {name} don't exist or were " f"specified twice." + f"Some documents in {name} don't exist or were " f"specified twice.", ) def validate_documents(self, documents): @@ -331,7 +328,7 @@ class BulkEditSerializer(DocumentListSerializer): count = Tag.objects.filter(id__in=tags).count() if not count == len(tags): raise serializers.ValidationError( - f"Some tags in {name} don't exist or were specified twice." + f"Some tags in {name} don't exist or were specified twice.", ) def validate_method(self, method): @@ -456,7 +453,7 @@ class PostDocumentSerializer(serializers.Serializer): if not is_mime_type_supported(mime_type): raise serializers.ValidationError( - _("File type %(type)s not supported") % {"type": mime_type} + _("File type %(type)s not supported") % {"type": mime_type}, ) return document.name, document_data @@ -483,11 +480,13 @@ class PostDocumentSerializer(serializers.Serializer): class BulkDownloadSerializer(DocumentListSerializer): content = serializers.ChoiceField( - choices=["archive", "originals", "both"], default="archive" + choices=["archive", "originals", "both"], + default="archive", ) compression = serializers.ChoiceField( - choices=["none", "deflated", "bzip2", "lzma"], default="none" + choices=["none", "deflated", "bzip2", "lzma"], + default="none", ) def validate_compression(self, compression): diff --git a/src/documents/signals/handlers.py b/src/documents/signals/handlers.py index d0d28a2bc..71f2cdc55 100644 --- a/src/documents/signals/handlers.py +++ b/src/documents/signals/handlers.py @@ -1,24 +1,27 @@ import logging import os +import shutil -from django.utils import termcolors from django.conf import settings -from django.contrib.admin.models import ADDITION, LogEntry +from django.contrib.admin.models import ADDITION +from django.contrib.admin.models import LogEntry from django.contrib.auth.models import User from django.contrib.contenttypes.models import ContentType -from django.db import models, DatabaseError +from django.db import DatabaseError +from django.db import models from django.db.models import Q from django.dispatch import receiver -from django.utils import termcolors, timezone +from django.utils import termcolors +from django.utils import timezone from filelock import FileLock from .. import matching -from ..file_handling import ( - delete_empty_directories, - create_source_path_directory, - generate_unique_filename, -) -from ..models import Document, Tag, MatchingModel +from ..file_handling import create_source_path_directory +from ..file_handling import delete_empty_directories +from ..file_handling import generate_unique_filename +from ..models import Document +from ..models import MatchingModel +from ..models import Tag logger = logging.getLogger("paperless.handlers") @@ -72,7 +75,7 @@ def set_correspondent( print( termcolors.colorize(str(document), fg="green") if color - else str(document) + else str(document), ) print(f"{base_url}/documents/{document.pk}") else: @@ -82,7 +85,7 @@ def set_correspondent( if color else str(document) ) - + f" [{document.pk}]" + + f" [{document.pk}]", ) print(f"Suggest correspondent {selected}") else: @@ -139,7 +142,7 @@ def set_document_type( print( termcolors.colorize(str(document), fg="green") if color - else str(document) + else str(document), ) print(f"{base_url}/documents/{document.pk}") else: @@ -149,7 +152,7 @@ def set_document_type( if color else str(document) ) - + f" [{document.pk}]" + + f" [{document.pk}]", ) print(f"Suggest document type {selected}") else: @@ -176,9 +179,9 @@ def set_tags( if replace: Document.tags.through.objects.filter(document=document).exclude( - Q(tag__is_inbox_tag=True) + Q(tag__is_inbox_tag=True), ).exclude( - Q(tag__match="") & ~Q(tag__matching_algorithm=Tag.MATCH_AUTO) + Q(tag__match="") & ~Q(tag__matching_algorithm=Tag.MATCH_AUTO), ).delete() current_tags = set(document.tags.all()) @@ -198,7 +201,7 @@ def set_tags( print( termcolors.colorize(str(document), fg="green") if color - else str(document) + else str(document), ) print(f"{base_url}/documents/{document.pk}") else: @@ -208,7 +211,7 @@ def set_tags( if color else str(document) ) - + f" [{document.pk}]" + + f" [{document.pk}]", ) if relevant_tags: print("Suggest tags: " + ", ".join([t.name for t in relevant_tags])) @@ -250,11 +253,11 @@ def cleanup_document_deletion(sender, instance, using, **kwargs): logger.debug(f"Moving {instance.source_path} to trash at {new_file_path}") try: - os.rename(instance.source_path, new_file_path) + shutil.move(instance.source_path, new_file_path) except OSError as e: logger.error( f"Failed to move {instance.source_path} to trash at " - f"{new_file_path}: {e}. Skipping cleanup!" + f"{new_file_path}: {e}. Skipping cleanup!", ) return @@ -270,16 +273,18 @@ def cleanup_document_deletion(sender, instance, using, **kwargs): except OSError as e: logger.warning( f"While deleting document {str(instance)}, the file " - f"{filename} could not be deleted: {e}" + f"{filename} could not be deleted: {e}", ) delete_empty_directories( - os.path.dirname(instance.source_path), root=settings.ORIGINALS_DIR + os.path.dirname(instance.source_path), + root=settings.ORIGINALS_DIR, ) if instance.has_archive_version: delete_empty_directories( - os.path.dirname(instance.archive_path), root=settings.ARCHIVE_DIR + os.path.dirname(instance.archive_path), + root=settings.ARCHIVE_DIR, ) @@ -297,7 +302,7 @@ def validate_move(instance, old_path, new_path): # Can't do anything if the new file already exists. Skip updating file. logger.warning( f"Document {str(instance)}: Cannot rename file " - f"since target path {new_path} already exists." + f"since target path {new_path} already exists.", ) raise CannotMoveFilesException() @@ -331,12 +336,11 @@ def update_filename_and_move_files(sender, instance, **kwargs): if instance.has_archive_version: instance.archive_filename = generate_unique_filename( - instance, archive_filename=True + instance, + archive_filename=True, ) - move_archive = ( - old_archive_filename != instance.archive_filename - ) # NOQA: E501 + move_archive = old_archive_filename != instance.archive_filename else: move_archive = False @@ -374,7 +378,7 @@ def update_filename_and_move_files(sender, instance, **kwargs): if move_archive and os.path.isfile(instance.archive_path): os.rename(instance.archive_path, old_archive_path) - except Exception as e: + except Exception: # This is fine, since: # A: if we managed to move source from A to B, we will also # manage to move it from B to A. If not, we have a serious @@ -393,14 +397,16 @@ def update_filename_and_move_files(sender, instance, **kwargs): # something has failed above. if not os.path.isfile(old_source_path): delete_empty_directories( - os.path.dirname(old_source_path), root=settings.ORIGINALS_DIR + os.path.dirname(old_source_path), + root=settings.ORIGINALS_DIR, ) if instance.has_archive_version and not os.path.isfile( - old_archive_path - ): # NOQA: E501 + old_archive_path, + ): delete_empty_directories( - os.path.dirname(old_archive_path), root=settings.ARCHIVE_DIR + os.path.dirname(old_archive_path), + root=settings.ARCHIVE_DIR, ) diff --git a/src/documents/tasks.py b/src/documents/tasks.py index 569ebf0a7..e9a015d67 100644 --- a/src/documents/tasks.py +++ b/src/documents/tasks.py @@ -1,15 +1,30 @@ import logging +import os +import shutil +import tempfile +from typing import List # for type hinting. Can be removed, if only Python >3.8 is used import tqdm +from asgiref.sync import async_to_sync +from channels.layers import get_channel_layer from django.conf import settings from django.db.models.signals import post_save +from documents import index +from documents import sanity_checker +from documents.classifier import DocumentClassifier +from documents.classifier import load_classifier +from documents.consumer import Consumer +from documents.consumer import ConsumerError +from documents.models import Correspondent +from documents.models import Document +from documents.models import DocumentType +from documents.models import Tag +from documents.sanity_checker import SanityCheckFailedException +from pdf2image import convert_from_path +from pikepdf import Pdf +from pyzbar import pyzbar from whoosh.writing import AsyncWriter -from documents import index, sanity_checker -from documents.classifier import DocumentClassifier, load_classifier -from documents.consumer import Consumer, ConsumerError -from documents.models import Document, Tag, DocumentType, Correspondent -from documents.sanity_checker import SanityCheckFailedException logger = logging.getLogger("paperless.tasks") @@ -47,7 +62,7 @@ def train_classifier(): try: if classifier.train(): logger.info( - "Saving updated classifier model to {}...".format(settings.MODEL_FILE) + "Saving updated classifier model to {}...".format(settings.MODEL_FILE), ) classifier.save() else: @@ -57,6 +72,115 @@ def train_classifier(): logger.warning("Classifier error: " + str(e)) +def barcode_reader(image) -> List[str]: + """ + Read any barcodes contained in image + Returns a list containing all found barcodes + """ + barcodes = [] + # Decode the barcode image + detected_barcodes = pyzbar.decode(image) + + if detected_barcodes: + # Traverse through all the detected barcodes in image + for barcode in detected_barcodes: + if barcode.data: + decoded_barcode = barcode.data.decode("utf-8") + barcodes.append(decoded_barcode) + logger.debug( + f"Barcode of type {str(barcode.type)} found: {decoded_barcode}", + ) + return barcodes + + +def scan_file_for_separating_barcodes(filepath: str) -> List[int]: + """ + Scan the provided file for page separating barcodes + Returns a list of pagenumbers, which separate the file + """ + separator_page_numbers = [] + separator_barcode = str(settings.CONSUMER_BARCODE_STRING) + # use a temporary directory in case the file os too big to handle in memory + with tempfile.TemporaryDirectory() as path: + pages_from_path = convert_from_path(filepath, output_folder=path) + for current_page_number, page in enumerate(pages_from_path): + current_barcodes = barcode_reader(page) + if separator_barcode in current_barcodes: + separator_page_numbers.append(current_page_number) + return separator_page_numbers + + +def separate_pages(filepath: str, pages_to_split_on: List[int]) -> List[str]: + """ + Separate the provided file on the pages_to_split_on. + The pages which are defined by page_numbers will be removed. + Returns a list of (temporary) filepaths to consume. + These will need to be deleted later. + """ + os.makedirs(settings.SCRATCH_DIR, exist_ok=True) + tempdir = tempfile.mkdtemp(prefix="paperless-", dir=settings.SCRATCH_DIR) + fname = os.path.splitext(os.path.basename(filepath))[0] + pdf = Pdf.open(filepath) + document_paths = [] + logger.debug(f"Temp dir is {str(tempdir)}") + if not pages_to_split_on: + logger.warning("No pages to split on!") + else: + # go from the first page to the first separator page + dst = Pdf.new() + for n, page in enumerate(pdf.pages): + if n < pages_to_split_on[0]: + dst.pages.append(page) + output_filename = "{}_document_0.pdf".format(fname) + savepath = os.path.join(tempdir, output_filename) + with open(savepath, "wb") as out: + dst.save(out) + document_paths = [savepath] + + # iterate through the rest of the document + for count, page_number in enumerate(pages_to_split_on): + logger.debug(f"Count: {str(count)} page_number: {str(page_number)}") + dst = Pdf.new() + try: + next_page = pages_to_split_on[count + 1] + except IndexError: + next_page = len(pdf.pages) + # skip the first page_number. This contains the barcode page + for page in range(page_number + 1, next_page): + logger.debug( + f"page_number: {str(page_number)} next_page: {str(next_page)}", + ) + dst.pages.append(pdf.pages[page]) + output_filename = "{}_document_{}.pdf".format(fname, str(count + 1)) + logger.debug(f"pdf no:{str(count)} has {str(len(dst.pages))} pages") + savepath = os.path.join(tempdir, output_filename) + with open(savepath, "wb") as out: + dst.save(out) + document_paths.append(savepath) + logger.debug(f"Temp files are {str(document_paths)}") + return document_paths + + +def save_to_dir( + filepath: str, + newname: str = None, + target_dir: str = settings.CONSUMPTION_DIR, +): + """ + Copies filepath to target_dir. + Optionally rename the file. + """ + if os.path.isfile(filepath) and os.path.isdir(target_dir): + dst = shutil.copy(filepath, target_dir) + logging.debug(f"saved {str(filepath)} to {str(dst)}") + if newname: + dst_new = os.path.join(target_dir, newname) + logger.debug(f"moving {str(dst)} to {str(dst_new)}") + os.rename(dst, dst_new) + else: + logger.warning(f"{str(filepath)} or {str(target_dir)} don't exist.") + + def consume_file( path, override_filename=None, @@ -67,6 +191,48 @@ def consume_file( task_id=None, ): + # check for separators in current document + if settings.CONSUMER_ENABLE_BARCODES: + separators = [] + document_list = [] + separators = scan_file_for_separating_barcodes(path) + if separators: + logger.debug(f"Pages with separators found in: {str(path)}") + document_list = separate_pages(path, separators) + if document_list: + for n, document in enumerate(document_list): + # save to consumption dir + # rename it to the original filename with number prefix + if override_filename: + newname = f"{str(n)}_" + override_filename + else: + newname = None + save_to_dir(document, newname=newname) + # if we got here, the document was successfully split + # and can safely be deleted + logger.debug("Deleting file {}".format(path)) + os.unlink(path) + # notify the sender, otherwise the progress bar + # in the UI stays stuck + payload = { + "filename": override_filename, + "task_id": task_id, + "current_progress": 100, + "max_progress": 100, + "status": "SUCCESS", + "message": "finished", + } + try: + async_to_sync(get_channel_layer().group_send)( + "status_updates", + {"type": "status_update", "data": payload}, + ) + except OSError as e: + logger.warning("OSError. It could be, the broker cannot be reached.") + logger.warning(str(e)) + return "File successfully split" + + # continue with consumption if no barcode was found document = Consumer().try_consume_file( path, override_filename=override_filename, @@ -82,7 +248,7 @@ def consume_file( else: raise ConsumerError( "Unknown error: Returned document was null, but " - "no error message was given." + "no error message was given.", ) diff --git a/src/documents/templates/index.html b/src/documents/templates/index.html index 538c0dded..2778bce7a 100644 --- a/src/documents/templates/index.html +++ b/src/documents/templates/index.html @@ -13,13 +13,75 @@ <meta name="full_name" content="{{full_name}}"> <meta name="cookie_prefix" content="{{cookie_prefix}}"> <meta name="robots" content="noindex,nofollow"> - <link rel="icon" type="image/x-icon" href="favicon.ico"> - <link rel="manifest" href="{% static webmanifest %}"> + <link rel="icon" type="image/x-icon" href="favicon.ico"> + <link rel="manifest" href="{% static webmanifest %}"> <link rel="stylesheet" href="{% static styles_css %}"> <link rel="apple-touch-icon" href="{% static apple_touch_icon %}"> </head> -<body> - <app-root>{% translate "Paperless-ngx is loading..." %}</app-root> +<body class="color-scheme-system"> + <app-root> + <script type="text/javascript"> + setTimeout(() => { + let warning = document.getElementsByClassName('warning').item(0) + if (warning) { + warning.classList.remove('hide') + warning.classList.add('show') + } + }, 8000) + </script> + <style type="text/css"> + html, body { + width: 100%; + height: 100%; + } + + @-webkit-keyframes pulsate { + 0% { + opacity: 0.1; + } + 50% { + opacity: 0.3; + } + 100% { + opacity: 0.1; + } + } + + .app-loader svg, .app-loader h6 { + opacity: 0.1; + -webkit-animation: pulsate 2s ease-out; + -webkit-animation-iteration-count: infinite; + } + + svg.logo .leaf { + fill: var(--bs-body-color) !important; + } + </style> + <div class="bg-light w-100 h-100 d-flex align-items-center"> + <div class="app-loader align-self-center text-center mx-auto"> + <svg class="logo mb-2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2897.4 896.6" height="6em"> + <path class="leaf" d="M140,713.7c-3.4-16.4-10.3-49.1-11.2-49.1c-145.7-87.1-128.4-238-80.2-324.2C59,449,251.2,524,139.1,656.8 c-0.9,1.7,5.2,22.4,10.3,41.4c22.4-37.9,56-83.6,54.3-87.9C65.9,273.9,496.9,248.1,586.6,39.4c40.5,201.8-20.7,513.9-367.2,593.2 c-1.7,0.9-62.9,108.6-65.5,109.5c0-1.7-25.9-0.9-22.4-9.5C133.1,727.4,136.6,720.6,140,713.7L140,713.7z M135.7,632.6 c44-50.9-7.8-137.9-38.8-166.4C149.5,556.7,146,609.3,135.7,632.6L135.7,632.6z" transform="translate(0)" style="fill:#17541f"/> + <g class="text" style="fill:#000"> + <path d="M1022.3,428.7c-17.8-19.9-42.7-29.8-74.7-29.8c-22.3,0-42.4,5.7-60.5,17.3c-18.1,11.6-32.3,27.5-42.5,47.8 s-15.3,42.9-15.3,67.8c0,24.9,5.1,47.5,15.3,67.8c10.3,20.3,24.4,36.2,42.5,47.8c18.1,11.5,38.3,17.3,60.5,17.3 c32,0,56.9-9.9,74.7-29.8v20.4v0.2h84.5V408.3h-84.5V428.7z M1010.5,575c-10.2,11.7-23.6,17.6-40.2,17.6s-29.9-5.9-40-17.6 s-15.1-26.1-15.1-43.3c0-17.1,5-31.6,15.1-43.3s23.4-17.6,40-17.6c16.6,0,30,5.9,40.2,17.6s15.3,26.1,15.3,43.3 S1020.7,563.3,1010.5,575z" transform="translate(0)"/> + <path d="M1381,416.1c-18.1-11.5-38.3-17.3-60.5-17.4c-32,0-56.9,9.9-74.7,29.8v-20.4h-84.5v390.7h84.5v-164 c17.8,19.9,42.7,29.8,74.7,29.8c22.3,0,42.4-5.7,60.5-17.3s32.3-27.5,42.5-47.8c10.2-20.3,15.3-42.9,15.3-67.8s-5.1-47.5-15.3-67.8 C1413.2,443.6,1399.1,427.7,1381,416.1z M1337.9,575c-10.1,11.7-23.4,17.6-40,17.6s-29.9-5.9-40-17.6s-15.1-26.1-15.1-43.3 c0-17.1,5-31.6,15.1-43.3s23.4-17.6,40-17.6s29.9,5.9,40,17.6s15.1,26.1,15.1,43.3S1347.9,563.3,1337.9,575z" transform="translate(0)"/> + <path d="M1672.2,416.8c-20.5-12-43-18-67.6-18c-24.9,0-47.6,5.9-68,17.6c-20.4,11.7-36.5,27.7-48.2,48s-17.6,42.7-17.6,67.3 c0.3,25.2,6.2,47.8,17.8,68c11.5,20.2,28,36,49.3,47.6c21.3,11.5,45.9,17.3,73.8,17.3c48.6,0,86.8-14.7,114.7-44l-52.5-48.9 c-8.6,8.3-17.6,14.6-26.7,19c-9.3,4.3-21.1,6.4-35.3,6.4c-11.6,0-22.5-3.6-32.7-10.9c-10.3-7.3-17.1-16.5-20.7-27.8h180l0.4-11.6 c0-29.6-6-55.7-18-78.2S1692.6,428.8,1672.2,416.8z M1558.3,503.2c2.1-12.1,7.5-21.8,16.2-29.1s18.7-10.9,30-10.9 s21.2,3.6,29.8,10.9c8.6,7.2,13.9,16.9,16,29.1H1558.3z" transform="translate(0)"/> + <path d="M1895.3,411.7c-11,5.6-20.3,13.7-28,24.4h-0.1v-28h-84.5v247.3h84.5V536.3c0-22.6,4.7-38.1,14.2-46.5 c9.5-8.5,22.7-12.7,39.6-12.7c6.2,0,13.5,1,21.8,3.1l10.7-72c-5.9-3.3-14.5-4.9-25.8-4.9C1917.1,403.3,1906.3,406.1,1895.3,411.7z" transform="translate(0)"/> + <rect x="1985" y="277.4" width="84.5" height="377.8" transform="translate(0)"/> + <path d="M2313.2,416.8c-20.5-12-43-18-67.6-18c-24.9,0-47.6,5.9-68,17.6s-36.5,27.7-48.2,48c-11.7,20.3-17.6,42.7-17.6,67.3 c0.3,25.2,6.2,47.8,17.8,68c11.5,20.2,28,36,49.3,47.6c21.3,11.5,45.9,17.3,73.8,17.3c48.6,0,86.8-14.7,114.7-44l-52.5-48.9 c-8.6,8.3-17.6,14.6-26.7,19c-9.3,4.3-21.1,6.4-35.3,6.4c-11.6,0-22.5-3.6-32.7-10.9c-10.3-7.3-17.1-16.5-20.7-27.8h180l0.4-11.6 c0-29.6-6-55.7-18-78.2S2333.6,428.8,2313.2,416.8z M2199.3,503.2c2.1-12.1,7.5-21.8,16.2-29.1s18.7-10.9,30-10.9 s21.2,3.6,29.8,10.9c8.6,7.2,13.9,16.9,16,29.1H2199.3z" transform="translate(0)"/> + <path d="M2583.6,507.7c-13.8-4.4-30.6-8.1-50.5-11.1c-15.1-2.7-26.1-5.2-32.9-7.6c-6.8-2.4-10.2-6.1-10.2-11.1s2.3-8.7,6.7-10.9 c4.4-2.2,11.5-3.3,21.3-3.3c11.6,0,24.3,2.4,38.1,7.2c13.9,4.8,26.2,11,36.9,18.4l32.4-58.2c-11.3-7.4-26.2-14.7-44.9-21.8 c-18.7-7.1-39.6-10.7-62.7-10.7c-33.7,0-60.2,7.6-79.3,22.7c-19.1,15.1-28.7,36.1-28.7,63.1c0,19,4.8,33.9,14.4,44.7 c9.6,10.8,21,18.5,34,22.9c13.1,4.5,28.9,8.3,47.6,11.6c14.6,2.7,25.1,5.3,31.6,7.8s9.8,6.5,9.8,11.8c0,10.4-9.7,15.6-29.3,15.6 c-13.7,0-28.5-2.3-44.7-6.9c-16.1-4.6-29.2-11.3-39.3-20.2l-33.3,60c9.2,7.4,24.6,14.7,46.2,22c21.7,7.3,45.2,10.9,70.7,10.9 c34.7,0,62.9-7.4,84.5-22.4c21.7-15,32.5-37.3,32.5-66.9c0-19.3-5-34.2-15.1-44.9S2597.4,512.1,2583.6,507.7z" transform="translate(0)"/> + <path d="M2883.4,575.3c0-19.3-5-34.2-15.1-44.9s-22-18.3-35.8-22.7c-13.8-4.4-30.6-8.1-50.5-11.1c-15.1-2.7-26.1-5.2-32.9-7.6 c-6.8-2.4-10.2-6.1-10.2-11.1s2.3-8.7,6.7-10.9c4.4-2.2,11.5-3.3,21.3-3.3c11.6,0,24.3,2.4,38.1,7.2c13.9,4.8,26.2,11,36.9,18.4 l32.4-58.2c-11.3-7.4-26.2-14.7-44.9-21.8c-18.7-7.1-39.6-10.7-62.7-10.7c-33.7,0-60.2,7.6-79.3,22.7 c-19.1,15.1-28.7,36.1-28.7,63.1c0,19,4.8,33.9,14.4,44.7c9.6,10.8,21,18.5,34,22.9c13.1,4.5,28.9,8.3,47.6,11.6 c14.6,2.7,25.1,5.3,31.6,7.8s9.8,6.5,9.8,11.8c0,10.4-9.7,15.6-29.3,15.6c-13.7,0-28.5-2.3-44.7-6.9c-16.1-4.6-29.2-11.3-39.3-20.2 l-33.3,60c9.2,7.4,24.6,14.7,46.2,22c21.7,7.3,45.2,10.9,70.7,10.9c34.7,0,62.9-7.4,84.5-22.4 C2872.6,627.2,2883.4,604.9,2883.4,575.3z" transform="translate(0)"/> + <rect x="2460.7" y="738.7" width="59.6" height="17.2" transform="translate(0)"/> + <path d="M2596.5,706.4c-5.7,0-11,1-15.8,3s-9,5-12.5,8.9v-9.4h-19.4v93.6h19.4v-52c0-8.6,2.1-15.3,6.3-20c4.2-4.7,9.5-7.1,15.9-7.1 c7.8,0,13.4,2.3,16.8,6.7c3.4,4.5,5.1,11.3,5.1,20.5v52h19.4v-56.8c0-12.8-3.2-22.6-9.5-29.3 C2615.8,709.8,2607.3,706.4,2596.5,706.4z" transform="translate(0)"/> + <path d="M2733.8,717.7c-3.6-3.4-7.9-6.1-13.1-8.2s-10.6-3.1-16.2-3.1c-8.7,0-16.5,2.1-23.5,6.3s-12.5,10-16.5,17.3 c-4,7.3-6,15.4-6,24.4c0,8.9,2,17.1,6,24.3c4,7.3,9.5,13,16.5,17.2s14.9,6.3,23.5,6.3c5.6,0,11-1,16.2-3.1 c5.1-2.1,9.5-4.8,13.1-8.2v24.4c0,8.5-2.5,14.8-7.6,18.7c-5,3.9-11,5.9-18,5.9c-6.7,0-12.4-1.6-17.3-4.7c-4.8-3.1-7.6-7.7-8.3-13.8 h-19.4c0.6,7.7,2.9,14.2,7.1,19.5s9.6,9.3,16.2,12c6.6,2.7,13.8,4,21.7,4c12.8,0,23.5-3.4,32-10.1c8.6-6.7,12.8-17.1,12.8-31.1 V708.9h-19.2V717.7z M2732.2,770.1c-2.5,4.7-6,8.3-10.4,11.2c-4.4,2.7-9.4,4-14.9,4c-5.7,0-10.8-1.4-15.2-4.3s-7.8-6.7-10.2-11.4 c-2.3-4.8-3.5-9.8-3.5-15.2c0-5.5,1.1-10.6,3.5-15.3s5.8-8.5,10.2-11.3s9.5-4.2,15.2-4.2c5.5,0,10.5,1.4,14.9,4s7.9,6.3,10.4,11 s3.8,10,3.8,15.8S2734.7,765.4,2732.2,770.1z" transform="translate(0)"/> + <polygon points="2867.9,708.9 2846.5,708.9 2820.9,741.9 2795.5,708.9 2773.1,708.9 2809.1,755 2771.5,802.5 2792.9,802.5 2820.1,767.9 2847.2,802.6 2869.6,802.6 2832,754.4 " transform="translate(0)"/> + <path d="M757.6,293.7c-20-10.8-42.6-16.2-67.8-16.2H600c-8.5,39.2-21.1,76.4-37.6,111.3c-9.9,20.8-21.1,40.6-33.6,59.4v207.2h88.9 V521.5h72c25.2,0,47.8-5.4,67.8-16.2s35.7-25.6,47.1-44.2c11.4-18.7,17.1-39.1,17.1-61.3c0.1-22.7-5.6-43.3-17-61.9 C793.3,319.2,777.6,304.5,757.6,293.7z M716.6,434.3c-9.3,8.9-21.6,13.3-36.7,13.3l-62.2,0.4v-92.5l62.2-0.4 c15.1,0,27.3,4.4,36.7,13.3c9.4,8.9,14,19.9,14,32.9C730.6,414.5,726,425.4,716.6,434.3z" transform="translate(0)"/> + </g> + </svg> + <h6 class="m-auto">{% translate "Paperless-ngx is loading..." %}</h6> + <p class="warning m-auto mt-3 small fade hide">{% translate "Still here?! Hmm, something might be wrong." %} <a href="https://paperless-ngx.readthedocs.io/en/latest/">{% translate "Here's a link to the docs." %}</a></p> + </div> + </div> + </app-root> <script src="{% static runtime_js %}" defer></script> <script src="{% static polyfills_js %}" defer></script> <script src="{% static main_js %}" defer></script> diff --git a/src/documents/tests/data/model.pickle b/src/documents/tests/data/model.pickle index db303ec80..e097bda06 100644 Binary files a/src/documents/tests/data/model.pickle and b/src/documents/tests/data/model.pickle differ diff --git a/src/documents/tests/factories.py b/src/documents/tests/factories.py index c2907d932..83644c411 100644 --- a/src/documents/tests/factories.py +++ b/src/documents/tests/factories.py @@ -1,7 +1,8 @@ from factory import Faker from factory.django import DjangoModelFactory -from ..models import Document, Correspondent +from ..models import Correspondent +from ..models import Document class CorrespondentFactory(DjangoModelFactory): diff --git a/src/documents/tests/samples/barcodes/barcode-128-PATCHT.png b/src/documents/tests/samples/barcodes/barcode-128-PATCHT.png new file mode 100644 index 000000000..80517d56d Binary files /dev/null and b/src/documents/tests/samples/barcodes/barcode-128-PATCHT.png differ diff --git a/src/documents/tests/samples/barcodes/barcode-128-custom.pdf b/src/documents/tests/samples/barcodes/barcode-128-custom.pdf new file mode 100644 index 000000000..f603dff5f Binary files /dev/null and b/src/documents/tests/samples/barcodes/barcode-128-custom.pdf differ diff --git a/src/documents/tests/samples/barcodes/barcode-128-custom.png b/src/documents/tests/samples/barcodes/barcode-128-custom.png new file mode 100644 index 000000000..c3f1b803a Binary files /dev/null and b/src/documents/tests/samples/barcodes/barcode-128-custom.png differ diff --git a/src/documents/tests/samples/barcodes/barcode-39-PATCHT-distorsion.png b/src/documents/tests/samples/barcodes/barcode-39-PATCHT-distorsion.png new file mode 100644 index 000000000..3f858f6ad Binary files /dev/null and b/src/documents/tests/samples/barcodes/barcode-39-PATCHT-distorsion.png differ diff --git a/src/documents/tests/samples/barcodes/barcode-39-PATCHT-distorsion2.png b/src/documents/tests/samples/barcodes/barcode-39-PATCHT-distorsion2.png new file mode 100644 index 000000000..cc81f8e36 Binary files /dev/null and b/src/documents/tests/samples/barcodes/barcode-39-PATCHT-distorsion2.png differ diff --git a/src/documents/tests/samples/barcodes/barcode-39-PATCHT-unreadable.png b/src/documents/tests/samples/barcodes/barcode-39-PATCHT-unreadable.png new file mode 100644 index 000000000..1e24b4d84 Binary files /dev/null and b/src/documents/tests/samples/barcodes/barcode-39-PATCHT-unreadable.png differ diff --git a/src/documents/tests/samples/barcodes/barcode-39-PATCHT.png b/src/documents/tests/samples/barcodes/barcode-39-PATCHT.png new file mode 100644 index 000000000..0078026c8 Binary files /dev/null and b/src/documents/tests/samples/barcodes/barcode-39-PATCHT.png differ diff --git a/src/documents/tests/samples/barcodes/barcode-39-custom.pdf b/src/documents/tests/samples/barcodes/barcode-39-custom.pdf new file mode 100644 index 000000000..ca78b93be --- /dev/null +++ b/src/documents/tests/samples/barcodes/barcode-39-custom.pdf @@ -0,0 +1,243 @@ +%PDF-1.6 +%äüöß +2 0 obj +<</Length 3 0 R/Filter/FlateDecode>> +stream +xœ]QËjÄ0 ¼û+t.Ä+ÙVlƒ1äµÐÞ=”žú:mË_ÙÞ¦¡b<£‘Ôßê¨ÑàÈÚx†àH‡žàú¦ïà³1ä\?Ô¸*"Ô¼ëuÖW8 D½¾?%¤L ZtÈØ£Ç;ÉÄl7àpÌ6á„s!3.¹ +å¸×æçõA-«:ýk€Å<⟿2¿þ¦ú—ËåΤZj}3ŠÅzØ(Ž¹óL ÎÒ•–zB ˆÈ “-¡#.Bêë<2sHäk&Ü +NYR±¦¡·Ç±~'ñ§6:-%.Õ['‚;n+Ùœ·%œàDQ›ÁYÖV¦7ÎÉèNïÿ•ä—uÕn"®g#¼œÕáþì`þ‚RôÒæmx +endstream +endobj + +3 0 obj +284 +endobj + +4 0 obj +<</Type/XObject/Subtype/Image/Width 828/Height 236/BitsPerComponent 8/Length 5 0 R +/Filter/FlateDecode/ColorSpace/DeviceRGB +>> +stream +xœíÛÁn`IŽdÑüÿŸîYÌ¢„`”ñòÝA8—¢é+½Mý÷ßÿÎÿüeþûËÏü÷—i~æ2j˜þÞ­ü­¾ô®¡ï–vÒ¶ÆßØ’ÝƶիÉ$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©¾!q“Ë]Cß-í¤m¿±%»m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍ橇èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@߸É审ï–vÒ¶ÆßØ’ÝƶիÉ$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©¾!q“Ë]Cß-í¤m¿±%»m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍ橇èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@߸É审ï–vÒ¶ÆßØ’ÝƶիÉ$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©¾!q“Ë]Cß-í¤m¿±%»m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍ橇èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@߸É审ï–vÒ¶ÆßØ’ÝƶիÉ$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©¾!q“Ë]Cß-í¤m¿±%»m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍ橇èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@߸É审ï–vÒ¶ÆßØ’ÝƶիÉ$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©¾!q“Ë]Cß-í¤m¿±%»m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍ橇èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@߸É审ï–vÒ¶ÆßØ’ÝƶիÉ$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©¾!q“Ë]Cß-í¤m¿±%»m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍ橇èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@߸É审ï–vÒ¶ÆßØ’ÝƶիÉ$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©¾!q“Ë]Cß-í¤m¿±%»m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍ橇èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@߸É审ï–vÒ¶ÆßØ’ÝƶիÉ$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©¾!q“Ë]Cß-í¤m¿±%»m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍ橇èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@߸É审ï–vÒ¶ÆßØ’ÝƶիÉ$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©¾!q“Ë]Cß-í¤m¿±%»m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍ橇èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@߸É审ï–vÒ¶ÆßØ’ÝƶիÉ$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©¾!q“Ë]Cß-í¤m¿±%»m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍ橇èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@߸É审ï–vÒ¶ÆßØ’ÝƶիÉ$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©¾!q“Ë]Cß-í¤m¿±%»m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍ橇èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@߸É审ï–vÒ¶ÆßØ’ÝƶիÉ$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©¾!q“Ë]Cß-í¤m¿±%»m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍ橇èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@߸É审ï–vÒ¶ÆßØ’ÝƶիÉ$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©¾!q“Ë]Cß-í¤m¿±%»m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍ橇èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@߸É审ï–vÒ¶ÆßØ’ÝƶիÉ$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©¾!q“Ë]Cß-í¤m¿±%»m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍ橇èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@߸É审ï–vÒ¶ÆßØ’ÝƶիÉ$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©¾!q“Ë]Cß-í¤m¿±%»m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍ橇èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@߸É审ï–vÒ¶ÆßØ’ÝƶիÉ$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©¾!q“Ë]Cß-í¤m¿±%»m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍ橇èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@߸É审ï–vÒ¶ÆßØ’ÝƶիÉ$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©¾!q“Ë]Cß-í¤m¿±%»m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍ橇èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@߸É审ï–vÒ¶ÆßØ’ÝƶիÉ$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©¾!q“Ë]Cß-í¤m¿±%»m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍ橇èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@߸É审ï–vÒ¶ÆßØ’ÝƶիÉ$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©¾!q“Ë]Cß-í¤m¿±%»m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍ橇èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@߸É审ï–vÒ¶ÆßØ’ÝƶիÉ$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©¾!q“Ë]Cß-í¤m¿±%»m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍ橇èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@߸É审ï–vÒ¶ÆßØ’ÝƶիÉ$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©¾!q“Ë]Cß-í¤m¿±%»m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍ橇èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@߸É审ï–vÒ¶ÆßØ’ÝƶիÉ$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©¾!q“Ë]Cß-í¤m¿±%»m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍ橇èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@߸É审ï–vÒ¶ÆßØ’ÝƶիÉ$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©¾!q“Ë]Cß-í¤m¿±%»m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍ橇èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@߸É审ï–vÒ¶ÆßØ’ÝƶիÉ$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©¾!q“Ë]Cß-í¤m¿±%»m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍ橇èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@߸É审ï–vÒ¶ÆßØ’ÝƶիÉ$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©¾!q“Ë]Cß-í¤m¿±%»m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍ橇èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ ÎäÝÐýÍ›7oÞ¼yóæÍ›7oÞ¼yóæÍ›7oÞ¼yóæÍ›7oÞ¼yóæÍ›7oÞ¼yóæÍ›7oÞ¼yóæÍ›7oÞ¼yóæÍ›7oÞ\Nþÿÿ9áw™ÉpÎd’ßûóVž9ýùßýdŸöóÖ›7oÞ¼yó†˜ü¯üÏ ¿ËÌ¿ +g2Éïýy+Ïœþüï~²OûyëÍ›7oÞ¼y³;?ÿÍýÿ•øÉü_§¿ý篔¿ål©þöÛ“Ý?ÿõò'§Î7oÞ¼yóæÍͼo¶dÞ7Ûß2ß¼yóæÍ›7»³õ-´û“œóæ›ío¿ýßùÉŸç}ï½yóæÍ›7Óyßlï›í}³½yóæÍ›7ÎùÛ_ÞßýEþö¯üï~ûŸßi»ßl¾ûÕdøfëÿK{óæÍ›7oþµyßlï›íò·ÿ¼û¾ÙÞ¼yóæÍ›Ÿç¿?æÏÍsòýÛoüÝo1|³ý|ÉÆÙüäÍoOºÿ™ð»ÿÞ¼yóæÍ›s~þëI|üù{§Úæ·ÿí{#Éù9?ùù³ùɛߞtÿ3áwÿ ¼yóæÍ›7ÿòüî#ÿÉä_ó¿õÍooœ½êo_8^ ù™©™¸Òï.Öï¾yóæÍ›7ÿæüî[(ÿÉä_“ßõ;çï¾FòÉU?‰ýéüùg¦fâJ¿»X¿ûæÍ›7oÞüksÿ=@ä_#ùÜ| ý®û½3—üí¿º7oÞ¼yóæÍŸó¾Ù~ç¤ûûf{óæÍ›7oÞüßùÛ_^âo÷ÖWÓ¿üÍö·÷oÿ7š^ìwÿ¥½yóæÍ›7ÿò¼o¶iÎï¶Þ7[²û¾ÙÞ¼yóæÍ›d.¿…þo¶ÿ¿¾¯’Ÿœ6úyÞwÚ›7oÞ¼y3÷Í–ük¯r~‰å?ù¾ÙÞ¼yóæÍóü÷—¹ùÉ?·gþÝ’Ï´uòÛ§ÎÝË÷i?o½yóæÍ›7oˆÙý˜þäŸ[3IøÙÐtÉûÔ¹{ù>íç­7oÞ¼yóæÍ›7oÞ¼yóæÍ›7oÞ¼yóæÍ›7oÞ¼yóæÍ›7oÞ¼yóæÍ›7oÞ¼yóæÍ›7oÞ¼yóæÍ›7oÞ¼yóæÍ›7oÞ¼yóæÍ›7oÞ¼yóæÍ›7oÞ¼yóæÍ›7oÞ¼yóæÍ›7oÞü;ó�gÞù +endstream +endobj + +5 0 obj +11207 +endobj + +7 0 obj +<</Length 8 0 R/Filter/FlateDecode/Length1 14992>> +stream +xœÝzy\U¶ð=U½A7ôBoС»š +„„¥ K²Q!lI0tD:ÑÐ 4ºCw—q‚£qAó—Qã22¾èsflLôEÇQttæ9Ž£>õ͸dd¾qyó&ŽèdÔ§¡øNݪf‰Ñù½÷ûþú +ªêÞsÏ9÷l÷Üs âƒ{ÂÄ@†K„ÎþPô†Ý B~CX:÷ƹ5M¶UØž „ù÷îè®þ;ÿõ‚Ó„¨Ž¢=¾«ïÒîŠýŒC!Ù¿é ‡º*—ŠYRŽ<–õ ,^ªÅ~ööôÇ/ù"uâìÆþwú"¡{?CÚö…þÐ%Ñ<U+ƒýFìs¡þð·þ¢ ûH¯E#±x¹nYOHãÑÁp´ñÎŽç YŽ]Vâ ø#]È4RŸaUjV—’ª7¤¥MfK†Õfw83³\ ²ÝäÿÿK}ØHƒz 1’(}λØQ’IŽ2}JêÍ>ÅÆé/ÿ_J¡“_wÈqr¼I.Tꈟô’=™{=C^E¨tùÉvòþ¶£äŽËxArHÒ䜗ŸÜNŽ‘_Í›ÅOúÉå(Ë£äMXJ^ÀP‰OAG®$Ï#×OvÞ¹X1éøè¦Íî9зÉ]Ì d#óvŽH#Œ1‘çÈÝ°9ÇQσ3¯þÓkÉøl&=d/¶é¥^sæ-’2ý7Ôê +²‘|¬#}s(ž„{ÙTô_ ¹mú …ù’ƒÚö"æ1†™º;7‘]x‡�ug²ë¾ÁBÿã‹m%i°˜Í%)çeʉQü’)>Í.$©¤uz2 ›Þ4ý76$¨ÚU ÔkT/~Ûš›TýHM¦ß/»Ô›Õ ·ÄDQ¿c{ ­µ¥yëÓæó7mÜÐP_W[³¾zPµvÍêU++W,_V±´ÄW\T˜¿(/w!Ÿãõ8­f“1=MŸš¢ÓjÔ*–RÈ% X›`s9s]ˆ¯åC E…\­³§¦¨°–¯ &¸—À—*oh  >”à‚\"_¡9à`B@Ìî³0S˜Á·š¬–¦à¹ÄK5<w¶oiÃöÁ>À%>¢íóh[•G;iØñz‘‚J%IËÕ&êöö ×QFÓ§®çׇS‹ +ÉXª›zl%òùèä¯Ú`òkWŽ1D—&M‹šÖ†ºþ-mµ5.¯7PT¸!‘Î×Ð!²ž²LhÖ'´”%×+‰NnàÆ +LJo<a"ÁCߺ -Á†v˜­¾6a.H,æk‹/{ωš‡…|Mm¢@âºiëÌ<›f§„„:×ÄsÃ'¨ÿÑ©ùÑäšþN¤f‚YŸ€­m^érÕ¡­‡‡ëx®n88:1=ÔÁs&~xÌ`ŽÖ¢¹‰¿ Yœ˜~âW¢îÆ@Âì•Eõº­›[v´%˜Ü:®'„ü­â½+\^ó Žÿ›† šƒöz%3ÜpB ØI mi“ûép=B_A Á¥‘ñ䈭UJŽÌyôí¦æ¶á„*wC_‹¿!”êÀèºHr oJ¤æòòÃ3Wé P\¥ÚÐÕË%Ôyh$¤šK€q#‘ ›h'ý3ùõ‘ 'È3[¸JÙH|jùÚ ò»·Ç‰ 84tC-m ¡BHñXíX‰)BAtXo ufÂÇGV¾zÆ»’Xµ½Ím”D!KX×'H°S¡Jøjéºâj‡ƒ5²/~KÛã¤lzb¬œs+#å$P#!Û×c”åÕ·uu'<AW®»n®ÍåMôp€o ¤°C -žpÑàÐXiiÛÔÌoÚ²½m…"ˆ< ±Så֞ņosÉl0�º\×ƸØ�"šÀÕaƒ¯^Ï„6W‡· N¡RàV¯æÚÀE’Ø(Fb1W®Qð¤þ<¦j)œÖ7$¹i¤.òYßàò¼òUTÈà0§LŒ:ɨ É!LS8 Ãø\ß@A’-RÐsm|˜ð=\Bð·IºIæ¡VVŒAm®øªe^oŽ±ÐLÄ‹ÃÉŽdÌD]k®qõ´?Óm8kxCr˜Öñ›š‡%æ¼Â äD +aa…ÙEs´ y̽œ —4]ÐÃc‚ -æž•~C×0ßܶšbc>¹Âu™4—…l‚M-ÕE…˜ÚªÇx¸n˘�×5oo{Ü„uáu-m0À¬VÆâXÛãnÊHP (u8©#qÚŠÅw=.2DGU@û'€P˜. Òy‚‘a&y¢<:‘@QÉ#B[…0 ¢0zÉdBªZÐ )‚Ic\c AÈXǦ�9f€4p!ÕV +>Cc)‚KÆB A–ðºÖÙ©[··3àîì¢Oœ¨Zº0\œ=èlÜVj¹.)P¾è¤ÅFìèü…ðkÑMüZDcH¤òáê„ž¯–àU¼J†k$¸Cì€äCè{¤ØÑæÅ%Ée½à6}$y*€IeØô~Z,Ï Ï` j…ÕÂI £gt¬Ín :Hauº3›Â)¬…!L{€Xªì`´Ã„ž¶Ã!;ì·C»ÈQøÅ“vxÙ#t,j‡&;xè€ OØá^:¡d‚J(±Ã»ttˆÂK(dÕ4G&;DšèØ$…'’sÈ¥™¤ŒÆé4CtEó%ç¸pæÚ¼•kçYð¯Hc¤ªÀLÊœôi.súÚw^Xf¶€£Ò\¶´Ä[±ÜÌç7{Íü¢b(�³Ã«Þ(›ºÐµ^uwËýëK–¾QáRÝn}V‰Ï¿ªÕu±«B*¨€X±r{ÏÙä áRbµf¦¥§§d¦¸=ÙYþ@6±bÇ‘é¶ †Q«Í[jÓˆ&<0*±sØQ=à÷€àpðÐaJŽâÐ+”2á‘9ð¹Æœg�EwÔºªLj”Q3X u—––€U»ÊJí6T\²F9Ÿ£Uš‹*¼P§møת˾3(^|Å;¯Ú/ví»JÙÏzŠ¯þ§k§nË,*ÊdvŽfOeH-5ã,Â…S€õ©EÝHôxZºGè&ƒÆlvØÙ”æ�aÁIJ6ÁfñlFƒÙhöŒ6«T¨<í€Ã`¢:Àï�ÁãH8`„v9˜@0I!ˆ:s~ŒH&h§V˜q?Érš~‹Î§0—)Êkøœ¼Šòeh�vVéË…¢BA(,R(fŽ€Õ»r_øj¥¤'ËeJk°eúóû<É'¡Ü«µf¥aH,^’æe·?àr˜X½? eíCK º‚KÀ¿¸%ððh_MK )/A÷ê# AßÈBg$\TQæ°—•V”û ˜¡â:lü¢<>Gc³Ún–ymì'u?*)Zºé’g”þèð®»|K*·´ž·ù–íU<èn<œmùðªš.+ÏöÖtÖ}çç¥~Ÿ¿¦rsViñúmÒ1ƒlœ>Å~ˆñœ=$4YUz’™iR™Üž “?þBgíÔÉ”‰ŒcK€±c˜ÖÏ\BƒtˆBäFÂï(Ñ9™’æôž Lêš\ Ï™Ë-¨iÞ@§H1 V4ÂrsÏ1¯í¾]ÜÿÖë}Í &.~!z†®Þ½=0(ž©ÛüÀá=pÚYôåã™EðÒS?[Ä|h¦:zÅF6>s/9 lqU‹Ã™êHÍá+F¥Õ•Æùiöl—Öµ% ÒšXâ°F‡!•%<Lð0NûA„9m´óìRÄØ$UŠ_IRQIéÙ(y8•sÈKÐÊð9‹ìÙ@#Ê󤥈ßq1è˜%7þw/îîÖ…}L×û÷l\t†íÎ,Z¾°ðËÿúXüÒÞ°Xtú|NvóøϼSf³”££Ò&ôi +¹Oˆªñ¼¦ñð”©fÕ¨•íu=<§‡ãz8ª‡[õpµâzèÒÃB=Xõ Ò㚤‡õ¸,õÔƒ_‚ÆõÐÃíšô@ô0I»ˆ7mÞšT–älj¾pÎâ”l‚>Ÿ]‚iå@]Ýœ¼Ò€ñ¹›}†¸p÷ëªÌºÜ\g0dªX<–æ¤æl 8mf3†§Ñì13- KµkU¯6bóˆih´/a`ãB”ˆÌD_™¥Ò''R©8É‘t®B%?.ÂÅh._ UP!y÷Še M›µ¬tÙrxõΛöˆbÆàØ'Fî8X¿±«9gÅ}@®º¦ýPMg)ûÌw¿7u ³hç 8w^¾ŽUݺÀ·ç%^t«Ô;§ä¯L±Žý‚% àO´Ùá48Ý™ŒÒT}¶3ÃlHÇEhKÇe¸%À’q7t»a›7|ê†÷Üðº~é†ÇÜp½p4迪ÝPꆅn°ºA㆞ÏÜðnxÖ ¸á¨nvÃÕyµ¸¡Žbç¸Áâ•N»áŠÿœŽ»á$þ :Ü°Õ 5n(wCžìIü9ŽÏç¾,ÍŠÏ(öŒ4·&¹ çÏ•g!•ˆ&Ý0á†W’ÝšäÞEu•¹Ÿ¦̸n8ì†!7DÝÐä£tÉlŸW;ì¦á9xÖ:÷Ú}Ö5ø­ørf/É�4£KÕGrýãÚÏQ2ûZX.%9›Ö%¿ ùÕæFŸ×³¼¼mÃrñÎ ¿UüìØÙ!Þ´.ë,/«÷ÞÁFq}¸¦"Ì-ø¶ÙqÿármâÃÚä˜çqá +’‘áÔ Z§6Û½�+’Æ ìØþ@ªÝfALÖ´5ÀšŽRÇ=Gý‚~¬|ÚV6lKÒ°èF»23†Å0¨ÅeƒÌϵ]ûÿªB™_ŸäÍ/PjÎûéJ¹>ÙÒº ”‹vï,¬œ)OÚšÛ•ú„îÛ,Y5ý¥êS¬uÄBòÈIá–”²@žn³yä¨òåš‚\‹GmP‚£ô¬ZíÌpÚÛNU0àd3lí ËH>·¡|ˆæC0„|˜È‡{)»~ +áòáÝ|§Ú%ù°òe:lʇIÊ‚PÊWòa„ò’)gŒöµ2W¶ž’¹h¾rÎd.ÙxŽ¹Æ+ÏÚ³Sm`¨-SË–ãp¿Ñhݘ»TÞ\ö©;òòÛ÷ ?ùòäðÝ?~èŒst” “éS7]õè/Å¿O±…ýâò¨¨í¯šúæ¦÷±(þAVÅíG÷>° ã'×=ó+úºßÜqg%[„"³V ƒÍ®1³É̤«Í,c5™Òü“QkHÅL–jk§u>*ät<³S–ѵb¦»¥¥²”ê‚5OŽfŽó¥m“¹£`eéõ¥?«÷íKÊê—V³Ï‹.ûTuÒã{J/×ÄfÜ?6£lvV›Õz»ÚîpêŒX¡ëLv+kÅŒj'NX+8¡Ä œLN˜tÂ+NqÂþ°Ú0§ÚÞ9³‡•ÍÆ-îdé •/R¡f– +5ÎLKvóÒÑíâò?¿yíÈò‚æ¸xúŸ|s_åÂÅðÉ_¦<â—øÄž×õJuŠ$ë#(k*Jû„p%JKÔ¥M÷t&ÆêÇ Di'œà§òÊÂNPyÇ R¦‚G¤âË$«î¥ ?ÍhJæÓË*Ëdø¼ð윷ók¹n&(çØLÞd}­-WêU Aö±áõßÿþÿxëøw¯¹jϾ+¯‚·E³øÉ_Ï|þ·ß?ûÄÄŸ~þýôMüh‡:´ƒ 3ÙAa{&€1Kg3ڲݙX—3=™¸Ñgf,»?`1Ô[ûLš›ŸpkÀ½c­Ÿfª7pn0ѽDNV³¥éœâDÖfv…% s91MJÛ¾ }“'9›3Û�Uô–çjÍþ]Ën-)¹ÛÛ/þöièoï‰ÀÍÀ›–á#~‹~…§ø¨?ûTìÞ +w?xôØ)>;Pמ›–ë„-ù–Ü\‡Ãâa5ééDC + +ó3,–XÀ—<KÜ&7“ºÝ<Ÿ ðZV DµCZƨ­–Í +ÂD!ŒB°°›< —ù.¼0YŠR½ÌXúÈé#é8 Í –Jåø±ˆ-sPU±èñAÅòµrõ£‘ŽÍ¸1¶¥<Â&¾øÓSé«‹Z{ÏmÃ7:´»oÏPE¼¯î<\?=rãc£Ðÿèo + ëI;wøÁ«¯×궦h†¾wíåÙΣÀd™ÅÇn¸ßjûê÷j´Å(ÚÂIrÈ%B½KO8«UC4üB+ǹíîx€ØMvô½Ï•)æXÀ˜æIó¥±)lZZJ&› °Za!…0±FBp!`wæ‹€”`f³¦Ü’¶¡¹µ9nÏRàZÌ&ÂÓ}Z²%C:AŽ¼žMLõÿùíûoˆý⟯[Çs}ËGFSî¸gìExäËK¾{åU—²Gýñ1qD|X¼+ç? æÖ×›xôÈÍPI×mâóly˜ˆº…ÿv˜­æܧô ô|ŽÃãI·Úî X­,«º'Î>¸C“¾ƒ‡Mô¸ñÞæáe<åáV®æ¡‡U<ðàáAÏÃE_ñð¯óðcîâá:ìâAÅÃi^¤p¤ìâA滇¯’¬~1-<ÔPd·Ræ%Ïv9–ÉÊ)¥Š’=ÇÃq:Óå”oK’ø4å0 ž˜¢<øyðQ9ñd•,ËÚÏõ©gÞÊüÚà¼d$•]¾²9¾ç¹µlöt‰![!Åó"%;©ÏÀµ÷ÞœpçÖÔT¬Ù +G“m¡iéõ/9oEÔÊeð²Êó7Íë^@÷™–éSª÷1v]d­à5³R8.ÈÖ¤·H*¤°©©U&Ÿ­Øϲ!¹øf"r&{ª9Ü7‰·Ô‘!}›ÂS¯Ù„âeUPÆjXø„x+섶W'5ÕîºÇƒâô©ÏO þzUî:Í;Vè¶Cg™øöO |â¿‹¿ß³¼øßÄç«$ ¦O©ïÆÈIn‚§Æ É̲¨Iš1­=ÀÙ[0’¡Ê‚ª®,hÉ‚š,(Ï‚…Y`Í‚ãYp4 nÍ‚«³ ž„›²�±OgÁD0¯dA" F² šþ,øZ±ôÚœóqYÙÜmƒÁf«ŠçV˜åŽÉ‹ HuíqxaTüüŒøwñóQÆ9 +ã/©þšUQ‘uæÝO&?9É–ÓöÛâ-“ô¼óÈiôE‘ôÆ¡[ä&æEf_±[g]²DÝ€%VÖuVÕ¤&|ðŠÆ}0IŸ%>à|rÊ ×7~£É˜IÅšŠÙ=_ÚìÜxÓ87¬ãsm»ñž5ß=ðÝÎ5“oÜ÷Ô:¾û¶kn_Ó¹ÿÀþÎ5è{«zõ5únÃÎuEÅ+¶í¿pä±ñÏG7ö×m[Sè[µãªà³oäyi~ÄSÇè76;Y&¸‰Ac6˜N+Û°f¤§´ÒU¸¡WÉ{þîÝ;/<×Þl¡ÙásÖä•c#ûûÞëÍ>üÝ«Ì!¨F1!Ž‹Ïˆ fDü¹øÈõ°\âûâǪ́x?¦¶‡Äû0Š¬"DóGSW +–tܼ€¤XV§K³°Y™i'¦¿–¥¤5¤é5NsŠ^’‘ÑaŸÑ³ «ÓèpA�Ø4Œ  ñd U)„*HOÊ +ä&îSs‹^ewöò0['¦€@r—ÝÉ‹¶ãâòÑQ¸ ŽÃ;04::5q\uåW/»*äšöŒŠ=S‘õUí/•ë+!êêb$h>5§*Kš UZ“ŠÍ°¦¥›Óƒ‹Ù &ZeЪŒ`l¤‚å´Þ³ÂëVxÎ +Ç­pÔ +·Záj+Ä­Ðe…+ÔX¡Ü + ­`µ‚Ê +ÿSüÊo!˜‹­¢8ãV`V±Âa+ Y!j¿+”X³‚É +é,„&+œ{¥ÃÜYàx^&³‡¼2éƒ ®¨â™/-—•Òg úù«Lþ ÆzY`½ð’X¼ð¼ýÐÔ ÇLM^ 7|�¯UHúâ+ä)¸J¼BÕ3µGöÆ¢ºcÑFÜd@Xk3™\i.�=Íj¶˜Ó4*g ¸\)ª”LLvÚö@ +kJƒKHe1qð +QNÒ}0)ûì¡ë¬ÏDTº®f¯”ž±$ERfbðà‹SoÜ;ʬ?3yó•pñMâÓâµúýŸýxìØíL£¨JFáCO^󋼩ÿtU0pÅ‘+§~q€ê5}F½õJ!Ò(øÔV’fMsf:ðHêÀéƒ5á¾bÒ& ÉÄõŸ \&LdÂH&D3ég9í&Os²ñòÒùÐr&È婪£â«â‡Ç/¹ÿ³?O}1èÿEü‘˜3ŠçñšÉùêräà‘ëQñ8&ŠT²ðtD¨®@Y]è:†k&–ŒªÙ†Œ` Ý10E`‰Ád`RÔƒÊå²¢; =ನôÁ€Ši¨Ø‰lɆh6ø³AÚ,•Âü¬Ã/î-³9`iIHÆ—’0šÜ»¼ [^³—“öMïªÑQö¯Õ\ôõ·á" xÄÛ@Œ¿²:ã«WeÙŧßLŸ:="vÝ7uÒô…øOx +Y®n¡5ZPøo•FÏ›c‹'Û^©Ï°TÓ¤³éî +5VµŠÖCÖo(ÒvÌ)©f+4,šâ´bú¦ +­|~y&×Yç(Ò^§c3Sm¢gÄy‘’MÖo2¥žò©‡æˆ"×’F,ÛÚϵ¼Ï™þÁ˜äDºž|è2Ÿ‰Ž2ü•>Zà©ŠþiÃ.oŸ¹gÍÝßO¸óÖ×” ~ñ‚Ù6ûáµm^µe[ùuËV쨛ßUþn7}Š)R]‰;g½°(5=]›Á²§Ê 7ø1 è˜ëÍ[ð|q/=EW9ÁçTR€rÒ/K~Æ·T–Ò/j<äšù + 0[™—Ïx,„ÍÁö˯Wýîw«JV6óW[w1·-zã–©ýëªMëœ*ÆWæ‘þôÛÛ«ÿN<òÿ÷ý[Í+¿ýï-±wVé¿Þt‹ò…tZ¯XKΟA‚³þåË£©Äø'’«Âj“©$l6i‘ȱ¿o/³I¶3ñö©·‘UÌC¶û›ñíÇwÞÕØÞ†ã-ê_‘UŒ\ïm6Y…o«D‡ïU8×*Äë@¾V*Á³°že–àÏݬ•½Œ=¥6© iÔÜ©™ÔƵÿ¥‹ê>Hùm*—z«žè7êOΤmM;‘þƒô¨6RŒç 9£›ˆ`}Íü‚ý%¤Q7 Ìè¼mF@ÌmJ›!ZÒ­´YÌCýJ[…8×)m¬yÉJ[ƒûûýJ[K.#Ç•¶ŽX¡Xi§t¨VÚ©0�~¥­' ˜§fþc¶˜yKi§‘ +V§´ÓI»F’^%ý§ß({¾Ò©X¥Ít¯´Y² ¹­Bœ]J[M²T×*m q«~¨´µä´êi¥­#ùêcJ;…,P¿­´S™wÔŸ+m=Y¡{MiÈ)z¥F.JIΕNÊS^­éÝÕï½,ÜÅu…â!®3½t°wWOœËï\Ì•–,-áê#‘]}an}d0 Å{#Å©ëÏF+å¶"‹†P¼Û0ÐYÜØÛ–q¹æð`o÷Öð®=}¡Áu±Îð@Wx+âÎÆ8»¿-<“:¥ÅK‹KfÏÆíq!.>ê +÷‡/æ"Ýóåàûzcñð {¸ÖâæbΊ‡â\h ‹k™!lêîîí S`gx0BäH¼%½hÏ`o¬«·Sš-V<£Àk4ÇÃ{ÃÜy¡x<‹ T‡b8JÖÒ;‰rûzz;{¸}¡×ŽõîÀÁŽK¹ù4Ž†P—È^d¹7\ˆrw†c=½»¸˜¤²BÍÅ{BqIéþp|°·3Ô×w)º¬?ŠTè£}½ñœ¸?ã6‡÷q[#ý¡‡ŠeQÐ6ÝhS®·?:ÙKe,Šu†Ã8Y¨+ÔÑÛ×Gn=¡ÁP'Z ÍÖÛ£ACpÑÐ@QížÁH4Œ’ž_ß8‹ˆÊÖŒEúöâÌö@8Ü%͈bï ÷!N܉\,éÓDA»â=Es$ïŽ Ä‘4Â…ººPq´V¤sO¿ä'4s<)\¨s0‚cѾP¹ôÇŠ{âñèJŸoß¾}Å!Å5è™bäìû¶±ø¥Ñ°âA‰K_#º@rÝê_I‰æ \SíS‡Âq +B!—ŒÌ¥ÅK•)ÐŒ½Ñx¬8ÖÛWÜåkªk$5¤—ìÂ;Ž÷e$Lº‡wû!lu’‰’KÉ ÅêA(Gòºߥ¤„,Å›#õˆÁñ>¤çÈzl"•ô Q¾2€i4•Ž|;·RlmU¤h Ô…ØÚ€ôÈ¡é:pt._Ž4SH/¦Y‰rÙƒr„²ŽÄ*Œ8]ƒÃ#8÷yü£ñm´›)E¹–â]rNÊÄ·9qÔÒq:"IÚO¥¿a¤û6{pˆ¦Þ‹áH˜öº(W‰w+b4S,?¥”,§³ P¬–sÌØ„3v#}'õd³“ò–"BæÁvbÓ‹ÐÞƒT‚.J—Ô-†3ÝçŽf*Ý^:çy.õct¬û1E/Ùf-TŠB%[ìCI¤y{h;DíÙE©¥P(;0ê¸o‡ShCŠ_è{)%šBÅÞÝô£óà•Oöòü¹9j§µºìé~SÜN„÷áÏ¥Ê*ëG«Èsu(ëh]•=ŠÆý”/G6ã{ŠõÛ€7‡úxÖ*rÜt+qÊQÚ(¶#T‹¤‹¨o$MÂTR©¢+¿)úèܲl=4:BÔ·aÅ×qªAÒ^]Š¦’ÔQ +)"µ4.¤õVlz>æ‰Æsr”-876%ŸôQycsxPi»ft”­-aõ)3É÷Ñ|tñŒºi¼Éí¢ÜŠ¾ÁæÝÔ6qeÖ•¨ d˱AÚ=Ôòz’£9þ5Ë…¨}# +]”f¥¸"K?]=4£d%–>”Nú)¦q8wÕt*k¦X‘Ù÷¿¦“äŠR Î]ƒ3²ô£ŒÊê˜Yu{æ¬ß¤'š15Ò|Uâ§N±wiÕœ3—Òœ9_ 9{±§òĨ-‹©»p¼ gh$J-N¦ Hç¸ÆRüë: L�z`É ’ÍÐNZaY¾«Æ÷zìKïbXC†o Â×b5ÂWaîôà³ +ï&¼á­Â[Æ(A ¾}J¿û…Hñ2>Þ´ +¡Ò{#öð]¯¼ë^‹ïZ¥¿ûø&AÐb^EŸOƒJ8SðòpS°ÿ+ðCŸþ”ùdr±çáɧ'™¦Û?~øc¶äc0~ :ò‘é#ÿGÁ¢|¤I5žù ˜ÿ4±Âóîš“­XóN+9‰š,9é?9t2qR}ØÖwX»Ç4ΗŒGLJÆ_ŸŸ× =uø)æçOú<Æ'=O2žcMÇöcƒ‚ñAσŒÿ®à]Ìá»Áx·çnßÝìGŠ=GêÝžÛo[䙸mò6æÄôø±ÛÒÌuOB4’5hÃÍÇØiÏÃëlpªeħoÞMxGð>„7žy݃·…lû÷A³ëæ‚›/¿ù†›ÕÑk†®9| ;tàðæá½OïebþÅžÈ@g ~‰'³ÌÙª-c[58 Î.lèÈͯ ¶ žvDÚ±½Ä³½~±'£ÌÒªF…Uˆhd=lÛÄFØCìÓ¬V·ÕïölÁ{Â?égŠ¡ÎØäiò5±'¦'„ð&/rÛÝ8´‘ÝP·ØÓP¿Âc¬÷Ôûê_®·þãzM{=Ü‹¿u×=]Ç +u‹}uBÛ[· ÁÕj/³µšÁØj*3¶2€Ž.#­>ã´‘1Ûû¬‘TfÈj8‡ÇZš +6ÐNoÝ”Ðùw$àºDn³ô¶lOh®KÖí;ÚÆ�þ)pààAR½)QÚÜ–f6%º°!H!l˜²Çì¤:‹Å èØÞƒOR°§�;c2”ÌŒ“‚Ä0EÅ(HrðY !@¢¤Þ#ÒC,‰$ê˜ÂŽËÚpîü¿TQlV +endstream +endobj + +8 0 obj +8993 +endobj + +9 0 obj +<</Type/FontDescriptor/FontName/CAAAAA+LiberationSerif +/Flags 4 +/FontBBox[-543 -303 1277 981]/ItalicAngle 0 +/Ascent 891 +/Descent -216 +/CapHeight 981 +/StemV 80 +/FontFile2 7 0 R +>> +endobj + +10 0 obj +<</Length 360/Filter/FlateDecode>> +stream +xœ]’Ënƒ0E÷|…—é"“‡„RH$}¨´@ì!E*9dÁß×3“¶R ãñ½Ã5㸬«ÚõsüêGÓÀ,ºÞY×ñæ ˆ3\z©DØÞÌ÷½ÍÐNQ¼Íra¨]7æy¿…½ëì±:Øñ Qüâ-øÞ]Äê£lº¹MÓ àf!£¢ºÐç©žÛbr­k¶ûyYËŸà}™@$´VÅŒ®SkÀ·îQ.e!òÓ©ˆÀÙ{©d˹3Ÿ­R¤RfºœovÈ)óYoSäŒ8‘ÈÖw˪ï¸^"ï™ò5Ôó‘ëGä’X'Èkˆ¬¡ïž˜Ã¡r%™3dΟ¢Fqþû+ÌŸH…ýçפáüy9Fuί©?ç×2çט_qþ ³)ίñìꞟzVü]<»âü[Mƒ¸ÿq Þ™ŸQ só>Œ™.Í'Û;ø½{Ó8¡‹žo@±g +endstream +endobj + +11 0 obj +<</Type/Font/Subtype/TrueType/BaseFont/CAAAAA+LiberationSerif +/FirstChar 0 +/LastChar 30 +/Widths[777 610 500 277 389 250 500 500 277 443 500 500 666 333 443 500 +443 500 500 443 666 722 556 722 889 722 666 722 610 443 277 ] +/FontDescriptor 9 0 R +/ToUnicode 10 0 R +>> +endobj + +12 0 obj +<</Length 13 0 R/Filter/FlateDecode/Length1 10276>> +stream +xœå8kxוçÎŒ~J²%¿Öȃm9~ÈØ1x0¶01‰_¸H€±„$#- IÆ!mŠišœPh“>iCÚ¦iK“xLšàд¡ÛM»» ]H›MÚ”†mÒí—MSè.IÛ$–÷Ü«±14Íýöߎ4sÏûž×½w¤d|4Ù0<Èþ_ÌY\.Àó�$Ï¿7)>¶ËÓ‚ðE�îàPlçÈ—Om» „�tßÛ9¼oÈüµ¯[²déCA_ þ/‹j +— å!$ ¦>¡C|âKB#ÉÛ~¤/[‹ø8âòpÔﻹpI>âg/ñÝ;ÍŸçq1â >8qä-€"íÄ¢‰äK„ÌHIÊŃ1˜yd%â÷£OG‘FðC¯lµçxA£Õé32³²sr ðÿîÒ<¯yîÐ� ìcÏk.a˜a `ö»úLmžýóÿ¥zö$ŤÞ†70~?‡Ó À¿.”&•¤ŠVäÁëp~ò÷¬¢=ÙÈÀWá<< Oü9¾CfàeRŒ}~ +!JkWÈ�úsi£p˜¼Oö;<HŒŒ»mçál­Æþ»ˆÞÝá~Ò5 ¾/sÏÂWøÜYx}¾•;Œ´Yx ž'õ¤ð=x˜Hà|‡ZÄvÿ:|î¼JÕ<–zZs`¦L³ïÀ“ð4ËÀ~˜�ï¼ÒeòGr×d1Ñ“¹šþpŽ©ëàwqOrÜÌ}ˆ|vâí#¿DéÃüÚëÂ9‘Š¦BD÷¡¿%=p­<–z*õl‡IîEè‡ÿ‚‡‹Wÿï`äÞCêä?gÿ¦™ï~Èš1̾6¦= ŒEø%í¡ÙgSû1¯gá¿0û/’byýÖ-wÿ¦¾Þžî®[oÙØyó†Žõ®ö¶u­kå–5«›oZµòÆË›–Ö;ëjk•åK¤2»­Èl2rs²23ô:­Fà95¢B¼í +_.š\>©]òuÔÖˆíE¡¶ÚšvÉåUDŸ¨à THŒ$ùÑ+*8ø½ŠŒ’C×IÊiIy^’Åfh¦SH¢r¶M§É–7‡Û$¨¼Åà[,T0$»5˜WÔ[±]qí M´{ÑG2••¹NZ̬­©Ì,³RRlŠ8ÖpŽöUSèsè´i»/ t÷¸ÛÛ¬v»§¶fƒ’+µ1¬c&í:EÇLŠaê:Ü#NÕœ™¸wÚ;¼ÕÙ)àÛæVxêNðíw+¦j¥JjSªn½#*5R[»RM­vöÎÏÓyuJ¢hÊ’8ñ6`8Ò[¸–âS)ÚrãÛ@A…[§^·^VæzbÂ%‰® ï„ozv|‡$¥‰©ìì‰X;¦ºÝhbzöô=VÅu¯G1zCd•G ÝÕÛ©ä÷lu+\¹K ù‚ßÉ~£Õnš—éþ{lÀ´`r0Ãv;MÃ=Ó2ì@Dïq§qvXO‚ì¬ö(œ—rÎÌq,ý”3>Ç™W÷JXÛÎ>÷„"”oHí˜ñ{|Êøì®]´0’QÉ}Çj—&òLâJ§‡ÉŠèÕ†@XT4˜$ÔZ¨€}CU&Œ É}'=¼eÅ *LyâJ ÍP;íR»Wýî ¡ÝQn„MnEnC@ö©kŸªw¢†Ï‹ ·±b*N)¦˜¥ÖùêR·ÚÃ}n¦¢ª)æu +xýª–âlgëJlŸð¶¥] ¶¤÷SÐ8{qj™h}¼–§ +¬Ã.«hŸp†›×Àu7$º­vEö`…=’;è¡m‡ªºheÍáa½²ÉÝÙ'uölqߨ:’fPsByûuf$·5mPÑ—ëE7gå=(hD‚èB@jmƧ¢+×ãmÄ„3*mÜÖfÑM¬0'n(Ub{°M•£ø5F5´ÖuÌYÓRí¬ë°Ú=öôU[Ã![T'F =MjÇ ·)dè±?×u0ÍemzÑ-%¹ÛMc£éaYV“Ár®ÖjÓ5Ø‚dašÀŽì9„&SqU[&WYÏðy´ã:ö†9¶8¡—:û&¨qI5èùh Ë7š¬l/  Z½W4â’f zbJ–éb­¢F¤ ©ÏÝ̤q?¹Ãz;+:Iç¦ÖÚÜÚZ§$r°gJ&û¶¸ŸÂ#W<¸É}’#Ü:o«gj òÜO‰ø†È¨¥R"EDŠPK½ˆè™¼õ)`œqF`¸š�£éçhüÓ\šfLOTÁ&’CŽæÈsÒÒôiÚ8£±k +hÊäL¬—3äl.‡³NJ:‰”ÓxJfx<›äëjõ2ò4ŸÊ­i‰q”Óì¿:uÿ÷ãÙ€jì‰µÒ Û¥(„ÅÆc¥] ÐFù˜'4áõÐÅXü…Hk°LÒtD›­dJÁV%Kj¥ôJoIÓµ”®Ã%ÕDZöÝ +¡°ÕmÇ%)–ü³uÂø­”7• ãïjѹ³ø6Ò€ï<èÀ&çh9 Ïñz / ©å¬ó¬)¬\ij45.­Ï·›ìù&»é¬|ïØFþ¬æÀ»û5Mï +o¤_s¡­]h+ +ÁwÉ=ÙùùV«`È(¼ ¼]Ì6[ÍÖAÁl3sf¹ {ƒÙ,h4ùƒœpÑ GÈ{ÐNŽÚɸÄìÄk'Ýv"ÛI=ûŠv20°G½ ¥ŠZªMy°²ÈY=¸}€èl!s–}òV.­'f¡Š˜ì¢`1ku¥„,«0Š†åùË(¹a¹fWêâ,Ì´pwŽdÜuð»§>µo,…§Û{zS¯§&ÈOßI>{æÍÇ'oûæbó$yq°;õÍ©ŒŸ¤†wbÜ4ÏþAn… +h„¹eIe¥NgÉ5Ôð¼ÁÂ7-Ó:z=Z-xrù\m.á ¹¶\.CÈÍËËêñä‹àìò,±CÁ3M¤«‰ `l Õ&h¤ñA#Æ680Gü6<¬ˆ¦¬¢iÙòÒ„a•iuåkHcCÅd.hlXaÉ奲ŠJI›¯Ëå,”´†4‘C_U^9÷ÆÍ›nÝ‘zÅúæsgSU/–;µ¥»‚™Ú½ž£;z«×ßÔ:²ÆüÝcßV8aÅ®ë{søÆ¿œNíÝÚ®ý¢6S+„‚/rœ u4ßÒÙ±=ýUv7&"%tA¬‘Ëõ�†¢Âœ¼n>Ǩ1€åxÙ_DΑÉ"2XDœEXKZMhiii¬^Ðd¦e•öRbi\Ã56Zh`Ó O²ùL¡Jv·.··- òÍž±º¼S¥ñZۆߚy‹¾¼C7ÖbÖ¢Zå%fKf†ç3,|I±6§Ë“™©5‚Ùkærx³ÀÔåAY’‹œ˜æ–ÆkRLÓ &#`J 5uD*3–¯Ðär\ï;©+$÷/ϼ+¦~—íuÿòB÷p)1xÁLʉ–d“ê3ßÉíó§>—šr¢ ²>¡¾Ý‡¾e᯴z¹Ä¤Í-dº<FÞÜåá b…Ä[H´÷|^ðw‹¹cv±H«, +÷¥~Jͤ.‘ð$ƒ¦~õñÛfᎽ„çJSM½HjÐ ©N½šúÓK}æ‰�óeú² 9€+&òyyù‹3ò3ʤ<È.éò²Zz¤-�KL"´NÔ%ö˜wËÔˆžÙëH“¤•Ê8“1檱÷s!a=i¡9ã7 +YÂÖÙüì—?M|«–ãH±>õÚh|OäBôvÃ>Ç?âïÁ ÜR˽ƒ'É=œ4ùƒSO§Žþx>oµ˜·<(†¨¼®0Óh*ÈÊâyS&o-)ÈêõئCÉÕ`ãiµù¸ÞŒÛãÙo$Fú…‚ãVµ’A+鲧•õÞ�.3çÀÀ‚m„î"×®±«-g²ØÙ²ÒpWÆÌÝ|%õ.ɼòÆ;37CH¤ôïæÉCúˆ™Ø‰Û@L=—ú7ý_;€uá§&>vç´G³oUšÏƒ>'{uZë"KY6@Y¹q‘V[uC¹Éh2&<§MäK&rÐD\&Òl"%&’a"Ù&o3X­ØÁV«ÍV”ðØt|FÂ#꼺˜NÑÑiêu²n\wTwN§Ñéð—+võÀžt”jŸãÆèÜ>¾þvÛd{¦T¶¤²Ã]Ž;K5iJl‹Y¾„n1¸™ZJ‰P•zÿòk©+…¤Ôú|0vðS;¶í»Ý7°y·>õû»ð×cŸýú$¹û'/Ÿ¶ø¹ÀÎí×üÛ6û½nó“?û©òÉ‹„üI¬ïz¬o%æ£$è“ëJótÚ"Lˆ6/_b°'=ÙƒÍÀeðÜN-Ö„ÇÂB™‹oϵElœ+bãüÒ¡;!‹gE..dÜ41Š<MºCiY— •©?¾úç5D_yxï~®âÑÀéWysæÏ©—ƒ»w nã^JJÝ{ü‘òû~û›Îþ™—ónêkÇî<v÷Øèá²½g?]SÂ*\S]²3W§ÓC¾ ¨7z¾Û“WmÑáÁ"r´ˆ\."JIñ"r wCvªÅãØ”-¬R ÖFÀ¶ž&¶®ìMR:ù♡;èbº’­¹ñѱG¦…U3_K½6yˆk{z"ttýGc?ž›¤¾u o6ÜŸ—ÛuZ»ÙZ’PbÖ +U7Øs +ùÂÒÏ?X‰×Šç“Õfå2«µÐÈgöx̺%:3]Ð}Qn õ7ùâ¼ÅqÖ]l_p¦Ï)V…l¨ŠÊ¥$ÝH•u[t¯ÐÑ}•– °”l©Ù×^}«òÏ–ã{‡7‡þøðæK¯üèÍÅÍÞ>ܲuÿ³cëIóW?ü¹ò[äfyÙj‹³çÀöc~þÓ%­k›+òJVlÃX‹gÿÈ}Fs#î²7É‹ó³³3sô9‚PP˜£ÑjðÐêõZÃüæÏ|75Î¥œ5ÍüÙj’šW4Z-’z¦jÉCûÔ¡/¸•³g›[ì«Cywâ>þÃTê‡3?ëêÌ}¬ Ô³Pû�æºî“·V�Øô¶R£N_ªwT–ñflca o6flz°¼î ¿pO:È&¹ÉA^qï;ȱ9Ôé œÍAÀA.:È9Q七Œ;ˆ—ñÔU¼gÏàµâ¬‡°‰ +´Qúu(½]›ŒìHµ_=h±,…ê»Cš­3ñÙõïNý^=w—þK“vÅ—Çx8õÆC½a 7H?61ó4ß±9Z“ÿMÛÇbøx䥞題ã÷ÎÐu}7öÜõŒi–ÅÅZƒ!§rp1šñ„1™¹eáÅ.>vÆ°Óåšæ21rìUw;[ºFìž<ruý +G^ú§Ä·k¹ Mê’ž Âà{gΦ^Þ¿ÊÙSWR/¶K·›¾,¼˜Ú¡œK]H½3}ò™ï=r†ýéGÏ™â/]ØòÀ ¡ùm,û¿ëŸ6„*®þ•6û†öŒ†€cSÿ,ЭIÝ +ë®þ}xÝÿoF-ÀYÍOá€f~1Üc·ð»7Q˜[ €£ïõHÛcwŠuTö5ÚKØG_'KHˆ<IÞçz¹ÓÜi¾•˜¿"ìNhê4ŸTg5âÏtÒ§»œ° _Éoá7áïÊ-%‘yß>2ï'bDÕ ¨Â<”@X…0Ã*¬Áê}A…µ©°n‡S*¬3YªÂKÚU8“„IŸ +gÁ"îéùò븗U8šx­ +çB zB„ ÄáûU˜@©@T˜½`Sa– •*,€CتÂ(îTa-T_Ua\~¬ÂzphN©p,Ò¼ªÂ™Ü š÷T8 nÔŸUálØ–¡QáØ•áSá\X–ñ\[xg8¾=¾¤OôGcûâᡤèðW‰ õKëÅõÑèÎá ¸.Eã¾d8©Ë\w½XƒØ‹&:|ÉqCÄ_·1¼#˜–û|‘Dkt8°6áFÁ¸X+^ǽ©ôG‚ñ%4Ô-­«¿*@ùµ”¿@'œ}b2î G|ñÝbtèZWÄxpg8‘ Æ‘Žˆýu}ub·/Œ$E_$ nšWì +ûƒŒèÆ“>Ž&Cèð®Ñx8ûél‰ºù8$¤/Üoñ%“ÁD4ÒêKà\èÙÚxx$Z#Ž…Âþ8æKˆ`"¼3‚ÌûÄkuDäú0–H$ºMî Ö ßCñ`"Žì4-‰`<<¤š“!_’F>LÆÃ~ßðð>,ÝH Uw`­ÆÂÉÝ7|¢.í¦eS*†Gbñè^æ^mÂ#8/àÛ'ÑFÈ÷ù1Y˜±°?Á’9c¾Hmûh< ¢“›×o¼*ˆn¥™ˆï &˜t$ $h!â0*áÄÃÑènÊP4Žî’¡ÚþE#ITŠ¾@�cÆDEý£#´D˜áäœs><Š¼Ø°/‰VFu¡d2¶Êé«ó©UñcQêвóÃxÉ}± ZŠ8µ22¼+¡Ue¥¥AômØ(vÅ0?.tNTjĹÆ\Z·TÓŽ%u‰ðp]4¾ÓÙåÚm¸!íÄ;‰÷í¸Q@ÄÛ‡¸!?D!û ΤBHñUÇU86@=,Å[„õ(Eþ0ꋸiGQ>Æž>f7 +¨ƒLÆùpk õª^t0í„6 ¾-lD½È]hW„>Ä"€VćQs-Â~”Š LeE¨ÅûÃu?œ+ÎÛþ“IÌK4 WKñ®ÿ@ súµóú<O˜ÍAódê÷ŽqØ´( }hVD” ²&dX€Y¥¶ûQ¢Iu3Mš—$›-¤6}ÀŒ]8ãêûY=ç$ýÌ6í‹´å(Â!5û`”U5’To.¶Îü·õøàécÞíesÞÂèO0^+â 5®tÎÖ²ùF£¹COè¼!ûX>L›vZDÕܽ'~è<¢ªëSëÁOeÓ^R5ßCì™`óFpá¹nI°8ìn ½YÆ|,ÿéš 7ÉdýHÆÏ>uÕ`~Ò³îP×Õ[¥¡ùØQÞ^Æ*{5énR»TdÔÂQæû\öjYE¨ÿAæ…|lÕï@a6OÚë «hP­p’y;—¥€õ0Æ(µÐκ®õ šÉ͸Glü@‹él-ìÈ[+{YÞ®ÚŽ0oŒÏ,•VgJG<Ìö¢ÝóUb]–Î^€Y«ý;ùb¹Iª³F™Gü¤ëœî¨(ꎲª¥WQº‡““9ËoTÕ‹!‡Î•öe„­Šë»¬ÂWJ'zG?u¬û®¿ºRêTŸÿk=êWŒep᪈Ïû2‚>nT×|d~­.Xµs•èÃg#Û%bjÿ¸Ổ×Y kåús)Û1¯"ÝaÄ“ÌŸËe‹a'ò»p†é÷çô/†¼p­í'-@ÈJè'kÔ±•Èøžm#kq´áx4’UH¿GäÃCø¼‚7G`5¾_÷Ówlâıq:Ö*˜EÍ*¤ß€¸é•8Vªxâå8–«¸Dʘ|™ŠW#Gè&:ú{NAî&çfÈ33Ä8C¢ïù=2þöÑ·|›ÿÓå&›óòñËÜà%â¼4x)zéø¥W/iþãuÑö»×WÛ~{±ÒöïWÛ^]}¡ÿ7«ñíýBýîáûk³H)Ú6âSÄ[Æ›Ÿ=CJeGñ"ׯùY¼B~%4Û~ñÂ"ÛÏ_¨°yÏ=æ<O‹ç5Ó³g?_¼Ø…ã÷Îgæ¸ Ó¤@6g~Xa“¿_µÖ%¿¬Ò5MìrÅ“«m0M¢ÓdúT¦ N8%ž’OyOÅNièpôÔ¹S—Oi¦‰(çt èÞ'¸Ÿ8÷‡–åÜ'²r]†“ƒ'¹)¾ÙFÝ.†¼»ðæá> :_,;*ª\¶IçdËäñIÁ0IäÉÜ<{tüQþ⣗å¾{¢Év¢»Âö±’’“ÍÔ£’'‰á;Äðmò4)$ùÐŒu°Èïn¶=p¬ÒöU¼¿‚÷ø1òE—Ãvü “_à>ïj²î·ÝÏÝw´ÂöÙÏTØ GlG¢Gö9rDóé{+l]‡‰á^"ß›epÙqŸºË`¼‹,ÿ„ëÜ^œ{ï$Þ ¼«bÄ#|Œ\‰‘‹ýGŒ ň'F¦g/ËwÄ0ÑH‡-âj°•¢þâÆ¢~]#߯źøP×;Ø`Äqû–Û6W¥më–Ûl[\Kmù yý¬®ÐÀ÷Gybà[ø.>Êïç5ƒ}DîsÔ¸ä¾Ò2|ä¹v÷~´÷ž^¾§k‘­ï⮪.ÎÓîâ¦Iž\ë*·mpÛ:\vÛz ú/.LYÔaí/h°ô›ˆ¡ßØ`èçv,ÌÚ¦‰é¤5£\‹£ÍÐb4ì7ƒÓÐeˆŽ^5Ìt-H»dà£@º€Œ ™&G§6õUWwNëf{;]÷V…TÊûèSîÙ¢h*пe«{ŠO{î:|Zw* }nÅ»ØÓ©)0Ž€qñT´zÉDr´Z½H"I CD‚²%Í‹0r"‘L&!­’¨N@5}"ƒàLe¨0µ¥~ }ŽMC˜d"I…˜ò(}2ŒR©!vá ‰ùé™åôPô?OAO3 +endstream +endobj + +13 0 obj +6443 +endobj + +14 0 obj +<</Type/FontDescriptor/FontName/BAAAAA+LiberationSans-Bold +/Flags 4 +/FontBBox[-481 -376 1303 1033]/ItalicAngle 0 +/Ascent 905 +/Descent -211 +/CapHeight 1033 +/StemV 80 +/FontFile2 12 0 R +>> +endobj + +15 0 obj +<</Length 289/Filter/FlateDecode>> +stream +xœ]‘Ín„ …÷<ËébâÿL'1&S­‰‹þ¤¶€pµ$ â·/\¦mÒä»ÜsnàÕ]Ó)i£W³ð,¥Öe3è�“T$I©ÜÞ*ÜùÌ4‰œ·ßW s§Æ¥,Iôæz«5;=\Å2À‰^Œ�#ÕDuïê~Óú fP–Ƥª¨€ÑÍybú™Í¡ëØ ×–v?:ËŸà}×@S¬“p¾X5ã`˜š€”q\Ѳm+Jüë%E° #ÿdÆI'ã<­§È§Äs†|Æó<œgž‹À­çSàÜó9páù9=_3ô^_<?„ù¨¯£¦ Œ3ÃÌÆs8ÅGÝnïŸçóÿ‰òÍ~fåS’ +~ÿQ/Ú»p}ÚìŽT +endstream +endobj + +16 0 obj +<</Type/Font/Subtype/TrueType/BaseFont/BAAAAA+LiberationSans-Bold +/FirstChar 0 +/LastChar 15 +/Widths[750 722 556 389 556 610 610 556 277 556 556 610 556 333 889 610 +] +/FontDescriptor 14 0 R +/ToUnicode 15 0 R +>> +endobj + +17 0 obj +<</F1 16 0 R/F2 11 0 R +>> +endobj + +18 0 obj +<</Font 17 0 R +/XObject<</Im4 4 0 R>> +/ProcSet[/PDF/Text/ImageC/ImageI/ImageB] +>> +endobj + +1 0 obj +<</Type/Page/Parent 6 0 R/Resources 18 0 R/MediaBox[0 0 595.303937007874 841.889763779528]/Group<</S/Transparency/CS/DeviceRGB/I true>>/Contents 2 0 R>> +endobj + +6 0 obj +<</Type/Pages +/Resources 18 0 R +/MediaBox[ 0 0 595 841 ] +/Kids[ 1 0 R ] +/Count 1>> +endobj + +19 0 obj +<</Type/Catalog/Pages 6 0 R +/OpenAction[1 0 R /XYZ null null 0] +/Lang(de-DE) +>> +endobj + +20 0 obj +<</Creator<FEFF005700720069007400650072> +/Producer<FEFF004C0069006200720065004F0066006600690063006500200037002E0031> +/CreationDate(D:20220401110308+02'00')>> +endobj + +xref +0 21 +0000000000 65535 f +0000029273 00000 n +0000000019 00000 n +0000000374 00000 n +0000000394 00000 n +0000011762 00000 n +0000029442 00000 n +0000011784 00000 n +0000020862 00000 n +0000020883 00000 n +0000021078 00000 n +0000021508 00000 n +0000021790 00000 n +0000028320 00000 n +0000028342 00000 n +0000028545 00000 n +0000028904 00000 n +0000029131 00000 n +0000029174 00000 n +0000029541 00000 n +0000029638 00000 n +trailer +<</Size 21/Root 19 0 R +/Info 20 0 R +/ID [ <77F1D5E7090F17C94EF7E43CF16B016F> +<77F1D5E7090F17C94EF7E43CF16B016F> ] +/DocChecksum /2F8AB12D558369FCB5C37CF4905E79AE +>> +startxref +29813 +%%EOF diff --git a/src/documents/tests/samples/barcodes/barcode-39-custom.png b/src/documents/tests/samples/barcodes/barcode-39-custom.png new file mode 100644 index 000000000..5c2d7b4f7 Binary files /dev/null and b/src/documents/tests/samples/barcodes/barcode-39-custom.png differ diff --git a/src/documents/tests/samples/barcodes/barcode-qr-custom.pdf b/src/documents/tests/samples/barcodes/barcode-qr-custom.pdf new file mode 100644 index 000000000..0d60b9eed Binary files /dev/null and b/src/documents/tests/samples/barcodes/barcode-qr-custom.pdf differ diff --git a/src/documents/tests/samples/barcodes/barcode-qr-custom.png b/src/documents/tests/samples/barcodes/barcode-qr-custom.png new file mode 100644 index 000000000..6574638bc Binary files /dev/null and b/src/documents/tests/samples/barcodes/barcode-qr-custom.png differ diff --git a/src/documents/tests/samples/barcodes/patch-code-t-middle.pdf b/src/documents/tests/samples/barcodes/patch-code-t-middle.pdf new file mode 100644 index 000000000..2ccb76947 Binary files /dev/null and b/src/documents/tests/samples/barcodes/patch-code-t-middle.pdf differ diff --git a/src/documents/tests/samples/barcodes/patch-code-t-middle_reverse.pdf b/src/documents/tests/samples/barcodes/patch-code-t-middle_reverse.pdf new file mode 100644 index 000000000..e1f8bc39c Binary files /dev/null and b/src/documents/tests/samples/barcodes/patch-code-t-middle_reverse.pdf differ diff --git a/src/documents/tests/samples/barcodes/patch-code-t-qr.pdf b/src/documents/tests/samples/barcodes/patch-code-t-qr.pdf new file mode 100644 index 000000000..9d2299510 Binary files /dev/null and b/src/documents/tests/samples/barcodes/patch-code-t-qr.pdf differ diff --git a/src/documents/tests/samples/barcodes/patch-code-t.pbm b/src/documents/tests/samples/barcodes/patch-code-t.pbm new file mode 100644 index 000000000..7e7214070 Binary files /dev/null and b/src/documents/tests/samples/barcodes/patch-code-t.pbm differ diff --git a/src/documents/tests/samples/barcodes/patch-code-t.pdf b/src/documents/tests/samples/barcodes/patch-code-t.pdf new file mode 100644 index 000000000..3a8a2a2ff Binary files /dev/null and b/src/documents/tests/samples/barcodes/patch-code-t.pdf differ diff --git a/src/documents/tests/samples/barcodes/qr-code-PATCHT.png b/src/documents/tests/samples/barcodes/qr-code-PATCHT.png new file mode 100644 index 000000000..6f1d587ff Binary files /dev/null and b/src/documents/tests/samples/barcodes/qr-code-PATCHT.png differ diff --git a/src/documents/tests/samples/barcodes/several-patcht-codes.pdf b/src/documents/tests/samples/barcodes/several-patcht-codes.pdf new file mode 100644 index 000000000..de4c715c8 Binary files /dev/null and b/src/documents/tests/samples/barcodes/several-patcht-codes.pdf differ diff --git a/src/documents/tests/test_admin.py b/src/documents/tests/test_admin.py index 3e292dcfc..92e2d1f95 100644 --- a/src/documents/tests/test_admin.py +++ b/src/documents/tests/test_admin.py @@ -3,7 +3,6 @@ from unittest import mock from django.contrib.admin.sites import AdminSite from django.test import TestCase from django.utils import timezone - from documents import index from documents.admin import DocumentAdmin from documents.models import Document @@ -42,7 +41,8 @@ class TestDocumentAdmin(DirectoriesMixin, TestCase): docs = [] for i in range(42): doc = Document.objects.create( - title="Many documents with the same title", checksum=f"{i:02}" + title="Many documents with the same title", + checksum=f"{i:02}", ) docs.append(doc) index.add_or_update_document(doc) @@ -61,6 +61,7 @@ class TestDocumentAdmin(DirectoriesMixin, TestCase): def test_created(self): doc = Document.objects.create( - title="test", created=timezone.datetime(2020, 4, 12) + title="test", + created=timezone.make_aware(timezone.datetime(2020, 4, 12)), ) self.assertEqual(self.doc_admin.created_(doc), "2020-04-12") diff --git a/src/documents/tests/test_api.py b/src/documents/tests/test_api.py index 8778e313d..9c43f174a 100644 --- a/src/documents/tests/test_api.py +++ b/src/documents/tests/test_api.py @@ -11,20 +11,19 @@ import pytest from django.conf import settings from django.contrib.auth.models import User from django.test import override_settings +from django.utils import timezone +from documents import bulk_edit +from documents import index +from documents.models import Correspondent +from documents.models import Document +from documents.models import DocumentType +from documents.models import MatchingModel +from documents.models import SavedView +from documents.models import Tag +from documents.tests.utils import DirectoriesMixin from rest_framework.test import APITestCase from whoosh.writing import AsyncWriter -from documents import index, bulk_edit -from documents.models import ( - Document, - Correspondent, - DocumentType, - Tag, - SavedView, - MatchingModel, -) -from documents.tests.utils import DirectoriesMixin - class TestDocumentApi(DirectoriesMixin, APITestCase): def setUp(self): @@ -71,7 +70,9 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): returned_doc["title"] = "the new title" response = self.client.put( - "/api/documents/{}/".format(doc.pk), returned_doc, format="json" + "/api/documents/{}/".format(doc.pk), + returned_doc, + format="json", ) self.assertEqual(response.status_code, 200) @@ -126,7 +127,8 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): self.assertEqual(len(results[0]), 2) response = self.client.get( - "/api/documents/?fields=id,conteasdnt", format="json" + "/api/documents/?fields=id,conteasdnt", + format="json", ) self.assertEqual(response.status_code, 200) results = response.data["results"] @@ -161,7 +163,8 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): ) with open( - os.path.join(self.dirs.thumbnail_dir, "{:07d}.png".format(doc.pk)), "wb" + os.path.join(self.dirs.thumbnail_dir, "{:07d}.png".format(doc.pk)), + "wb", ) as f: f.write(content_thumbnail) @@ -205,7 +208,7 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): self.assertEqual(response.content, content_archive) response = self.client.get( - "/api/documents/{}/download/?original=true".format(doc.pk) + "/api/documents/{}/download/?original=true".format(doc.pk), ) self.assertEqual(response.status_code, 200) @@ -217,7 +220,7 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): self.assertEqual(response.content, content_archive) response = self.client.get( - "/api/documents/{}/preview/?original=true".format(doc.pk) + "/api/documents/{}/preview/?original=true".format(doc.pk), ) self.assertEqual(response.status_code, 200) @@ -226,7 +229,9 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): def test_document_actions_not_existing_file(self): doc = Document.objects.create( - title="none", filename=os.path.basename("asd"), mime_type="application/pdf" + title="none", + filename=os.path.basename("asd"), + mime_type="application/pdf", ) response = self.client.get("/api/documents/{}/download/".format(doc.pk)) @@ -241,13 +246,19 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): def test_document_filters(self): doc1 = Document.objects.create( - title="none1", checksum="A", mime_type="application/pdf" + title="none1", + checksum="A", + mime_type="application/pdf", ) doc2 = Document.objects.create( - title="none2", checksum="B", mime_type="application/pdf" + title="none2", + checksum="B", + mime_type="application/pdf", ) doc3 = Document.objects.create( - title="none3", checksum="C", mime_type="application/pdf" + title="none3", + checksum="C", + mime_type="application/pdf", ) tag_inbox = Tag.objects.create(name="t1", is_inbox_tag=True) @@ -272,7 +283,7 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): self.assertCountEqual([results[0]["id"], results[1]["id"]], [doc2.id, doc3.id]) response = self.client.get( - "/api/documents/?tags__id__in={},{}".format(tag_inbox.id, tag_3.id) + "/api/documents/?tags__id__in={},{}".format(tag_inbox.id, tag_3.id), ) self.assertEqual(response.status_code, 200) results = response.data["results"] @@ -280,7 +291,7 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): self.assertCountEqual([results[0]["id"], results[1]["id"]], [doc1.id, doc3.id]) response = self.client.get( - "/api/documents/?tags__id__in={},{}".format(tag_2.id, tag_3.id) + "/api/documents/?tags__id__in={},{}".format(tag_2.id, tag_3.id), ) self.assertEqual(response.status_code, 200) results = response.data["results"] @@ -288,7 +299,7 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): self.assertCountEqual([results[0]["id"], results[1]["id"]], [doc2.id, doc3.id]) response = self.client.get( - "/api/documents/?tags__id__all={},{}".format(tag_2.id, tag_3.id) + "/api/documents/?tags__id__all={},{}".format(tag_2.id, tag_3.id), ) self.assertEqual(response.status_code, 200) results = response.data["results"] @@ -296,14 +307,14 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): self.assertEqual(results[0]["id"], doc3.id) response = self.client.get( - "/api/documents/?tags__id__all={},{}".format(tag_inbox.id, tag_3.id) + "/api/documents/?tags__id__all={},{}".format(tag_inbox.id, tag_3.id), ) self.assertEqual(response.status_code, 200) results = response.data["results"] self.assertEqual(len(results), 0) response = self.client.get( - "/api/documents/?tags__id__all={}a{}".format(tag_inbox.id, tag_3.id) + "/api/documents/?tags__id__all={}a{}".format(tag_inbox.id, tag_3.id), ) self.assertEqual(response.status_code, 200) results = response.data["results"] @@ -316,7 +327,7 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): self.assertCountEqual([results[0]["id"], results[1]["id"]], [doc1.id, doc2.id]) response = self.client.get( - "/api/documents/?tags__id__none={},{}".format(tag_3.id, tag_2.id) + "/api/documents/?tags__id__none={},{}".format(tag_3.id, tag_2.id), ) self.assertEqual(response.status_code, 200) results = response.data["results"] @@ -324,7 +335,7 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): self.assertEqual(results[0]["id"], doc1.id) response = self.client.get( - "/api/documents/?tags__id__none={},{}".format(tag_2.id, tag_inbox.id) + "/api/documents/?tags__id__none={},{}".format(tag_2.id, tag_inbox.id), ) self.assertEqual(response.status_code, 200) results = response.data["results"] @@ -442,7 +453,7 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): for i in range(1, 6): response = self.client.get( - f"/api/documents/?query=content&page={i}&page_size=10" + f"/api/documents/?query=content&page={i}&page_size=10", ) results = response.data["results"] self.assertEqual(response.data["count"], 55) @@ -567,11 +578,15 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): d3.tags.add(t) d3.tags.add(t2) d4 = Document.objects.create( - checksum="4", created=datetime.datetime(2020, 7, 13), content="test" + checksum="4", + created=timezone.make_aware(datetime.datetime(2020, 7, 13)), + content="test", ) d4.tags.add(t2) d5 = Document.objects.create( - checksum="5", added=datetime.datetime(2020, 7, 13), content="test" + checksum="5", + added=timezone.make_aware(datetime.datetime(2020, 7, 13)), + content="test", ) d6 = Document.objects.create(checksum="6", content="test2") @@ -590,31 +605,35 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): self.assertCountEqual(search_query("&correspondent__id=" + str(c.id)), [d1.id]) self.assertCountEqual(search_query("&document_type__id=" + str(dt.id)), [d2.id]) self.assertCountEqual( - search_query("&correspondent__isnull"), [d2.id, d3.id, d4.id, d5.id] + search_query("&correspondent__isnull"), + [d2.id, d3.id, d4.id, d5.id], ) self.assertCountEqual( - search_query("&document_type__isnull"), [d1.id, d3.id, d4.id, d5.id] + search_query("&document_type__isnull"), + [d1.id, d3.id, d4.id, d5.id], ) self.assertCountEqual( - search_query("&tags__id__all=" + str(t.id) + "," + str(t2.id)), [d3.id] + search_query("&tags__id__all=" + str(t.id) + "," + str(t2.id)), + [d3.id], ) self.assertCountEqual(search_query("&tags__id__all=" + str(t.id)), [d3.id]) self.assertCountEqual( - search_query("&tags__id__all=" + str(t2.id)), [d3.id, d4.id] + search_query("&tags__id__all=" + str(t2.id)), + [d3.id, d4.id], ) self.assertIn( d4.id, search_query( "&created__date__lt=" - + datetime.datetime(2020, 9, 2).strftime("%Y-%m-%d") + + datetime.datetime(2020, 9, 2).strftime("%Y-%m-%d"), ), ) self.assertNotIn( d4.id, search_query( "&created__date__gt=" - + datetime.datetime(2020, 9, 2).strftime("%Y-%m-%d") + + datetime.datetime(2020, 9, 2).strftime("%Y-%m-%d"), ), ) @@ -622,40 +641,44 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): d4.id, search_query( "&created__date__lt=" - + datetime.datetime(2020, 1, 2).strftime("%Y-%m-%d") + + datetime.datetime(2020, 1, 2).strftime("%Y-%m-%d"), ), ) self.assertIn( d4.id, search_query( "&created__date__gt=" - + datetime.datetime(2020, 1, 2).strftime("%Y-%m-%d") + + datetime.datetime(2020, 1, 2).strftime("%Y-%m-%d"), ), ) self.assertIn( d5.id, search_query( - "&added__date__lt=" + datetime.datetime(2020, 9, 2).strftime("%Y-%m-%d") + "&added__date__lt=" + + datetime.datetime(2020, 9, 2).strftime("%Y-%m-%d"), ), ) self.assertNotIn( d5.id, search_query( - "&added__date__gt=" + datetime.datetime(2020, 9, 2).strftime("%Y-%m-%d") + "&added__date__gt=" + + datetime.datetime(2020, 9, 2).strftime("%Y-%m-%d"), ), ) self.assertNotIn( d5.id, search_query( - "&added__date__lt=" + datetime.datetime(2020, 1, 2).strftime("%Y-%m-%d") + "&added__date__lt=" + + datetime.datetime(2020, 1, 2).strftime("%Y-%m-%d"), ), ) self.assertIn( d5.id, search_query( - "&added__date__gt=" + datetime.datetime(2020, 1, 2).strftime("%Y-%m-%d") + "&added__date__gt=" + + datetime.datetime(2020, 1, 2).strftime("%Y-%m-%d"), ), ) @@ -695,18 +718,22 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): return [hit["id"] for hit in r.data["results"]] self.assertListEqual( - search_query("&ordering=archive_serial_number"), [d3.id, d1.id, d2.id] + search_query("&ordering=archive_serial_number"), + [d3.id, d1.id, d2.id], ) self.assertListEqual( - search_query("&ordering=-archive_serial_number"), [d2.id, d1.id, d3.id] + search_query("&ordering=-archive_serial_number"), + [d2.id, d1.id, d3.id], ) self.assertListEqual(search_query("&ordering=title"), [d3.id, d2.id, d1.id]) self.assertListEqual(search_query("&ordering=-title"), [d1.id, d2.id, d3.id]) self.assertListEqual( - search_query("&ordering=correspondent__name"), [d1.id, d3.id, d2.id] + search_query("&ordering=correspondent__name"), + [d1.id, d3.id, d2.id], ) self.assertListEqual( - search_query("&ordering=-correspondent__name"), [d2.id, d3.id, d1.id] + search_query("&ordering=-correspondent__name"), + [d2.id, d3.id, d1.id], ) def test_statistics(self): @@ -735,10 +762,12 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): def test_upload(self, m): with open( - os.path.join(os.path.dirname(__file__), "samples", "simple.pdf"), "rb" + os.path.join(os.path.dirname(__file__), "samples", "simple.pdf"), + "rb", ) as f: response = self.client.post( - "/api/documents/post_document/", {"document": f} + "/api/documents/post_document/", + {"document": f}, ) self.assertEqual(response.status_code, 200) @@ -756,7 +785,8 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): def test_upload_empty_metadata(self, m): with open( - os.path.join(os.path.dirname(__file__), "samples", "simple.pdf"), "rb" + os.path.join(os.path.dirname(__file__), "samples", "simple.pdf"), + "rb", ) as f: response = self.client.post( "/api/documents/post_document/", @@ -778,10 +808,12 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): def test_upload_invalid_form(self, m): with open( - os.path.join(os.path.dirname(__file__), "samples", "simple.pdf"), "rb" + os.path.join(os.path.dirname(__file__), "samples", "simple.pdf"), + "rb", ) as f: response = self.client.post( - "/api/documents/post_document/", {"documenst": f} + "/api/documents/post_document/", + {"documenst": f}, ) self.assertEqual(response.status_code, 400) m.assert_not_called() @@ -790,10 +822,12 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): def test_upload_invalid_file(self, m): with open( - os.path.join(os.path.dirname(__file__), "samples", "simple.zip"), "rb" + os.path.join(os.path.dirname(__file__), "samples", "simple.zip"), + "rb", ) as f: response = self.client.post( - "/api/documents/post_document/", {"document": f} + "/api/documents/post_document/", + {"document": f}, ) self.assertEqual(response.status_code, 400) m.assert_not_called() @@ -801,7 +835,8 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): @mock.patch("documents.views.async_task") def test_upload_with_title(self, async_task): with open( - os.path.join(os.path.dirname(__file__), "samples", "simple.pdf"), "rb" + os.path.join(os.path.dirname(__file__), "samples", "simple.pdf"), + "rb", ) as f: response = self.client.post( "/api/documents/post_document/", @@ -819,10 +854,12 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): def test_upload_with_correspondent(self, async_task): c = Correspondent.objects.create(name="test-corres") with open( - os.path.join(os.path.dirname(__file__), "samples", "simple.pdf"), "rb" + os.path.join(os.path.dirname(__file__), "samples", "simple.pdf"), + "rb", ) as f: response = self.client.post( - "/api/documents/post_document/", {"document": f, "correspondent": c.id} + "/api/documents/post_document/", + {"document": f, "correspondent": c.id}, ) self.assertEqual(response.status_code, 200) @@ -835,10 +872,12 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): @mock.patch("documents.views.async_task") def test_upload_with_invalid_correspondent(self, async_task): with open( - os.path.join(os.path.dirname(__file__), "samples", "simple.pdf"), "rb" + os.path.join(os.path.dirname(__file__), "samples", "simple.pdf"), + "rb", ) as f: response = self.client.post( - "/api/documents/post_document/", {"document": f, "correspondent": 3456} + "/api/documents/post_document/", + {"document": f, "correspondent": 3456}, ) self.assertEqual(response.status_code, 400) @@ -848,10 +887,12 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): def test_upload_with_document_type(self, async_task): dt = DocumentType.objects.create(name="invoice") with open( - os.path.join(os.path.dirname(__file__), "samples", "simple.pdf"), "rb" + os.path.join(os.path.dirname(__file__), "samples", "simple.pdf"), + "rb", ) as f: response = self.client.post( - "/api/documents/post_document/", {"document": f, "document_type": dt.id} + "/api/documents/post_document/", + {"document": f, "document_type": dt.id}, ) self.assertEqual(response.status_code, 200) @@ -864,10 +905,12 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): @mock.patch("documents.views.async_task") def test_upload_with_invalid_document_type(self, async_task): with open( - os.path.join(os.path.dirname(__file__), "samples", "simple.pdf"), "rb" + os.path.join(os.path.dirname(__file__), "samples", "simple.pdf"), + "rb", ) as f: response = self.client.post( - "/api/documents/post_document/", {"document": f, "document_type": 34578} + "/api/documents/post_document/", + {"document": f, "document_type": 34578}, ) self.assertEqual(response.status_code, 400) @@ -878,10 +921,12 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): t1 = Tag.objects.create(name="tag1") t2 = Tag.objects.create(name="tag2") with open( - os.path.join(os.path.dirname(__file__), "samples", "simple.pdf"), "rb" + os.path.join(os.path.dirname(__file__), "samples", "simple.pdf"), + "rb", ) as f: response = self.client.post( - "/api/documents/post_document/", {"document": f, "tags": [t2.id, t1.id]} + "/api/documents/post_document/", + {"document": f, "tags": [t2.id, t1.id]}, ) self.assertEqual(response.status_code, 200) @@ -896,7 +941,8 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): t1 = Tag.objects.create(name="tag1") t2 = Tag.objects.create(name="tag2") with open( - os.path.join(os.path.dirname(__file__), "samples", "simple.pdf"), "rb" + os.path.join(os.path.dirname(__file__), "samples", "simple.pdf"), + "rb", ) as f: response = self.client.post( "/api/documents/post_document/", @@ -947,7 +993,9 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): def test_get_metadata_no_archive(self): doc = Document.objects.create( - title="test", filename="file.pdf", mime_type="application/pdf" + title="test", + filename="file.pdf", + mime_type="application/pdf", ) shutil.copy( @@ -994,7 +1042,8 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): self.assertEqual(response.status_code, 200) self.assertEqual( - response.data, {"correspondents": [], "tags": [], "document_types": []} + response.data, + {"correspondents": [], "tags": [], "document_types": []}, ) def test_get_suggestions_invalid_doc(self): @@ -1005,10 +1054,15 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): @mock.patch("documents.views.match_tags") @mock.patch("documents.views.match_document_types") def test_get_suggestions( - self, match_document_types, match_tags, match_correspondents + self, + match_document_types, + match_tags, + match_correspondents, ): doc = Document.objects.create( - title="test", mime_type="application/pdf", content="this is an invoice!" + title="test", + mime_type="application/pdf", + content="this is an invoice!", ) match_tags.return_value = [Tag(id=56), Tag(id=123)] match_document_types.return_value = [DocumentType(id=23)] @@ -1089,7 +1143,9 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): self.assertEqual(v1.user, self.user) response = self.client.patch( - f"/api/saved_views/{v1.id}/", {"show_in_sidebar": False}, format="json" + f"/api/saved_views/{v1.id}/", + {"show_in_sidebar": False}, + format="json", ) v1 = SavedView.objects.get(id=v1.id) @@ -1178,7 +1234,9 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): def test_regex_no_algorithm(self): for endpoint in ["correspondents", "tags", "document_types"]: response = self.client.post( - f"/api/{endpoint}/", {"name": "test", "match": "[0-9]"}, format="json" + f"/api/{endpoint}/", + {"name": "test", "match": "[0-9]"}, + format="json", ) self.assertEqual(response.status_code, 201, endpoint) @@ -1195,7 +1253,9 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): def test_tag_color(self): response = self.client.post( - "/api/tags/", {"name": "tag", "colour": 3}, format="json" + "/api/tags/", + {"name": "tag", "colour": 3}, + format="json", ) self.assertEqual(response.status_code, 201) self.assertEqual(Tag.objects.get(id=response.data["id"]).color, "#b2df8a") @@ -1208,14 +1268,17 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): def test_tag_color_invalid(self): response = self.client.post( - "/api/tags/", {"name": "tag", "colour": 34}, format="json" + "/api/tags/", + {"name": "tag", "colour": 34}, + format="json", ) self.assertEqual(response.status_code, 400) def test_tag_color_custom(self): tag = Tag.objects.create(name="test", color="#abcdef") self.assertEqual( - self.client.get(f"/api/tags/{tag.id}/", format="json").data["colour"], 1 + self.client.get(f"/api/tags/{tag.id}/", format="json").data["colour"], + 1, ) @@ -1231,32 +1294,42 @@ class TestDocumentApiV2(DirectoriesMixin, APITestCase): def test_tag_validate_color(self): self.assertEqual( self.client.post( - "/api/tags/", {"name": "test", "color": "#12fFaA"}, format="json" + "/api/tags/", + {"name": "test", "color": "#12fFaA"}, + format="json", ).status_code, 201, ) self.assertEqual( self.client.post( - "/api/tags/", {"name": "test1", "color": "abcdef"}, format="json" + "/api/tags/", + {"name": "test1", "color": "abcdef"}, + format="json", ).status_code, 400, ) self.assertEqual( self.client.post( - "/api/tags/", {"name": "test2", "color": "#abcdfg"}, format="json" + "/api/tags/", + {"name": "test2", "color": "#abcdfg"}, + format="json", ).status_code, 400, ) self.assertEqual( self.client.post( - "/api/tags/", {"name": "test3", "color": "#asd"}, format="json" + "/api/tags/", + {"name": "test3", "color": "#asd"}, + format="json", ).status_code, 400, ) self.assertEqual( self.client.post( - "/api/tags/", {"name": "test4", "color": "#12121212"}, format="json" + "/api/tags/", + {"name": "test4", "color": "#12121212"}, + format="json", ).status_code, 400, ) @@ -1308,10 +1381,16 @@ class TestBulkEdit(DirectoriesMixin, APITestCase): self.t2 = Tag.objects.create(name="t2") self.doc1 = Document.objects.create(checksum="A", title="A") self.doc2 = Document.objects.create( - checksum="B", title="B", correspondent=self.c1, document_type=self.dt1 + checksum="B", + title="B", + correspondent=self.c1, + document_type=self.dt1, ) self.doc3 = Document.objects.create( - checksum="C", title="C", correspondent=self.c2, document_type=self.dt2 + checksum="C", + title="C", + correspondent=self.c2, + document_type=self.dt2, ) self.doc4 = Document.objects.create(checksum="D", title="D") self.doc5 = Document.objects.create(checksum="E", title="E") @@ -1322,7 +1401,8 @@ class TestBulkEdit(DirectoriesMixin, APITestCase): def test_set_correspondent(self): self.assertEqual(Document.objects.filter(correspondent=self.c2).count(), 1) bulk_edit.set_correspondent( - [self.doc1.id, self.doc2.id, self.doc3.id], self.c2.id + [self.doc1.id, self.doc2.id, self.doc3.id], + self.c2.id, ) self.assertEqual(Document.objects.filter(correspondent=self.c2).count(), 3) self.async_task.assert_called_once() @@ -1340,7 +1420,8 @@ class TestBulkEdit(DirectoriesMixin, APITestCase): def test_set_document_type(self): self.assertEqual(Document.objects.filter(document_type=self.dt2).count(), 1) bulk_edit.set_document_type( - [self.doc1.id, self.doc2.id, self.doc3.id], self.dt2.id + [self.doc1.id, self.doc2.id, self.doc3.id], + self.dt2.id, ) self.assertEqual(Document.objects.filter(document_type=self.dt2).count(), 3) self.async_task.assert_called_once() @@ -1358,7 +1439,8 @@ class TestBulkEdit(DirectoriesMixin, APITestCase): def test_add_tag(self): self.assertEqual(Document.objects.filter(tags__id=self.t1.id).count(), 2) bulk_edit.add_tag( - [self.doc1.id, self.doc2.id, self.doc3.id, self.doc4.id], self.t1.id + [self.doc1.id, self.doc2.id, self.doc3.id, self.doc4.id], + self.t1.id, ) self.assertEqual(Document.objects.filter(tags__id=self.t1.id).count(), 4) self.async_task.assert_called_once() @@ -1410,7 +1492,7 @@ class TestBulkEdit(DirectoriesMixin, APITestCase): "documents": [self.doc1.id], "method": "set_correspondent", "parameters": {"correspondent": self.c1.id}, - } + }, ), content_type="application/json", ) @@ -1430,7 +1512,7 @@ class TestBulkEdit(DirectoriesMixin, APITestCase): "documents": [self.doc1.id], "method": "set_correspondent", "parameters": {"correspondent": None}, - } + }, ), content_type="application/json", ) @@ -1450,7 +1532,7 @@ class TestBulkEdit(DirectoriesMixin, APITestCase): "documents": [self.doc1.id], "method": "set_document_type", "parameters": {"document_type": self.dt1.id}, - } + }, ), content_type="application/json", ) @@ -1470,7 +1552,7 @@ class TestBulkEdit(DirectoriesMixin, APITestCase): "documents": [self.doc1.id], "method": "set_document_type", "parameters": {"document_type": None}, - } + }, ), content_type="application/json", ) @@ -1490,7 +1572,7 @@ class TestBulkEdit(DirectoriesMixin, APITestCase): "documents": [self.doc1.id], "method": "add_tag", "parameters": {"tag": self.t1.id}, - } + }, ), content_type="application/json", ) @@ -1510,7 +1592,7 @@ class TestBulkEdit(DirectoriesMixin, APITestCase): "documents": [self.doc1.id], "method": "remove_tag", "parameters": {"tag": self.t1.id}, - } + }, ), content_type="application/json", ) @@ -1533,7 +1615,7 @@ class TestBulkEdit(DirectoriesMixin, APITestCase): "add_tags": [self.t1.id], "remove_tags": [self.t2.id], }, - } + }, ), content_type="application/json", ) @@ -1550,7 +1632,7 @@ class TestBulkEdit(DirectoriesMixin, APITestCase): response = self.client.post( "/api/documents/bulk_edit/", json.dumps( - {"documents": [self.doc1.id], "method": "delete", "parameters": {}} + {"documents": [self.doc1.id], "method": "delete", "parameters": {}}, ), content_type="application/json", ) @@ -1575,7 +1657,11 @@ class TestBulkEdit(DirectoriesMixin, APITestCase): response = self.client.post( "/api/documents/bulk_edit/", json.dumps( - {"documents": [self.doc2.id], "method": "exterminate", "parameters": {}} + { + "documents": [self.doc2.id], + "method": "exterminate", + "parameters": {}, + }, ), content_type="application/json", ) @@ -1591,7 +1677,7 @@ class TestBulkEdit(DirectoriesMixin, APITestCase): "documents": [self.doc2.id], "method": "set_correspondent", "parameters": {"correspondent": 345657}, - } + }, ), content_type="application/json", ) @@ -1608,7 +1694,7 @@ class TestBulkEdit(DirectoriesMixin, APITestCase): "documents": [self.doc2.id], "method": "set_correspondent", "parameters": {}, - } + }, ), content_type="application/json", ) @@ -1623,7 +1709,7 @@ class TestBulkEdit(DirectoriesMixin, APITestCase): "documents": [self.doc2.id], "method": "set_document_type", "parameters": {"document_type": 345657}, - } + }, ), content_type="application/json", ) @@ -1640,7 +1726,7 @@ class TestBulkEdit(DirectoriesMixin, APITestCase): "documents": [self.doc2.id], "method": "set_document_type", "parameters": {}, - } + }, ), content_type="application/json", ) @@ -1655,7 +1741,7 @@ class TestBulkEdit(DirectoriesMixin, APITestCase): "documents": [self.doc2.id], "method": "add_tag", "parameters": {"tag": 345657}, - } + }, ), content_type="application/json", ) @@ -1667,7 +1753,7 @@ class TestBulkEdit(DirectoriesMixin, APITestCase): response = self.client.post( "/api/documents/bulk_edit/", json.dumps( - {"documents": [self.doc2.id], "method": "add_tag", "parameters": {}} + {"documents": [self.doc2.id], "method": "add_tag", "parameters": {}}, ), content_type="application/json", ) @@ -1682,7 +1768,7 @@ class TestBulkEdit(DirectoriesMixin, APITestCase): "documents": [self.doc2.id], "method": "remove_tag", "parameters": {"tag": 345657}, - } + }, ), content_type="application/json", ) @@ -1694,7 +1780,7 @@ class TestBulkEdit(DirectoriesMixin, APITestCase): response = self.client.post( "/api/documents/bulk_edit/", json.dumps( - {"documents": [self.doc2.id], "method": "remove_tag", "parameters": {}} + {"documents": [self.doc2.id], "method": "remove_tag", "parameters": {}}, ), content_type="application/json", ) @@ -1712,7 +1798,7 @@ class TestBulkEdit(DirectoriesMixin, APITestCase): "add_tags": [self.t2.id, 1657], "remove_tags": [1123123], }, - } + }, ), content_type="application/json", ) @@ -1726,7 +1812,7 @@ class TestBulkEdit(DirectoriesMixin, APITestCase): "documents": [self.doc2.id], "method": "modify_tags", "parameters": {"remove_tags": [1123123]}, - } + }, ), content_type="application/json", ) @@ -1739,7 +1825,7 @@ class TestBulkEdit(DirectoriesMixin, APITestCase): "documents": [self.doc2.id], "method": "modify_tags", "parameters": {"add_tags": [self.t2.id, 1657]}, - } + }, ), content_type="application/json", ) @@ -1769,7 +1855,7 @@ class TestBulkEdit(DirectoriesMixin, APITestCase): response = self.client.post( "/api/documents/selection_data/", json.dumps( - {"documents": [self.doc1.id, self.doc2.id, self.doc4.id, self.doc5.id]} + {"documents": [self.doc1.id, self.doc2.id, self.doc4.id, self.doc5.id]}, ), content_type="application/json", ) @@ -1811,21 +1897,21 @@ class TestBulkDownload(DirectoriesMixin, APITestCase): filename="docA.pdf", mime_type="application/pdf", checksum="B", - created=datetime.datetime(2021, 1, 1), + created=timezone.make_aware(datetime.datetime(2021, 1, 1)), ) self.doc2b = Document.objects.create( title="document A", filename="docA2.pdf", mime_type="application/pdf", checksum="D", - created=datetime.datetime(2021, 1, 1), + created=timezone.make_aware(datetime.datetime(2021, 1, 1)), ) self.doc3 = Document.objects.create( title="document B", filename="docB.jpg", mime_type="image/jpeg", checksum="C", - created=datetime.datetime(2020, 3, 21), + created=timezone.make_aware(datetime.datetime(2020, 3, 21)), archive_filename="docB.pdf", archive_checksum="D", ) @@ -1851,7 +1937,7 @@ class TestBulkDownload(DirectoriesMixin, APITestCase): response = self.client.post( "/api/documents/bulk_download/", json.dumps( - {"documents": [self.doc2.id, self.doc3.id], "content": "originals"} + {"documents": [self.doc2.id, self.doc3.id], "content": "originals"}, ), content_type="application/json", ) @@ -1909,17 +1995,20 @@ class TestBulkDownload(DirectoriesMixin, APITestCase): with self.doc2.source_file as f: self.assertEqual( - f.read(), zipf.read("originals/2021-01-01 document A.pdf") + f.read(), + zipf.read("originals/2021-01-01 document A.pdf"), ) with self.doc3.archive_file as f: self.assertEqual( - f.read(), zipf.read("archive/2020-03-21 document B.pdf") + f.read(), + zipf.read("archive/2020-03-21 document B.pdf"), ) with self.doc3.source_file as f: self.assertEqual( - f.read(), zipf.read("originals/2020-03-21 document B.jpg") + f.read(), + zipf.read("originals/2020-03-21 document B.jpg"), ) def test_filename_clashes(self): @@ -1948,7 +2037,7 @@ class TestBulkDownload(DirectoriesMixin, APITestCase): response = self.client.post( "/api/documents/bulk_download/", json.dumps( - {"documents": [self.doc2.id, self.doc2b.id], "compression": "lzma"} + {"documents": [self.doc2.id, self.doc2b.id], "compression": "lzma"}, ), content_type="application/json", ) @@ -1963,13 +2052,16 @@ class TestApiAuth(APITestCase): self.assertEqual(self.client.get(f"/api/documents/{d.id}/").status_code, 401) self.assertEqual( - self.client.get(f"/api/documents/{d.id}/download/").status_code, 401 + self.client.get(f"/api/documents/{d.id}/download/").status_code, + 401, ) self.assertEqual( - self.client.get(f"/api/documents/{d.id}/preview/").status_code, 401 + self.client.get(f"/api/documents/{d.id}/preview/").status_code, + 401, ) self.assertEqual( - self.client.get(f"/api/documents/{d.id}/thumb/").status_code, 401 + self.client.get(f"/api/documents/{d.id}/thumb/").status_code, + 401, ) self.assertEqual(self.client.get("/api/tags/").status_code, 401) @@ -1982,10 +2074,12 @@ class TestApiAuth(APITestCase): self.assertEqual(self.client.get("/api/search/autocomplete/").status_code, 401) self.assertEqual(self.client.get("/api/documents/bulk_edit/").status_code, 401) self.assertEqual( - self.client.get("/api/documents/bulk_download/").status_code, 401 + self.client.get("/api/documents/bulk_download/").status_code, + 401, ) self.assertEqual( - self.client.get("/api/documents/selection_data/").status_code, 401 + self.client.get("/api/documents/selection_data/").status_code, + 401, ) def test_api_version_no_auth(self): diff --git a/src/documents/tests/test_checks.py b/src/documents/tests/test_checks.py index 7a1a81ec1..b7136a3dc 100644 --- a/src/documents/tests/test_checks.py +++ b/src/documents/tests/test_checks.py @@ -4,10 +4,11 @@ from unittest import mock from django.core.checks import Error from django.test import TestCase -from .factories import DocumentFactory -from .. import document_consumer_declaration -from ..checks import changed_password_check, parser_check +from ..checks import changed_password_check +from ..checks import parser_check from ..models import Document +from ..signals import document_consumer_declaration +from .factories import DocumentFactory class ChecksTestCase(TestCase): @@ -30,7 +31,7 @@ class ChecksTestCase(TestCase): [ Error( "No parsers found. This is a bug. The consumer won't be " - "able to consume any documents without parsers." - ) + "able to consume any documents without parsers.", + ), ], ) diff --git a/src/documents/tests/test_classifier.py b/src/documents/tests/test_classifier.py index dad8231a7..b03ecf7d3 100644 --- a/src/documents/tests/test_classifier.py +++ b/src/documents/tests/test_classifier.py @@ -5,14 +5,15 @@ from unittest import mock import pytest from django.conf import settings -from django.test import TestCase, override_settings - -from documents.classifier import ( - DocumentClassifier, - IncompatibleClassifierVersionError, - load_classifier, -) -from documents.models import Correspondent, Document, Tag, DocumentType +from django.test import override_settings +from django.test import TestCase +from documents.classifier import DocumentClassifier +from documents.classifier import IncompatibleClassifierVersionError +from documents.classifier import load_classifier +from documents.models import Correspondent +from documents.models import Document +from documents.models import DocumentType +from documents.models import Tag from documents.tests.utils import DirectoriesMixin @@ -23,26 +24,37 @@ class TestClassifier(DirectoriesMixin, TestCase): def generate_test_data(self): self.c1 = Correspondent.objects.create( - name="c1", matching_algorithm=Correspondent.MATCH_AUTO + name="c1", + matching_algorithm=Correspondent.MATCH_AUTO, ) self.c2 = Correspondent.objects.create(name="c2") self.c3 = Correspondent.objects.create( - name="c3", matching_algorithm=Correspondent.MATCH_AUTO + name="c3", + matching_algorithm=Correspondent.MATCH_AUTO, ) self.t1 = Tag.objects.create( - name="t1", matching_algorithm=Tag.MATCH_AUTO, pk=12 + name="t1", + matching_algorithm=Tag.MATCH_AUTO, + pk=12, ) self.t2 = Tag.objects.create( - name="t2", matching_algorithm=Tag.MATCH_ANY, pk=34, is_inbox_tag=True + name="t2", + matching_algorithm=Tag.MATCH_ANY, + pk=34, + is_inbox_tag=True, ) self.t3 = Tag.objects.create( - name="t3", matching_algorithm=Tag.MATCH_AUTO, pk=45 + name="t3", + matching_algorithm=Tag.MATCH_AUTO, + pk=45, ) self.dt = DocumentType.objects.create( - name="dt", matching_algorithm=DocumentType.MATCH_AUTO + name="dt", + matching_algorithm=DocumentType.MATCH_AUTO, ) self.dt2 = DocumentType.objects.create( - name="dt2", matching_algorithm=DocumentType.MATCH_AUTO + name="dt2", + matching_algorithm=DocumentType.MATCH_AUTO, ) self.doc1 = Document.objects.create( @@ -59,7 +71,9 @@ class TestClassifier(DirectoriesMixin, TestCase): checksum="B", ) self.doc_inbox = Document.objects.create( - title="doc235", content="aa", checksum="C" + title="doc235", + content="aa", + checksum="C", ) self.doc1.tags.add(self.t1) @@ -90,27 +104,33 @@ class TestClassifier(DirectoriesMixin, TestCase): self.generate_test_data() self.classifier.train() self.assertListEqual( - list(self.classifier.correspondent_classifier.classes_), [-1, self.c1.pk] + list(self.classifier.correspondent_classifier.classes_), + [-1, self.c1.pk], ) self.assertListEqual( - list(self.classifier.tags_binarizer.classes_), [self.t1.pk, self.t3.pk] + list(self.classifier.tags_binarizer.classes_), + [self.t1.pk, self.t3.pk], ) def testPredict(self): self.generate_test_data() self.classifier.train() self.assertEqual( - self.classifier.predict_correspondent(self.doc1.content), self.c1.pk + self.classifier.predict_correspondent(self.doc1.content), + self.c1.pk, ) self.assertEqual(self.classifier.predict_correspondent(self.doc2.content), None) self.assertListEqual( - self.classifier.predict_tags(self.doc1.content), [self.t1.pk] + self.classifier.predict_tags(self.doc1.content), + [self.t1.pk], ) self.assertListEqual( - self.classifier.predict_tags(self.doc2.content), [self.t1.pk, self.t3.pk] + self.classifier.predict_tags(self.doc2.content), + [self.t1.pk, self.t3.pk], ) self.assertEqual( - self.classifier.predict_document_type(self.doc1.content), self.dt.pk + self.classifier.predict_document_type(self.doc1.content), + self.dt.pk, ) self.assertEqual(self.classifier.predict_document_type(self.doc2.content), None) @@ -133,7 +153,8 @@ class TestClassifier(DirectoriesMixin, TestCase): current_ver = DocumentClassifier.FORMAT_VERSION with mock.patch( - "documents.classifier.DocumentClassifier.FORMAT_VERSION", current_ver + 1 + "documents.classifier.DocumentClassifier.FORMAT_VERSION", + current_ver + 1, ): # assure that we won't load old classifiers. self.assertRaises(IncompatibleClassifierVersionError, classifier2.load) @@ -157,7 +178,7 @@ class TestClassifier(DirectoriesMixin, TestCase): self.assertFalse(new_classifier.train()) @override_settings( - MODEL_FILE=os.path.join(os.path.dirname(__file__), "data", "model.pickle") + MODEL_FILE=os.path.join(os.path.dirname(__file__), "data", "model.pickle"), ) def test_load_and_classify(self): self.generate_test_data() @@ -169,7 +190,8 @@ class TestClassifier(DirectoriesMixin, TestCase): def test_one_correspondent_predict(self): c1 = Correspondent.objects.create( - name="c1", matching_algorithm=Correspondent.MATCH_AUTO + name="c1", + matching_algorithm=Correspondent.MATCH_AUTO, ) doc1 = Document.objects.create( title="doc1", @@ -183,7 +205,8 @@ class TestClassifier(DirectoriesMixin, TestCase): def test_one_correspondent_predict_manydocs(self): c1 = Correspondent.objects.create( - name="c1", matching_algorithm=Correspondent.MATCH_AUTO + name="c1", + matching_algorithm=Correspondent.MATCH_AUTO, ) doc1 = Document.objects.create( title="doc1", @@ -192,7 +215,9 @@ class TestClassifier(DirectoriesMixin, TestCase): checksum="A", ) doc2 = Document.objects.create( - title="doc2", content="this is a document from noone", checksum="B" + title="doc2", + content="this is a document from noone", + checksum="B", ) self.classifier.train() @@ -201,7 +226,8 @@ class TestClassifier(DirectoriesMixin, TestCase): def test_one_type_predict(self): dt = DocumentType.objects.create( - name="dt", matching_algorithm=DocumentType.MATCH_AUTO + name="dt", + matching_algorithm=DocumentType.MATCH_AUTO, ) doc1 = Document.objects.create( @@ -216,7 +242,8 @@ class TestClassifier(DirectoriesMixin, TestCase): def test_one_type_predict_manydocs(self): dt = DocumentType.objects.create( - name="dt", matching_algorithm=DocumentType.MATCH_AUTO + name="dt", + matching_algorithm=DocumentType.MATCH_AUTO, ) doc1 = Document.objects.create( @@ -227,7 +254,9 @@ class TestClassifier(DirectoriesMixin, TestCase): ) doc2 = Document.objects.create( - title="doc1", content="this is a document from c2", checksum="B" + title="doc1", + content="this is a document from c2", + checksum="B", ) self.classifier.train() @@ -238,7 +267,9 @@ class TestClassifier(DirectoriesMixin, TestCase): t1 = Tag.objects.create(name="t1", matching_algorithm=Tag.MATCH_AUTO, pk=12) doc1 = Document.objects.create( - title="doc1", content="this is a document from c1", checksum="A" + title="doc1", + content="this is a document from c1", + checksum="A", ) doc1.tags.add(t1) @@ -249,7 +280,9 @@ class TestClassifier(DirectoriesMixin, TestCase): t1 = Tag.objects.create(name="t1", matching_algorithm=Tag.MATCH_AUTO, pk=12) doc1 = Document.objects.create( - title="doc1", content="this is a document from c1", checksum="A" + title="doc1", + content="this is a document from c1", + checksum="A", ) self.classifier.train() @@ -260,7 +293,9 @@ class TestClassifier(DirectoriesMixin, TestCase): t2 = Tag.objects.create(name="t2", matching_algorithm=Tag.MATCH_AUTO, pk=121) doc4 = Document.objects.create( - title="doc1", content="this is a document from c4", checksum="D" + title="doc1", + content="this is a document from c4", + checksum="D", ) doc4.tags.add(t1) @@ -273,16 +308,24 @@ class TestClassifier(DirectoriesMixin, TestCase): t2 = Tag.objects.create(name="t2", matching_algorithm=Tag.MATCH_AUTO, pk=121) doc1 = Document.objects.create( - title="doc1", content="this is a document from c1", checksum="A" + title="doc1", + content="this is a document from c1", + checksum="A", ) doc2 = Document.objects.create( - title="doc1", content="this is a document from c2", checksum="B" + title="doc1", + content="this is a document from c2", + checksum="B", ) doc3 = Document.objects.create( - title="doc1", content="this is a document from c3", checksum="C" + title="doc1", + content="this is a document from c3", + checksum="C", ) doc4 = Document.objects.create( - title="doc1", content="this is a document from c4", checksum="D" + title="doc1", + content="this is a document from c4", + checksum="D", ) doc1.tags.add(t1) @@ -300,10 +343,14 @@ class TestClassifier(DirectoriesMixin, TestCase): t1 = Tag.objects.create(name="t1", matching_algorithm=Tag.MATCH_AUTO, pk=12) doc1 = Document.objects.create( - title="doc1", content="this is a document from c1", checksum="A" + title="doc1", + content="this is a document from c1", + checksum="A", ) doc2 = Document.objects.create( - title="doc2", content="this is a document from c2", checksum="B" + title="doc2", + content="this is a document from c2", + checksum="B", ) doc1.tags.add(t1) @@ -316,10 +363,14 @@ class TestClassifier(DirectoriesMixin, TestCase): t1 = Tag.objects.create(name="t1", matching_algorithm=Tag.MATCH_AUTO, pk=12) doc1 = Document.objects.create( - title="doc1", content="this is a document from c1", checksum="A" + title="doc1", + content="this is a document from c1", + checksum="A", ) doc2 = Document.objects.create( - title="doc2", content="this is a document from c2", checksum="B" + title="doc2", + content="this is a document from c2", + checksum="B", ) doc1.tags.add(t1) @@ -338,13 +389,15 @@ class TestClassifier(DirectoriesMixin, TestCase): load.assert_called_once() @override_settings( - CACHES={"default": {"BACKEND": "django.core.cache.backends.locmem.LocMemCache"}} + CACHES={ + "default": {"BACKEND": "django.core.cache.backends.locmem.LocMemCache"}, + }, ) @override_settings( - MODEL_FILE=os.path.join(os.path.dirname(__file__), "data", "model.pickle") + MODEL_FILE=os.path.join(os.path.dirname(__file__), "data", "model.pickle"), ) @pytest.mark.skip( - reason="Disabled caching due to high memory usage - need to investigate." + reason="Disabled caching due to high memory usage - need to investigate.", ) def test_load_classifier_cached(self): classifier = load_classifier() diff --git a/src/documents/tests/test_consumer.py b/src/documents/tests/test_consumer.py index 6c79c7713..af54255e0 100644 --- a/src/documents/tests/test_consumer.py +++ b/src/documents/tests/test_consumer.py @@ -5,14 +5,26 @@ import tempfile from unittest import mock from unittest.mock import MagicMock -from django.conf import settings -from django.test import TestCase, override_settings +try: + import zoneinfo +except ImportError: + import backports.zoneinfo as zoneinfo -from .utils import DirectoriesMixin -from ..consumer import Consumer, ConsumerError -from ..models import FileInfo, Tag, Correspondent, DocumentType, Document -from ..parsers import DocumentParser, ParseError +from django.conf import settings +from django.test import override_settings +from django.test import TestCase + +from ..consumer import Consumer +from ..consumer import ConsumerError +from ..models import Correspondent +from ..models import Document +from ..models import DocumentType +from ..models import FileInfo +from ..models import Tag +from ..parsers import DocumentParser +from ..parsers import ParseError from ..tasks import sanity_check +from .utils import DirectoriesMixin class TestAttributes(TestCase): @@ -33,12 +45,18 @@ class TestAttributes(TestCase): def test_guess_attributes_from_name_when_title_starts_with_dash(self): self._test_guess_attributes_from_name( - "- weird but should not break.pdf", None, "- weird but should not break", () + "- weird but should not break.pdf", + None, + "- weird but should not break", + (), ) def test_guess_attributes_from_name_when_title_ends_with_dash(self): self._test_guess_attributes_from_name( - "weird but should not break -.pdf", None, "weird but should not break -", () + "weird but should not break -.pdf", + None, + "weird but should not break -", + (), ) @@ -53,7 +71,12 @@ class TestFieldPermutations(TestCase): valid_tags = ["tag", "tig,tag", "tag1,tag2,tag-3"] def _test_guessed_attributes( - self, filename, created=None, correspondent=None, title=None, tags=None + self, + filename, + created=None, + correspondent=None, + title=None, + tags=None, ): info = FileInfo.from_filename(filename) @@ -131,7 +154,7 @@ class TestFieldPermutations(TestCase): FILENAME_PARSE_TRANSFORMS=[ (all_patt, "all.gif"), (all_patt, "anotherall.gif"), - ] + ], ): info = FileInfo.from_filename(filename) self.assertEqual(info.title, "all") @@ -141,7 +164,7 @@ class TestFieldPermutations(TestCase): FILENAME_PARSE_TRANSFORMS=[ (none_patt, "none.gif"), (all_patt, "anotherall.gif"), - ] + ], ): info = FileInfo.from_filename(filename) self.assertEqual(info.title, "anotherall") @@ -238,7 +261,9 @@ class TestConsumer(DirectoriesMixin, TestCase): def make_dummy_parser(self, logging_group, progress_callback=None): return DummyParser( - logging_group, self.dirs.scratch_dir, self.get_test_archive_file() + logging_group, + self.dirs.scratch_dir, + self.get_test_archive_file(), ) def make_faulty_parser(self, logging_group, progress_callback=None): @@ -257,7 +282,7 @@ class TestConsumer(DirectoriesMixin, TestCase): "mime_types": {"application/pdf": ".pdf"}, "weight": 0, }, - ) + ), ] self.addCleanup(patcher.stop) @@ -282,13 +307,17 @@ class TestConsumer(DirectoriesMixin, TestCase): def get_test_archive_file(self): src = os.path.join( - os.path.dirname(__file__), "samples", "documents", "archive", "0000001.pdf" + os.path.dirname(__file__), + "samples", + "documents", + "archive", + "0000001.pdf", ) dst = os.path.join(self.dirs.scratch_dir, "sample_archive.pdf") shutil.copy(src, dst) return dst - @override_settings(PAPERLESS_FILENAME_FORMAT=None) + @override_settings(PAPERLESS_FILENAME_FORMAT=None, TIME_ZONE="America/Chicago") def testNormalOperation(self): filename = self.get_test_file() @@ -296,7 +325,8 @@ class TestConsumer(DirectoriesMixin, TestCase): self.assertEqual(document.content, "The Text") self.assertEqual( - document.title, os.path.splitext(os.path.basename(filename))[0] + document.title, + os.path.splitext(os.path.basename(filename))[0], ) self.assertIsNone(document.correspondent) self.assertIsNone(document.document_type) @@ -316,6 +346,8 @@ class TestConsumer(DirectoriesMixin, TestCase): self._assert_first_last_send_progress() + self.assertEqual(document.created.tzinfo, zoneinfo.ZoneInfo("America/Chicago")) + @override_settings(PAPERLESS_FILENAME_FORMAT=None) def testDeleteMacFiles(self): # https://github.com/jonaswinkler/paperless-ng/discussions/1037 @@ -339,7 +371,8 @@ class TestConsumer(DirectoriesMixin, TestCase): override_filename = "Statement for November.pdf" document = self.consumer.try_consume_file( - filename, override_filename=override_filename + filename, + override_filename=override_filename, ) self.assertEqual(document.title, "Statement for November") @@ -348,7 +381,8 @@ class TestConsumer(DirectoriesMixin, TestCase): def testOverrideTitle(self): document = self.consumer.try_consume_file( - self.get_test_file(), override_title="Override Title" + self.get_test_file(), + override_title="Override Title", ) self.assertEqual(document.title, "Override Title") self._assert_first_last_send_progress() @@ -357,7 +391,8 @@ class TestConsumer(DirectoriesMixin, TestCase): c = Correspondent.objects.create(name="test") document = self.consumer.try_consume_file( - self.get_test_file(), override_correspondent_id=c.pk + self.get_test_file(), + override_correspondent_id=c.pk, ) self.assertEqual(document.correspondent.id, c.id) self._assert_first_last_send_progress() @@ -366,7 +401,8 @@ class TestConsumer(DirectoriesMixin, TestCase): dt = DocumentType.objects.create(name="test") document = self.consumer.try_consume_file( - self.get_test_file(), override_document_type_id=dt.pk + self.get_test_file(), + override_document_type_id=dt.pk, ) self.assertEqual(document.document_type.id, dt.id) self._assert_first_last_send_progress() @@ -376,7 +412,8 @@ class TestConsumer(DirectoriesMixin, TestCase): t2 = Tag.objects.create(name="t2") t3 = Tag.objects.create(name="t3") document = self.consumer.try_consume_file( - self.get_test_file(), override_tag_ids=[t1.id, t3.id] + self.get_test_file(), + override_tag_ids=[t1.id, t3.id], ) self.assertIn(t1, document.tags.all()) @@ -446,7 +483,7 @@ class TestConsumer(DirectoriesMixin, TestCase): "mime_types": {"application/pdf": ".pdf"}, "weight": 0, }, - ) + ), ] self.assertRaisesMessage( @@ -595,16 +632,16 @@ class TestConsumer(DirectoriesMixin, TestCase): "mime_types": {"application/pdf": ".pdf", "image/png": ".png"}, "weight": 0, }, - ) + ), ] doc1 = self.consumer.try_consume_file( - os.path.join(settings.CONSUMPTION_DIR, "simple.png") + os.path.join(settings.CONSUMPTION_DIR, "simple.png"), ) doc2 = self.consumer.try_consume_file( - os.path.join(settings.CONSUMPTION_DIR, "simple.pdf") + os.path.join(settings.CONSUMPTION_DIR, "simple.pdf"), ) doc3 = self.consumer.try_consume_file( - os.path.join(settings.CONSUMPTION_DIR, "simple.png.pdf") + os.path.join(settings.CONSUMPTION_DIR, "simple.png.pdf"), ) self.assertEqual(doc1.filename, "simple.png") @@ -691,7 +728,9 @@ class PostConsumeTestCase(TestCase): with override_settings(POST_CONSUME_SCRIPT=script.name): c = Correspondent.objects.create(name="my_bank") doc = Document.objects.create( - title="Test", mime_type="application/pdf", correspondent=c + title="Test", + mime_type="application/pdf", + correspondent=c, ) tag1 = Tag.objects.create(name="a") tag2 = Tag.objects.create(name="b") diff --git a/src/documents/tests/test_date_parsing.py b/src/documents/tests/test_date_parsing.py index d5dbaf60b..06ad9876c 100644 --- a/src/documents/tests/test_date_parsing.py +++ b/src/documents/tests/test_date_parsing.py @@ -5,15 +5,16 @@ from uuid import uuid4 from dateutil import tz from django.conf import settings -from django.test import TestCase, override_settings - +from django.test import override_settings +from django.test import TestCase from documents.parsers import parse_date class TestDate(TestCase): SAMPLE_FILES = os.path.join( - os.path.dirname(__file__), "../../paperless_tesseract/tests/samples" + os.path.dirname(__file__), + "../../paperless_tesseract/tests/samples", ) SCRATCH = "/tmp/paperless-tests-{}".format(str(uuid4())[:8]) @@ -99,6 +100,57 @@ class TestDate(TestCase): datetime.datetime(2020, 3, 1, 0, 0, tzinfo=tz.gettz(settings.TIME_ZONE)), ) + def test_date_format_10(self): + text = "Customer Number Currency 22-MAR-2022 Credit Card 1934829304" + self.assertEqual( + parse_date("", text), + datetime.datetime(2022, 3, 22, 0, 0, tzinfo=tz.gettz(settings.TIME_ZONE)), + ) + + def test_date_format_11(self): + text = "Customer Number Currency 22 MAR 2022 Credit Card 1934829304" + self.assertEqual( + parse_date("", text), + datetime.datetime(2022, 3, 22, 0, 0, tzinfo=tz.gettz(settings.TIME_ZONE)), + ) + + def test_date_format_12(self): + text = "Customer Number Currency 22/MAR/2022 Credit Card 1934829304" + self.assertEqual( + parse_date("", text), + datetime.datetime(2022, 3, 22, 0, 0, tzinfo=tz.gettz(settings.TIME_ZONE)), + ) + + def test_date_format_13(self): + text = "Customer Number Currency 22.MAR.2022 Credit Card 1934829304" + self.assertEqual( + parse_date("", text), + datetime.datetime(2022, 3, 22, 0, 0, tzinfo=tz.gettz(settings.TIME_ZONE)), + ) + + def test_date_format_14(self): + text = "Customer Number Currency 22.MAR 2022 Credit Card 1934829304" + self.assertEqual( + parse_date("", text), + datetime.datetime(2022, 3, 22, 0, 0, tzinfo=tz.gettz(settings.TIME_ZONE)), + ) + + def test_date_format_15(self): + text = "Customer Number Currency 22.MAR.22 Credit Card 1934829304" + self.assertIsNone(parse_date("", text), None) + + def test_date_format_16(self): + text = "Customer Number Currency 22.MAR,22 Credit Card 1934829304" + self.assertIsNone(parse_date("", text), None) + + def test_date_format_17(self): + text = "Customer Number Currency 22,MAR,2022 Credit Card 1934829304" + self.assertIsNone(parse_date("", text), None) + + def test_date_format_18(self): + text = "Customer Number Currency 22 MAR,2022 Credit Card 1934829304" + self.assertIsNone(parse_date("", text), None) + def test_crazy_date_past(self, *args): self.assertIsNone(parse_date("", "01-07-0590 00:00:00")) @@ -111,11 +163,11 @@ class TestDate(TestCase): @override_settings(FILENAME_DATE_ORDER="YMD") def test_filename_date_parse_invalid(self, *args): self.assertIsNone( - parse_date("/tmp/20 408000l 2475 - test.pdf", "No date in here") + parse_date("/tmp/20 408000l 2475 - test.pdf", "No date in here"), ) @override_settings( - IGNORE_DATES=(datetime.date(2019, 11, 3), datetime.date(2020, 1, 17)) + IGNORE_DATES=(datetime.date(2019, 11, 3), datetime.date(2020, 1, 17)), ) def test_ignored_dates(self, *args): text = "lorem ipsum 110319, 20200117 and lorem 13.02.2018 lorem " "ipsum" diff --git a/src/documents/tests/test_document_model.py b/src/documents/tests/test_document_model.py index 3a7a88b87..a99d6dd18 100644 --- a/src/documents/tests/test_document_model.py +++ b/src/documents/tests/test_document_model.py @@ -3,10 +3,12 @@ import tempfile from pathlib import Path from unittest import mock -from django.test import TestCase, override_settings +from django.test import override_settings +from django.test import TestCase from django.utils import timezone -from ..models import Document, Correspondent +from ..models import Correspondent +from ..models import Document class TestDocument(TestCase): diff --git a/src/documents/tests/test_file_handling.py b/src/documents/tests/test_file_handling.py index 6ffa4481d..7743458b4 100644 --- a/src/documents/tests/test_file_handling.py +++ b/src/documents/tests/test_file_handling.py @@ -9,17 +9,19 @@ from unittest import mock from django.conf import settings from django.db import DatabaseError -from django.test import TestCase, override_settings +from django.test import override_settings +from django.test import TestCase from django.utils import timezone +from ..file_handling import create_source_path_directory +from ..file_handling import delete_empty_directories +from ..file_handling import generate_filename +from ..file_handling import generate_unique_filename +from ..models import Correspondent +from ..models import Document +from ..models import DocumentType +from ..models import Tag from .utils import DirectoriesMixin -from ..file_handling import ( - generate_filename, - create_source_path_directory, - delete_empty_directories, - generate_unique_filename, -) -from ..models import Document, Correspondent, Tag, DocumentType class TestFileHandling(DirectoriesMixin, TestCase): @@ -34,7 +36,8 @@ class TestFileHandling(DirectoriesMixin, TestCase): document.storage_type = Document.STORAGE_TYPE_GPG self.assertEqual( - generate_filename(document), "{:07d}.pdf.gpg".format(document.pk) + generate_filename(document), + "{:07d}.pdf.gpg".format(document.pk), ) @override_settings(PAPERLESS_FILENAME_FORMAT="{correspondent}/{correspondent}") @@ -75,7 +78,8 @@ class TestFileHandling(DirectoriesMixin, TestCase): self.assertEqual(os.path.isdir(settings.ORIGINALS_DIR + "/test"), True) self.assertEqual(os.path.isdir(settings.ORIGINALS_DIR + "/none"), False) self.assertEqual( - os.path.isfile(settings.ORIGINALS_DIR + "/test/test.pdf.gpg"), True + os.path.isfile(settings.ORIGINALS_DIR + "/test/test.pdf.gpg"), + True, ) @override_settings(PAPERLESS_FILENAME_FORMAT="{correspondent}/{correspondent}") @@ -93,7 +97,8 @@ class TestFileHandling(DirectoriesMixin, TestCase): # Test source_path self.assertEqual( - document.source_path, settings.ORIGINALS_DIR + "/none/none.pdf" + document.source_path, + settings.ORIGINALS_DIR + "/none/none.pdf", ) # Make the folder read- and execute-only (no writing and no renaming) @@ -105,7 +110,8 @@ class TestFileHandling(DirectoriesMixin, TestCase): # Check proper handling of files self.assertEqual( - os.path.isfile(settings.ORIGINALS_DIR + "/none/none.pdf"), True + os.path.isfile(settings.ORIGINALS_DIR + "/none/none.pdf"), + True, ) self.assertEqual(document.filename, "none/none.pdf") @@ -145,7 +151,8 @@ class TestFileHandling(DirectoriesMixin, TestCase): # Check proper handling of files self.assertTrue(os.path.isfile(document.source_path)) self.assertEqual( - os.path.isfile(settings.ORIGINALS_DIR + "/none/none.pdf"), True + os.path.isfile(settings.ORIGINALS_DIR + "/none/none.pdf"), + True, ) self.assertEqual(document.filename, "none/none.pdf") @@ -167,7 +174,8 @@ class TestFileHandling(DirectoriesMixin, TestCase): pk = document.pk document.delete() self.assertEqual( - os.path.isfile(settings.ORIGINALS_DIR + "/none/none.pdf"), False + os.path.isfile(settings.ORIGINALS_DIR + "/none/none.pdf"), + False, ) self.assertEqual(os.path.isdir(settings.ORIGINALS_DIR + "/none"), False) @@ -192,7 +200,8 @@ class TestFileHandling(DirectoriesMixin, TestCase): self.assertEqual(os.path.isfile(settings.TRASH_DIR + "/none/none.pdf"), False) document.delete() self.assertEqual( - os.path.isfile(settings.ORIGINALS_DIR + "/none/none.pdf"), False + os.path.isfile(settings.ORIGINALS_DIR + "/none/none.pdf"), + False, ) self.assertEqual(os.path.isdir(settings.ORIGINALS_DIR + "/none"), False) self.assertEqual(os.path.isfile(settings.TRASH_DIR + "/none.pdf"), True) @@ -363,7 +372,9 @@ class TestFileHandling(DirectoriesMixin, TestCase): self.assertEqual(generate_filename(doc), "doc1 tag1,tag2.pdf") doc = Document.objects.create( - title="doc2", checksum="B", mime_type="application/pdf" + title="doc2", + checksum="B", + mime_type="application/pdf", ) self.assertEqual(generate_filename(doc), "doc2.pdf") @@ -380,12 +391,14 @@ class TestFileHandling(DirectoriesMixin, TestCase): ) @override_settings( - PAPERLESS_FILENAME_FORMAT="{created_year}-{created_month}-{created_day}" + PAPERLESS_FILENAME_FORMAT="{created_year}-{created_month}-{created_day}", ) def test_created_year_month_day(self): d1 = timezone.make_aware(datetime.datetime(2020, 3, 6, 1, 1, 1)) doc1 = Document.objects.create( - title="doc1", mime_type="application/pdf", created=d1 + title="doc1", + mime_type="application/pdf", + created=d1, ) self.assertEqual(generate_filename(doc1), "2020-03-06.pdf") @@ -395,12 +408,14 @@ class TestFileHandling(DirectoriesMixin, TestCase): self.assertEqual(generate_filename(doc1), "2020-11-16.pdf") @override_settings( - PAPERLESS_FILENAME_FORMAT="{added_year}-{added_month}-{added_day}" + PAPERLESS_FILENAME_FORMAT="{added_year}-{added_month}-{added_day}", ) def test_added_year_month_day(self): d1 = timezone.make_aware(datetime.datetime(232, 1, 9, 1, 1, 1)) doc1 = Document.objects.create( - title="doc1", mime_type="application/pdf", added=d1 + title="doc1", + mime_type="application/pdf", + added=d1, ) self.assertEqual(generate_filename(doc1), "232-01-09.pdf") @@ -410,7 +425,7 @@ class TestFileHandling(DirectoriesMixin, TestCase): self.assertEqual(generate_filename(doc1), "2020-11-16.pdf") @override_settings( - PAPERLESS_FILENAME_FORMAT="{correspondent}/{correspondent}/{correspondent}" + PAPERLESS_FILENAME_FORMAT="{correspondent}/{correspondent}/{correspondent}", ) def test_nested_directory_cleanup(self): document = Document() @@ -431,7 +446,8 @@ class TestFileHandling(DirectoriesMixin, TestCase): document.delete() self.assertEqual( - os.path.isfile(settings.ORIGINALS_DIR + "/none/none/none.pdf"), False + os.path.isfile(settings.ORIGINALS_DIR + "/none/none/none.pdf"), + False, ) self.assertEqual(os.path.isdir(settings.ORIGINALS_DIR + "/none/none"), False) self.assertEqual(os.path.isdir(settings.ORIGINALS_DIR + "/none"), False) @@ -456,7 +472,8 @@ class TestFileHandling(DirectoriesMixin, TestCase): os.makedirs(os.path.join(tmp, "notempty", "empty")) delete_empty_directories( - os.path.join(tmp, "notempty", "empty"), root=settings.ORIGINALS_DIR + os.path.join(tmp, "notempty", "empty"), + root=settings.ORIGINALS_DIR, ) self.assertEqual(os.path.isdir(os.path.join(tmp, "notempty")), True) self.assertEqual(os.path.isfile(os.path.join(tmp, "notempty", "file")), True) @@ -483,10 +500,16 @@ class TestFileHandling(DirectoriesMixin, TestCase): @override_settings(PAPERLESS_FILENAME_FORMAT="{title}") def test_duplicates(self): document = Document.objects.create( - mime_type="application/pdf", title="qwe", checksum="A", pk=1 + mime_type="application/pdf", + title="qwe", + checksum="A", + pk=1, ) document2 = Document.objects.create( - mime_type="application/pdf", title="qwe", checksum="B", pk=2 + mime_type="application/pdf", + title="qwe", + checksum="B", + pk=2, ) Path(document.source_path).touch() Path(document2.source_path).touch() @@ -584,10 +607,12 @@ class TestFileHandlingWithArchive(DirectoriesMixin, TestCase): self.assertTrue(os.path.isfile(doc.source_path)) self.assertTrue(os.path.isfile(doc.archive_path)) self.assertEqual( - doc.source_path, os.path.join(settings.ORIGINALS_DIR, "none", "my_doc.pdf") + doc.source_path, + os.path.join(settings.ORIGINALS_DIR, "none", "my_doc.pdf"), ) self.assertEqual( - doc.archive_path, os.path.join(settings.ARCHIVE_DIR, "none", "my_doc.pdf") + doc.archive_path, + os.path.join(settings.ARCHIVE_DIR, "none", "my_doc.pdf"), ) @override_settings(PAPERLESS_FILENAME_FORMAT="{correspondent}/{title}") @@ -851,7 +876,10 @@ class TestFilenameGeneration(TestCase): def test_invalid_characters(self): doc = Document.objects.create( - title="This. is the title.", mime_type="application/pdf", pk=1, checksum="1" + title="This. is the title.", + mime_type="application/pdf", + pk=1, + checksum="1", ) self.assertEqual(generate_filename(doc), "This. is the title.pdf") @@ -877,7 +905,9 @@ class TestFilenameGeneration(TestCase): def run(): doc = Document.objects.create( - checksum=str(uuid.uuid4()), title=str(uuid.uuid4()), content="wow" + checksum=str(uuid.uuid4()), + title=str(uuid.uuid4()), + content="wow", ) doc.filename = generate_unique_filename(doc) Path(doc.thumbnail_path).touch() diff --git a/src/documents/tests/test_importer.py b/src/documents/tests/test_importer.py index 73215173a..5101a269f 100644 --- a/src/documents/tests/test_importer.py +++ b/src/documents/tests/test_importer.py @@ -1,7 +1,7 @@ from django.core.management.base import CommandError from django.test import TestCase - from documents.settings import EXPORTER_FILE_NAME + from ..management.commands.document_importer import Command @@ -12,7 +12,9 @@ class TestImporter(TestCase): def test_check_manifest_exists(self): cmd = Command() self.assertRaises( - CommandError, cmd._check_manifest_exists, "/tmp/manifest.json" + CommandError, + cmd._check_manifest_exists, + "/tmp/manifest.json", ) def test_check_manifest(self): @@ -26,11 +28,11 @@ class TestImporter(TestCase): self.assertTrue("The manifest file contains a record" in str(cm.exception)) cmd.manifest = [ - {"model": "documents.document", EXPORTER_FILE_NAME: "noexist.pdf"} + {"model": "documents.document", EXPORTER_FILE_NAME: "noexist.pdf"}, ] # self.assertRaises(CommandError, cmd._check_manifest) with self.assertRaises(CommandError) as cm: cmd._check_manifest() self.assertTrue( - 'The manifest file refers to "noexist.pdf"' in str(cm.exception) + 'The manifest file refers to "noexist.pdf"' in str(cm.exception), ) diff --git a/src/documents/tests/test_index.py b/src/documents/tests/test_index.py index 31ad2aebf..696648427 100644 --- a/src/documents/tests/test_index.py +++ b/src/documents/tests/test_index.py @@ -1,5 +1,4 @@ from django.test import TestCase - from documents import index from documents.models import Document from documents.tests.utils import DirectoriesMixin @@ -9,7 +8,9 @@ class TestAutoComplete(DirectoriesMixin, TestCase): def test_auto_complete(self): doc1 = Document.objects.create( - title="doc1", checksum="A", content="test test2 test3" + title="doc1", + checksum="A", + content="test test2 test3", ) doc2 = Document.objects.create(title="doc2", checksum="B", content="test test2") doc3 = Document.objects.create(title="doc3", checksum="C", content="test2") @@ -21,10 +22,12 @@ class TestAutoComplete(DirectoriesMixin, TestCase): ix = index.open_index() self.assertListEqual( - index.autocomplete(ix, "tes"), [b"test3", b"test", b"test2"] + index.autocomplete(ix, "tes"), + [b"test3", b"test", b"test2"], ) self.assertListEqual( - index.autocomplete(ix, "tes", limit=3), [b"test3", b"test", b"test2"] + index.autocomplete(ix, "tes", limit=3), + [b"test3", b"test", b"test2"], ) self.assertListEqual(index.autocomplete(ix, "tes", limit=1), [b"test3"]) self.assertListEqual(index.autocomplete(ix, "tes", limit=0), []) diff --git a/src/documents/tests/test_management.py b/src/documents/tests/test_management.py index f3c3a3fae..7cb2e22d7 100644 --- a/src/documents/tests/test_management.py +++ b/src/documents/tests/test_management.py @@ -1,16 +1,14 @@ -import hashlib -import tempfile import filecmp +import hashlib import os import shutil +import tempfile from pathlib import Path from unittest import mock -from django.test import TestCase, override_settings - - from django.core.management import call_command - +from django.test import override_settings +from django.test import TestCase from documents.file_handling import generate_filename from documents.management.commands.document_archiver import handle_document from documents.models import Document @@ -34,7 +32,8 @@ class TestArchiver(DirectoriesMixin, TestCase): doc = self.make_models() shutil.copy( - sample_file, os.path.join(self.dirs.originals_dir, f"{doc.id:07}.pdf") + sample_file, + os.path.join(self.dirs.originals_dir, f"{doc.id:07}.pdf"), ) call_command("document_archiver") @@ -43,7 +42,8 @@ class TestArchiver(DirectoriesMixin, TestCase): doc = self.make_models() shutil.copy( - sample_file, os.path.join(self.dirs.originals_dir, f"{doc.id:07}.pdf") + sample_file, + os.path.join(self.dirs.originals_dir, f"{doc.id:07}.pdf"), ) handle_document(doc.pk) @@ -90,7 +90,8 @@ class TestArchiver(DirectoriesMixin, TestCase): ) shutil.copy(sample_file, os.path.join(self.dirs.originals_dir, f"document.pdf")) shutil.copy( - sample_file, os.path.join(self.dirs.originals_dir, f"document_01.pdf") + sample_file, + os.path.join(self.dirs.originals_dir, f"document_01.pdf"), ) handle_document(doc2.pk) @@ -120,7 +121,9 @@ class TestDecryptDocuments(TestCase): os.makedirs(thumb_dir, exist_ok=True) override_settings( - ORIGINALS_DIR=originals_dir, THUMBNAIL_DIR=thumb_dir, PASSPHRASE="test" + ORIGINALS_DIR=originals_dir, + THUMBNAIL_DIR=thumb_dir, + PASSPHRASE="test", ).enable() doc = Document.objects.create( @@ -206,7 +209,7 @@ class TestRenamer(DirectoriesMixin, TestCase): class TestCreateClassifier(TestCase): @mock.patch( - "documents.management.commands.document_create_classifier.train_classifier" + "documents.management.commands.document_create_classifier.train_classifier", ) def test_create_classifier(self, m): call_command("document_create_classifier") @@ -224,7 +227,10 @@ class TestSanityChecker(DirectoriesMixin, TestCase): def test_errors(self): doc = Document.objects.create( - title="test", content="test", filename="test.pdf", checksum="abc" + title="test", + content="test", + filename="test.pdf", + checksum="abc", ) Path(doc.source_path).touch() Path(doc.thumbnail_path).touch() diff --git a/src/documents/tests/test_management_consumer.py b/src/documents/tests/test_management_consumer.py index 31ab69339..d99b01e66 100644 --- a/src/documents/tests/test_management_consumer.py +++ b/src/documents/tests/test_management_consumer.py @@ -6,12 +6,13 @@ from time import sleep from unittest import mock from django.conf import settings -from django.core.management import call_command, CommandError -from django.test import override_settings, TransactionTestCase - -from documents.models import Tag +from django.core.management import call_command +from django.core.management import CommandError +from django.test import override_settings +from django.test import TransactionTestCase from documents.consumer import ConsumerError from documents.management.commands import document_consumer +from documents.models import Tag from documents.tests.utils import DirectoriesMixin @@ -41,7 +42,7 @@ class ConsumerMixin: super(ConsumerMixin, self).setUp() self.t = None patcher = mock.patch( - "documents.management.commands.document_consumer.async_task" + "documents.management.commands.document_consumer.async_task", ) self.task_mock = patcher.start() self.addCleanup(patcher.stop) @@ -208,13 +209,16 @@ class TestConsumer(DirectoriesMixin, ConsumerMixin, TransactionTestCase): self.t_start() shutil.copy( - self.sample_file, os.path.join(self.dirs.consumption_dir, ".DS_STORE") + self.sample_file, + os.path.join(self.dirs.consumption_dir, ".DS_STORE"), ) shutil.copy( - self.sample_file, os.path.join(self.dirs.consumption_dir, "my_file.pdf") + self.sample_file, + os.path.join(self.dirs.consumption_dir, "my_file.pdf"), ) shutil.copy( - self.sample_file, os.path.join(self.dirs.consumption_dir, "._my_file.pdf") + self.sample_file, + os.path.join(self.dirs.consumption_dir, "._my_file.pdf"), ) shutil.copy( self.sample_file, @@ -256,9 +260,26 @@ class TestConsumer(DirectoriesMixin, ConsumerMixin, TransactionTestCase): f'_is_ignored("{file_path}") != {expected_ignored}', ) + @mock.patch("documents.management.commands.document_consumer.open") + def test_consume_file_busy(self, open_mock): + + # Calling this mock always raises this + open_mock.side_effect = OSError + + self.t_start() + + f = os.path.join(self.dirs.consumption_dir, "my_file.pdf") + shutil.copy(self.sample_file, f) + + self.wait_for_task_mock_call() + + self.task_mock.assert_not_called() + @override_settings( - CONSUMER_POLLING=1, CONSUMER_POLLING_DELAY=3, CONSUMER_POLLING_RETRY_COUNT=20 + CONSUMER_POLLING=1, + CONSUMER_POLLING_DELAY=3, + CONSUMER_POLLING_RETRY_COUNT=20, ) class TestConsumerPolling(TestConsumer): # just do all the tests with polling @@ -319,7 +340,9 @@ class TestConsumerTags(DirectoriesMixin, ConsumerMixin, TransactionTestCase): self.assertCountEqual(kwargs["override_tag_ids"], tag_ids) @override_settings( - CONSUMER_POLLING=1, CONSUMER_POLLING_DELAY=1, CONSUMER_POLLING_RETRY_COUNT=20 + CONSUMER_POLLING=1, + CONSUMER_POLLING_DELAY=1, + CONSUMER_POLLING_RETRY_COUNT=20, ) def test_consume_file_with_path_tags_polling(self): self.test_consume_file_with_path_tags() diff --git a/src/documents/tests/test_management_exporter.py b/src/documents/tests/test_management_exporter.py index e833b0eef..23cf1f225 100644 --- a/src/documents/tests/test_management_exporter.py +++ b/src/documents/tests/test_management_exporter.py @@ -7,13 +7,17 @@ from pathlib import Path from unittest import mock from django.core.management import call_command -from django.test import TestCase, override_settings - +from django.test import override_settings +from django.test import TestCase from documents.management.commands import document_exporter -from documents.models import Document, Tag, DocumentType, Correspondent +from documents.models import Correspondent +from documents.models import Document +from documents.models import DocumentType +from documents.models import Tag from documents.sanity_checker import check_sanity from documents.settings import EXPORTER_FILE_NAME -from documents.tests.utils import DirectoriesMixin, paperless_environment +from documents.tests.utils import DirectoriesMixin +from documents.tests.utils import paperless_environment class TestExportImport(DirectoriesMixin, TestCase): @@ -66,8 +70,9 @@ class TestExportImport(DirectoriesMixin, TestCase): def _get_document_from_manifest(self, manifest, id): f = list( filter( - lambda d: d["model"] == "documents.document" and d["pk"] == id, manifest - ) + lambda d: d["model"] == "documents.document" and d["pk"] == id, + manifest, + ), ) if len(f) == 1: return f[0] @@ -76,7 +81,10 @@ class TestExportImport(DirectoriesMixin, TestCase): @override_settings(PASSPHRASE="test") def _do_export( - self, use_filename_format=False, compare_checksums=False, delete=False + self, + use_filename_format=False, + compare_checksums=False, + delete=False, ): args = ["document_exporter", self.target] if use_filename_format: @@ -104,7 +112,8 @@ class TestExportImport(DirectoriesMixin, TestCase): self.assertEqual(len(manifest), 8) self.assertEqual( - len(list(filter(lambda e: e["model"] == "documents.document", manifest))), 4 + len(list(filter(lambda e: e["model"] == "documents.document", manifest))), + 4, ) self.assertTrue(os.path.exists(os.path.join(self.target, "manifest.json"))) @@ -129,7 +138,8 @@ class TestExportImport(DirectoriesMixin, TestCase): for element in manifest: if element["model"] == "documents.document": fname = os.path.join( - self.target, element[document_exporter.EXPORTER_FILE_NAME] + self.target, + element[document_exporter.EXPORTER_FILE_NAME], ) self.assertTrue(os.path.exists(fname)) self.assertTrue( @@ -137,8 +147,8 @@ class TestExportImport(DirectoriesMixin, TestCase): os.path.join( self.target, element[document_exporter.EXPORTER_THUMBNAIL_NAME], - ) - ) + ), + ), ) with open(fname, "rb") as f: @@ -146,12 +156,14 @@ class TestExportImport(DirectoriesMixin, TestCase): self.assertEqual(checksum, element["fields"]["checksum"]) self.assertEqual( - element["fields"]["storage_type"], Document.STORAGE_TYPE_UNENCRYPTED + element["fields"]["storage_type"], + Document.STORAGE_TYPE_UNENCRYPTED, ) if document_exporter.EXPORTER_ARCHIVE_NAME in element: fname = os.path.join( - self.target, element[document_exporter.EXPORTER_ARCHIVE_NAME] + self.target, + element[document_exporter.EXPORTER_ARCHIVE_NAME], ) self.assertTrue(os.path.exists(fname)) @@ -188,7 +200,7 @@ class TestExportImport(DirectoriesMixin, TestCase): ) with override_settings( - PAPERLESS_FILENAME_FORMAT="{created_year}/{correspondent}/{title}" + PAPERLESS_FILENAME_FORMAT="{created_year}/{correspondent}/{title}", ): self.test_exporter(use_filename_format=True) @@ -205,7 +217,7 @@ class TestExportImport(DirectoriesMixin, TestCase): st_mtime_1 = os.stat(os.path.join(self.target, "manifest.json")).st_mtime with mock.patch( - "documents.management.commands.document_exporter.shutil.copy2" + "documents.management.commands.document_exporter.shutil.copy2", ) as m: self._do_export() m.assert_not_called() @@ -216,7 +228,7 @@ class TestExportImport(DirectoriesMixin, TestCase): Path(self.d1.source_path).touch() with mock.patch( - "documents.management.commands.document_exporter.shutil.copy2" + "documents.management.commands.document_exporter.shutil.copy2", ) as m: self._do_export() self.assertEqual(m.call_count, 1) @@ -239,7 +251,7 @@ class TestExportImport(DirectoriesMixin, TestCase): self.assertTrue(os.path.exists(os.path.join(self.target, "manifest.json"))) with mock.patch( - "documents.management.commands.document_exporter.shutil.copy2" + "documents.management.commands.document_exporter.shutil.copy2", ) as m: self._do_export() m.assert_not_called() @@ -250,7 +262,7 @@ class TestExportImport(DirectoriesMixin, TestCase): self.d2.save() with mock.patch( - "documents.management.commands.document_exporter.shutil.copy2" + "documents.management.commands.document_exporter.shutil.copy2", ) as m: self._do_export(compare_checksums=True) self.assertEqual(m.call_count, 1) @@ -270,26 +282,29 @@ class TestExportImport(DirectoriesMixin, TestCase): doc_from_manifest = self._get_document_from_manifest(manifest, self.d3.id) self.assertTrue( os.path.isfile( - os.path.join(self.target, doc_from_manifest[EXPORTER_FILE_NAME]) - ) + os.path.join(self.target, doc_from_manifest[EXPORTER_FILE_NAME]), + ), ) self.d3.delete() manifest = self._do_export() self.assertRaises( - ValueError, self._get_document_from_manifest, manifest, self.d3.id + ValueError, + self._get_document_from_manifest, + manifest, + self.d3.id, ) self.assertTrue( os.path.isfile( - os.path.join(self.target, doc_from_manifest[EXPORTER_FILE_NAME]) - ) + os.path.join(self.target, doc_from_manifest[EXPORTER_FILE_NAME]), + ), ) manifest = self._do_export(delete=True) self.assertFalse( os.path.isfile( - os.path.join(self.target, doc_from_manifest[EXPORTER_FILE_NAME]) - ) + os.path.join(self.target, doc_from_manifest[EXPORTER_FILE_NAME]), + ), ) self.assertTrue(len(manifest), 6) @@ -316,7 +331,7 @@ class TestExportImport(DirectoriesMixin, TestCase): self.assertTrue(os.path.exists(os.path.join(self.target, "manifest.json"))) self.assertTrue(os.path.isfile(os.path.join(self.target, "wow2", "none.pdf"))) self.assertTrue( - os.path.isfile(os.path.join(self.target, "wow2", "none_01.pdf")) + os.path.isfile(os.path.join(self.target, "wow2", "none_01.pdf")), ) def test_export_missing_files(self): diff --git a/src/documents/tests/test_management_retagger.py b/src/documents/tests/test_management_retagger.py index 77fc9d2ad..18b55626f 100644 --- a/src/documents/tests/test_management_retagger.py +++ b/src/documents/tests/test_management_retagger.py @@ -1,35 +1,50 @@ from django.core.management import call_command from django.test import TestCase - -from documents.models import Document, Tag, Correspondent, DocumentType +from documents.models import Correspondent +from documents.models import Document +from documents.models import DocumentType +from documents.models import Tag from documents.tests.utils import DirectoriesMixin class TestRetagger(DirectoriesMixin, TestCase): def make_models(self): self.d1 = Document.objects.create( - checksum="A", title="A", content="first document" + checksum="A", + title="A", + content="first document", ) self.d2 = Document.objects.create( - checksum="B", title="B", content="second document" + checksum="B", + title="B", + content="second document", ) self.d3 = Document.objects.create( - checksum="C", title="C", content="unrelated document" + checksum="C", + title="C", + content="unrelated document", ) self.d4 = Document.objects.create( - checksum="D", title="D", content="auto document" + checksum="D", + title="D", + content="auto document", ) self.tag_first = Tag.objects.create( - name="tag1", match="first", matching_algorithm=Tag.MATCH_ANY + name="tag1", + match="first", + matching_algorithm=Tag.MATCH_ANY, ) self.tag_second = Tag.objects.create( - name="tag2", match="second", matching_algorithm=Tag.MATCH_ANY + name="tag2", + match="second", + matching_algorithm=Tag.MATCH_ANY, ) self.tag_inbox = Tag.objects.create(name="test", is_inbox_tag=True) self.tag_no_match = Tag.objects.create(name="test2") self.tag_auto = Tag.objects.create( - name="tagauto", matching_algorithm=Tag.MATCH_AUTO + name="tagauto", + matching_algorithm=Tag.MATCH_AUTO, ) self.d3.tags.add(self.tag_inbox) @@ -37,17 +52,25 @@ class TestRetagger(DirectoriesMixin, TestCase): self.d4.tags.add(self.tag_auto) self.correspondent_first = Correspondent.objects.create( - name="c1", match="first", matching_algorithm=Correspondent.MATCH_ANY + name="c1", + match="first", + matching_algorithm=Correspondent.MATCH_ANY, ) self.correspondent_second = Correspondent.objects.create( - name="c2", match="second", matching_algorithm=Correspondent.MATCH_ANY + name="c2", + match="second", + matching_algorithm=Correspondent.MATCH_ANY, ) self.doctype_first = DocumentType.objects.create( - name="dt1", match="first", matching_algorithm=DocumentType.MATCH_ANY + name="dt1", + match="first", + matching_algorithm=DocumentType.MATCH_ANY, ) self.doctype_second = DocumentType.objects.create( - name="dt2", match="second", matching_algorithm=DocumentType.MATCH_ANY + name="dt2", + match="second", + matching_algorithm=DocumentType.MATCH_ANY, ) def get_updated_docs(self): @@ -98,10 +121,12 @@ class TestRetagger(DirectoriesMixin, TestCase): self.assertIsNotNone(Tag.objects.get(id=self.tag_second.id)) self.assertCountEqual( - [tag.id for tag in d_first.tags.all()], [self.tag_first.id] + [tag.id for tag in d_first.tags.all()], + [self.tag_first.id], ) self.assertCountEqual( - [tag.id for tag in d_second.tags.all()], [self.tag_second.id] + [tag.id for tag in d_second.tags.all()], + [self.tag_second.id], ) self.assertCountEqual( [tag.id for tag in d_unrelated.tags.all()], @@ -133,7 +158,10 @@ class TestRetagger(DirectoriesMixin, TestCase): def test_add_tags_suggest_url(self): call_command( - "document_retagger", "--tags", "--suggest", "--base-url=http://localhost" + "document_retagger", + "--tags", + "--suggest", + "--base-url=http://localhost", ) d_first, d_second, d_unrelated, d_auto = self.get_updated_docs() diff --git a/src/documents/tests/test_management_superuser.py b/src/documents/tests/test_management_superuser.py index fa62a9f14..b4e91fd66 100644 --- a/src/documents/tests/test_management_superuser.py +++ b/src/documents/tests/test_management_superuser.py @@ -5,9 +5,11 @@ from unittest import mock from django.contrib.auth.models import User from django.core.management import call_command from django.test import TestCase - from documents.management.commands.document_thumbnails import _process_document -from documents.models import Document, Tag, Correspondent, DocumentType +from documents.models import Correspondent +from documents.models import Document +from documents.models import DocumentType +from documents.models import Tag from documents.tests.utils import DirectoriesMixin diff --git a/src/documents/tests/test_management_thumbnails.py b/src/documents/tests/test_management_thumbnails.py index 6af94ce99..daf56c586 100644 --- a/src/documents/tests/test_management_thumbnails.py +++ b/src/documents/tests/test_management_thumbnails.py @@ -4,9 +4,11 @@ from unittest import mock from django.core.management import call_command from django.test import TestCase - from documents.management.commands.document_thumbnails import _process_document -from documents.models import Document, Tag, Correspondent, DocumentType +from documents.models import Correspondent +from documents.models import Document +from documents.models import DocumentType +from documents.models import Tag from documents.tests.utils import DirectoriesMixin diff --git a/src/documents/tests/test_matchables.py b/src/documents/tests/test_matchables.py index df47db9ba..c12883c1f 100644 --- a/src/documents/tests/test_matchables.py +++ b/src/documents/tests/test_matchables.py @@ -1,37 +1,52 @@ import shutil import tempfile from random import randint +from typing import Iterable from django.contrib.admin.models import LogEntry from django.contrib.auth.models import User -from django.test import TestCase, override_settings +from django.test import override_settings +from django.test import TestCase from .. import matching -from ..models import Correspondent, Document, Tag, DocumentType +from ..models import Correspondent +from ..models import Document +from ..models import DocumentType +from ..models import Tag from ..signals import document_consumption_finished -class TestMatching(TestCase): - def _test_matching(self, text, algorithm, true, false): +class _TestMatchingBase(TestCase): + def _test_matching( + self, + match_text: str, + match_algorithm: str, + should_match: Iterable[str], + no_match: Iterable[str], + case_sensitive: bool = False, + ): for klass in (Tag, Correspondent, DocumentType): instance = klass.objects.create( name=str(randint(10000, 99999)), - match=text, - matching_algorithm=getattr(klass, algorithm), + match=match_text, + matching_algorithm=getattr(klass, match_algorithm), + is_insensitive=not case_sensitive, ) - for string in true: + for string in should_match: doc = Document(content=string) self.assertTrue( matching.matches(instance, doc), - '"%s" should match "%s" but it does not' % (text, string), + '"%s" should match "%s" but it does not' % (match_text, string), ) - for string in false: + for string in no_match: doc = Document(content=string) self.assertFalse( matching.matches(instance, doc), - '"%s" should not match "%s" but it does' % (text, string), + '"%s" should not match "%s" but it does' % (match_text, string), ) + +class TestMatching(_TestMatchingBase): def test_match_all(self): self._test_matching( @@ -162,7 +177,7 @@ class TestMatching(TestCase): def test_match_regex(self): self._test_matching( - "alpha\w+gamma", + r"alpha\w+gamma", "MATCH_REGEX", ( "I have alpha_and_gamma in me", @@ -181,7 +196,7 @@ class TestMatching(TestCase): ) def test_tach_invalid_regex(self): - self._test_matching("[[", "MATCH_REGEX", [], ["Don't match this"]) + self._test_matching("[", "MATCH_REGEX", [], ["Don't match this"]) def test_match_fuzzy(self): @@ -198,6 +213,169 @@ class TestMatching(TestCase): ) +class TestCaseSensitiveMatching(_TestMatchingBase): + def test_match_all(self): + self._test_matching( + "alpha charlie gamma", + "MATCH_ALL", + ( + "I have alpha, charlie, and gamma in me", + "I have gamma, charlie, and alpha in me", + ), + ( + "I have Alpha, charlie, and gamma in me", + "I have gamma, Charlie, and alpha in me", + "I have alpha, charlie, and Gamma in me", + "I have gamma, charlie, and ALPHA in me", + ), + case_sensitive=True, + ) + + self._test_matching( + "Alpha charlie Gamma", + "MATCH_ALL", + ( + "I have Alpha, charlie, and Gamma in me", + "I have Gamma, charlie, and Alpha in me", + ), + ( + "I have Alpha, charlie, and gamma in me", + "I have gamma, charlie, and alpha in me", + "I have alpha, charlie, and Gamma in me", + "I have Gamma, Charlie, and ALPHA in me", + ), + case_sensitive=True, + ) + + self._test_matching( + 'brown fox "lazy dogs"', + "MATCH_ALL", + ( + "the quick brown fox jumped over the lazy dogs", + "the quick brown fox jumped over the lazy dogs", + ), + ( + "the quick Brown fox jumped over the lazy dogs", + "the quick brown Fox jumped over the lazy dogs", + "the quick brown fox jumped over the Lazy dogs", + "the quick brown fox jumped over the lazy Dogs", + ), + case_sensitive=True, + ) + + def test_match_any(self): + self._test_matching( + "alpha charlie gamma", + "MATCH_ANY", + ( + "I have alpha in me", + "I have charlie in me", + "I have gamma in me", + "I have alpha, charlie, and gamma in me", + "I have alpha and charlie in me", + ), + ( + "I have Alpha in me", + "I have chaRLie in me", + "I have gamMA in me", + "I have aLPha, cHArlie, and gAMma in me", + "I have AlphA and CharlIe in me", + ), + case_sensitive=True, + ) + + self._test_matching( + "Alpha Charlie Gamma", + "MATCH_ANY", + ( + "I have Alpha in me", + "I have Charlie in me", + "I have Gamma in me", + "I have Alpha, Charlie, and Gamma in me", + "I have Alpha and Charlie in me", + ), + ( + "I have alpha in me", + "I have ChaRLie in me", + "I have GamMA in me", + "I have ALPha, CHArlie, and GAMma in me", + "I have AlphA and CharlIe in me", + ), + case_sensitive=True, + ) + + self._test_matching( + '"brown fox" " lazy dogs "', + "MATCH_ANY", + ( + "the quick brown fox", + "jumped over the lazy dogs.", + ), + ( + "the quick Brown fox", + "jumped over the lazy Dogs.", + ), + case_sensitive=True, + ) + + def test_match_literal(self): + + self._test_matching( + "alpha charlie gamma", + "MATCH_LITERAL", + ("I have 'alpha charlie gamma' in me",), + ( + "I have 'Alpha charlie gamma' in me", + "I have 'alpha Charlie gamma' in me", + "I have 'alpha charlie Gamma' in me", + "I have 'Alpha Charlie Gamma' in me", + ), + case_sensitive=True, + ) + + self._test_matching( + "Alpha Charlie Gamma", + "MATCH_LITERAL", + ("I have 'Alpha Charlie Gamma' in me",), + ( + "I have 'Alpha charlie gamma' in me", + "I have 'alpha Charlie gamma' in me", + "I have 'alpha charlie Gamma' in me", + "I have 'alpha charlie gamma' in me", + ), + case_sensitive=True, + ) + + def test_match_regex(self): + self._test_matching( + r"alpha\w+gamma", + "MATCH_REGEX", + ( + "I have alpha_and_gamma in me", + "I have alphas_and_gamma in me", + ), + ( + "I have Alpha_and_Gamma in me", + "I have alpHAs_and_gaMMa in me", + ), + case_sensitive=True, + ) + + self._test_matching( + r"Alpha\w+gamma", + "MATCH_REGEX", + ( + "I have Alpha_and_gamma in me", + "I have Alphas_and_gamma in me", + ), + ( + "I have Alpha_and_Gamma in me", + "I have alphas_and_gamma in me", + ), + case_sensitive=True, + ) + + @override_settings(POST_CONSUME_SCRIPT=None) class TestDocumentConsumptionFinishedSignal(TestCase): """ @@ -209,7 +387,8 @@ class TestDocumentConsumptionFinishedSignal(TestCase): TestCase.setUp(self) User.objects.create_user(username="test_consumer", password="12345") self.doc_contains = Document.objects.create( - content="I contain the keyword.", mime_type="application/pdf" + content="I contain the keyword.", + mime_type="application/pdf", ) self.index_dir = tempfile.mkdtemp() @@ -221,43 +400,56 @@ class TestDocumentConsumptionFinishedSignal(TestCase): def test_tag_applied_any(self): t1 = Tag.objects.create( - name="test", match="keyword", matching_algorithm=Tag.MATCH_ANY + name="test", + match="keyword", + matching_algorithm=Tag.MATCH_ANY, ) document_consumption_finished.send( - sender=self.__class__, document=self.doc_contains + sender=self.__class__, + document=self.doc_contains, ) self.assertTrue(list(self.doc_contains.tags.all()) == [t1]) def test_tag_not_applied(self): Tag.objects.create( - name="test", match="no-match", matching_algorithm=Tag.MATCH_ANY + name="test", + match="no-match", + matching_algorithm=Tag.MATCH_ANY, ) document_consumption_finished.send( - sender=self.__class__, document=self.doc_contains + sender=self.__class__, + document=self.doc_contains, ) self.assertTrue(list(self.doc_contains.tags.all()) == []) def test_correspondent_applied(self): correspondent = Correspondent.objects.create( - name="test", match="keyword", matching_algorithm=Correspondent.MATCH_ANY + name="test", + match="keyword", + matching_algorithm=Correspondent.MATCH_ANY, ) document_consumption_finished.send( - sender=self.__class__, document=self.doc_contains + sender=self.__class__, + document=self.doc_contains, ) self.assertTrue(self.doc_contains.correspondent == correspondent) def test_correspondent_not_applied(self): Tag.objects.create( - name="test", match="no-match", matching_algorithm=Correspondent.MATCH_ANY + name="test", + match="no-match", + matching_algorithm=Correspondent.MATCH_ANY, ) document_consumption_finished.send( - sender=self.__class__, document=self.doc_contains + sender=self.__class__, + document=self.doc_contains, ) self.assertEqual(self.doc_contains.correspondent, None) def test_logentry_created(self): document_consumption_finished.send( - sender=self.__class__, document=self.doc_contains + sender=self.__class__, + document=self.doc_contains, ) self.assertEqual(LogEntry.objects.count(), 1) diff --git a/src/documents/tests/test_migration_archive_files.py b/src/documents/tests/test_migration_archive_files.py index 97f8899bc..1cb088185 100644 --- a/src/documents/tests/test_migration_archive_files.py +++ b/src/documents/tests/test_migration_archive_files.py @@ -6,9 +6,9 @@ from unittest import mock from django.conf import settings from django.test import override_settings - from documents.parsers import ParseError -from documents.tests.utils import DirectoriesMixin, TestMigrations +from documents.tests.utils import DirectoriesMixin +from documents.tests.utils import TestMigrations STORAGE_TYPE_GPG = "gpg" @@ -93,10 +93,18 @@ def make_test_document( simple_jpg = os.path.join(os.path.dirname(__file__), "samples", "simple.jpg") simple_pdf = os.path.join(os.path.dirname(__file__), "samples", "simple.pdf") simple_pdf2 = os.path.join( - os.path.dirname(__file__), "samples", "documents", "originals", "0000002.pdf" + os.path.dirname(__file__), + "samples", + "documents", + "originals", + "0000002.pdf", ) simple_pdf3 = os.path.join( - os.path.dirname(__file__), "samples", "documents", "originals", "0000003.pdf" + os.path.dirname(__file__), + "samples", + "documents", + "originals", + "0000003.pdf", ) simple_txt = os.path.join(os.path.dirname(__file__), "samples", "simple.txt") simple_png = os.path.join(os.path.dirname(__file__), "samples", "simple-noalpha.png") @@ -121,19 +129,43 @@ class TestMigrateArchiveFiles(DirectoriesMixin, TestMigrations): simple_pdf, ) self.no_text = make_test_document( - Document, "no-text", "image/png", simple_png2, "no-text.png", simple_pdf + Document, + "no-text", + "image/png", + simple_png2, + "no-text.png", + simple_pdf, ) self.doc_no_archive = make_test_document( - Document, "no_archive", "text/plain", simple_txt, "no_archive.txt" + Document, + "no_archive", + "text/plain", + simple_txt, + "no_archive.txt", ) self.clash1 = make_test_document( - Document, "clash", "application/pdf", simple_pdf, "clash.pdf", simple_pdf + Document, + "clash", + "application/pdf", + simple_pdf, + "clash.pdf", + simple_pdf, ) self.clash2 = make_test_document( - Document, "clash", "image/jpeg", simple_jpg, "clash.jpg", simple_pdf + Document, + "clash", + "image/jpeg", + simple_jpg, + "clash.jpg", + simple_pdf, ) self.clash3 = make_test_document( - Document, "clash", "image/png", simple_png, "clash.png", simple_pdf + Document, + "clash", + "image/png", + simple_png, + "clash.png", + simple_pdf, ) self.clash4 = make_test_document( Document, @@ -147,7 +179,8 @@ class TestMigrateArchiveFiles(DirectoriesMixin, TestMigrations): self.assertEqual(archive_path_old(self.clash1), archive_path_old(self.clash2)) self.assertEqual(archive_path_old(self.clash1), archive_path_old(self.clash3)) self.assertNotEqual( - archive_path_old(self.clash1), archive_path_old(self.clash4) + archive_path_old(self.clash1), + archive_path_old(self.clash4), ) def testArchiveFilesMigrated(self): @@ -171,19 +204,23 @@ class TestMigrateArchiveFiles(DirectoriesMixin, TestMigrations): self.assertEqual(archive_checksum, doc.archive_checksum) self.assertEqual( - Document.objects.filter(archive_checksum__isnull=False).count(), 6 + Document.objects.filter(archive_checksum__isnull=False).count(), + 6, ) def test_filenames(self): Document = self.apps.get_model("documents", "Document") self.assertEqual( - Document.objects.get(id=self.unrelated.id).archive_filename, "unrelated.pdf" + Document.objects.get(id=self.unrelated.id).archive_filename, + "unrelated.pdf", ) self.assertEqual( - Document.objects.get(id=self.no_text.id).archive_filename, "no-text.pdf" + Document.objects.get(id=self.no_text.id).archive_filename, + "no-text.pdf", ) self.assertEqual( - Document.objects.get(id=self.doc_no_archive.id).archive_filename, None + Document.objects.get(id=self.doc_no_archive.id).archive_filename, + None, ) self.assertEqual( Document.objects.get(id=self.clash1.id).archive_filename, @@ -198,7 +235,8 @@ class TestMigrateArchiveFiles(DirectoriesMixin, TestMigrations): f"{self.clash3.id:07}.pdf", ) self.assertEqual( - Document.objects.get(id=self.clash4.id).archive_filename, "clash.png.pdf" + Document.objects.get(id=self.clash4.id).archive_filename, + "clash.png.pdf", ) @@ -207,16 +245,20 @@ class TestMigrateArchiveFilesWithFilenameFormat(TestMigrateArchiveFiles): def test_filenames(self): Document = self.apps.get_model("documents", "Document") self.assertEqual( - Document.objects.get(id=self.unrelated.id).archive_filename, "unrelated.pdf" + Document.objects.get(id=self.unrelated.id).archive_filename, + "unrelated.pdf", ) self.assertEqual( - Document.objects.get(id=self.no_text.id).archive_filename, "no-text.pdf" + Document.objects.get(id=self.no_text.id).archive_filename, + "no-text.pdf", ) self.assertEqual( - Document.objects.get(id=self.doc_no_archive.id).archive_filename, None + Document.objects.get(id=self.doc_no_archive.id).archive_filename, + None, ) self.assertEqual( - Document.objects.get(id=self.clash1.id).archive_filename, "none/clash.pdf" + Document.objects.get(id=self.clash1.id).archive_filename, + "none/clash.pdf", ) self.assertEqual( Document.objects.get(id=self.clash2.id).archive_filename, @@ -227,7 +269,8 @@ class TestMigrateArchiveFilesWithFilenameFormat(TestMigrateArchiveFiles): "none/clash_02.pdf", ) self.assertEqual( - Document.objects.get(id=self.clash4.id).archive_filename, "clash.png.pdf" + Document.objects.get(id=self.clash4.id).archive_filename, + "clash.png.pdf", ) @@ -248,12 +291,19 @@ class TestMigrateArchiveFilesErrors(DirectoriesMixin, TestMigrations): Document = self.apps.get_model("documents", "Document") doc = make_test_document( - Document, "clash", "application/pdf", simple_pdf, "clash.pdf", simple_pdf + Document, + "clash", + "application/pdf", + simple_pdf, + "clash.pdf", + simple_pdf, ) os.unlink(archive_path_old(doc)) self.assertRaisesMessage( - ValueError, "does not exist at: ", self.performMigration + ValueError, + "does not exist at: ", + self.performMigration, ) def test_parser_missing(self): @@ -277,7 +327,9 @@ class TestMigrateArchiveFilesErrors(DirectoriesMixin, TestMigrations): ) self.assertRaisesMessage( - ValueError, "no parsers are available", self.performMigration + ValueError, + "no parsers are available", + self.performMigration, ) @mock.patch("documents.migrations.1012_fix_archive_files.parse_wrapper") @@ -286,7 +338,12 @@ class TestMigrateArchiveFilesErrors(DirectoriesMixin, TestMigrations): Document = self.apps.get_model("documents", "Document") doc1 = make_test_document( - Document, "document", "image/png", simple_png, "document.png", simple_pdf + Document, + "document", + "image/png", + simple_png, + "document.png", + simple_pdf, ) doc2 = make_test_document( Document, @@ -311,8 +368,8 @@ class TestMigrateArchiveFilesErrors(DirectoriesMixin, TestMigrations): filter( lambda log: "Parse error, will try again in 5 seconds" in log, capture.output, - ) - ) + ), + ), ), 4, ) @@ -324,8 +381,8 @@ class TestMigrateArchiveFilesErrors(DirectoriesMixin, TestMigrations): lambda log: "Unable to regenerate archive document for ID:" in log, capture.output, - ) - ) + ), + ), ), 2, ) @@ -347,7 +404,12 @@ class TestMigrateArchiveFilesErrors(DirectoriesMixin, TestMigrations): Document = self.apps.get_model("documents", "Document") doc1 = make_test_document( - Document, "document", "image/png", simple_png, "document.png", simple_pdf + Document, + "document", + "image/png", + simple_png, + "document.png", + simple_pdf, ) doc2 = make_test_document( Document, @@ -368,8 +430,8 @@ class TestMigrateArchiveFilesErrors(DirectoriesMixin, TestMigrations): lambda log: "Parser did not return an archive document for document" in log, capture.output, - ) - ) + ), + ), ), 2, ) @@ -405,7 +467,11 @@ class TestMigrateArchiveFilesBackwards(DirectoriesMixin, TestMigrations): "unrelated.pdf", ) doc_no_archive = make_test_document( - Document, "no_archive", "text/plain", simple_txt, "no_archive.txt" + Document, + "no_archive", + "text/plain", + simple_txt, + "no_archive.txt", ) clashB = make_test_document( Document, @@ -434,13 +500,14 @@ class TestMigrateArchiveFilesBackwards(DirectoriesMixin, TestMigrations): self.assertEqual(archive_checksum, doc.archive_checksum) self.assertEqual( - Document.objects.filter(archive_checksum__isnull=False).count(), 2 + Document.objects.filter(archive_checksum__isnull=False).count(), + 2, ) @override_settings(PAPERLESS_FILENAME_FORMAT="{correspondent}/{title}") class TestMigrateArchiveFilesBackwardsWithFilenameFormat( - TestMigrateArchiveFilesBackwards + TestMigrateArchiveFilesBackwards, ): pass @@ -505,5 +572,7 @@ class TestMigrateArchiveFilesBackwardsErrors(DirectoriesMixin, TestMigrations): ) self.assertRaisesMessage( - ValueError, "file already exists.", self.performMigration + ValueError, + "file already exists.", + self.performMigration, ) diff --git a/src/documents/tests/test_migration_mime_type.py b/src/documents/tests/test_migration_mime_type.py index 57cb84ad4..a08c3d74d 100644 --- a/src/documents/tests/test_migration_mime_type.py +++ b/src/documents/tests/test_migration_mime_type.py @@ -3,9 +3,9 @@ import shutil from django.conf import settings from django.test import override_settings - from documents.parsers import get_default_file_extension -from documents.tests.utils import DirectoriesMixin, TestMigrations +from documents.tests.utils import DirectoriesMixin +from documents.tests.utils import TestMigrations STORAGE_TYPE_UNENCRYPTED = "unencrypted" STORAGE_TYPE_GPG = "gpg" @@ -46,7 +46,9 @@ class TestMigrateMimeType(DirectoriesMixin, TestMigrations): def setUpBeforeMigration(self, apps): Document = apps.get_model("documents", "Document") doc = Document.objects.create( - title="test", file_type="pdf", filename="file1.pdf" + title="test", + file_type="pdf", + filename="file1.pdf", ) self.doc_id = doc.id shutil.copy( @@ -55,7 +57,9 @@ class TestMigrateMimeType(DirectoriesMixin, TestMigrations): ) doc2 = Document.objects.create( - checksum="B", file_type="pdf", storage_type=STORAGE_TYPE_GPG + checksum="B", + file_type="pdf", + storage_type=STORAGE_TYPE_GPG, ) self.doc2_id = doc2.id shutil.copy( @@ -88,7 +92,9 @@ class TestMigrateMimeTypeBackwards(DirectoriesMixin, TestMigrations): def setUpBeforeMigration(self, apps): Document = apps.get_model("documents", "Document") doc = Document.objects.create( - title="test", mime_type="application/pdf", filename="file1.pdf" + title="test", + mime_type="application/pdf", + filename="file1.pdf", ) self.doc_id = doc.id shutil.copy( diff --git a/src/documents/tests/test_migration_remove_null_characters.py b/src/documents/tests/test_migration_remove_null_characters.py index 9c8000550..09fd80883 100644 --- a/src/documents/tests/test_migration_remove_null_characters.py +++ b/src/documents/tests/test_migration_remove_null_characters.py @@ -1,4 +1,5 @@ -from documents.tests.utils import DirectoriesMixin, TestMigrations +from documents.tests.utils import DirectoriesMixin +from documents.tests.utils import TestMigrations class TestMigrateNullCharacters(DirectoriesMixin, TestMigrations): diff --git a/src/documents/tests/test_migration_tag_colors.py b/src/documents/tests/test_migration_tag_colors.py index e209ce5e6..6cc2fa3f7 100644 --- a/src/documents/tests/test_migration_tag_colors.py +++ b/src/documents/tests/test_migration_tag_colors.py @@ -1,4 +1,5 @@ -from documents.tests.utils import DirectoriesMixin, TestMigrations +from documents.tests.utils import DirectoriesMixin +from documents.tests.utils import TestMigrations class TestMigrateTagColor(DirectoriesMixin, TestMigrations): diff --git a/src/documents/tests/test_models.py b/src/documents/tests/test_models.py index 77bb507f5..d230511ff 100644 --- a/src/documents/tests/test_models.py +++ b/src/documents/tests/test_models.py @@ -1,7 +1,9 @@ from django.test import TestCase -from .factories import DocumentFactory, CorrespondentFactory -from ..models import Document, Correspondent +from ..models import Correspondent +from ..models import Document +from .factories import CorrespondentFactory +from .factories import DocumentFactory class CorrespondentTestCase(TestCase): diff --git a/src/documents/tests/test_parsers.py b/src/documents/tests/test_parsers.py index a914bbf93..ab0311783 100644 --- a/src/documents/tests/test_parsers.py +++ b/src/documents/tests/test_parsers.py @@ -4,16 +4,14 @@ import tempfile from tempfile import TemporaryDirectory from unittest import mock -from django.test import TestCase, override_settings - -from documents.parsers import ( - get_parser_class, - get_supported_file_extensions, - get_default_file_extension, - get_parser_class_for_mime_type, - DocumentParser, - is_file_ext_supported, -) +from django.test import override_settings +from django.test import TestCase +from documents.parsers import DocumentParser +from documents.parsers import get_default_file_extension +from documents.parsers import get_parser_class +from documents.parsers import get_parser_class_for_mime_type +from documents.parsers import get_supported_file_extensions +from documents.parsers import is_file_ext_supported from paperless_tesseract.parsers import RasterisedDocumentParser from paperless_text.parsers import TextDocumentParser diff --git a/src/documents/tests/test_sanity_check.py b/src/documents/tests/test_sanity_check.py index f3953bab9..7a1b64ce4 100644 --- a/src/documents/tests/test_sanity_check.py +++ b/src/documents/tests/test_sanity_check.py @@ -6,9 +6,9 @@ from pathlib import Path import filelock from django.conf import settings from django.test import TestCase - from documents.models import Document -from documents.sanity_checker import check_sanity, SanityCheckMessages +from documents.sanity_checker import check_sanity +from documents.sanity_checker import SanityCheckMessages from documents.tests.utils import DirectoriesMixin @@ -23,7 +23,8 @@ class TestSanityCheckMessages(TestCase): self.assertEqual(len(capture.output), 1) self.assertEqual(capture.records[0].levelno, logging.INFO) self.assertEqual( - capture.records[0].message, "Sanity checker detected no issues." + capture.records[0].message, + "Sanity checker detected no issues.", ) def test_info(self): diff --git a/src/documents/tests/test_settings.py b/src/documents/tests/test_settings.py index 25fe0e317..9b8edab27 100644 --- a/src/documents/tests/test_settings.py +++ b/src/documents/tests/test_settings.py @@ -2,8 +2,8 @@ import logging from unittest import mock from django.test import TestCase - -from paperless.settings import default_task_workers, default_threads_per_worker +from paperless.settings import default_task_workers +from paperless.settings import default_threads_per_worker class TestSettings(TestCase): @@ -21,7 +21,7 @@ class TestSettings(TestCase): def test_workers_threads(self): for i in range(1, 64): with mock.patch( - "paperless.settings.multiprocessing.cpu_count" + "paperless.settings.multiprocessing.cpu_count", ) as cpu_count: cpu_count.return_value = i diff --git a/src/documents/tests/test_tasks.py b/src/documents/tests/test_tasks.py index a0cae7307..c78fa16c2 100644 --- a/src/documents/tests/test_tasks.py +++ b/src/documents/tests/test_tasks.py @@ -1,14 +1,21 @@ import os +import shutil +import tempfile from unittest import mock from django.conf import settings +from django.test import override_settings from django.test import TestCase from django.utils import timezone - from documents import tasks -from documents.models import Document, Tag, Correspondent, DocumentType -from documents.sanity_checker import SanityCheckMessages, SanityCheckFailedException +from documents.models import Correspondent +from documents.models import Document +from documents.models import DocumentType +from documents.models import Tag +from documents.sanity_checker import SanityCheckFailedException +from documents.sanity_checker import SanityCheckMessages from documents.tests.utils import DirectoriesMixin +from PIL import Image class TestTasks(DirectoriesMixin, TestCase): @@ -86,6 +93,318 @@ class TestTasks(DirectoriesMixin, TestCase): mtime3 = os.stat(settings.MODEL_FILE).st_mtime self.assertNotEqual(mtime2, mtime3) + def test_barcode_reader(self): + test_file = os.path.join( + os.path.dirname(__file__), + "samples", + "barcodes", + "barcode-39-PATCHT.png", + ) + img = Image.open(test_file) + separator_barcode = str(settings.CONSUMER_BARCODE_STRING) + self.assertEqual(tasks.barcode_reader(img), [separator_barcode]) + + def test_barcode_reader2(self): + test_file = os.path.join( + os.path.dirname(__file__), + "samples", + "barcodes", + "patch-code-t.pbm", + ) + img = Image.open(test_file) + separator_barcode = str(settings.CONSUMER_BARCODE_STRING) + self.assertEqual(tasks.barcode_reader(img), [separator_barcode]) + + def test_barcode_reader_distorsion(self): + test_file = os.path.join( + os.path.dirname(__file__), + "samples", + "barcodes", + "barcode-39-PATCHT-distorsion.png", + ) + img = Image.open(test_file) + separator_barcode = str(settings.CONSUMER_BARCODE_STRING) + self.assertEqual(tasks.barcode_reader(img), [separator_barcode]) + + def test_barcode_reader_distorsion2(self): + test_file = os.path.join( + os.path.dirname(__file__), + "samples", + "barcodes", + "barcode-39-PATCHT-distorsion2.png", + ) + img = Image.open(test_file) + separator_barcode = str(settings.CONSUMER_BARCODE_STRING) + self.assertEqual(tasks.barcode_reader(img), [separator_barcode]) + + def test_barcode_reader_unreadable(self): + test_file = os.path.join( + os.path.dirname(__file__), + "samples", + "barcodes", + "barcode-39-PATCHT-unreadable.png", + ) + img = Image.open(test_file) + self.assertEqual(tasks.barcode_reader(img), []) + + def test_barcode_reader_qr(self): + test_file = os.path.join( + os.path.dirname(__file__), + "samples", + "barcodes", + "qr-code-PATCHT.png", + ) + img = Image.open(test_file) + separator_barcode = str(settings.CONSUMER_BARCODE_STRING) + self.assertEqual(tasks.barcode_reader(img), [separator_barcode]) + + def test_barcode_reader_128(self): + test_file = os.path.join( + os.path.dirname(__file__), + "samples", + "barcodes", + "barcode-128-PATCHT.png", + ) + img = Image.open(test_file) + separator_barcode = str(settings.CONSUMER_BARCODE_STRING) + self.assertEqual(tasks.barcode_reader(img), [separator_barcode]) + + def test_barcode_reader_no_barcode(self): + test_file = os.path.join(os.path.dirname(__file__), "samples", "simple.png") + img = Image.open(test_file) + self.assertEqual(tasks.barcode_reader(img), []) + + def test_barcode_reader_custom_separator(self): + test_file = os.path.join( + os.path.dirname(__file__), + "samples", + "barcodes", + "barcode-39-custom.png", + ) + img = Image.open(test_file) + self.assertEqual(tasks.barcode_reader(img), ["CUSTOM BARCODE"]) + + def test_barcode_reader_custom_qr_separator(self): + test_file = os.path.join( + os.path.dirname(__file__), + "samples", + "barcodes", + "barcode-qr-custom.png", + ) + img = Image.open(test_file) + self.assertEqual(tasks.barcode_reader(img), ["CUSTOM BARCODE"]) + + def test_barcode_reader_custom_128_separator(self): + test_file = os.path.join( + os.path.dirname(__file__), + "samples", + "barcodes", + "barcode-128-custom.png", + ) + img = Image.open(test_file) + self.assertEqual(tasks.barcode_reader(img), ["CUSTOM BARCODE"]) + + def test_scan_file_for_separating_barcodes(self): + test_file = os.path.join( + os.path.dirname(__file__), + "samples", + "barcodes", + "patch-code-t.pdf", + ) + pages = tasks.scan_file_for_separating_barcodes(test_file) + self.assertEqual(pages, [0]) + + def test_scan_file_for_separating_barcodes2(self): + test_file = os.path.join(os.path.dirname(__file__), "samples", "simple.pdf") + pages = tasks.scan_file_for_separating_barcodes(test_file) + self.assertEqual(pages, []) + + def test_scan_file_for_separating_barcodes3(self): + test_file = os.path.join( + os.path.dirname(__file__), + "samples", + "barcodes", + "patch-code-t-middle.pdf", + ) + pages = tasks.scan_file_for_separating_barcodes(test_file) + self.assertEqual(pages, [1]) + + def test_scan_file_for_separating_barcodes4(self): + test_file = os.path.join( + os.path.dirname(__file__), + "samples", + "barcodes", + "several-patcht-codes.pdf", + ) + pages = tasks.scan_file_for_separating_barcodes(test_file) + self.assertEqual(pages, [2, 5]) + + def test_scan_file_for_separating_barcodes_upsidedown(self): + test_file = os.path.join( + os.path.dirname(__file__), + "samples", + "barcodes", + "patch-code-t-middle_reverse.pdf", + ) + pages = tasks.scan_file_for_separating_barcodes(test_file) + self.assertEqual(pages, [1]) + + def test_scan_file_for_separating_qr_barcodes(self): + test_file = os.path.join( + os.path.dirname(__file__), + "samples", + "barcodes", + "patch-code-t-qr.pdf", + ) + pages = tasks.scan_file_for_separating_barcodes(test_file) + self.assertEqual(pages, [0]) + + @override_settings(CONSUMER_BARCODE_STRING="CUSTOM BARCODE") + def test_scan_file_for_separating_custom_barcodes(self): + test_file = os.path.join( + os.path.dirname(__file__), + "samples", + "barcodes", + "barcode-39-custom.pdf", + ) + pages = tasks.scan_file_for_separating_barcodes(test_file) + self.assertEqual(pages, [0]) + + @override_settings(CONSUMER_BARCODE_STRING="CUSTOM BARCODE") + def test_scan_file_for_separating_custom_qr_barcodes(self): + test_file = os.path.join( + os.path.dirname(__file__), + "samples", + "barcodes", + "barcode-qr-custom.pdf", + ) + pages = tasks.scan_file_for_separating_barcodes(test_file) + self.assertEqual(pages, [0]) + + @override_settings(CONSUMER_BARCODE_STRING="CUSTOM BARCODE") + def test_scan_file_for_separating_custom_128_barcodes(self): + test_file = os.path.join( + os.path.dirname(__file__), + "samples", + "barcodes", + "barcode-128-custom.pdf", + ) + pages = tasks.scan_file_for_separating_barcodes(test_file) + self.assertEqual(pages, [0]) + + def test_scan_file_for_separating_wrong_qr_barcodes(self): + test_file = os.path.join( + os.path.dirname(__file__), + "samples", + "barcodes", + "barcode-39-custom.pdf", + ) + pages = tasks.scan_file_for_separating_barcodes(test_file) + self.assertEqual(pages, []) + + def test_separate_pages(self): + test_file = os.path.join( + os.path.dirname(__file__), + "samples", + "barcodes", + "patch-code-t-middle.pdf", + ) + pages = tasks.separate_pages(test_file, [1]) + self.assertEqual(len(pages), 2) + + def test_separate_pages_no_list(self): + test_file = os.path.join( + os.path.dirname(__file__), + "samples", + "barcodes", + "patch-code-t-middle.pdf", + ) + with self.assertLogs("paperless.tasks", level="WARNING") as cm: + pages = tasks.separate_pages(test_file, []) + self.assertEqual(pages, []) + self.assertEqual( + cm.output, + [ + f"WARNING:paperless.tasks:No pages to split on!", + ], + ) + + def test_save_to_dir(self): + test_file = os.path.join( + os.path.dirname(__file__), + "samples", + "barcodes", + "patch-code-t.pdf", + ) + tempdir = tempfile.mkdtemp(prefix="paperless-", dir=settings.SCRATCH_DIR) + tasks.save_to_dir(test_file, target_dir=tempdir) + target_file = os.path.join(tempdir, "patch-code-t.pdf") + self.assertTrue(os.path.isfile(target_file)) + + def test_save_to_dir2(self): + test_file = os.path.join( + os.path.dirname(__file__), + "samples", + "barcodes", + "patch-code-t.pdf", + ) + nonexistingdir = "/nowhere" + if os.path.isdir(nonexistingdir): + self.fail("non-existing dir exists") + else: + with self.assertLogs("paperless.tasks", level="WARNING") as cm: + tasks.save_to_dir(test_file, target_dir=nonexistingdir) + self.assertEqual( + cm.output, + [ + f"WARNING:paperless.tasks:{str(test_file)} or {str(nonexistingdir)} don't exist.", + ], + ) + + def test_save_to_dir3(self): + test_file = os.path.join( + os.path.dirname(__file__), + "samples", + "barcodes", + "patch-code-t.pdf", + ) + tempdir = tempfile.mkdtemp(prefix="paperless-", dir=settings.SCRATCH_DIR) + tasks.save_to_dir(test_file, newname="newname.pdf", target_dir=tempdir) + target_file = os.path.join(tempdir, "newname.pdf") + self.assertTrue(os.path.isfile(target_file)) + + def test_barcode_splitter(self): + test_file = os.path.join( + os.path.dirname(__file__), + "samples", + "barcodes", + "patch-code-t-middle.pdf", + ) + tempdir = tempfile.mkdtemp(prefix="paperless-", dir=settings.SCRATCH_DIR) + separators = tasks.scan_file_for_separating_barcodes(test_file) + self.assertTrue(separators) + document_list = tasks.separate_pages(test_file, separators) + self.assertTrue(document_list) + for document in document_list: + tasks.save_to_dir(document, target_dir=tempdir) + target_file1 = os.path.join(tempdir, "patch-code-t-middle_document_0.pdf") + target_file2 = os.path.join(tempdir, "patch-code-t-middle_document_1.pdf") + self.assertTrue(os.path.isfile(target_file1)) + self.assertTrue(os.path.isfile(target_file2)) + + @override_settings(CONSUMER_ENABLE_BARCODES=True) + def test_consume_barcode_file(self): + test_file = os.path.join( + os.path.dirname(__file__), + "samples", + "barcodes", + "patch-code-t-middle.pdf", + ) + dst = os.path.join(settings.SCRATCH_DIR, "patch-code-t-middle.pd") + shutil.copy(test_file, dst) + + self.assertEqual(tasks.consume_file(dst), "File successfully split") + @mock.patch("documents.tasks.sanity_checker.check_sanity") def test_sanity_check_success(self, m): m.return_value = SanityCheckMessages() @@ -106,7 +425,8 @@ class TestTasks(DirectoriesMixin, TestCase): messages.warning("Some warning") m.return_value = messages self.assertEqual( - tasks.sanity_check(), "Sanity check exited with warnings. See log." + tasks.sanity_check(), + "Sanity check exited with warnings. See log.", ) m.assert_called_once() @@ -116,7 +436,8 @@ class TestTasks(DirectoriesMixin, TestCase): messages.info("Some info") m.return_value = messages self.assertEqual( - tasks.sanity_check(), "Sanity check exited with infos. See log." + tasks.sanity_check(), + "Sanity check exited with infos. See log.", ) m.assert_called_once() diff --git a/src/documents/tests/test_views.py b/src/documents/tests/test_views.py index dcae72797..ce457a7f3 100644 --- a/src/documents/tests/test_views.py +++ b/src/documents/tests/test_views.py @@ -25,7 +25,7 @@ class TestViews(TestCase): ]: if language_given: self.client.cookies.load( - {settings.LANGUAGE_COOKIE_NAME: language_given} + {settings.LANGUAGE_COOKIE_NAME: language_given}, ) elif settings.LANGUAGE_COOKIE_NAME in self.client.cookies.keys(): self.client.cookies.pop(settings.LANGUAGE_COOKIE_NAME) @@ -51,5 +51,6 @@ class TestViews(TestCase): f"frontend/{language_actual}/polyfills.js", ) self.assertEqual( - response.context_data["main_js"], f"frontend/{language_actual}/main.js" + response.context_data["main_js"], + f"frontend/{language_actual}/main.js", ) diff --git a/src/documents/tests/utils.py b/src/documents/tests/utils.py index 3aa9cf880..f4d3bee87 100644 --- a/src/documents/tests/utils.py +++ b/src/documents/tests/utils.py @@ -7,7 +7,8 @@ from contextlib import contextmanager from django.apps import apps from django.db import connection from django.db.migrations.executor import MigrationExecutor -from django.test import override_settings, TransactionTestCase +from django.test import override_settings +from django.test import TransactionTestCase def setup_directories(): @@ -97,7 +98,7 @@ class TestMigrations(TransactionTestCase): assert ( self.migrate_from and self.migrate_to ), "TestCase '{}' must define migrate_from and migrate_to properties".format( - type(self).__name__ + type(self).__name__, ) self.migrate_from = [(self.app, self.migrate_from)] self.migrate_to = [(self.app, self.migrate_to)] diff --git a/src/documents/views.py b/src/documents/views.py index 9e4d960ab..831e68b68 100644 --- a/src/documents/views.py +++ b/src/documents/views.py @@ -1,67 +1,79 @@ +import json import logging import os import tempfile +import urllib import uuid import zipfile from datetime import datetime from time import mktime -from urllib.parse import quote_plus from unicodedata import normalize +from urllib.parse import quote from django.conf import settings -from django.db.models import Count, Max, Case, When, IntegerField +from django.db.models import Case +from django.db.models import Count +from django.db.models import IntegerField +from django.db.models import Max +from django.db.models import When from django.db.models.functions import Lower -from django.http import HttpResponse, HttpResponseBadRequest, Http404 +from django.http import Http404 +from django.http import HttpResponse +from django.http import HttpResponseBadRequest +from django.utils.decorators import method_decorator from django.utils.translation import get_language from django.views.decorators.cache import cache_control from django.views.generic import TemplateView from django_filters.rest_framework import DjangoFilterBackend from django_q.tasks import async_task +from packaging import version as packaging_version +from paperless import version +from paperless.db import GnuPG +from paperless.views import StandardPagination from rest_framework import parsers from rest_framework.decorators import action from rest_framework.exceptions import NotFound -from rest_framework.filters import OrderingFilter, SearchFilter +from rest_framework.filters import OrderingFilter +from rest_framework.filters import SearchFilter from rest_framework.generics import GenericAPIView -from rest_framework.mixins import ( - DestroyModelMixin, - ListModelMixin, - RetrieveModelMixin, - UpdateModelMixin, -) +from rest_framework.mixins import DestroyModelMixin +from rest_framework.mixins import ListModelMixin +from rest_framework.mixins import RetrieveModelMixin +from rest_framework.mixins import UpdateModelMixin from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from rest_framework.views import APIView -from rest_framework.viewsets import GenericViewSet, ModelViewSet, ViewSet +from rest_framework.viewsets import GenericViewSet +from rest_framework.viewsets import ModelViewSet +from rest_framework.viewsets import ViewSet -from paperless.db import GnuPG -from paperless.views import StandardPagination -from .bulk_download import ( - OriginalAndArchiveStrategy, - OriginalsOnlyStrategy, - ArchiveOnlyStrategy, -) +from .bulk_download import ArchiveOnlyStrategy +from .bulk_download import OriginalAndArchiveStrategy +from .bulk_download import OriginalsOnlyStrategy from .classifier import load_classifier -from .filters import ( - CorrespondentFilterSet, - DocumentFilterSet, - TagFilterSet, - DocumentTypeFilterSet, -) -from .matching import match_correspondents, match_tags, match_document_types -from .models import Correspondent, Document, Tag, DocumentType, SavedView +from .filters import CorrespondentFilterSet +from .filters import DocumentFilterSet +from .filters import DocumentTypeFilterSet +from .filters import TagFilterSet +from .matching import match_correspondents +from .matching import match_document_types +from .matching import match_tags +from .models import Correspondent +from .models import Document +from .models import DocumentType +from .models import SavedView +from .models import Tag from .parsers import get_parser_class_for_mime_type -from .serialisers import ( - CorrespondentSerializer, - DocumentSerializer, - TagSerializerVersion1, - TagSerializer, - DocumentTypeSerializer, - PostDocumentSerializer, - SavedViewSerializer, - BulkEditSerializer, - DocumentListSerializer, - BulkDownloadSerializer, -) +from .serialisers import BulkDownloadSerializer +from .serialisers import BulkEditSerializer +from .serialisers import CorrespondentSerializer +from .serialisers import DocumentListSerializer +from .serialisers import DocumentSerializer +from .serialisers import DocumentTypeSerializer +from .serialisers import PostDocumentSerializer +from .serialisers import SavedViewSerializer +from .serialisers import TagSerializer +from .serialisers import TagSerializerVersion1 logger = logging.getLogger("paperless.api") @@ -89,16 +101,14 @@ class IndexView(TemplateView): context["full_name"] = self.request.user.get_full_name() context["styles_css"] = f"frontend/{self.get_language()}/styles.css" context["runtime_js"] = f"frontend/{self.get_language()}/runtime.js" - context[ - "polyfills_js" - ] = f"frontend/{self.get_language()}/polyfills.js" # NOQA: E501 + context["polyfills_js"] = f"frontend/{self.get_language()}/polyfills.js" context["main_js"] = f"frontend/{self.get_language()}/main.js" context[ "webmanifest" - ] = f"frontend/{self.get_language()}/manifest.webmanifest" # NOQA: E501 + ] = f"frontend/{self.get_language()}/manifest.webmanifest" # noqa: E501 context[ "apple_touch_icon" - ] = f"frontend/{self.get_language()}/apple-touch-icon.png" # NOQA: E501 + ] = f"frontend/{self.get_language()}/apple-touch-icon.png" # noqa: E501 return context @@ -106,7 +116,8 @@ class CorrespondentViewSet(ModelViewSet): model = Correspondent queryset = Correspondent.objects.annotate( - document_count=Count("documents"), last_correspondence=Max("documents__created") + document_count=Count("documents"), + last_correspondence=Max("documents__created"), ).order_by(Lower("name")) serializer_class = CorrespondentSerializer @@ -127,7 +138,7 @@ class TagViewSet(ModelViewSet): model = Tag queryset = Tag.objects.annotate(document_count=Count("documents")).order_by( - Lower("name") + Lower("name"), ) def get_serializer_class(self): @@ -147,7 +158,7 @@ class DocumentTypeViewSet(ModelViewSet): model = DocumentType queryset = DocumentType.objects.annotate( - document_count=Count("documents") + document_count=Count("documents"), ).order_by(Lower("name")) serializer_class = DocumentTypeSerializer @@ -220,9 +231,7 @@ class DocumentViewSet( def file_response(self, pk, request, disposition): doc = Document.objects.get(id=pk) - if ( - not self.original_requested(request) and doc.has_archive_version - ): # NOQA: E501 + if not self.original_requested(request) and doc.has_archive_version: file_handle = doc.archive_file filename = doc.get_public_filename(archive=True) mime_type = "application/pdf" @@ -239,7 +248,7 @@ class DocumentViewSet( # RFC 5987 addresses this issue # see https://datatracker.ietf.org/doc/html/rfc5987#section-4.2 filename_normalized = normalize("NFKD", filename).encode("ascii", "ignore") - filename_encoded = quote_plus(filename) + filename_encoded = quote(filename) content_disposition = ( f"{disposition}; " f'filename="{filename_normalized}"; ' @@ -258,7 +267,7 @@ class DocumentViewSet( try: return parser.extract_metadata(file, mime_type) - except Exception as e: + except Exception: # TODO: cover GPG errors, remove later. return [] else: @@ -291,7 +300,8 @@ class DocumentViewSet( if doc.has_archive_version: meta["archive_size"] = self.get_filesize(doc.archive_path) meta["archive_metadata"] = self.get_metadata( - doc.archive_path, "application/pdf" + doc.archive_path, + "application/pdf", ) else: meta["archive_size"] = None @@ -315,7 +325,7 @@ class DocumentViewSet( "document_types": [ dt.id for dt in match_document_types(doc, classifier) ], - } + }, ) @action(methods=["get"], detail=True) @@ -327,7 +337,7 @@ class DocumentViewSet( raise Http404() @action(methods=["get"], detail=True) - @cache_control(public=False, max_age=315360000) + @method_decorator(cache_control(public=False, max_age=315360000)) def thumb(self, request, pk=None): try: doc = Document.objects.get(id=pk) @@ -357,7 +367,7 @@ class SearchResultSerializer(DocumentSerializer): "score": instance.score, "highlights": instance.highlights("content", text=doc.content) if doc - else None, # NOQA: E501 + else None, "rank": instance.rank, } @@ -500,7 +510,9 @@ class PostDocumentView(GenericAPIView): os.makedirs(settings.SCRATCH_DIR, exist_ok=True) with tempfile.NamedTemporaryFile( - prefix="paperless-upload-", dir=settings.SCRATCH_DIR, delete=False + prefix="paperless-upload-", + dir=settings.SCRATCH_DIR, + delete=False, ) as f: f.write(doc_data) os.utime(f.name, times=(t, t)) @@ -537,20 +549,20 @@ class SelectionDataView(GenericAPIView): correspondents = Correspondent.objects.annotate( document_count=Count( - Case(When(documents__id__in=ids, then=1), output_field=IntegerField()) - ) + Case(When(documents__id__in=ids, then=1), output_field=IntegerField()), + ), ) tags = Tag.objects.annotate( document_count=Count( - Case(When(documents__id__in=ids, then=1), output_field=IntegerField()) - ) + Case(When(documents__id__in=ids, then=1), output_field=IntegerField()), + ), ) types = DocumentType.objects.annotate( document_count=Count( - Case(When(documents__id__in=ids, then=1), output_field=IntegerField()) - ) + Case(When(documents__id__in=ids, then=1), output_field=IntegerField()), + ), ) r = Response( @@ -565,7 +577,7 @@ class SelectionDataView(GenericAPIView): "selected_document_types": [ {"id": t.id, "document_count": t.document_count} for t in types ], - } + }, ) return r @@ -612,7 +624,7 @@ class StatisticsView(APIView): { "documents_total": documents_total, "documents_inbox": documents_inbox, - } + }, ) @@ -632,7 +644,9 @@ class BulkDownloadView(GenericAPIView): os.makedirs(settings.SCRATCH_DIR, exist_ok=True) temp = tempfile.NamedTemporaryFile( - dir=settings.SCRATCH_DIR, suffix="-compressed-archive", delete=False + dir=settings.SCRATCH_DIR, + suffix="-compressed-archive", + delete=False, ) if content == "both": @@ -651,7 +665,45 @@ class BulkDownloadView(GenericAPIView): with open(temp.name, "rb") as f: response = HttpResponse(f, content_type="application/zip") response["Content-Disposition"] = '{}; filename="{}"'.format( - "attachment", "documents.zip" + "attachment", + "documents.zip", ) return response + + +class RemoteVersionView(GenericAPIView): + def get(self, request, format=None): + remote_version = "0.0.0" + is_greater_than_current = False + # TODO: this can likely be removed when frontend settings are saved to DB + feature_is_set = settings.ENABLE_UPDATE_CHECK != "default" + if feature_is_set and settings.ENABLE_UPDATE_CHECK: + try: + with urllib.request.urlopen( + "https://api.github.com/repos/" + + "paperless-ngx/paperless-ngx/releases/latest", + ) as response: + remote = response.read().decode("utf-8") + try: + remote_json = json.loads(remote) + remote_version = remote_json["tag_name"].replace("ngx-", "") + except ValueError: + logger.debug("An error occured parsing remote version json") + except urllib.error.URLError: + logger.debug("An error occured checking for available updates") + + current_version = ".".join([str(_) for _ in version.__version__[:3]]) + is_greater_than_current = packaging_version.parse( + remote_version, + ) > packaging_version.parse( + current_version, + ) + + return Response( + { + "version": remote_version, + "update_available": is_greater_than_current, + "feature_is_set": feature_is_set, + }, + ) diff --git a/src/locale/be_BY/LC_MESSAGES/django.po b/src/locale/be_BY/LC_MESSAGES/django.po new file mode 100644 index 000000000..b8d6db222 --- /dev/null +++ b/src/locale/be_BY/LC_MESSAGES/django.po @@ -0,0 +1,714 @@ +msgid "" +msgstr "" +"Project-Id-Version: paperless-ngx\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-03-02 11:20-0800\n" +"PO-Revision-Date: 2022-03-31 10:58\n" +"Last-Translator: \n" +"Language-Team: Belarusian\n" +"Language: be_BY\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || n%10>=5 && n%10<=9 || n%100>=11 && n%100<=14 ? 2 : 3);\n" +"X-Crowdin-Project: paperless-ngx\n" +"X-Crowdin-Project-ID: 500308\n" +"X-Crowdin-Language: be\n" +"X-Crowdin-File: /dev/src/locale/en_US/LC_MESSAGES/django.po\n" +"X-Crowdin-File-ID: 14\n" + +#: documents/apps.py:10 +msgid "Documents" +msgstr "Дакументы" + +#: documents/models.py:32 +msgid "Any word" +msgstr "Любое Ñлова" + +#: documents/models.py:33 +msgid "All words" +msgstr "УÑе Ñловы" + +#: documents/models.py:34 +msgid "Exact match" +msgstr "Дакладнае Ñупадзенне" + +#: documents/models.py:35 +msgid "Regular expression" +msgstr "РÑгулÑрны выраз" + +#: documents/models.py:36 +msgid "Fuzzy word" +msgstr "Ðевыразнае Ñлова" + +#: documents/models.py:37 +msgid "Automatic" +msgstr "Ðўтаматычна" + +#: documents/models.py:40 documents/models.py:314 paperless_mail/models.py:23 +#: paperless_mail/models.py:107 +msgid "name" +msgstr "назва" + +#: documents/models.py:42 +msgid "match" +msgstr "Ñупадзенне" + +#: documents/models.py:45 +msgid "matching algorithm" +msgstr "алгарытм ÑупаÑтаўленнÑ" + +#: documents/models.py:48 +msgid "is insensitive" +msgstr "без уліку Ñ€ÑгіÑтра" + +#: documents/models.py:61 documents/models.py:104 +msgid "correspondent" +msgstr "карÑÑпандÑнт" + +#: documents/models.py:62 +msgid "correspondents" +msgstr "карÑÑпандÑнты" + +#: documents/models.py:67 +msgid "color" +msgstr "колер" + +#: documents/models.py:70 +msgid "is inbox tag" +msgstr "гÑта ўваходны Ñ‚Ñг" + +#: documents/models.py:73 +msgid "Marks this tag as an inbox tag: All newly consumed documents will be tagged with inbox tags." +msgstr "Пазначыць гÑÑ‚Ñ‹ Ñ‚Ñг Ñк Ñ‚Ñг папкі \"УваходныÑ\": УÑе нÑдаўна ÑÐ¿Ð°Ð¶Ñ‹Ñ‚Ñ‹Ñ Ð´Ð°ÐºÑƒÐ¼ÐµÐ½Ñ‚Ñ‹ будуць пазначаны Ñ‚Ñгамі \"УваходныÑ\"." + +#: documents/models.py:79 +msgid "tag" +msgstr "Ñ‚Ñг" + +#: documents/models.py:80 documents/models.py:130 +msgid "tags" +msgstr "Ñ‚Ñгі" + +#: documents/models.py:85 documents/models.py:115 +msgid "document type" +msgstr "тып дакумента" + +#: documents/models.py:86 +msgid "document types" +msgstr "тыпы дакументаў" + +#: documents/models.py:94 +msgid "Unencrypted" +msgstr "Ðезашыфраваны" + +#: documents/models.py:95 +msgid "Encrypted with GNU Privacy Guard" +msgstr "Зашыфравана з дапамогай GNU Privacy Guard" + +#: documents/models.py:107 +msgid "title" +msgstr "назва" + +#: documents/models.py:119 +msgid "content" +msgstr "змеÑÑ‚" + +#: documents/models.py:122 +msgid "The raw, text-only data of the document. This field is primarily used for searching." +msgstr "ÐÐµÐ°Ð¿Ñ€Ð°Ñ†Ð°Ð²Ð°Ð½Ñ‹Ñ Ñ‚ÑкÑÑ‚Ð°Ð²Ñ‹Ñ Ð´Ð°Ð½Ñ‹Ñ Ð´Ð°ÐºÑƒÐ¼ÐµÐ½Ñ‚Ð°. ГÑта поле Ñž аÑноўным выкарыÑтоўваецца Ð´Ð»Ñ Ð¿Ð¾ÑˆÑƒÐºÑƒ." + +#: documents/models.py:127 +msgid "mime type" +msgstr "тып MIME" + +#: documents/models.py:134 +msgid "checksum" +msgstr "ÐºÐ°Ð½Ñ‚Ñ€Ð¾Ð»ÑŒÐ½Ð°Ñ Ñума" + +#: documents/models.py:138 +msgid "The checksum of the original document." +msgstr "ÐšÐ°Ð½Ñ‚Ñ€Ð¾Ð»ÑŒÐ½Ð°Ñ Ñума зыходнага дакумента." + +#: documents/models.py:142 +msgid "archive checksum" +msgstr "ÐºÐ°Ð½Ñ‚Ñ€Ð¾Ð»ÑŒÐ½Ð°Ñ Ñума архіва" + +#: documents/models.py:147 +msgid "The checksum of the archived document." +msgstr "ÐšÐ°Ð½Ñ‚Ñ€Ð¾Ð»ÑŒÐ½Ð°Ñ Ñума архіўнага дакумента." + +#: documents/models.py:150 documents/models.py:295 +msgid "created" +msgstr "Ñтвораны" + +#: documents/models.py:153 +msgid "modified" +msgstr "мадыфікаваны" + +#: documents/models.py:157 +msgid "storage type" +msgstr "тып захоўваннÑ" + +#: documents/models.py:165 +msgid "added" +msgstr "дададзена" + +#: documents/models.py:169 +msgid "filename" +msgstr "Ñ–Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð°" + +#: documents/models.py:175 +msgid "Current filename in storage" +msgstr "ЦÑперашнÑе Ñ–Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° Ñž Ñховішчы" + +#: documents/models.py:179 +msgid "archive filename" +msgstr "Ñ–Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° архіва" + +#: documents/models.py:185 +msgid "Current archive filename in storage" +msgstr "ЦÑперашнÑе Ñ–Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° архіва Ñž Ñховішчы" + +#: documents/models.py:189 +msgid "archive serial number" +msgstr "парадкавы нумар архіва" + +#: documents/models.py:195 +msgid "The position of this document in your physical document archive." +msgstr "ÐŸÐ°Ð·Ñ–Ñ†Ñ‹Ñ Ð³Ñтага дакумента Ñž вашым фізічным архіве дакументаў." + +#: documents/models.py:201 +msgid "document" +msgstr "дакумент" + +#: documents/models.py:202 +msgid "documents" +msgstr "дакументы" + +#: documents/models.py:280 +msgid "debug" +msgstr "адладка" + +#: documents/models.py:281 +msgid "information" +msgstr "інфармацыÑ" + +#: documents/models.py:282 +msgid "warning" +msgstr "папÑÑ€Ñджанне" + +#: documents/models.py:283 +msgid "error" +msgstr "памылка" + +#: documents/models.py:284 +msgid "critical" +msgstr "крытычны" + +#: documents/models.py:287 +msgid "group" +msgstr "група" + +#: documents/models.py:289 +msgid "message" +msgstr "паведамленне" + +#: documents/models.py:292 +msgid "level" +msgstr "узровень" + +#: documents/models.py:299 +msgid "log" +msgstr "лог" + +#: documents/models.py:300 +msgid "logs" +msgstr "логі" + +#: documents/models.py:310 documents/models.py:360 +msgid "saved view" +msgstr "захаваны выглÑд" + +#: documents/models.py:311 +msgid "saved views" +msgstr "Ð·Ð°Ñ…Ð°Ð²Ð°Ð½Ñ‹Ñ Ð²Ñ‹Ð³Ð»Ñды" + +#: documents/models.py:313 +msgid "user" +msgstr "карыÑтальнік" + +#: documents/models.py:317 +msgid "show on dashboard" +msgstr "паказаць на панÑлі" + +#: documents/models.py:320 +msgid "show in sidebar" +msgstr "паказаць у бакавой панÑлі" + +#: documents/models.py:324 +msgid "sort field" +msgstr "поле ÑартаваннÑ" + +#: documents/models.py:326 +msgid "sort reverse" +msgstr "Ñартаваць у адваротным парадку" + +#: documents/models.py:331 +msgid "title contains" +msgstr "назва змÑшчае" + +#: documents/models.py:332 +msgid "content contains" +msgstr "змеÑÑ‚ змÑшчае" + +#: documents/models.py:333 +msgid "ASN is" +msgstr "ASN" + +#: documents/models.py:334 +msgid "correspondent is" +msgstr "карÑÑпандÑнт" + +#: documents/models.py:335 +msgid "document type is" +msgstr "тып дакумента" + +#: documents/models.py:336 +msgid "is in inbox" +msgstr "ва ўваходных" + +#: documents/models.py:337 +msgid "has tag" +msgstr "мае Ñ‚Ñг" + +#: documents/models.py:338 +msgid "has any tag" +msgstr "мае любы Ñ‚Ñг" + +#: documents/models.py:339 +msgid "created before" +msgstr "Ñтворана перад" + +#: documents/models.py:340 +msgid "created after" +msgstr "Ñтворана паÑлÑ" + +#: documents/models.py:341 +msgid "created year is" +msgstr "год ÑтварÑннÑ" + +#: documents/models.py:342 +msgid "created month is" +msgstr "меÑÑц ÑтварÑннÑ" + +#: documents/models.py:343 +msgid "created day is" +msgstr "дзень ÑтварÑннÑ" + +#: documents/models.py:344 +msgid "added before" +msgstr "даданы перад" + +#: documents/models.py:345 +msgid "added after" +msgstr "даданы паÑлÑ" + +#: documents/models.py:346 +msgid "modified before" +msgstr "зменены перад" + +#: documents/models.py:347 +msgid "modified after" +msgstr "зменены паÑлÑ" + +#: documents/models.py:348 +msgid "does not have tag" +msgstr "не мае Ñ‚Ñга" + +#: documents/models.py:349 +msgid "does not have ASN" +msgstr "не мае ASN" + +#: documents/models.py:350 +msgid "title or content contains" +msgstr "назва або змеÑÑ‚ ÑмÑшчае" + +#: documents/models.py:351 +msgid "fulltext query" +msgstr "поўнатÑкÑтавы запыт" + +#: documents/models.py:352 +msgid "more like this" +msgstr "больш падобнага" + +#: documents/models.py:353 +msgid "has tags in" +msgstr "мае Ñ‚Ñгі Ñž" + +#: documents/models.py:363 +msgid "rule type" +msgstr "тып правіла" + +#: documents/models.py:365 +msgid "value" +msgstr "значÑнне" + +#: documents/models.py:368 +msgid "filter rule" +msgstr "правіла фільтрацыі" + +#: documents/models.py:369 +msgid "filter rules" +msgstr "правілы фільтрацыі" + +#: documents/serialisers.py:64 +#, python-format +msgid "Invalid regular expression: %(error)s" +msgstr "ÐÑправільны Ñ€ÑгулÑрны выраз: %(error)s" + +#: documents/serialisers.py:185 +msgid "Invalid color." +msgstr "ÐÑправільны колер." + +#: documents/serialisers.py:459 +#, python-format +msgid "File type %(type)s not supported" +msgstr "Тып файла %(type)s не падтрымліваецца" + +#: documents/templates/index.html:22 +msgid "Paperless-ngx is loading..." +msgstr "Paperless-ngx загружаецца..." + +#: documents/templates/registration/logged_out.html:14 +msgid "Paperless-ngx signed out" +msgstr "Выкананы выхад з Paperless-ngx" + +#: documents/templates/registration/logged_out.html:59 +msgid "You have been successfully logged out. Bye!" +msgstr "Ð’Ñ‹ паÑпÑхова выйшлі з ÑÑ–ÑÑ‚Ñмы. Да пабачÑннÑ!" + +#: documents/templates/registration/logged_out.html:60 +msgid "Sign in again" +msgstr "УвайÑці зноў" + +#: documents/templates/registration/login.html:15 +msgid "Paperless-ngx sign in" +msgstr "УвайÑці Ñž Paperless-ngx" + +#: documents/templates/registration/login.html:61 +msgid "Please sign in." +msgstr "Калі лаÑка, увайдзіце." + +#: documents/templates/registration/login.html:64 +msgid "Your username and password didn't match. Please try again." +msgstr "ÐÑÐ¿Ñ€Ð°Ð²Ñ–Ð»ÑŒÐ½Ñ‹Ñ Ñ–Ð¼Ñ ÐºÐ°Ñ€Ñ‹Ñтальніка або пароль! ПаÑпрабуйце ÑÑˆÑ‡Ñ Ñ€Ð°Ð·." + +#: documents/templates/registration/login.html:67 +msgid "Username" +msgstr "Ð†Ð¼Ñ ÐºÐ°Ñ€Ñ‹Ñтальніка" + +#: documents/templates/registration/login.html:68 +msgid "Password" +msgstr "Пароль" + +#: documents/templates/registration/login.html:73 +msgid "Sign in" +msgstr "УвайÑці" + +#: paperless/settings.py:299 +msgid "English (US)" +msgstr "ÐнглійÑÐºÐ°Ñ (ЗШÐ)" + +#: paperless/settings.py:300 +msgid "Czech" +msgstr "ЧÑшÑкаÑ" + +#: paperless/settings.py:301 +msgid "Danish" +msgstr "ДацкаÑ" + +#: paperless/settings.py:302 +msgid "German" +msgstr "ÐÑмецкаÑ" + +#: paperless/settings.py:303 +msgid "English (GB)" +msgstr "ÐнглійÑÐºÐ°Ñ (Ð’ÑлікабрытаніÑ)" + +#: paperless/settings.py:304 +msgid "Spanish" +msgstr "ІÑпанÑкаÑ" + +#: paperless/settings.py:305 +msgid "French" +msgstr "ФранцузÑкаÑ" + +#: paperless/settings.py:306 +msgid "Italian" +msgstr "ІтальÑнÑкаÑ" + +#: paperless/settings.py:307 +msgid "Luxembourgish" +msgstr "ЛюкÑембургÑкаÑ" + +#: paperless/settings.py:308 +msgid "Dutch" +msgstr "ÐідÑрландÑкаÑ" + +#: paperless/settings.py:309 +msgid "Polish" +msgstr "ПольÑкаÑ" + +#: paperless/settings.py:310 +msgid "Portuguese (Brazil)" +msgstr "ПартугальÑÐºÐ°Ñ (БразіліÑ)" + +#: paperless/settings.py:311 +msgid "Portuguese" +msgstr "ПартугальÑкаÑ" + +#: paperless/settings.py:312 +msgid "Romanian" +msgstr "РумынÑкаÑ" + +#: paperless/settings.py:313 +msgid "Russian" +msgstr "РуÑкаÑ" + +#: paperless/settings.py:314 +msgid "Swedish" +msgstr "ШведÑкаÑ" + +#: paperless/urls.py:139 +msgid "Paperless-ngx administration" +msgstr "ÐдмініÑтраванне Paperless-ngx" + +#: paperless_mail/admin.py:29 +msgid "Authentication" +msgstr "ÐўтÑнтыфікацыÑ" + +#: paperless_mail/admin.py:30 +msgid "Advanced settings" +msgstr "ÐŸÐ°ÑˆÑ‹Ñ€Ð°Ð½Ñ‹Ñ Ð½Ð°Ð»Ð°Ð´Ñ‹" + +#: paperless_mail/admin.py:47 +msgid "Filter" +msgstr "Фільтр" + +#: paperless_mail/admin.py:50 +msgid "Paperless will only process mails that match ALL of the filters given below." +msgstr "Paperless-ngx будзе апрацоўваць толькі ліÑÑ‚Ñ‹, ÑÐºÑ–Ñ Ð°Ð´Ð¿Ð°Ð²Ñдаюць УСІМ фільтрам, прыведзеным ніжÑй." + +#: paperless_mail/admin.py:64 +msgid "Actions" +msgstr "ДзеÑнні" + +#: paperless_mail/admin.py:67 +msgid "The action applied to the mail. This action is only performed when documents were consumed from the mail. Mails without attachments will remain entirely untouched." +msgstr "ДзеÑнне раÑпаўÑюджваецца на пошту. ГÑта дзеÑнне выконваецца толькі тады, калі дакументы былі Ñпажыты з пошты. Пошты без укладаннÑÑž заÑтануцца цалкам некранутымі." + +#: paperless_mail/admin.py:75 +msgid "Metadata" +msgstr "МетаданыÑ" + +#: paperless_mail/admin.py:78 +msgid "Assign metadata to documents consumed from this rule automatically. If you do not assign tags, types or correspondents here, paperless will still process all matching rules that you have defined." +msgstr "Ðўтаматычна прызначаць Ð¼ÐµÑ‚Ð°Ð´Ð°Ð´Ð·ÐµÐ½Ñ‹Ñ Ð´Ð°ÐºÑƒÐ¼ÐµÐ½Ñ‚Ð°Ð¼, атрыманым з гÑтага правіла. Калі вы не прызначаеце тут Ñ‚Ñгі, тыпы ці карÑÑпандÑнты, Paperless-ngx уÑÑ‘ роўна будуць апрацоўваць уÑе Ð°Ð´Ð¿Ð°Ð²ÐµÐ´Ð½Ñ‹Ñ Ð¿Ñ€Ð°Ð²Ñ–Ð»Ñ‹, ÑÐºÑ–Ñ Ð²Ñ‹ вызначылі." + +#: paperless_mail/apps.py:9 +msgid "Paperless mail" +msgstr "Paperless-ngx пошта" + +#: paperless_mail/models.py:10 +msgid "mail account" +msgstr "паштовы акаўнт" + +#: paperless_mail/models.py:11 +msgid "mail accounts" +msgstr "Ð¿Ð°ÑˆÑ‚Ð¾Ð²Ñ‹Ñ Ð°ÐºÐ°ÑžÐ½Ñ‚Ñ‹" + +#: paperless_mail/models.py:18 +msgid "No encryption" +msgstr "Без шыфраваннÑ" + +#: paperless_mail/models.py:19 +msgid "Use SSL" +msgstr "ВыкарыÑтоўваць SSL" + +#: paperless_mail/models.py:20 +msgid "Use STARTTLS" +msgstr "ВыкарыÑтоўваць STARTTLS" + +#: paperless_mail/models.py:25 +msgid "IMAP server" +msgstr "Сервер IMAP" + +#: paperless_mail/models.py:28 +msgid "IMAP port" +msgstr "Порт IMAP" + +#: paperless_mail/models.py:32 +msgid "This is usually 143 for unencrypted and STARTTLS connections, and 993 for SSL connections." +msgstr "Звычайна гÑта 143 Ð´Ð»Ñ Ð½ÐµÐ·Ð°ÑˆÑ‹Ñ„Ñ€Ð°Ð²Ð°Ð½Ñ‹Ñ… Ñ– STARTTLS злучÑннÑÑž Ñ– 993 Ð´Ð»Ñ Ð·Ð»ÑƒÑ‡ÑннÑÑž SSL." + +#: paperless_mail/models.py:38 +msgid "IMAP security" +msgstr "БÑÑпека IMAP" + +#: paperless_mail/models.py:41 +msgid "username" +msgstr "Ñ–Ð¼Ñ ÐºÐ°Ñ€Ñ‹Ñтальніка" + +#: paperless_mail/models.py:43 +msgid "password" +msgstr "пароль" + +#: paperless_mail/models.py:46 +msgid "character set" +msgstr "кадзіроўка" + +#: paperless_mail/models.py:50 +msgid "The character set to use when communicating with the mail server, such as 'UTF-8' or 'US-ASCII'." +msgstr "Кадзіроўка Ð´Ð»Ñ ÑувÑзі з паштовым Ñерверам, напрыклад «UTF-8» або «US-ASCII»." + +#: paperless_mail/models.py:61 +msgid "mail rule" +msgstr "правіла пошты" + +#: paperless_mail/models.py:62 +msgid "mail rules" +msgstr "правілы пошты" + +#: paperless_mail/models.py:68 +msgid "Only process attachments." +msgstr "Ðпрацоўваць толькі ўкладанні." + +#: paperless_mail/models.py:71 +msgid "Process all files, including 'inline' attachments." +msgstr "Ðпрацоўваць уÑе файлы, уключаючы 'убудаваныÑ' укладанні." + +#: paperless_mail/models.py:81 +msgid "Mark as read, don't process read mails" +msgstr "Пазначыць Ñк прачытанае, не апрацоўваць Ð¿Ñ€Ð°Ñ‡Ñ‹Ñ‚Ð°Ð½Ñ‹Ñ Ð»Ñ–ÑÑ‚Ñ‹" + +#: paperless_mail/models.py:82 +msgid "Flag the mail, don't process flagged mails" +msgstr "Пазначыць пошту, не апрацоўваць Ð¿Ð°Ð·Ð½Ð°Ñ‡Ð°Ð½Ñ‹Ñ Ð»Ñ–ÑÑ‚Ñ‹" + +#: paperless_mail/models.py:83 +msgid "Move to specified folder" +msgstr "ПерамÑÑціць у паказаную папку" + +#: paperless_mail/models.py:84 +msgid "Delete" +msgstr "Выдаліць" + +#: paperless_mail/models.py:91 +msgid "Use subject as title" +msgstr "ТÑма Ñž ÑкаÑці загалоўка" + +#: paperless_mail/models.py:92 +msgid "Use attachment filename as title" +msgstr "ВыкарыÑтоўваць Ñ–Ð¼Ñ ÑžÐºÐ»Ð°Ð´Ð·ÐµÐ½Ð°Ð³Ð° файла Ñк загаловак" + +#: paperless_mail/models.py:101 +msgid "Do not assign a correspondent" +msgstr "Ðе прызначаць карÑÑпандÑнта" + +#: paperless_mail/models.py:102 +msgid "Use mail address" +msgstr "ВыкарыÑтоўваць email адраÑ" + +#: paperless_mail/models.py:103 +msgid "Use name (or mail address if not available)" +msgstr "ВыкарыÑтоўваць Ñ–Ð¼Ñ (або Ð°Ð´Ñ€Ð°Ñ Ñлектроннай пошты, калі недаÑтупна)" + +#: paperless_mail/models.py:104 +msgid "Use correspondent selected below" +msgstr "ВыкарыÑтоўваць карÑÑпандÑнта, абранага ніжÑй" + +#: paperless_mail/models.py:109 +msgid "order" +msgstr "парадак" + +#: paperless_mail/models.py:115 +msgid "account" +msgstr "ўліковы запіÑ" + +#: paperless_mail/models.py:119 +msgid "folder" +msgstr "каталог" + +#: paperless_mail/models.py:122 +msgid "Subfolders must be separated by dots." +msgstr "Падкаталогі павінны быць падзелены кропкамі." + +#: paperless_mail/models.py:126 +msgid "filter from" +msgstr "фільтр па адпраўніку" + +#: paperless_mail/models.py:129 +msgid "filter subject" +msgstr "фільтр па Ñ‚Ñме" + +#: paperless_mail/models.py:132 +msgid "filter body" +msgstr "фільтр па Ñ‚ÑкÑце паведамленнÑ" + +#: paperless_mail/models.py:136 +msgid "filter attachment filename" +msgstr "фільтр па імені ўкладаннÑ" + +#: paperless_mail/models.py:141 +msgid "Only consume documents which entirely match this filename if specified. Wildcards such as *.pdf or *invoice* are allowed. Case insensitive." +msgstr "Ðпрацоўваць толькі дакументы, ÑÐºÑ–Ñ Ñ†Ð°Ð»ÐºÐ°Ð¼ Ñупадаюць з імем файла (калі Ñно пазначана). МаÑкі, напрыклад *.pdf ці *рахунак*, дазволеныÑ. Без уліку Ñ€ÑгіÑтра." + +#: paperless_mail/models.py:148 +msgid "maximum age" +msgstr "макÑімальны ўзроÑÑ‚" + +#: paperless_mail/models.py:148 +msgid "Specified in days." +msgstr "Указваецца Ñž днÑÑ…." + +#: paperless_mail/models.py:152 +msgid "attachment type" +msgstr "тып укладаннÑ" + +#: paperless_mail/models.py:156 +msgid "Inline attachments include embedded images, so it's best to combine this option with a filename filter." +msgstr "Ð£Ð±ÑƒÐ´Ð°Ð²Ð°Ð½Ñ‹Ñ ÑžÐºÐ»Ð°Ð´Ð°Ð½Ð½Ñ– ўключаюць ÑƒÐ±ÑƒÐ´Ð°Ð²Ð°Ð½Ñ‹Ñ Ð²Ñ‹Ñвы, таму лепш камбінаваць гÑÑ‚Ñ‹ варыÑнт з фільтрам імёнаў файла." + +#: paperless_mail/models.py:162 +msgid "action" +msgstr "дзеÑнне" + +#: paperless_mail/models.py:168 +msgid "action parameter" +msgstr "параметр дзеÑннÑ" + +#: paperless_mail/models.py:173 +msgid "Additional parameter for the action selected above, i.e., the target folder of the move to folder action. Subfolders must be separated by dots." +msgstr "Дадатковы параметр Ð´Ð»Ñ Ð´Ð·ÐµÑннÑ, абранага вышÑй, гÑта значыць, мÑÑ‚Ð°Ð²Ð°Ñ Ð¿Ð°Ð¿ÐºÐ° дзеÑÐ½Ð½Ñ Ð¿ÐµÑ€Ð°Ð¼ÑшчÑÐ½Ð½Ñ Ñž папку. Падпапкі павінны быць Ð¿Ð°Ð´Ð·ÐµÐ»ÐµÐ½Ñ‹Ñ ÐºÑ€Ð¾Ð¿ÐºÐ°Ð¼Ñ–." + +#: paperless_mail/models.py:181 +msgid "assign title from" +msgstr "прызначыць загаловак з" + +#: paperless_mail/models.py:189 +msgid "assign this tag" +msgstr "прызначыць гÑÑ‚Ñ‹ Ñ‚Ñг" + +#: paperless_mail/models.py:197 +msgid "assign this document type" +msgstr "прызначыць гÑÑ‚Ñ‹ тып дакумента" + +#: paperless_mail/models.py:201 +msgid "assign correspondent from" +msgstr "прызначыць карÑÑпандÑнта з" + +#: paperless_mail/models.py:211 +msgid "assign this correspondent" +msgstr "прызначыць гÑтага карÑÑпандÑнта" + diff --git a/src/locale/de_DE/LC_MESSAGES/django.po b/src/locale/de_DE/LC_MESSAGES/django.po index 3301220e6..231a8393d 100644 --- a/src/locale/de_DE/LC_MESSAGES/django.po +++ b/src/locale/de_DE/LC_MESSAGES/django.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: paperless-ngx\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-03-02 11:20-0800\n" -"PO-Revision-Date: 2022-03-02 22:29\n" +"PO-Revision-Date: 2022-03-11 13:56\n" "Last-Translator: \n" "Language-Team: German\n" "Language: de_DE\n" @@ -344,7 +344,7 @@ msgstr "Ähnliche Dokumente" #: documents/models.py:353 msgid "has tags in" -msgstr "" +msgstr "hat Tags in" #: documents/models.py:363 msgid "rule type" @@ -378,11 +378,11 @@ msgstr "Dateityp %(type)s nicht unterstützt" #: documents/templates/index.html:22 msgid "Paperless-ngx is loading..." -msgstr "" +msgstr "Paperless-ngx wird geladen..." #: documents/templates/registration/logged_out.html:14 msgid "Paperless-ngx signed out" -msgstr "" +msgstr "Paperless-ngx abgemeldet" #: documents/templates/registration/logged_out.html:59 msgid "You have been successfully logged out. Bye!" @@ -394,7 +394,7 @@ msgstr "Erneut anmelden" #: documents/templates/registration/login.html:15 msgid "Paperless-ngx sign in" -msgstr "" +msgstr "Paperless-ngx Anmeldung" #: documents/templates/registration/login.html:61 msgid "Please sign in." @@ -422,11 +422,11 @@ msgstr "Englisch (US)" #: paperless/settings.py:300 msgid "Czech" -msgstr "" +msgstr "Tschechisch" #: paperless/settings.py:301 msgid "Danish" -msgstr "" +msgstr "Dänisch" #: paperless/settings.py:302 msgid "German" @@ -450,7 +450,7 @@ msgstr "Italienisch" #: paperless/settings.py:307 msgid "Luxembourgish" -msgstr "" +msgstr "Luxemburgisch" #: paperless/settings.py:308 msgid "Dutch" @@ -482,7 +482,7 @@ msgstr "Schwedisch" #: paperless/urls.py:139 msgid "Paperless-ngx administration" -msgstr "" +msgstr "Paperless-ngx Administration" #: paperless_mail/admin.py:29 msgid "Authentication" diff --git a/src/locale/es_ES/LC_MESSAGES/django.po b/src/locale/es_ES/LC_MESSAGES/django.po index cb917010d..1c96e42e5 100644 --- a/src/locale/es_ES/LC_MESSAGES/django.po +++ b/src/locale/es_ES/LC_MESSAGES/django.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: paperless-ngx\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-03-02 11:20-0800\n" -"PO-Revision-Date: 2022-03-02 22:29\n" +"PO-Revision-Date: 2022-03-26 21:49\n" "Last-Translator: \n" "Language-Team: Spanish\n" "Language: es_ES\n" @@ -72,7 +72,7 @@ msgstr "interlocutores" #: documents/models.py:67 msgid "color" -msgstr "" +msgstr "color" #: documents/models.py:70 msgid "is inbox tag" @@ -200,7 +200,7 @@ msgstr "alerta" #: documents/models.py:283 msgid "error" -msgstr "" +msgstr "error" #: documents/models.py:284 msgid "critical" @@ -220,11 +220,11 @@ msgstr "nivel" #: documents/models.py:299 msgid "log" -msgstr "" +msgstr "log" #: documents/models.py:300 msgid "logs" -msgstr "" +msgstr "logs" #: documents/models.py:310 documents/models.py:360 msgid "saved view" @@ -344,7 +344,7 @@ msgstr "más contenido similar" #: documents/models.py:353 msgid "has tags in" -msgstr "" +msgstr "tiene etiquetas en" #: documents/models.py:363 msgid "rule type" @@ -378,11 +378,11 @@ msgstr "Tipo de fichero %(type)s no suportado" #: documents/templates/index.html:22 msgid "Paperless-ngx is loading..." -msgstr "" +msgstr "Paperless-ngx está cargando..." #: documents/templates/registration/logged_out.html:14 msgid "Paperless-ngx signed out" -msgstr "" +msgstr "Paperless-ngx cerró sesión" #: documents/templates/registration/logged_out.html:59 msgid "You have been successfully logged out. Bye!" @@ -394,7 +394,7 @@ msgstr "Iniciar sesión de nuevo" #: documents/templates/registration/login.html:15 msgid "Paperless-ngx sign in" -msgstr "" +msgstr "Paperless-ngx inicio de sesión" #: documents/templates/registration/login.html:61 msgid "Please sign in." @@ -422,11 +422,11 @@ msgstr "Inglés (US)" #: paperless/settings.py:300 msgid "Czech" -msgstr "" +msgstr "Checo" #: paperless/settings.py:301 msgid "Danish" -msgstr "" +msgstr "Danés" #: paperless/settings.py:302 msgid "German" @@ -450,7 +450,7 @@ msgstr "Italiano" #: paperless/settings.py:307 msgid "Luxembourgish" -msgstr "" +msgstr "Luxemburgués" #: paperless/settings.py:308 msgid "Dutch" @@ -482,7 +482,7 @@ msgstr "Sueco" #: paperless/urls.py:139 msgid "Paperless-ngx administration" -msgstr "" +msgstr "Administración de Paperless-ngx" #: paperless_mail/admin.py:29 msgid "Authentication" diff --git a/src/locale/fi_FI/LC_MESSAGES/django.po b/src/locale/fi_FI/LC_MESSAGES/django.po new file mode 100644 index 000000000..7ea331a4e --- /dev/null +++ b/src/locale/fi_FI/LC_MESSAGES/django.po @@ -0,0 +1,714 @@ +msgid "" +msgstr "" +"Project-Id-Version: paperless-ngx\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-03-02 11:20-0800\n" +"PO-Revision-Date: 2022-03-31 08:58\n" +"Last-Translator: \n" +"Language-Team: Finnish\n" +"Language: fi_FI\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Crowdin-Project: paperless-ngx\n" +"X-Crowdin-Project-ID: 500308\n" +"X-Crowdin-Language: fi\n" +"X-Crowdin-File: /dev/src/locale/en_US/LC_MESSAGES/django.po\n" +"X-Crowdin-File-ID: 14\n" + +#: documents/apps.py:10 +msgid "Documents" +msgstr "Dokumentit" + +#: documents/models.py:32 +msgid "Any word" +msgstr "Mikä tahansa sana" + +#: documents/models.py:33 +msgid "All words" +msgstr "Kaikki sanat" + +#: documents/models.py:34 +msgid "Exact match" +msgstr "Tarkka osuma" + +#: documents/models.py:35 +msgid "Regular expression" +msgstr "Säännöllinen lauseke (regex)" + +#: documents/models.py:36 +msgid "Fuzzy word" +msgstr "Sumea sana" + +#: documents/models.py:37 +msgid "Automatic" +msgstr "Automaattinen" + +#: documents/models.py:40 documents/models.py:314 paperless_mail/models.py:23 +#: paperless_mail/models.py:107 +msgid "name" +msgstr "nimi" + +#: documents/models.py:42 +msgid "match" +msgstr "osuma" + +#: documents/models.py:45 +msgid "matching algorithm" +msgstr "tunnistusalgoritmi" + +#: documents/models.py:48 +msgid "is insensitive" +msgstr "ei ole herkkä" + +#: documents/models.py:61 documents/models.py:104 +msgid "correspondent" +msgstr "yhteyshenkilö" + +#: documents/models.py:62 +msgid "correspondents" +msgstr "yhteyshenkilöt" + +#: documents/models.py:67 +msgid "color" +msgstr "väri" + +#: documents/models.py:70 +msgid "is inbox tag" +msgstr "on uusien tunniste" + +#: documents/models.py:73 +msgid "Marks this tag as an inbox tag: All newly consumed documents will be tagged with inbox tags." +msgstr "Merkitsee tämän tunnisteen uusien tunnisteeksi: Kaikille vastasyötetyille tiedostoille annetaan tämä tunniste." + +#: documents/models.py:79 +msgid "tag" +msgstr "tunniste" + +#: documents/models.py:80 documents/models.py:130 +msgid "tags" +msgstr "tunnisteet" + +#: documents/models.py:85 documents/models.py:115 +msgid "document type" +msgstr "asiakirjatyyppi" + +#: documents/models.py:86 +msgid "document types" +msgstr "asiakirjatyypit" + +#: documents/models.py:94 +msgid "Unencrypted" +msgstr "Salaamaton" + +#: documents/models.py:95 +msgid "Encrypted with GNU Privacy Guard" +msgstr "GNU Privacy Guard -salattu" + +#: documents/models.py:107 +msgid "title" +msgstr "otsikko" + +#: documents/models.py:119 +msgid "content" +msgstr "sisältö" + +#: documents/models.py:122 +msgid "The raw, text-only data of the document. This field is primarily used for searching." +msgstr "Raaka vain teksti -muotoinen dokumentin sisältö. Kenttää käytetään pääasiassa hakutoiminnossa." + +#: documents/models.py:127 +msgid "mime type" +msgstr "mime-tyyppi" + +#: documents/models.py:134 +msgid "checksum" +msgstr "tarkistussumma" + +#: documents/models.py:138 +msgid "The checksum of the original document." +msgstr "Alkuperäisen dokumentin tarkistussumma." + +#: documents/models.py:142 +msgid "archive checksum" +msgstr "arkistotarkastussumma" + +#: documents/models.py:147 +msgid "The checksum of the archived document." +msgstr "Arkistoidun dokumentin tarkistussumma." + +#: documents/models.py:150 documents/models.py:295 +msgid "created" +msgstr "luotu" + +#: documents/models.py:153 +msgid "modified" +msgstr "muokattu" + +#: documents/models.py:157 +msgid "storage type" +msgstr "tallennustilan tyyppi" + +#: documents/models.py:165 +msgid "added" +msgstr "lisätty" + +#: documents/models.py:169 +msgid "filename" +msgstr "tiedostonimi" + +#: documents/models.py:175 +msgid "Current filename in storage" +msgstr "Tiedostonimi tallennustilassa" + +#: documents/models.py:179 +msgid "archive filename" +msgstr "arkistointitiedostonimi" + +#: documents/models.py:185 +msgid "Current archive filename in storage" +msgstr "Tämänhetkinen arkistointitiedostoimi tallennustilassa" + +#: documents/models.py:189 +msgid "archive serial number" +msgstr "arkistointisarjanumero" + +#: documents/models.py:195 +msgid "The position of this document in your physical document archive." +msgstr "Dokumentin sijainti fyysisessa dokumenttiarkistossa." + +#: documents/models.py:201 +msgid "document" +msgstr "dokumentti" + +#: documents/models.py:202 +msgid "documents" +msgstr "dokumentit" + +#: documents/models.py:280 +msgid "debug" +msgstr "virheenjäljitys" + +#: documents/models.py:281 +msgid "information" +msgstr "informaatio" + +#: documents/models.py:282 +msgid "warning" +msgstr "varoitus" + +#: documents/models.py:283 +msgid "error" +msgstr "virhe" + +#: documents/models.py:284 +msgid "critical" +msgstr "kriittinen" + +#: documents/models.py:287 +msgid "group" +msgstr "ryhmä" + +#: documents/models.py:289 +msgid "message" +msgstr "viesti" + +#: documents/models.py:292 +msgid "level" +msgstr "taso" + +#: documents/models.py:299 +msgid "log" +msgstr "loki" + +#: documents/models.py:300 +msgid "logs" +msgstr "lokit" + +#: documents/models.py:310 documents/models.py:360 +msgid "saved view" +msgstr "tallennettu näkymä" + +#: documents/models.py:311 +msgid "saved views" +msgstr "tallennetut näkymät" + +#: documents/models.py:313 +msgid "user" +msgstr "käyttäjä" + +#: documents/models.py:317 +msgid "show on dashboard" +msgstr "näytä etusivulla" + +#: documents/models.py:320 +msgid "show in sidebar" +msgstr "näytä sivupaneelissa" + +#: documents/models.py:324 +msgid "sort field" +msgstr "lajittelukenttä" + +#: documents/models.py:326 +msgid "sort reverse" +msgstr "lajittele käänteisesti" + +#: documents/models.py:331 +msgid "title contains" +msgstr "otsikko sisältää" + +#: documents/models.py:332 +msgid "content contains" +msgstr "sisältö sisältää" + +#: documents/models.py:333 +msgid "ASN is" +msgstr "ASN on" + +#: documents/models.py:334 +msgid "correspondent is" +msgstr "yhteyshenkilö on" + +#: documents/models.py:335 +msgid "document type is" +msgstr "dokumenttityyppi on" + +#: documents/models.py:336 +msgid "is in inbox" +msgstr "on uusi" + +#: documents/models.py:337 +msgid "has tag" +msgstr "on tagattu" + +#: documents/models.py:338 +msgid "has any tag" +msgstr "on mikä tahansa tagi" + +#: documents/models.py:339 +msgid "created before" +msgstr "luotu ennen" + +#: documents/models.py:340 +msgid "created after" +msgstr "luotu jälkeen" + +#: documents/models.py:341 +msgid "created year is" +msgstr "luotu vuonna" + +#: documents/models.py:342 +msgid "created month is" +msgstr "luotu kuukautena" + +#: documents/models.py:343 +msgid "created day is" +msgstr "" + +#: documents/models.py:344 +msgid "added before" +msgstr "" + +#: documents/models.py:345 +msgid "added after" +msgstr "" + +#: documents/models.py:346 +msgid "modified before" +msgstr "" + +#: documents/models.py:347 +msgid "modified after" +msgstr "" + +#: documents/models.py:348 +msgid "does not have tag" +msgstr "" + +#: documents/models.py:349 +msgid "does not have ASN" +msgstr "" + +#: documents/models.py:350 +msgid "title or content contains" +msgstr "" + +#: documents/models.py:351 +msgid "fulltext query" +msgstr "" + +#: documents/models.py:352 +msgid "more like this" +msgstr "" + +#: documents/models.py:353 +msgid "has tags in" +msgstr "" + +#: documents/models.py:363 +msgid "rule type" +msgstr "" + +#: documents/models.py:365 +msgid "value" +msgstr "" + +#: documents/models.py:368 +msgid "filter rule" +msgstr "" + +#: documents/models.py:369 +msgid "filter rules" +msgstr "" + +#: documents/serialisers.py:64 +#, python-format +msgid "Invalid regular expression: %(error)s" +msgstr "" + +#: documents/serialisers.py:185 +msgid "Invalid color." +msgstr "" + +#: documents/serialisers.py:459 +#, python-format +msgid "File type %(type)s not supported" +msgstr "" + +#: documents/templates/index.html:22 +msgid "Paperless-ngx is loading..." +msgstr "" + +#: documents/templates/registration/logged_out.html:14 +msgid "Paperless-ngx signed out" +msgstr "" + +#: documents/templates/registration/logged_out.html:59 +msgid "You have been successfully logged out. Bye!" +msgstr "" + +#: documents/templates/registration/logged_out.html:60 +msgid "Sign in again" +msgstr "" + +#: documents/templates/registration/login.html:15 +msgid "Paperless-ngx sign in" +msgstr "" + +#: documents/templates/registration/login.html:61 +msgid "Please sign in." +msgstr "" + +#: documents/templates/registration/login.html:64 +msgid "Your username and password didn't match. Please try again." +msgstr "" + +#: documents/templates/registration/login.html:67 +msgid "Username" +msgstr "" + +#: documents/templates/registration/login.html:68 +msgid "Password" +msgstr "" + +#: documents/templates/registration/login.html:73 +msgid "Sign in" +msgstr "" + +#: paperless/settings.py:299 +msgid "English (US)" +msgstr "" + +#: paperless/settings.py:300 +msgid "Czech" +msgstr "" + +#: paperless/settings.py:301 +msgid "Danish" +msgstr "" + +#: paperless/settings.py:302 +msgid "German" +msgstr "" + +#: paperless/settings.py:303 +msgid "English (GB)" +msgstr "" + +#: paperless/settings.py:304 +msgid "Spanish" +msgstr "" + +#: paperless/settings.py:305 +msgid "French" +msgstr "" + +#: paperless/settings.py:306 +msgid "Italian" +msgstr "" + +#: paperless/settings.py:307 +msgid "Luxembourgish" +msgstr "" + +#: paperless/settings.py:308 +msgid "Dutch" +msgstr "" + +#: paperless/settings.py:309 +msgid "Polish" +msgstr "puola" + +#: paperless/settings.py:310 +msgid "Portuguese (Brazil)" +msgstr "portugali (Brasilia)" + +#: paperless/settings.py:311 +msgid "Portuguese" +msgstr "portugali" + +#: paperless/settings.py:312 +msgid "Romanian" +msgstr "romania" + +#: paperless/settings.py:313 +msgid "Russian" +msgstr "venäjä" + +#: paperless/settings.py:314 +msgid "Swedish" +msgstr "ruotsi" + +#: paperless/urls.py:139 +msgid "Paperless-ngx administration" +msgstr "Paperless-ngx hallintapaneeli" + +#: paperless_mail/admin.py:29 +msgid "Authentication" +msgstr "Autentikaatio" + +#: paperless_mail/admin.py:30 +msgid "Advanced settings" +msgstr "Edistyneet asetukset" + +#: paperless_mail/admin.py:47 +msgid "Filter" +msgstr "Suodatin" + +#: paperless_mail/admin.py:50 +msgid "Paperless will only process mails that match ALL of the filters given below." +msgstr "Paperless prosessoi vain sähköpostit jotka sopivat KAIKKIIN annettuihin filttereihin." + +#: paperless_mail/admin.py:64 +msgid "Actions" +msgstr "Toiminnot" + +#: paperless_mail/admin.py:67 +msgid "The action applied to the mail. This action is only performed when documents were consumed from the mail. Mails without attachments will remain entirely untouched." +msgstr "" + +#: paperless_mail/admin.py:75 +msgid "Metadata" +msgstr "Metatiedot" + +#: paperless_mail/admin.py:78 +msgid "Assign metadata to documents consumed from this rule automatically. If you do not assign tags, types or correspondents here, paperless will still process all matching rules that you have defined." +msgstr "Määritä tuodun dokumentin metadata tämän säännön perusteella automaattisesti. Jos et aseta tageja, tyyppejä tai omistajia täällä, Paperless prosessoi silti kaikki sopivat määritellyt säännöt." + +#: paperless_mail/apps.py:9 +msgid "Paperless mail" +msgstr "Paperless-sähköposti" + +#: paperless_mail/models.py:10 +msgid "mail account" +msgstr "sähköpostitili" + +#: paperless_mail/models.py:11 +msgid "mail accounts" +msgstr "sähköpostitilit" + +#: paperless_mail/models.py:18 +msgid "No encryption" +msgstr "Ei salausta" + +#: paperless_mail/models.py:19 +msgid "Use SSL" +msgstr "Käytä SSL-salausta" + +#: paperless_mail/models.py:20 +msgid "Use STARTTLS" +msgstr "Käytä STARTTLS-salausta" + +#: paperless_mail/models.py:25 +msgid "IMAP server" +msgstr "IMAP-palvelin" + +#: paperless_mail/models.py:28 +msgid "IMAP port" +msgstr "IMAP-portti" + +#: paperless_mail/models.py:32 +msgid "This is usually 143 for unencrypted and STARTTLS connections, and 993 for SSL connections." +msgstr "Tämä on yleensä 142 salaamattomille sekä STARTTLS-yhteyksille, ja 993 SSL-yhteyksille." + +#: paperless_mail/models.py:38 +msgid "IMAP security" +msgstr "IMAP-suojaus" + +#: paperless_mail/models.py:41 +msgid "username" +msgstr "käyttäjänimi" + +#: paperless_mail/models.py:43 +msgid "password" +msgstr "salasana" + +#: paperless_mail/models.py:46 +msgid "character set" +msgstr "merkistö" + +#: paperless_mail/models.py:50 +msgid "The character set to use when communicating with the mail server, such as 'UTF-8' or 'US-ASCII'." +msgstr "Merkistö määritellään sähköpostipalvelimen kanssa komminukointia varten. Se voi olla esimerkiksi \"UTF-8\" tai \"US-ASCII\"." + +#: paperless_mail/models.py:61 +msgid "mail rule" +msgstr "sähköpostisääntö" + +#: paperless_mail/models.py:62 +msgid "mail rules" +msgstr "sähköpostisäännöt" + +#: paperless_mail/models.py:68 +msgid "Only process attachments." +msgstr "Prosessoi vain liitteet." + +#: paperless_mail/models.py:71 +msgid "Process all files, including 'inline' attachments." +msgstr "Prosessoi kaikki tiedostot, sisältäen \"inline\"-liitteet." + +#: paperless_mail/models.py:81 +msgid "Mark as read, don't process read mails" +msgstr "Merkitse luetuksi, älä prosessoi luettuja sähköposteja" + +#: paperless_mail/models.py:82 +msgid "Flag the mail, don't process flagged mails" +msgstr "" + +#: paperless_mail/models.py:83 +msgid "Move to specified folder" +msgstr "" + +#: paperless_mail/models.py:84 +msgid "Delete" +msgstr "" + +#: paperless_mail/models.py:91 +msgid "Use subject as title" +msgstr "" + +#: paperless_mail/models.py:92 +msgid "Use attachment filename as title" +msgstr "" + +#: paperless_mail/models.py:101 +msgid "Do not assign a correspondent" +msgstr "" + +#: paperless_mail/models.py:102 +msgid "Use mail address" +msgstr "" + +#: paperless_mail/models.py:103 +msgid "Use name (or mail address if not available)" +msgstr "" + +#: paperless_mail/models.py:104 +msgid "Use correspondent selected below" +msgstr "" + +#: paperless_mail/models.py:109 +msgid "order" +msgstr "" + +#: paperless_mail/models.py:115 +msgid "account" +msgstr "" + +#: paperless_mail/models.py:119 +msgid "folder" +msgstr "" + +#: paperless_mail/models.py:122 +msgid "Subfolders must be separated by dots." +msgstr "" + +#: paperless_mail/models.py:126 +msgid "filter from" +msgstr "" + +#: paperless_mail/models.py:129 +msgid "filter subject" +msgstr "" + +#: paperless_mail/models.py:132 +msgid "filter body" +msgstr "" + +#: paperless_mail/models.py:136 +msgid "filter attachment filename" +msgstr "" + +#: paperless_mail/models.py:141 +msgid "Only consume documents which entirely match this filename if specified. Wildcards such as *.pdf or *invoice* are allowed. Case insensitive." +msgstr "" + +#: paperless_mail/models.py:148 +msgid "maximum age" +msgstr "" + +#: paperless_mail/models.py:148 +msgid "Specified in days." +msgstr "" + +#: paperless_mail/models.py:152 +msgid "attachment type" +msgstr "" + +#: paperless_mail/models.py:156 +msgid "Inline attachments include embedded images, so it's best to combine this option with a filename filter." +msgstr "" + +#: paperless_mail/models.py:162 +msgid "action" +msgstr "" + +#: paperless_mail/models.py:168 +msgid "action parameter" +msgstr "" + +#: paperless_mail/models.py:173 +msgid "Additional parameter for the action selected above, i.e., the target folder of the move to folder action. Subfolders must be separated by dots." +msgstr "" + +#: paperless_mail/models.py:181 +msgid "assign title from" +msgstr "" + +#: paperless_mail/models.py:189 +msgid "assign this tag" +msgstr "" + +#: paperless_mail/models.py:197 +msgid "assign this document type" +msgstr "" + +#: paperless_mail/models.py:201 +msgid "assign correspondent from" +msgstr "" + +#: paperless_mail/models.py:211 +msgid "assign this correspondent" +msgstr "" + diff --git a/src/locale/it_IT/LC_MESSAGES/django.po b/src/locale/it_IT/LC_MESSAGES/django.po index 84c710f76..65d0b7a9f 100644 --- a/src/locale/it_IT/LC_MESSAGES/django.po +++ b/src/locale/it_IT/LC_MESSAGES/django.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: paperless-ngx\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-03-02 11:20-0800\n" -"PO-Revision-Date: 2022-03-02 22:29\n" +"PO-Revision-Date: 2022-03-09 09:53\n" "Last-Translator: \n" "Language-Team: Italian\n" "Language: it_IT\n" @@ -84,7 +84,7 @@ msgstr "Contrassegna questo tag come tag in arrivo: tutti i documenti elaborati #: documents/models.py:79 msgid "tag" -msgstr "" +msgstr "tag" #: documents/models.py:80 documents/models.py:130 msgid "tags" @@ -124,7 +124,7 @@ msgstr "tipo mime" #: documents/models.py:134 msgid "checksum" -msgstr "" +msgstr "checksum" #: documents/models.py:138 msgid "The checksum of the original document." @@ -188,7 +188,7 @@ msgstr "documenti" #: documents/models.py:280 msgid "debug" -msgstr "" +msgstr "debug" #: documents/models.py:281 msgid "information" @@ -220,7 +220,7 @@ msgstr "livello" #: documents/models.py:299 msgid "log" -msgstr "" +msgstr "logs" #: documents/models.py:300 msgid "logs" @@ -344,7 +344,7 @@ msgstr "altro come questo" #: documents/models.py:353 msgid "has tags in" -msgstr "" +msgstr "ha tag in" #: documents/models.py:363 msgid "rule type" @@ -378,11 +378,11 @@ msgstr "Il tipo di file %(type)s non è supportato" #: documents/templates/index.html:22 msgid "Paperless-ngx is loading..." -msgstr "" +msgstr "Paperless-ngx è in caricamento..." #: documents/templates/registration/logged_out.html:14 msgid "Paperless-ngx signed out" -msgstr "" +msgstr "Disconnesso da Paperless-ngx" #: documents/templates/registration/logged_out.html:59 msgid "You have been successfully logged out. Bye!" @@ -394,7 +394,7 @@ msgstr "Accedi nuovamente" #: documents/templates/registration/login.html:15 msgid "Paperless-ngx sign in" -msgstr "" +msgstr "Accedi a Paperless-ngx" #: documents/templates/registration/login.html:61 msgid "Please sign in." @@ -410,7 +410,7 @@ msgstr "Nome utente" #: documents/templates/registration/login.html:68 msgid "Password" -msgstr "" +msgstr "Password" #: documents/templates/registration/login.html:73 msgid "Sign in" @@ -422,11 +422,11 @@ msgstr "Inglese (US)" #: paperless/settings.py:300 msgid "Czech" -msgstr "" +msgstr "Ceco" #: paperless/settings.py:301 msgid "Danish" -msgstr "" +msgstr "Danese" #: paperless/settings.py:302 msgid "German" @@ -450,7 +450,7 @@ msgstr "Italiano" #: paperless/settings.py:307 msgid "Luxembourgish" -msgstr "" +msgstr "Lussemburghese" #: paperless/settings.py:308 msgid "Dutch" @@ -482,7 +482,7 @@ msgstr "Svedese" #: paperless/urls.py:139 msgid "Paperless-ngx administration" -msgstr "" +msgstr "Amministrazione di Paperless-ngx" #: paperless_mail/admin.py:29 msgid "Authentication" @@ -562,7 +562,7 @@ msgstr "nome utente" #: paperless_mail/models.py:43 msgid "password" -msgstr "" +msgstr "password" #: paperless_mail/models.py:46 msgid "character set" @@ -634,7 +634,7 @@ msgstr "priorità" #: paperless_mail/models.py:115 msgid "account" -msgstr "" +msgstr "account" #: paperless_mail/models.py:119 msgid "folder" diff --git a/src/locale/lb_LU/LC_MESSAGES/django.po b/src/locale/lb_LU/LC_MESSAGES/django.po index 2c386d8b1..b7c9e626c 100644 --- a/src/locale/lb_LU/LC_MESSAGES/django.po +++ b/src/locale/lb_LU/LC_MESSAGES/django.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: paperless-ngx\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-03-02 11:20-0800\n" -"PO-Revision-Date: 2022-03-02 22:29\n" +"PO-Revision-Date: 2022-03-18 12:18\n" "Last-Translator: \n" "Language-Team: Luxembourgish\n" "Language: lb_LU\n" @@ -344,7 +344,7 @@ msgstr "ähnlech Dokumenter" #: documents/models.py:353 msgid "has tags in" -msgstr "" +msgstr "huet Etiketten an" #: documents/models.py:363 msgid "rule type" @@ -378,11 +378,11 @@ msgstr "Fichierstyp %(type)s net ënnerstëtzt" #: documents/templates/index.html:22 msgid "Paperless-ngx is loading..." -msgstr "" +msgstr "Paperless-ngx gëtt gelueden..." #: documents/templates/registration/logged_out.html:14 msgid "Paperless-ngx signed out" -msgstr "" +msgstr "Paperless-ngx ofgemellt" #: documents/templates/registration/logged_out.html:59 msgid "You have been successfully logged out. Bye!" @@ -394,7 +394,7 @@ msgstr "Nees umellen" #: documents/templates/registration/login.html:15 msgid "Paperless-ngx sign in" -msgstr "" +msgstr "Umeldung bei Paperless-ngx" #: documents/templates/registration/login.html:61 msgid "Please sign in." @@ -422,11 +422,11 @@ msgstr "Englesch (USA)" #: paperless/settings.py:300 msgid "Czech" -msgstr "" +msgstr "Tschechesch" #: paperless/settings.py:301 msgid "Danish" -msgstr "" +msgstr "Dänesch" #: paperless/settings.py:302 msgid "German" @@ -450,7 +450,7 @@ msgstr "Italienesch" #: paperless/settings.py:307 msgid "Luxembourgish" -msgstr "" +msgstr "Lëtzebuergesch" #: paperless/settings.py:308 msgid "Dutch" @@ -482,7 +482,7 @@ msgstr "Schwedesch" #: paperless/urls.py:139 msgid "Paperless-ngx administration" -msgstr "" +msgstr "Paperless-ngx-Administratioun" #: paperless_mail/admin.py:29 msgid "Authentication" diff --git a/src/locale/nl_NL/LC_MESSAGES/django.po b/src/locale/nl_NL/LC_MESSAGES/django.po index 5c6fb8c7a..567855af2 100644 --- a/src/locale/nl_NL/LC_MESSAGES/django.po +++ b/src/locale/nl_NL/LC_MESSAGES/django.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: paperless-ngx\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-03-02 11:20-0800\n" -"PO-Revision-Date: 2022-03-02 22:29\n" +"PO-Revision-Date: 2022-03-14 13:34\n" "Last-Translator: \n" "Language-Team: Dutch\n" "Language: nl_NL\n" @@ -64,7 +64,7 @@ msgstr "is niet hoofdlettergevoelig" #: documents/models.py:61 documents/models.py:104 msgid "correspondent" -msgstr "" +msgstr "correspondent" #: documents/models.py:62 msgid "correspondents" @@ -124,7 +124,7 @@ msgstr "mimetype" #: documents/models.py:134 msgid "checksum" -msgstr "" +msgstr "checksum" #: documents/models.py:138 msgid "The checksum of the original document." @@ -180,7 +180,7 @@ msgstr "De positie van dit document in je fysieke documentenarchief." #: documents/models.py:201 msgid "document" -msgstr "" +msgstr "document" #: documents/models.py:202 msgid "documents" @@ -188,7 +188,7 @@ msgstr "documenten" #: documents/models.py:280 msgid "debug" -msgstr "" +msgstr "debug" #: documents/models.py:281 msgid "information" @@ -264,11 +264,11 @@ msgstr "inhoud bevat" #: documents/models.py:333 msgid "ASN is" -msgstr "" +msgstr "ASN is" #: documents/models.py:334 msgid "correspondent is" -msgstr "" +msgstr "correspondent is" #: documents/models.py:335 msgid "document type is" @@ -344,7 +344,7 @@ msgstr "meer zoals dit" #: documents/models.py:353 msgid "has tags in" -msgstr "" +msgstr "heeft tags in" #: documents/models.py:363 msgid "rule type" @@ -378,11 +378,11 @@ msgstr "Bestandstype %(type)s niet ondersteund" #: documents/templates/index.html:22 msgid "Paperless-ngx is loading..." -msgstr "" +msgstr "Paperless-ngx is aan het laden..." #: documents/templates/registration/logged_out.html:14 msgid "Paperless-ngx signed out" -msgstr "" +msgstr "Paperless-ngx afgemeld" #: documents/templates/registration/logged_out.html:59 msgid "You have been successfully logged out. Bye!" @@ -394,7 +394,7 @@ msgstr "Meld je opnieuw aan" #: documents/templates/registration/login.html:15 msgid "Paperless-ngx sign in" -msgstr "" +msgstr "Paperless-ngx afgemeld" #: documents/templates/registration/login.html:61 msgid "Please sign in." @@ -422,11 +422,11 @@ msgstr "Engels (US)" #: paperless/settings.py:300 msgid "Czech" -msgstr "" +msgstr "Tsjechisch" #: paperless/settings.py:301 msgid "Danish" -msgstr "" +msgstr "Deens" #: paperless/settings.py:302 msgid "German" @@ -450,7 +450,7 @@ msgstr "Italiaans" #: paperless/settings.py:307 msgid "Luxembourgish" -msgstr "" +msgstr "Luxemburgs" #: paperless/settings.py:308 msgid "Dutch" @@ -482,7 +482,7 @@ msgstr "Zweeds" #: paperless/urls.py:139 msgid "Paperless-ngx administration" -msgstr "" +msgstr "Paperless-ngx administratie" #: paperless_mail/admin.py:29 msgid "Authentication" @@ -494,7 +494,7 @@ msgstr "Geavanceerde instellingen" #: paperless_mail/admin.py:47 msgid "Filter" -msgstr "" +msgstr "Filter" #: paperless_mail/admin.py:50 msgid "Paperless will only process mails that match ALL of the filters given below." @@ -510,7 +510,7 @@ msgstr "De actie die wordt toegepast op de mail. Deze actie wordt alleen uitgevo #: paperless_mail/admin.py:75 msgid "Metadata" -msgstr "" +msgstr "Metadata" #: paperless_mail/admin.py:78 msgid "Assign metadata to documents consumed from this rule automatically. If you do not assign tags, types or correspondents here, paperless will still process all matching rules that you have defined." @@ -634,7 +634,7 @@ msgstr "volgorde" #: paperless_mail/models.py:115 msgid "account" -msgstr "" +msgstr "account" #: paperless_mail/models.py:119 msgid "folder" diff --git a/src/locale/pl_PL/LC_MESSAGES/django.po b/src/locale/pl_PL/LC_MESSAGES/django.po index eeb0b1a22..2ff485da0 100644 --- a/src/locale/pl_PL/LC_MESSAGES/django.po +++ b/src/locale/pl_PL/LC_MESSAGES/django.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: paperless-ngx\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-03-02 11:20-0800\n" -"PO-Revision-Date: 2022-03-02 22:29\n" +"PO-Revision-Date: 2022-04-12 15:26\n" "Last-Translator: \n" "Language-Team: Polish\n" "Language: pl_PL\n" @@ -60,7 +60,7 @@ msgstr "algorytm dopasowania" #: documents/models.py:48 msgid "is insensitive" -msgstr "bez rozróżniania wielkoÅ›ci liter" +msgstr "bez rozróżniania wielkoÅ›ci znaków" #: documents/models.py:61 documents/models.py:104 msgid "correspondent" @@ -84,7 +84,7 @@ msgstr "Zaznacza ten tag jako tag skrzynki odbiorczej: Wszystkie nowo przetworzo #: documents/models.py:79 msgid "tag" -msgstr "" +msgstr "znacznik" #: documents/models.py:80 documents/models.py:130 msgid "tags" @@ -120,7 +120,7 @@ msgstr "Surowe, tekstowe dane dokumentu. To pole jest używane głównie do wysz #: documents/models.py:127 msgid "mime type" -msgstr "typ mime" +msgstr "mime type" #: documents/models.py:134 msgid "checksum" @@ -188,7 +188,7 @@ msgstr "dokumenty" #: documents/models.py:280 msgid "debug" -msgstr "" +msgstr "debugowanie" #: documents/models.py:281 msgid "information" @@ -220,7 +220,7 @@ msgstr "poziom" #: documents/models.py:299 msgid "log" -msgstr "" +msgstr "log" #: documents/models.py:300 msgid "logs" @@ -240,7 +240,7 @@ msgstr "użytkownik" #: documents/models.py:317 msgid "show on dashboard" -msgstr "pokaż na pulpicie" +msgstr "pokaż na stronie głównej" #: documents/models.py:320 msgid "show in sidebar" @@ -344,7 +344,7 @@ msgstr "podobne dokumenty" #: documents/models.py:353 msgid "has tags in" -msgstr "" +msgstr "ma znaczniki w" #: documents/models.py:363 msgid "rule type" @@ -378,11 +378,11 @@ msgstr "Typ pliku %(type)s nie jest obsÅ‚ugiwany" #: documents/templates/index.html:22 msgid "Paperless-ngx is loading..." -msgstr "" +msgstr "Wczytywanie Paperless-ngx..." #: documents/templates/registration/logged_out.html:14 msgid "Paperless-ngx signed out" -msgstr "" +msgstr "Wylogowano z Paperless-ngx" #: documents/templates/registration/logged_out.html:59 msgid "You have been successfully logged out. Bye!" @@ -394,7 +394,7 @@ msgstr "Zaloguj siÄ™ ponownie" #: documents/templates/registration/login.html:15 msgid "Paperless-ngx sign in" -msgstr "" +msgstr "Logowanie do Paperless-ngx" #: documents/templates/registration/login.html:61 msgid "Please sign in." @@ -422,11 +422,11 @@ msgstr "Angielski (USA)" #: paperless/settings.py:300 msgid "Czech" -msgstr "" +msgstr "Czeski" #: paperless/settings.py:301 msgid "Danish" -msgstr "" +msgstr "DuÅ„ski" #: paperless/settings.py:302 msgid "German" @@ -450,7 +450,7 @@ msgstr "WÅ‚oski" #: paperless/settings.py:307 msgid "Luxembourgish" -msgstr "" +msgstr "Luksemburski" #: paperless/settings.py:308 msgid "Dutch" @@ -482,7 +482,7 @@ msgstr "Szwedzki" #: paperless/urls.py:139 msgid "Paperless-ngx administration" -msgstr "" +msgstr "Administracja Paperless-ngx" #: paperless_mail/admin.py:29 msgid "Authentication" @@ -638,7 +638,7 @@ msgstr "konto" #: paperless_mail/models.py:119 msgid "folder" -msgstr "" +msgstr "folder" #: paperless_mail/models.py:122 msgid "Subfolders must be separated by dots." diff --git a/src/locale/pt_BR/LC_MESSAGES/django.po b/src/locale/pt_BR/LC_MESSAGES/django.po index c54de56f2..846222d3e 100644 --- a/src/locale/pt_BR/LC_MESSAGES/django.po +++ b/src/locale/pt_BR/LC_MESSAGES/django.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: paperless-ngx\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-03-02 11:20-0800\n" -"PO-Revision-Date: 2022-03-02 22:29\n" +"PO-Revision-Date: 2022-03-19 11:27\n" "Last-Translator: \n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" @@ -188,7 +188,7 @@ msgstr "documentos" #: documents/models.py:280 msgid "debug" -msgstr "" +msgstr "debug" #: documents/models.py:281 msgid "information" @@ -220,11 +220,11 @@ msgstr "nível" #: documents/models.py:299 msgid "log" -msgstr "" +msgstr "log" #: documents/models.py:300 msgid "logs" -msgstr "" +msgstr "logs" #: documents/models.py:310 documents/models.py:360 msgid "saved view" @@ -328,7 +328,7 @@ msgstr "não tem etiqueta" #: documents/models.py:349 msgid "does not have ASN" -msgstr "" +msgstr "não tem NSA" #: documents/models.py:350 msgid "title or content contains" @@ -336,7 +336,7 @@ msgstr "título ou conteúdo contém" #: documents/models.py:351 msgid "fulltext query" -msgstr "" +msgstr "pesquisa de texto completo" #: documents/models.py:352 msgid "more like this" @@ -344,7 +344,7 @@ msgstr "mais como este" #: documents/models.py:353 msgid "has tags in" -msgstr "" +msgstr "contém etiqueta em" #: documents/models.py:363 msgid "rule type" @@ -378,11 +378,11 @@ msgstr "Tipo de arquivo %(type)s não suportado" #: documents/templates/index.html:22 msgid "Paperless-ngx is loading..." -msgstr "" +msgstr "Paperless-ngx está carregando..." #: documents/templates/registration/logged_out.html:14 msgid "Paperless-ngx signed out" -msgstr "" +msgstr "Paperless-ngx saiu" #: documents/templates/registration/logged_out.html:59 msgid "You have been successfully logged out. Bye!" @@ -394,7 +394,7 @@ msgstr "Entre novamente" #: documents/templates/registration/login.html:15 msgid "Paperless-ngx sign in" -msgstr "" +msgstr "Entrar no Paperless-ngx" #: documents/templates/registration/login.html:61 msgid "Please sign in." @@ -422,11 +422,11 @@ msgstr "Inglês (EUA)" #: paperless/settings.py:300 msgid "Czech" -msgstr "" +msgstr "Tcheco" #: paperless/settings.py:301 msgid "Danish" -msgstr "" +msgstr "Dinamarquês" #: paperless/settings.py:302 msgid "German" @@ -450,7 +450,7 @@ msgstr "Italiano" #: paperless/settings.py:307 msgid "Luxembourgish" -msgstr "" +msgstr "Luxemburguês" #: paperless/settings.py:308 msgid "Dutch" @@ -482,7 +482,7 @@ msgstr "Sueco" #: paperless/urls.py:139 msgid "Paperless-ngx administration" -msgstr "" +msgstr "Administração do Paperless-ngx" #: paperless_mail/admin.py:29 msgid "Authentication" diff --git a/src/locale/pt_PT/LC_MESSAGES/django.po b/src/locale/pt_PT/LC_MESSAGES/django.po index 3a8e84796..1626df8b6 100644 --- a/src/locale/pt_PT/LC_MESSAGES/django.po +++ b/src/locale/pt_PT/LC_MESSAGES/django.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: paperless-ngx\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-03-02 11:20-0800\n" -"PO-Revision-Date: 2022-03-02 22:29\n" +"PO-Revision-Date: 2022-03-11 10:59\n" "Last-Translator: \n" "Language-Team: Portuguese\n" "Language: pt_PT\n" @@ -344,7 +344,7 @@ msgstr "mais como este" #: documents/models.py:353 msgid "has tags in" -msgstr "" +msgstr "tem etiquetas em" #: documents/models.py:363 msgid "rule type" @@ -378,11 +378,11 @@ msgstr "Tipo de arquivo %(type)s não suportado" #: documents/templates/index.html:22 msgid "Paperless-ngx is loading..." -msgstr "" +msgstr "O Paperless-ngx está a carregar..." #: documents/templates/registration/logged_out.html:14 msgid "Paperless-ngx signed out" -msgstr "" +msgstr "Paperless-ngx com sessão terminada" #: documents/templates/registration/logged_out.html:59 msgid "You have been successfully logged out. Bye!" @@ -394,7 +394,7 @@ msgstr "Iniciar sessão novamente" #: documents/templates/registration/login.html:15 msgid "Paperless-ngx sign in" -msgstr "" +msgstr "Início de sessão Paperless-ngx" #: documents/templates/registration/login.html:61 msgid "Please sign in." @@ -422,11 +422,11 @@ msgstr "Inglês (EUA)" #: paperless/settings.py:300 msgid "Czech" -msgstr "" +msgstr "Checo" #: paperless/settings.py:301 msgid "Danish" -msgstr "" +msgstr "Dinamarquês" #: paperless/settings.py:302 msgid "German" @@ -450,7 +450,7 @@ msgstr "Italiano" #: paperless/settings.py:307 msgid "Luxembourgish" -msgstr "" +msgstr "Luxemburguês" #: paperless/settings.py:308 msgid "Dutch" @@ -482,7 +482,7 @@ msgstr "Sueco" #: paperless/urls.py:139 msgid "Paperless-ngx administration" -msgstr "" +msgstr "Administração do Paperless-ngx" #: paperless_mail/admin.py:29 msgid "Authentication" diff --git a/src/locale/ro_RO/LC_MESSAGES/django.po b/src/locale/ro_RO/LC_MESSAGES/django.po index 823a9178a..9b8cb8ba4 100644 --- a/src/locale/ro_RO/LC_MESSAGES/django.po +++ b/src/locale/ro_RO/LC_MESSAGES/django.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: paperless-ngx\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-03-02 11:20-0800\n" -"PO-Revision-Date: 2022-03-02 22:28\n" +"PO-Revision-Date: 2022-03-14 13:34\n" "Last-Translator: \n" "Language-Team: Romanian\n" "Language: ro_RO\n" @@ -180,7 +180,7 @@ msgstr "PoziÈ›ia acestui document in arhiva fizica." #: documents/models.py:201 msgid "document" -msgstr "" +msgstr "document" #: documents/models.py:202 msgid "documents" @@ -344,7 +344,7 @@ msgstr "mai multe ca aceasta" #: documents/models.py:353 msgid "has tags in" -msgstr "" +msgstr "are etichete în" #: documents/models.py:363 msgid "rule type" @@ -378,11 +378,11 @@ msgstr "Tip de fiÈ™ier %(type)s nesuportat" #: documents/templates/index.html:22 msgid "Paperless-ngx is loading..." -msgstr "" +msgstr "Paperless-ngx se încarcă..." #: documents/templates/registration/logged_out.html:14 msgid "Paperless-ngx signed out" -msgstr "" +msgstr "Paperless-ngx s-a deconectat" #: documents/templates/registration/logged_out.html:59 msgid "You have been successfully logged out. Bye!" @@ -394,7 +394,7 @@ msgstr "ConectaÈ›i-vă din nou" #: documents/templates/registration/login.html:15 msgid "Paperless-ngx sign in" -msgstr "" +msgstr "Conectare Paperless-ngx" #: documents/templates/registration/login.html:61 msgid "Please sign in." @@ -422,11 +422,11 @@ msgstr "Engleză (Americană)" #: paperless/settings.py:300 msgid "Czech" -msgstr "" +msgstr "Cehă" #: paperless/settings.py:301 msgid "Danish" -msgstr "" +msgstr "Daneză" #: paperless/settings.py:302 msgid "German" @@ -450,7 +450,7 @@ msgstr "Italiană" #: paperless/settings.py:307 msgid "Luxembourgish" -msgstr "" +msgstr "Luxemburgheză" #: paperless/settings.py:308 msgid "Dutch" @@ -482,7 +482,7 @@ msgstr "Suedeză" #: paperless/urls.py:139 msgid "Paperless-ngx administration" -msgstr "" +msgstr "Administrare Paperless-ngx" #: paperless_mail/admin.py:29 msgid "Authentication" diff --git a/src/locale/ru_RU/LC_MESSAGES/django.po b/src/locale/ru_RU/LC_MESSAGES/django.po index de75294f1..af4a4316e 100644 --- a/src/locale/ru_RU/LC_MESSAGES/django.po +++ b/src/locale/ru_RU/LC_MESSAGES/django.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: paperless-ngx\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-03-02 11:20-0800\n" -"PO-Revision-Date: 2022-03-02 22:29\n" +"PO-Revision-Date: 2022-03-30 11:46\n" "Last-Translator: \n" "Language-Team: Russian\n" "Language: ru_RU\n" @@ -344,7 +344,7 @@ msgstr "больше похожих" #: documents/models.py:353 msgid "has tags in" -msgstr "" +msgstr "имеет теги в" #: documents/models.py:363 msgid "rule type" @@ -378,11 +378,11 @@ msgstr "Тип файла %(type)s не поддерживаетÑÑ" #: documents/templates/index.html:22 msgid "Paperless-ngx is loading..." -msgstr "" +msgstr "Paperless-ngx загружаетÑÑ..." #: documents/templates/registration/logged_out.html:14 msgid "Paperless-ngx signed out" -msgstr "" +msgstr "Выполнен выход из Paperless-ngx" #: documents/templates/registration/logged_out.html:59 msgid "You have been successfully logged out. Bye!" @@ -394,7 +394,7 @@ msgstr "Войти Ñнова" #: documents/templates/registration/login.html:15 msgid "Paperless-ngx sign in" -msgstr "" +msgstr "Войти в Paperless-ngx" #: documents/templates/registration/login.html:61 msgid "Please sign in." @@ -422,11 +422,11 @@ msgstr "ÐнглийÑкий (СШÐ)" #: paperless/settings.py:300 msgid "Czech" -msgstr "" +msgstr "ЧешÑкий" #: paperless/settings.py:301 msgid "Danish" -msgstr "" +msgstr "ДатÑкий" #: paperless/settings.py:302 msgid "German" @@ -446,11 +446,11 @@ msgstr "ФранцузÑкий" #: paperless/settings.py:306 msgid "Italian" -msgstr "" +msgstr "ИтальÑнÑкий" #: paperless/settings.py:307 msgid "Luxembourgish" -msgstr "" +msgstr "ЛюкÑембургÑкий" #: paperless/settings.py:308 msgid "Dutch" @@ -462,7 +462,7 @@ msgstr "ПольÑкий" #: paperless/settings.py:310 msgid "Portuguese (Brazil)" -msgstr "" +msgstr "ПортугальÑкий (БразилиÑ)" #: paperless/settings.py:311 msgid "Portuguese" @@ -470,7 +470,7 @@ msgstr "ПортугальÑкий" #: paperless/settings.py:312 msgid "Romanian" -msgstr "" +msgstr "РумынÑкий" #: paperless/settings.py:313 msgid "Russian" @@ -482,7 +482,7 @@ msgstr "ШведÑкий" #: paperless/urls.py:139 msgid "Paperless-ngx administration" -msgstr "" +msgstr "ÐдминиÑтрирование Paperless-ngx" #: paperless_mail/admin.py:29 msgid "Authentication" diff --git a/src/locale/sk_SK/LC_MESSAGES/django.po b/src/locale/sk_SK/LC_MESSAGES/django.po new file mode 100644 index 000000000..8e9383a2a --- /dev/null +++ b/src/locale/sk_SK/LC_MESSAGES/django.po @@ -0,0 +1,714 @@ +msgid "" +msgstr "" +"Project-Id-Version: paperless-ngx\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-03-02 11:20-0800\n" +"PO-Revision-Date: 2022-03-12 18:21\n" +"Last-Translator: \n" +"Language-Team: Slovak\n" +"Language: sk_SK\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 3;\n" +"X-Crowdin-Project: paperless-ngx\n" +"X-Crowdin-Project-ID: 500308\n" +"X-Crowdin-Language: sk\n" +"X-Crowdin-File: /dev/src/locale/en_US/LC_MESSAGES/django.po\n" +"X-Crowdin-File-ID: 14\n" + +#: documents/apps.py:10 +msgid "Documents" +msgstr "Dokumenty" + +#: documents/models.py:32 +msgid "Any word" +msgstr "Akékoľvek slovo" + +#: documents/models.py:33 +msgid "All words" +msgstr "VÅ¡etky slová" + +#: documents/models.py:34 +msgid "Exact match" +msgstr "Presná zhoda" + +#: documents/models.py:35 +msgid "Regular expression" +msgstr "Normálny výraz" + +#: documents/models.py:36 +msgid "Fuzzy word" +msgstr "Nejasné slovo" + +#: documents/models.py:37 +msgid "Automatic" +msgstr "Automatické" + +#: documents/models.py:40 documents/models.py:314 paperless_mail/models.py:23 +#: paperless_mail/models.py:107 +msgid "name" +msgstr "meno" + +#: documents/models.py:42 +msgid "match" +msgstr "zhoda" + +#: documents/models.py:45 +msgid "matching algorithm" +msgstr "zhodový algoritmus" + +#: documents/models.py:48 +msgid "is insensitive" +msgstr "je necitlivý" + +#: documents/models.py:61 documents/models.py:104 +msgid "correspondent" +msgstr "koreÅ¡pondencia" + +#: documents/models.py:62 +msgid "correspondents" +msgstr "zodpovedá" + +#: documents/models.py:67 +msgid "color" +msgstr "farba" + +#: documents/models.py:70 +msgid "is inbox tag" +msgstr "je Å¡títok poÅ¡ty" + +#: documents/models.py:73 +msgid "Marks this tag as an inbox tag: All newly consumed documents will be tagged with inbox tags." +msgstr "OznaÄí tento Å¡títok ako Å¡títok doruÄenej poÅ¡ty: VÅ¡etky novo spotrebované dokumenty budú oznaÄené Å¡títkami doruÄenej poÅ¡ty." + +#: documents/models.py:79 +msgid "tag" +msgstr "Å¡títok" + +#: documents/models.py:80 documents/models.py:130 +msgid "tags" +msgstr "Å¡títky" + +#: documents/models.py:85 documents/models.py:115 +msgid "document type" +msgstr "typ dokumentu" + +#: documents/models.py:86 +msgid "document types" +msgstr "typy dokumentov" + +#: documents/models.py:94 +msgid "Unencrypted" +msgstr "NeÅ¡ifrované" + +#: documents/models.py:95 +msgid "Encrypted with GNU Privacy Guard" +msgstr "Å ifrované pomocou GNU Privacy Guard" + +#: documents/models.py:107 +msgid "title" +msgstr "názov" + +#: documents/models.py:119 +msgid "content" +msgstr "obsah" + +#: documents/models.py:122 +msgid "The raw, text-only data of the document. This field is primarily used for searching." +msgstr "Nespracované, iba textové údaje dokumentu. Toto pole sa primárne používa na vyhľadávanie." + +#: documents/models.py:127 +msgid "mime type" +msgstr "" + +#: documents/models.py:134 +msgid "checksum" +msgstr "kontrolný súÄet" + +#: documents/models.py:138 +msgid "The checksum of the original document." +msgstr "Kontrolný súÄet originálneho dokumentu." + +#: documents/models.py:142 +msgid "archive checksum" +msgstr "archivovaÅ¥ kontrolný súÄet" + +#: documents/models.py:147 +msgid "The checksum of the archived document." +msgstr "Kontrolný súÄet archivovaného dokumentu." + +#: documents/models.py:150 documents/models.py:295 +msgid "created" +msgstr "vytovrené" + +#: documents/models.py:153 +msgid "modified" +msgstr "upravené" + +#: documents/models.py:157 +msgid "storage type" +msgstr "typ úložiska" + +#: documents/models.py:165 +msgid "added" +msgstr "pridané" + +#: documents/models.py:169 +msgid "filename" +msgstr "názov súboru" + +#: documents/models.py:175 +msgid "Current filename in storage" +msgstr "Aktuálny názov dokumentu v úložisku" + +#: documents/models.py:179 +msgid "archive filename" +msgstr "archovovaÅ¥ názov súboru" + +#: documents/models.py:185 +msgid "Current archive filename in storage" +msgstr "Aktuálny archovivaný názov dokumentu v úložisku" + +#: documents/models.py:189 +msgid "archive serial number" +msgstr "archivovaÅ¥ sériové Äíslo" + +#: documents/models.py:195 +msgid "The position of this document in your physical document archive." +msgstr "" + +#: documents/models.py:201 +msgid "document" +msgstr "" + +#: documents/models.py:202 +msgid "documents" +msgstr "" + +#: documents/models.py:280 +msgid "debug" +msgstr "" + +#: documents/models.py:281 +msgid "information" +msgstr "" + +#: documents/models.py:282 +msgid "warning" +msgstr "" + +#: documents/models.py:283 +msgid "error" +msgstr "" + +#: documents/models.py:284 +msgid "critical" +msgstr "" + +#: documents/models.py:287 +msgid "group" +msgstr "" + +#: documents/models.py:289 +msgid "message" +msgstr "" + +#: documents/models.py:292 +msgid "level" +msgstr "" + +#: documents/models.py:299 +msgid "log" +msgstr "" + +#: documents/models.py:300 +msgid "logs" +msgstr "" + +#: documents/models.py:310 documents/models.py:360 +msgid "saved view" +msgstr "" + +#: documents/models.py:311 +msgid "saved views" +msgstr "" + +#: documents/models.py:313 +msgid "user" +msgstr "" + +#: documents/models.py:317 +msgid "show on dashboard" +msgstr "" + +#: documents/models.py:320 +msgid "show in sidebar" +msgstr "" + +#: documents/models.py:324 +msgid "sort field" +msgstr "" + +#: documents/models.py:326 +msgid "sort reverse" +msgstr "" + +#: documents/models.py:331 +msgid "title contains" +msgstr "" + +#: documents/models.py:332 +msgid "content contains" +msgstr "" + +#: documents/models.py:333 +msgid "ASN is" +msgstr "" + +#: documents/models.py:334 +msgid "correspondent is" +msgstr "" + +#: documents/models.py:335 +msgid "document type is" +msgstr "" + +#: documents/models.py:336 +msgid "is in inbox" +msgstr "" + +#: documents/models.py:337 +msgid "has tag" +msgstr "" + +#: documents/models.py:338 +msgid "has any tag" +msgstr "" + +#: documents/models.py:339 +msgid "created before" +msgstr "" + +#: documents/models.py:340 +msgid "created after" +msgstr "" + +#: documents/models.py:341 +msgid "created year is" +msgstr "" + +#: documents/models.py:342 +msgid "created month is" +msgstr "" + +#: documents/models.py:343 +msgid "created day is" +msgstr "" + +#: documents/models.py:344 +msgid "added before" +msgstr "" + +#: documents/models.py:345 +msgid "added after" +msgstr "" + +#: documents/models.py:346 +msgid "modified before" +msgstr "" + +#: documents/models.py:347 +msgid "modified after" +msgstr "" + +#: documents/models.py:348 +msgid "does not have tag" +msgstr "" + +#: documents/models.py:349 +msgid "does not have ASN" +msgstr "" + +#: documents/models.py:350 +msgid "title or content contains" +msgstr "" + +#: documents/models.py:351 +msgid "fulltext query" +msgstr "" + +#: documents/models.py:352 +msgid "more like this" +msgstr "" + +#: documents/models.py:353 +msgid "has tags in" +msgstr "" + +#: documents/models.py:363 +msgid "rule type" +msgstr "" + +#: documents/models.py:365 +msgid "value" +msgstr "" + +#: documents/models.py:368 +msgid "filter rule" +msgstr "" + +#: documents/models.py:369 +msgid "filter rules" +msgstr "" + +#: documents/serialisers.py:64 +#, python-format +msgid "Invalid regular expression: %(error)s" +msgstr "" + +#: documents/serialisers.py:185 +msgid "Invalid color." +msgstr "" + +#: documents/serialisers.py:459 +#, python-format +msgid "File type %(type)s not supported" +msgstr "" + +#: documents/templates/index.html:22 +msgid "Paperless-ngx is loading..." +msgstr "" + +#: documents/templates/registration/logged_out.html:14 +msgid "Paperless-ngx signed out" +msgstr "" + +#: documents/templates/registration/logged_out.html:59 +msgid "You have been successfully logged out. Bye!" +msgstr "" + +#: documents/templates/registration/logged_out.html:60 +msgid "Sign in again" +msgstr "" + +#: documents/templates/registration/login.html:15 +msgid "Paperless-ngx sign in" +msgstr "" + +#: documents/templates/registration/login.html:61 +msgid "Please sign in." +msgstr "" + +#: documents/templates/registration/login.html:64 +msgid "Your username and password didn't match. Please try again." +msgstr "" + +#: documents/templates/registration/login.html:67 +msgid "Username" +msgstr "" + +#: documents/templates/registration/login.html:68 +msgid "Password" +msgstr "" + +#: documents/templates/registration/login.html:73 +msgid "Sign in" +msgstr "" + +#: paperless/settings.py:299 +msgid "English (US)" +msgstr "" + +#: paperless/settings.py:300 +msgid "Czech" +msgstr "" + +#: paperless/settings.py:301 +msgid "Danish" +msgstr "" + +#: paperless/settings.py:302 +msgid "German" +msgstr "" + +#: paperless/settings.py:303 +msgid "English (GB)" +msgstr "" + +#: paperless/settings.py:304 +msgid "Spanish" +msgstr "" + +#: paperless/settings.py:305 +msgid "French" +msgstr "" + +#: paperless/settings.py:306 +msgid "Italian" +msgstr "" + +#: paperless/settings.py:307 +msgid "Luxembourgish" +msgstr "" + +#: paperless/settings.py:308 +msgid "Dutch" +msgstr "" + +#: paperless/settings.py:309 +msgid "Polish" +msgstr "" + +#: paperless/settings.py:310 +msgid "Portuguese (Brazil)" +msgstr "" + +#: paperless/settings.py:311 +msgid "Portuguese" +msgstr "" + +#: paperless/settings.py:312 +msgid "Romanian" +msgstr "" + +#: paperless/settings.py:313 +msgid "Russian" +msgstr "" + +#: paperless/settings.py:314 +msgid "Swedish" +msgstr "" + +#: paperless/urls.py:139 +msgid "Paperless-ngx administration" +msgstr "" + +#: paperless_mail/admin.py:29 +msgid "Authentication" +msgstr "" + +#: paperless_mail/admin.py:30 +msgid "Advanced settings" +msgstr "" + +#: paperless_mail/admin.py:47 +msgid "Filter" +msgstr "" + +#: paperless_mail/admin.py:50 +msgid "Paperless will only process mails that match ALL of the filters given below." +msgstr "" + +#: paperless_mail/admin.py:64 +msgid "Actions" +msgstr "" + +#: paperless_mail/admin.py:67 +msgid "The action applied to the mail. This action is only performed when documents were consumed from the mail. Mails without attachments will remain entirely untouched." +msgstr "" + +#: paperless_mail/admin.py:75 +msgid "Metadata" +msgstr "" + +#: paperless_mail/admin.py:78 +msgid "Assign metadata to documents consumed from this rule automatically. If you do not assign tags, types or correspondents here, paperless will still process all matching rules that you have defined." +msgstr "" + +#: paperless_mail/apps.py:9 +msgid "Paperless mail" +msgstr "" + +#: paperless_mail/models.py:10 +msgid "mail account" +msgstr "" + +#: paperless_mail/models.py:11 +msgid "mail accounts" +msgstr "" + +#: paperless_mail/models.py:18 +msgid "No encryption" +msgstr "" + +#: paperless_mail/models.py:19 +msgid "Use SSL" +msgstr "" + +#: paperless_mail/models.py:20 +msgid "Use STARTTLS" +msgstr "" + +#: paperless_mail/models.py:25 +msgid "IMAP server" +msgstr "" + +#: paperless_mail/models.py:28 +msgid "IMAP port" +msgstr "" + +#: paperless_mail/models.py:32 +msgid "This is usually 143 for unencrypted and STARTTLS connections, and 993 for SSL connections." +msgstr "" + +#: paperless_mail/models.py:38 +msgid "IMAP security" +msgstr "" + +#: paperless_mail/models.py:41 +msgid "username" +msgstr "" + +#: paperless_mail/models.py:43 +msgid "password" +msgstr "" + +#: paperless_mail/models.py:46 +msgid "character set" +msgstr "" + +#: paperless_mail/models.py:50 +msgid "The character set to use when communicating with the mail server, such as 'UTF-8' or 'US-ASCII'." +msgstr "" + +#: paperless_mail/models.py:61 +msgid "mail rule" +msgstr "" + +#: paperless_mail/models.py:62 +msgid "mail rules" +msgstr "" + +#: paperless_mail/models.py:68 +msgid "Only process attachments." +msgstr "" + +#: paperless_mail/models.py:71 +msgid "Process all files, including 'inline' attachments." +msgstr "" + +#: paperless_mail/models.py:81 +msgid "Mark as read, don't process read mails" +msgstr "" + +#: paperless_mail/models.py:82 +msgid "Flag the mail, don't process flagged mails" +msgstr "" + +#: paperless_mail/models.py:83 +msgid "Move to specified folder" +msgstr "" + +#: paperless_mail/models.py:84 +msgid "Delete" +msgstr "" + +#: paperless_mail/models.py:91 +msgid "Use subject as title" +msgstr "" + +#: paperless_mail/models.py:92 +msgid "Use attachment filename as title" +msgstr "" + +#: paperless_mail/models.py:101 +msgid "Do not assign a correspondent" +msgstr "" + +#: paperless_mail/models.py:102 +msgid "Use mail address" +msgstr "" + +#: paperless_mail/models.py:103 +msgid "Use name (or mail address if not available)" +msgstr "" + +#: paperless_mail/models.py:104 +msgid "Use correspondent selected below" +msgstr "" + +#: paperless_mail/models.py:109 +msgid "order" +msgstr "" + +#: paperless_mail/models.py:115 +msgid "account" +msgstr "" + +#: paperless_mail/models.py:119 +msgid "folder" +msgstr "" + +#: paperless_mail/models.py:122 +msgid "Subfolders must be separated by dots." +msgstr "" + +#: paperless_mail/models.py:126 +msgid "filter from" +msgstr "" + +#: paperless_mail/models.py:129 +msgid "filter subject" +msgstr "" + +#: paperless_mail/models.py:132 +msgid "filter body" +msgstr "" + +#: paperless_mail/models.py:136 +msgid "filter attachment filename" +msgstr "" + +#: paperless_mail/models.py:141 +msgid "Only consume documents which entirely match this filename if specified. Wildcards such as *.pdf or *invoice* are allowed. Case insensitive." +msgstr "" + +#: paperless_mail/models.py:148 +msgid "maximum age" +msgstr "" + +#: paperless_mail/models.py:148 +msgid "Specified in days." +msgstr "" + +#: paperless_mail/models.py:152 +msgid "attachment type" +msgstr "" + +#: paperless_mail/models.py:156 +msgid "Inline attachments include embedded images, so it's best to combine this option with a filename filter." +msgstr "" + +#: paperless_mail/models.py:162 +msgid "action" +msgstr "" + +#: paperless_mail/models.py:168 +msgid "action parameter" +msgstr "" + +#: paperless_mail/models.py:173 +msgid "Additional parameter for the action selected above, i.e., the target folder of the move to folder action. Subfolders must be separated by dots." +msgstr "" + +#: paperless_mail/models.py:181 +msgid "assign title from" +msgstr "" + +#: paperless_mail/models.py:189 +msgid "assign this tag" +msgstr "" + +#: paperless_mail/models.py:197 +msgid "assign this document type" +msgstr "" + +#: paperless_mail/models.py:201 +msgid "assign correspondent from" +msgstr "" + +#: paperless_mail/models.py:211 +msgid "assign this correspondent" +msgstr "" + diff --git a/src/locale/sl_SI/LC_MESSAGES/django.po b/src/locale/sl_SI/LC_MESSAGES/django.po index 651136b87..90f95dad3 100644 --- a/src/locale/sl_SI/LC_MESSAGES/django.po +++ b/src/locale/sl_SI/LC_MESSAGES/django.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: paperless-ngx\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-03-02 11:20-0800\n" -"PO-Revision-Date: 2022-03-02 22:29\n" +"PO-Revision-Date: 2022-03-14 16:48\n" "Last-Translator: \n" "Language-Team: Slovenian\n" "Language: sl_SI\n" @@ -35,680 +35,680 @@ msgstr "ToÄno ujemanje" #: documents/models.py:35 msgid "Regular expression" -msgstr "" +msgstr "Regularni izraz" #: documents/models.py:36 msgid "Fuzzy word" -msgstr "" +msgstr "Fuzzy beseda" #: documents/models.py:37 msgid "Automatic" -msgstr "" +msgstr "Samodejno" #: documents/models.py:40 documents/models.py:314 paperless_mail/models.py:23 #: paperless_mail/models.py:107 msgid "name" -msgstr "" +msgstr "ime" #: documents/models.py:42 msgid "match" -msgstr "" +msgstr "ujemanje" #: documents/models.py:45 msgid "matching algorithm" -msgstr "" +msgstr "algoritem ujemanja" #: documents/models.py:48 msgid "is insensitive" -msgstr "" +msgstr "brez razlikovanje velikosti Ärk" #: documents/models.py:61 documents/models.py:104 msgid "correspondent" -msgstr "" +msgstr "dopisnik" #: documents/models.py:62 msgid "correspondents" -msgstr "" +msgstr "dopisniki" #: documents/models.py:67 msgid "color" -msgstr "" +msgstr "barva" #: documents/models.py:70 msgid "is inbox tag" -msgstr "" +msgstr "je vhodna oznaka" #: documents/models.py:73 msgid "Marks this tag as an inbox tag: All newly consumed documents will be tagged with inbox tags." -msgstr "" +msgstr "OznaÄi to oznako kot vhodno oznako: vsi na novo obdelani dokumenti bodo oznaÄeni z vhodno oznako." #: documents/models.py:79 msgid "tag" -msgstr "" +msgstr "oznaka" #: documents/models.py:80 documents/models.py:130 msgid "tags" -msgstr "" +msgstr "oznake" #: documents/models.py:85 documents/models.py:115 msgid "document type" -msgstr "" +msgstr "vrsta dokumenta" #: documents/models.py:86 msgid "document types" -msgstr "" +msgstr "vrste dokumentov" #: documents/models.py:94 msgid "Unencrypted" -msgstr "" +msgstr "NeÅ¡ifrirano" #: documents/models.py:95 msgid "Encrypted with GNU Privacy Guard" -msgstr "" +msgstr "Å ifrirano z GNU Privacy Guard" #: documents/models.py:107 msgid "title" -msgstr "" +msgstr "naslov" #: documents/models.py:119 msgid "content" -msgstr "" +msgstr "vsebina" #: documents/models.py:122 msgid "The raw, text-only data of the document. This field is primarily used for searching." -msgstr "" +msgstr "Neobdelani besedilni podatki dokumenta. To polje se uporablja predvsem za iskanje." #: documents/models.py:127 msgid "mime type" -msgstr "" +msgstr "vrsta mime" #: documents/models.py:134 msgid "checksum" -msgstr "" +msgstr "kontrolna vsota" #: documents/models.py:138 msgid "The checksum of the original document." -msgstr "" +msgstr "Kontrolna vsota izvirnega dokumenta." #: documents/models.py:142 msgid "archive checksum" -msgstr "" +msgstr "arhivska kontrolna vsota" #: documents/models.py:147 msgid "The checksum of the archived document." -msgstr "" +msgstr "Kontrolna vsota arhiviranega dokumenta." #: documents/models.py:150 documents/models.py:295 msgid "created" -msgstr "" +msgstr "ustvarjeno" #: documents/models.py:153 msgid "modified" -msgstr "" +msgstr "spremenjeno" #: documents/models.py:157 msgid "storage type" -msgstr "" +msgstr "vrsta shrambe" #: documents/models.py:165 msgid "added" -msgstr "" +msgstr "dodano" #: documents/models.py:169 msgid "filename" -msgstr "" +msgstr "ime datoteke" #: documents/models.py:175 msgid "Current filename in storage" -msgstr "" +msgstr "Trenutno ime dokumenta v shrambi" #: documents/models.py:179 msgid "archive filename" -msgstr "" +msgstr "ime arhivske datoteke" #: documents/models.py:185 msgid "Current archive filename in storage" -msgstr "" +msgstr "Trenutno ime arhivske datoteke v shrambi" #: documents/models.py:189 msgid "archive serial number" -msgstr "" +msgstr "arhivska serijska Å¡tevilka" #: documents/models.py:195 msgid "The position of this document in your physical document archive." -msgstr "" +msgstr "Položaj tega dokumenta v vaÅ¡em fiziÄnem arhivu dokumentov." #: documents/models.py:201 msgid "document" -msgstr "" +msgstr "dokument" #: documents/models.py:202 msgid "documents" -msgstr "" +msgstr "dokumenti" #: documents/models.py:280 msgid "debug" -msgstr "" +msgstr "razhroÅ¡Äevanje" #: documents/models.py:281 msgid "information" -msgstr "" +msgstr "informacija" #: documents/models.py:282 msgid "warning" -msgstr "" +msgstr "opozorilo" #: documents/models.py:283 msgid "error" -msgstr "" +msgstr "napaka" #: documents/models.py:284 msgid "critical" -msgstr "" +msgstr "kritiÄno" #: documents/models.py:287 msgid "group" -msgstr "" +msgstr "skupina" #: documents/models.py:289 msgid "message" -msgstr "" +msgstr "sporoÄilo" #: documents/models.py:292 msgid "level" -msgstr "" +msgstr "nivo" #: documents/models.py:299 msgid "log" -msgstr "" +msgstr "dnevnik" #: documents/models.py:300 msgid "logs" -msgstr "" +msgstr "dnevniki" #: documents/models.py:310 documents/models.py:360 msgid "saved view" -msgstr "" +msgstr "shranjeni pogled" #: documents/models.py:311 msgid "saved views" -msgstr "" +msgstr "shranjeni pogledi" #: documents/models.py:313 msgid "user" -msgstr "" +msgstr "uporabnik" #: documents/models.py:317 msgid "show on dashboard" -msgstr "" +msgstr "prikaži na pregledni ploÅ¡Äi" #: documents/models.py:320 msgid "show in sidebar" -msgstr "" +msgstr "prikaži v stranski vrstici" #: documents/models.py:324 msgid "sort field" -msgstr "" +msgstr "polje za razvrÅ¡Äanje" #: documents/models.py:326 msgid "sort reverse" -msgstr "" +msgstr "razvrsti obratno" #: documents/models.py:331 msgid "title contains" -msgstr "" +msgstr "naslov vsebuje" #: documents/models.py:332 msgid "content contains" -msgstr "" +msgstr "vsebina vsebuje" #: documents/models.py:333 msgid "ASN is" -msgstr "" +msgstr "ASN je" #: documents/models.py:334 msgid "correspondent is" -msgstr "" +msgstr "dopisnik je" #: documents/models.py:335 msgid "document type is" -msgstr "" +msgstr "vrsta dokumenta je" #: documents/models.py:336 msgid "is in inbox" -msgstr "" +msgstr "je v prejetem" #: documents/models.py:337 msgid "has tag" -msgstr "" +msgstr "ima oznako" #: documents/models.py:338 msgid "has any tag" -msgstr "" +msgstr "ima katero koli oznako" #: documents/models.py:339 msgid "created before" -msgstr "" +msgstr "ustvarjeno pred" #: documents/models.py:340 msgid "created after" -msgstr "" +msgstr "ustvarjeno po" #: documents/models.py:341 msgid "created year is" -msgstr "" +msgstr "leto nastanka" #: documents/models.py:342 msgid "created month is" -msgstr "" +msgstr "mesec nastanka" #: documents/models.py:343 msgid "created day is" -msgstr "" +msgstr "dan nastanka" #: documents/models.py:344 msgid "added before" -msgstr "" +msgstr "dodano pred" #: documents/models.py:345 msgid "added after" -msgstr "" +msgstr "dodano po" #: documents/models.py:346 msgid "modified before" -msgstr "" +msgstr "spremenjeno pred" #: documents/models.py:347 msgid "modified after" -msgstr "" +msgstr "spremenjeno po" #: documents/models.py:348 msgid "does not have tag" -msgstr "" +msgstr "nima oznake" #: documents/models.py:349 msgid "does not have ASN" -msgstr "" +msgstr "nima ASN" #: documents/models.py:350 msgid "title or content contains" -msgstr "" +msgstr "naslov ali vsebina vsebujeta" #: documents/models.py:351 msgid "fulltext query" -msgstr "" +msgstr "polnobesedilna poizvedba" #: documents/models.py:352 msgid "more like this" -msgstr "" +msgstr "veÄ takih" #: documents/models.py:353 msgid "has tags in" -msgstr "" +msgstr "ima oznake" #: documents/models.py:363 msgid "rule type" -msgstr "" +msgstr "vrsta pravila" #: documents/models.py:365 msgid "value" -msgstr "" +msgstr "vrednost" #: documents/models.py:368 msgid "filter rule" -msgstr "" +msgstr "filtriraj pravilo" #: documents/models.py:369 msgid "filter rules" -msgstr "" +msgstr "filtriraj pravila" #: documents/serialisers.py:64 #, python-format msgid "Invalid regular expression: %(error)s" -msgstr "" +msgstr "Neveljaven sploÅ¡en izraz: %(error)s" #: documents/serialisers.py:185 msgid "Invalid color." -msgstr "" +msgstr "NapaÄna barva." #: documents/serialisers.py:459 #, python-format msgid "File type %(type)s not supported" -msgstr "" +msgstr "Vrsta datoteke %(type)s ni podprta" #: documents/templates/index.html:22 msgid "Paperless-ngx is loading..." -msgstr "" +msgstr "Paperless-ngx se nalaga..." #: documents/templates/registration/logged_out.html:14 msgid "Paperless-ngx signed out" -msgstr "" +msgstr "Paperless-ngx odjavljen" #: documents/templates/registration/logged_out.html:59 msgid "You have been successfully logged out. Bye!" -msgstr "" +msgstr "UspeÅ¡no ste bili odjavljeni. Adijo!" #: documents/templates/registration/logged_out.html:60 msgid "Sign in again" -msgstr "" +msgstr "Ponovno se prijavite" #: documents/templates/registration/login.html:15 msgid "Paperless-ngx sign in" -msgstr "" +msgstr "Paperless-ngx prijava" #: documents/templates/registration/login.html:61 msgid "Please sign in." -msgstr "" +msgstr "Prosimo, prijavite se." #: documents/templates/registration/login.html:64 msgid "Your username and password didn't match. Please try again." -msgstr "" +msgstr "VaÅ¡e uporabniÅ¡ko ime in geslo se ne ujemata. Prosim poskusite ponovno." #: documents/templates/registration/login.html:67 msgid "Username" -msgstr "" +msgstr "UporabniÅ¡ko ime" #: documents/templates/registration/login.html:68 msgid "Password" -msgstr "" +msgstr "Geslo" #: documents/templates/registration/login.html:73 msgid "Sign in" -msgstr "" +msgstr "Prijava" #: paperless/settings.py:299 msgid "English (US)" -msgstr "" +msgstr "AngleÅ¡Äina (ZDA)" #: paperless/settings.py:300 msgid "Czech" -msgstr "" +msgstr "ÄŒeÅ¡Äina" #: paperless/settings.py:301 msgid "Danish" -msgstr "" +msgstr "DanÅ¡Äina" #: paperless/settings.py:302 msgid "German" -msgstr "" +msgstr "NemÅ¡Äina" #: paperless/settings.py:303 msgid "English (GB)" -msgstr "" +msgstr "AngleÅ¡Äina (GB)" #: paperless/settings.py:304 msgid "Spanish" -msgstr "" +msgstr "Å panÅ¡Äina" #: paperless/settings.py:305 msgid "French" -msgstr "" +msgstr "FrancoÅ¡Äina" #: paperless/settings.py:306 msgid "Italian" -msgstr "" +msgstr "ItalijanÅ¡Äina" #: paperless/settings.py:307 msgid "Luxembourgish" -msgstr "" +msgstr "LuksemburÅ¡ki" #: paperless/settings.py:308 msgid "Dutch" -msgstr "" +msgstr "NizozemÅ¡Äina" #: paperless/settings.py:309 msgid "Polish" -msgstr "" +msgstr "PoljÅ¡Äina" #: paperless/settings.py:310 msgid "Portuguese (Brazil)" -msgstr "" +msgstr "PortugalÅ¡Äina (Brazilija)" #: paperless/settings.py:311 msgid "Portuguese" -msgstr "" +msgstr "PortugalÅ¡Äina" #: paperless/settings.py:312 msgid "Romanian" -msgstr "" +msgstr "RomunÅ¡Äina" #: paperless/settings.py:313 msgid "Russian" -msgstr "" +msgstr "RuÅ¡Äina" #: paperless/settings.py:314 msgid "Swedish" -msgstr "" +msgstr "Å vedÅ¡Äina" #: paperless/urls.py:139 msgid "Paperless-ngx administration" -msgstr "" +msgstr "Paperless-ngx administracija" #: paperless_mail/admin.py:29 msgid "Authentication" -msgstr "" +msgstr "Avtentifikacija" #: paperless_mail/admin.py:30 msgid "Advanced settings" -msgstr "" +msgstr "Napredne nastavitve" #: paperless_mail/admin.py:47 msgid "Filter" -msgstr "" +msgstr "Filtriraj" #: paperless_mail/admin.py:50 msgid "Paperless will only process mails that match ALL of the filters given below." -msgstr "" +msgstr "Paperless bo obdelal samo e-poÅ¡tna sporoÄila, ki se ujemajo z VSEMI spodaj navedenimi filtri." #: paperless_mail/admin.py:64 msgid "Actions" -msgstr "" +msgstr "Dejanja" #: paperless_mail/admin.py:67 msgid "The action applied to the mail. This action is only performed when documents were consumed from the mail. Mails without attachments will remain entirely untouched." -msgstr "" +msgstr "Dejanje je veljalo za poÅ¡to. To dejanje se izvede samo, Äe so bili dokumenti uvoženi iz poÅ¡te. E-poÅ¡ta brez prilog bo ostala v celoti nedotaknjena." #: paperless_mail/admin.py:75 msgid "Metadata" -msgstr "" +msgstr "Metapodatki" #: paperless_mail/admin.py:78 msgid "Assign metadata to documents consumed from this rule automatically. If you do not assign tags, types or correspondents here, paperless will still process all matching rules that you have defined." -msgstr "" +msgstr "Samodejno dodelite metapodatke dokumentom, uporabljenim s tem pravilom. ÄŒe tukaj ne dodelite oznak, vrst ali korespondentov, bo paperless Å¡e vedno obdelal vsa ujemanja, ki ste jih definirali." #: paperless_mail/apps.py:9 msgid "Paperless mail" -msgstr "" +msgstr "Paperless poÅ¡ta" #: paperless_mail/models.py:10 msgid "mail account" -msgstr "" +msgstr "poÅ¡tni raÄun" #: paperless_mail/models.py:11 msgid "mail accounts" -msgstr "" +msgstr "poÅ¡tni raÄuni" #: paperless_mail/models.py:18 msgid "No encryption" -msgstr "" +msgstr "Brez Å¡ifriranja" #: paperless_mail/models.py:19 msgid "Use SSL" -msgstr "" +msgstr "Uporaba SSL" #: paperless_mail/models.py:20 msgid "Use STARTTLS" -msgstr "" +msgstr "Uporabi STARTTLS" #: paperless_mail/models.py:25 msgid "IMAP server" -msgstr "" +msgstr "IMAP strežnik" #: paperless_mail/models.py:28 msgid "IMAP port" -msgstr "" +msgstr "IMAP vrata" #: paperless_mail/models.py:32 msgid "This is usually 143 for unencrypted and STARTTLS connections, and 993 for SSL connections." -msgstr "" +msgstr "To je obiÄajno 143 za neÅ¡ifrirane in STARTTLS povezave ter 993 za povezave SSL." #: paperless_mail/models.py:38 msgid "IMAP security" -msgstr "" +msgstr "Varnost IMAP" #: paperless_mail/models.py:41 msgid "username" -msgstr "" +msgstr "uporabniÅ¡ko ime" #: paperless_mail/models.py:43 msgid "password" -msgstr "" +msgstr "geslo" #: paperless_mail/models.py:46 msgid "character set" -msgstr "" +msgstr "nabor znakov" #: paperless_mail/models.py:50 msgid "The character set to use when communicating with the mail server, such as 'UTF-8' or 'US-ASCII'." -msgstr "" +msgstr "Nabor znakov za uporabo pri komunikaciji s poÅ¡tnim strežnikom, na primer 'UTF-8' ali 'US-ASCII'." #: paperless_mail/models.py:61 msgid "mail rule" -msgstr "" +msgstr "poÅ¡tno pravilo" #: paperless_mail/models.py:62 msgid "mail rules" -msgstr "" +msgstr "poÅ¡tna pravila" #: paperless_mail/models.py:68 msgid "Only process attachments." -msgstr "" +msgstr "Obdelujte samo priloge." #: paperless_mail/models.py:71 msgid "Process all files, including 'inline' attachments." -msgstr "" +msgstr "Obdelajte vse datoteke, vkljuÄno z \"vgrajenimi\" prilogami." #: paperless_mail/models.py:81 msgid "Mark as read, don't process read mails" -msgstr "" +msgstr "OznaÄi kot prebrano, ne obdelujte prebrane poÅ¡te" #: paperless_mail/models.py:82 msgid "Flag the mail, don't process flagged mails" -msgstr "" +msgstr "OznaÄite poÅ¡to z zastavico, ne obdelujte oznaÄene poÅ¡te" #: paperless_mail/models.py:83 msgid "Move to specified folder" -msgstr "" +msgstr "Premakni v doloÄeno mapo" #: paperless_mail/models.py:84 msgid "Delete" -msgstr "" +msgstr "IzbriÅ¡i" #: paperless_mail/models.py:91 msgid "Use subject as title" -msgstr "" +msgstr "Uporabite zadevo kot naslov" #: paperless_mail/models.py:92 msgid "Use attachment filename as title" -msgstr "" +msgstr "Uporabite ime datoteke priloge kot naslov" #: paperless_mail/models.py:101 msgid "Do not assign a correspondent" -msgstr "" +msgstr "Ne dodelite dopisnika" #: paperless_mail/models.py:102 msgid "Use mail address" -msgstr "" +msgstr "Uporabite poÅ¡tni naslov" #: paperless_mail/models.py:103 msgid "Use name (or mail address if not available)" -msgstr "" +msgstr "Uporabi ime (ali e-poÅ¡tni naslov, Äe ime ni na voljo)" #: paperless_mail/models.py:104 msgid "Use correspondent selected below" -msgstr "" +msgstr "Uporabite dopisnika, izbranega spodaj" #: paperless_mail/models.py:109 msgid "order" -msgstr "" +msgstr "vrstni red" #: paperless_mail/models.py:115 msgid "account" -msgstr "" +msgstr "raÄun" #: paperless_mail/models.py:119 msgid "folder" -msgstr "" +msgstr "mapa" #: paperless_mail/models.py:122 msgid "Subfolders must be separated by dots." -msgstr "" +msgstr "Pod mape morajo biti loÄene s pikami." #: paperless_mail/models.py:126 msgid "filter from" -msgstr "" +msgstr "filtriraj prejeto" #: paperless_mail/models.py:129 msgid "filter subject" -msgstr "" +msgstr "filtriraj zadevo" #: paperless_mail/models.py:132 msgid "filter body" -msgstr "" +msgstr "filtriraj vsebino" #: paperless_mail/models.py:136 msgid "filter attachment filename" -msgstr "" +msgstr "filtriraj ime datoteke priloge" #: paperless_mail/models.py:141 msgid "Only consume documents which entirely match this filename if specified. Wildcards such as *.pdf or *invoice* are allowed. Case insensitive." -msgstr "" +msgstr "Uporabljajte samo dokumente, ki se v celoti ujemajo s tem imenom datoteke, Äe je navedeno. Dovoljeni so nadomestni znaki, kot sta *.pdf ali *raÄun*. NeobÄutljiva na velike in male Ärke." #: paperless_mail/models.py:148 msgid "maximum age" -msgstr "" +msgstr "najviÅ¡ja starost" #: paperless_mail/models.py:148 msgid "Specified in days." -msgstr "" +msgstr "DoloÄeno v dnevih." #: paperless_mail/models.py:152 msgid "attachment type" -msgstr "" +msgstr "vrsta priponke" #: paperless_mail/models.py:156 msgid "Inline attachments include embedded images, so it's best to combine this option with a filename filter." -msgstr "" +msgstr "Vgrajene priloge vkljuÄujejo vdelane slike, zato je najbolje, da to možnost združite s filtrom imen datoteke." #: paperless_mail/models.py:162 msgid "action" -msgstr "" +msgstr "dejanja" #: paperless_mail/models.py:168 msgid "action parameter" -msgstr "" +msgstr "parameter delovanja" #: paperless_mail/models.py:173 msgid "Additional parameter for the action selected above, i.e., the target folder of the move to folder action. Subfolders must be separated by dots." -msgstr "" +msgstr "Dodatni parameter za zgoraj izbrano dejanje, to je ciljna mapa dejanja premika v mapo. Podmape morajo biti loÄene s pikami." #: paperless_mail/models.py:181 msgid "assign title from" -msgstr "" +msgstr "dodeli naslov iz" #: paperless_mail/models.py:189 msgid "assign this tag" -msgstr "" +msgstr "dodeli to oznako" #: paperless_mail/models.py:197 msgid "assign this document type" -msgstr "" +msgstr "dodeli to vrsto dokumenta" #: paperless_mail/models.py:201 msgid "assign correspondent from" -msgstr "" +msgstr "dodeli dopisnika iz" #: paperless_mail/models.py:211 msgid "assign this correspondent" -msgstr "" +msgstr "dodeli tega dopisnika" diff --git a/src/locale/sr_CS/LC_MESSAGES/django.po b/src/locale/sr_CS/LC_MESSAGES/django.po new file mode 100644 index 000000000..278dafff8 --- /dev/null +++ b/src/locale/sr_CS/LC_MESSAGES/django.po @@ -0,0 +1,714 @@ +msgid "" +msgstr "" +"Project-Id-Version: paperless-ngx\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-03-02 11:20-0800\n" +"PO-Revision-Date: 2022-03-27 17:08\n" +"Last-Translator: \n" +"Language-Team: Serbian (Latin)\n" +"Language: sr_CS\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"X-Crowdin-Project: paperless-ngx\n" +"X-Crowdin-Project-ID: 500308\n" +"X-Crowdin-Language: sr-CS\n" +"X-Crowdin-File: /dev/src/locale/en_US/LC_MESSAGES/django.po\n" +"X-Crowdin-File-ID: 14\n" + +#: documents/apps.py:10 +msgid "Documents" +msgstr "Dokumenta" + +#: documents/models.py:32 +msgid "Any word" +msgstr "Bilo koja reÄ" + +#: documents/models.py:33 +msgid "All words" +msgstr "Sve reÄi" + +#: documents/models.py:34 +msgid "Exact match" +msgstr "TaÄno podudaranje" + +#: documents/models.py:35 +msgid "Regular expression" +msgstr "Regularni izraz" + +#: documents/models.py:36 +msgid "Fuzzy word" +msgstr "Fuzzy reÄ" + +#: documents/models.py:37 +msgid "Automatic" +msgstr "Automatski" + +#: documents/models.py:40 documents/models.py:314 paperless_mail/models.py:23 +#: paperless_mail/models.py:107 +msgid "name" +msgstr "naziv" + +#: documents/models.py:42 +msgid "match" +msgstr "poklapanje" + +#: documents/models.py:45 +msgid "matching algorithm" +msgstr "algoritam podudaranja" + +#: documents/models.py:48 +msgid "is insensitive" +msgstr "" + +#: documents/models.py:61 documents/models.py:104 +msgid "correspondent" +msgstr "dopisnik" + +#: documents/models.py:62 +msgid "correspondents" +msgstr "dopisnici" + +#: documents/models.py:67 +msgid "color" +msgstr "boja" + +#: documents/models.py:70 +msgid "is inbox tag" +msgstr "je oznaka prijemnog sanduÄeta" + +#: documents/models.py:73 +msgid "Marks this tag as an inbox tag: All newly consumed documents will be tagged with inbox tags." +msgstr "" + +#: documents/models.py:79 +msgid "tag" +msgstr "oznaka" + +#: documents/models.py:80 documents/models.py:130 +msgid "tags" +msgstr "oznake" + +#: documents/models.py:85 documents/models.py:115 +msgid "document type" +msgstr "tip dokumenta" + +#: documents/models.py:86 +msgid "document types" +msgstr "tipovi dokumenta" + +#: documents/models.py:94 +msgid "Unencrypted" +msgstr "" + +#: documents/models.py:95 +msgid "Encrypted with GNU Privacy Guard" +msgstr "" + +#: documents/models.py:107 +msgid "title" +msgstr "naslov" + +#: documents/models.py:119 +msgid "content" +msgstr "sadržaj" + +#: documents/models.py:122 +msgid "The raw, text-only data of the document. This field is primarily used for searching." +msgstr "" + +#: documents/models.py:127 +msgid "mime type" +msgstr "mime tip" + +#: documents/models.py:134 +msgid "checksum" +msgstr "kontrolna suma" + +#: documents/models.py:138 +msgid "The checksum of the original document." +msgstr "Kontrolna suma originalnog dokumenta." + +#: documents/models.py:142 +msgid "archive checksum" +msgstr "arhivni checksum" + +#: documents/models.py:147 +msgid "The checksum of the archived document." +msgstr "Kontrolna suma arhivnog dokumenta." + +#: documents/models.py:150 documents/models.py:295 +msgid "created" +msgstr "kreirano" + +#: documents/models.py:153 +msgid "modified" +msgstr "izmenjeno" + +#: documents/models.py:157 +msgid "storage type" +msgstr "tip skladiÅ¡ta" + +#: documents/models.py:165 +msgid "added" +msgstr "dodato" + +#: documents/models.py:169 +msgid "filename" +msgstr "naziv fajla" + +#: documents/models.py:175 +msgid "Current filename in storage" +msgstr "" + +#: documents/models.py:179 +msgid "archive filename" +msgstr "naziv fajla arhive" + +#: documents/models.py:185 +msgid "Current archive filename in storage" +msgstr "" + +#: documents/models.py:189 +msgid "archive serial number" +msgstr "arhivski serijski broj" + +#: documents/models.py:195 +msgid "The position of this document in your physical document archive." +msgstr "" + +#: documents/models.py:201 +msgid "document" +msgstr "dokument" + +#: documents/models.py:202 +msgid "documents" +msgstr "dokumenta" + +#: documents/models.py:280 +msgid "debug" +msgstr "okloni greÅ¡ke" + +#: documents/models.py:281 +msgid "information" +msgstr "informacija" + +#: documents/models.py:282 +msgid "warning" +msgstr "upozorenje" + +#: documents/models.py:283 +msgid "error" +msgstr "grеška" + +#: documents/models.py:284 +msgid "critical" +msgstr "kritiÄno" + +#: documents/models.py:287 +msgid "group" +msgstr "grupa" + +#: documents/models.py:289 +msgid "message" +msgstr "poruka" + +#: documents/models.py:292 +msgid "level" +msgstr "nivo" + +#: documents/models.py:299 +msgid "log" +msgstr "log" + +#: documents/models.py:300 +msgid "logs" +msgstr "logovi" + +#: documents/models.py:310 documents/models.py:360 +msgid "saved view" +msgstr "saÄuvani prikaz" + +#: documents/models.py:311 +msgid "saved views" +msgstr "saÄuvani prikazi" + +#: documents/models.py:313 +msgid "user" +msgstr "korisnik" + +#: documents/models.py:317 +msgid "show on dashboard" +msgstr "prikaži na kontrolnoj tabli" + +#: documents/models.py:320 +msgid "show in sidebar" +msgstr "prikaži u boÄnoj traci" + +#: documents/models.py:324 +msgid "sort field" +msgstr "polje za sortiranje" + +#: documents/models.py:326 +msgid "sort reverse" +msgstr "" + +#: documents/models.py:331 +msgid "title contains" +msgstr "naslov sadrži" + +#: documents/models.py:332 +msgid "content contains" +msgstr "sadržaj sadrži" + +#: documents/models.py:333 +msgid "ASN is" +msgstr "ASN je" + +#: documents/models.py:334 +msgid "correspondent is" +msgstr "dopisnik je" + +#: documents/models.py:335 +msgid "document type is" +msgstr "tip dokumenta je" + +#: documents/models.py:336 +msgid "is in inbox" +msgstr "je u prijemnog sanduÄetu" + +#: documents/models.py:337 +msgid "has tag" +msgstr "ima oznaku" + +#: documents/models.py:338 +msgid "has any tag" +msgstr "ima bilo koju oznaku" + +#: documents/models.py:339 +msgid "created before" +msgstr "kreiran pre" + +#: documents/models.py:340 +msgid "created after" +msgstr "kreiran posle" + +#: documents/models.py:341 +msgid "created year is" +msgstr "godina kreiranja je" + +#: documents/models.py:342 +msgid "created month is" +msgstr "mesec kreiranja je" + +#: documents/models.py:343 +msgid "created day is" +msgstr "dan kreiranja je" + +#: documents/models.py:344 +msgid "added before" +msgstr "dodat pre" + +#: documents/models.py:345 +msgid "added after" +msgstr "dodat posle" + +#: documents/models.py:346 +msgid "modified before" +msgstr "izmenjen pre" + +#: documents/models.py:347 +msgid "modified after" +msgstr "izmenjen posle" + +#: documents/models.py:348 +msgid "does not have tag" +msgstr "nema oznaku" + +#: documents/models.py:349 +msgid "does not have ASN" +msgstr "nema ASN" + +#: documents/models.py:350 +msgid "title or content contains" +msgstr "naslov i sadržaj sadrži" + +#: documents/models.py:351 +msgid "fulltext query" +msgstr "" + +#: documents/models.py:352 +msgid "more like this" +msgstr "viÅ¡e ovakvih" + +#: documents/models.py:353 +msgid "has tags in" +msgstr "ima oznake u" + +#: documents/models.py:363 +msgid "rule type" +msgstr "tip pravila" + +#: documents/models.py:365 +msgid "value" +msgstr "vrednost" + +#: documents/models.py:368 +msgid "filter rule" +msgstr "" + +#: documents/models.py:369 +msgid "filter rules" +msgstr "" + +#: documents/serialisers.py:64 +#, python-format +msgid "Invalid regular expression: %(error)s" +msgstr "" + +#: documents/serialisers.py:185 +msgid "Invalid color." +msgstr "" + +#: documents/serialisers.py:459 +#, python-format +msgid "File type %(type)s not supported" +msgstr "" + +#: documents/templates/index.html:22 +msgid "Paperless-ngx is loading..." +msgstr "" + +#: documents/templates/registration/logged_out.html:14 +msgid "Paperless-ngx signed out" +msgstr "" + +#: documents/templates/registration/logged_out.html:59 +msgid "You have been successfully logged out. Bye!" +msgstr "" + +#: documents/templates/registration/logged_out.html:60 +msgid "Sign in again" +msgstr "Prijavitе sе ponovo" + +#: documents/templates/registration/login.html:15 +msgid "Paperless-ngx sign in" +msgstr "" + +#: documents/templates/registration/login.html:61 +msgid "Please sign in." +msgstr "Prijavite se." + +#: documents/templates/registration/login.html:64 +msgid "Your username and password didn't match. Please try again." +msgstr "" + +#: documents/templates/registration/login.html:67 +msgid "Username" +msgstr "KorisniÄko ime" + +#: documents/templates/registration/login.html:68 +msgid "Password" +msgstr "Lozinka" + +#: documents/templates/registration/login.html:73 +msgid "Sign in" +msgstr "Prijavite se" + +#: paperless/settings.py:299 +msgid "English (US)" +msgstr "Engleski (US)" + +#: paperless/settings.py:300 +msgid "Czech" +msgstr "ÄŒeÅ¡ki" + +#: paperless/settings.py:301 +msgid "Danish" +msgstr "Danski" + +#: paperless/settings.py:302 +msgid "German" +msgstr "NemaÄki" + +#: paperless/settings.py:303 +msgid "English (GB)" +msgstr "Engleski (UK)" + +#: paperless/settings.py:304 +msgid "Spanish" +msgstr "Å panski" + +#: paperless/settings.py:305 +msgid "French" +msgstr "Francuski" + +#: paperless/settings.py:306 +msgid "Italian" +msgstr "Italijanski" + +#: paperless/settings.py:307 +msgid "Luxembourgish" +msgstr "LuksemburÅ¡ki" + +#: paperless/settings.py:308 +msgid "Dutch" +msgstr "Holandski" + +#: paperless/settings.py:309 +msgid "Polish" +msgstr "Poljski" + +#: paperless/settings.py:310 +msgid "Portuguese (Brazil)" +msgstr "Portugalski (Brazil)" + +#: paperless/settings.py:311 +msgid "Portuguese" +msgstr "Portugalski" + +#: paperless/settings.py:312 +msgid "Romanian" +msgstr "Rumunski" + +#: paperless/settings.py:313 +msgid "Russian" +msgstr "Ruski" + +#: paperless/settings.py:314 +msgid "Swedish" +msgstr "Å vedski" + +#: paperless/urls.py:139 +msgid "Paperless-ngx administration" +msgstr "Paperless-ngx administracija" + +#: paperless_mail/admin.py:29 +msgid "Authentication" +msgstr "" + +#: paperless_mail/admin.py:30 +msgid "Advanced settings" +msgstr "Napredna podeÅ¡avanja" + +#: paperless_mail/admin.py:47 +msgid "Filter" +msgstr "Filter" + +#: paperless_mail/admin.py:50 +msgid "Paperless will only process mails that match ALL of the filters given below." +msgstr "" + +#: paperless_mail/admin.py:64 +msgid "Actions" +msgstr "Radnje" + +#: paperless_mail/admin.py:67 +msgid "The action applied to the mail. This action is only performed when documents were consumed from the mail. Mails without attachments will remain entirely untouched." +msgstr "" + +#: paperless_mail/admin.py:75 +msgid "Metadata" +msgstr "Metapodaci" + +#: paperless_mail/admin.py:78 +msgid "Assign metadata to documents consumed from this rule automatically. If you do not assign tags, types or correspondents here, paperless will still process all matching rules that you have defined." +msgstr "" + +#: paperless_mail/apps.py:9 +msgid "Paperless mail" +msgstr "Paperless mejl" + +#: paperless_mail/models.py:10 +msgid "mail account" +msgstr "mejl nalog" + +#: paperless_mail/models.py:11 +msgid "mail accounts" +msgstr "mejl nalozi" + +#: paperless_mail/models.py:18 +msgid "No encryption" +msgstr "" + +#: paperless_mail/models.py:19 +msgid "Use SSL" +msgstr "Koristi SSL" + +#: paperless_mail/models.py:20 +msgid "Use STARTTLS" +msgstr "Koristi STARTTLS" + +#: paperless_mail/models.py:25 +msgid "IMAP server" +msgstr "IMAP server" + +#: paperless_mail/models.py:28 +msgid "IMAP port" +msgstr "IMAP port" + +#: paperless_mail/models.py:32 +msgid "This is usually 143 for unencrypted and STARTTLS connections, and 993 for SSL connections." +msgstr "" + +#: paperless_mail/models.py:38 +msgid "IMAP security" +msgstr "IMAP bezbednost" + +#: paperless_mail/models.py:41 +msgid "username" +msgstr "korisniÄko ime" + +#: paperless_mail/models.py:43 +msgid "password" +msgstr "lozinka" + +#: paperless_mail/models.py:46 +msgid "character set" +msgstr "karakter set" + +#: paperless_mail/models.py:50 +msgid "The character set to use when communicating with the mail server, such as 'UTF-8' or 'US-ASCII'." +msgstr "" + +#: paperless_mail/models.py:61 +msgid "mail rule" +msgstr "" + +#: paperless_mail/models.py:62 +msgid "mail rules" +msgstr "" + +#: paperless_mail/models.py:68 +msgid "Only process attachments." +msgstr "" + +#: paperless_mail/models.py:71 +msgid "Process all files, including 'inline' attachments." +msgstr "" + +#: paperless_mail/models.py:81 +msgid "Mark as read, don't process read mails" +msgstr "" + +#: paperless_mail/models.py:82 +msgid "Flag the mail, don't process flagged mails" +msgstr "" + +#: paperless_mail/models.py:83 +msgid "Move to specified folder" +msgstr "" + +#: paperless_mail/models.py:84 +msgid "Delete" +msgstr "ObriÅ¡i" + +#: paperless_mail/models.py:91 +msgid "Use subject as title" +msgstr "" + +#: paperless_mail/models.py:92 +msgid "Use attachment filename as title" +msgstr "" + +#: paperless_mail/models.py:101 +msgid "Do not assign a correspondent" +msgstr "Ne dodeljuj dopisnika" + +#: paperless_mail/models.py:102 +msgid "Use mail address" +msgstr "Koristi mejl adresu" + +#: paperless_mail/models.py:103 +msgid "Use name (or mail address if not available)" +msgstr "Koristi naziv (ili mejl adresu ako nije dostupno)" + +#: paperless_mail/models.py:104 +msgid "Use correspondent selected below" +msgstr "Koristi dopisnika ispod" + +#: paperless_mail/models.py:109 +msgid "order" +msgstr "raspored" + +#: paperless_mail/models.py:115 +msgid "account" +msgstr "nalog" + +#: paperless_mail/models.py:119 +msgid "folder" +msgstr "folder" + +#: paperless_mail/models.py:122 +msgid "Subfolders must be separated by dots." +msgstr "Podfolderi moraju biti odvojeni taÄkama." + +#: paperless_mail/models.py:126 +msgid "filter from" +msgstr "filter od" + +#: paperless_mail/models.py:129 +msgid "filter subject" +msgstr "filter naslov" + +#: paperless_mail/models.py:132 +msgid "filter body" +msgstr "filter telo poruke" + +#: paperless_mail/models.py:136 +msgid "filter attachment filename" +msgstr "filter naziv fajla priloga" + +#: paperless_mail/models.py:141 +msgid "Only consume documents which entirely match this filename if specified. Wildcards such as *.pdf or *invoice* are allowed. Case insensitive." +msgstr "" + +#: paperless_mail/models.py:148 +msgid "maximum age" +msgstr "" + +#: paperless_mail/models.py:148 +msgid "Specified in days." +msgstr "" + +#: paperless_mail/models.py:152 +msgid "attachment type" +msgstr "tip priloga" + +#: paperless_mail/models.py:156 +msgid "Inline attachments include embedded images, so it's best to combine this option with a filename filter." +msgstr "" + +#: paperless_mail/models.py:162 +msgid "action" +msgstr "radnja" + +#: paperless_mail/models.py:168 +msgid "action parameter" +msgstr "" + +#: paperless_mail/models.py:173 +msgid "Additional parameter for the action selected above, i.e., the target folder of the move to folder action. Subfolders must be separated by dots." +msgstr "" + +#: paperless_mail/models.py:181 +msgid "assign title from" +msgstr "dodeli naziv iz" + +#: paperless_mail/models.py:189 +msgid "assign this tag" +msgstr "dodeli ovu oznaku" + +#: paperless_mail/models.py:197 +msgid "assign this document type" +msgstr "dodeli ovaj tip dokumenta" + +#: paperless_mail/models.py:201 +msgid "assign correspondent from" +msgstr "dodeli dopisnika iz" + +#: paperless_mail/models.py:211 +msgid "assign this correspondent" +msgstr "dodeli ovog dopisnika" + diff --git a/src/locale/tr_TR/LC_MESSAGES/django.po b/src/locale/tr_TR/LC_MESSAGES/django.po new file mode 100644 index 000000000..c656cd105 --- /dev/null +++ b/src/locale/tr_TR/LC_MESSAGES/django.po @@ -0,0 +1,714 @@ +msgid "" +msgstr "" +"Project-Id-Version: paperless-ngx\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-03-02 11:20-0800\n" +"PO-Revision-Date: 2022-03-25 00:58\n" +"Last-Translator: \n" +"Language-Team: Turkish\n" +"Language: tr_TR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Crowdin-Project: paperless-ngx\n" +"X-Crowdin-Project-ID: 500308\n" +"X-Crowdin-Language: tr\n" +"X-Crowdin-File: /dev/src/locale/en_US/LC_MESSAGES/django.po\n" +"X-Crowdin-File-ID: 14\n" + +#: documents/apps.py:10 +msgid "Documents" +msgstr "Belgeler" + +#: documents/models.py:32 +msgid "Any word" +msgstr "Herhangi bir kelime" + +#: documents/models.py:33 +msgid "All words" +msgstr "Tüm Kelimeler" + +#: documents/models.py:34 +msgid "Exact match" +msgstr "Tam eÅŸleÅŸme" + +#: documents/models.py:35 +msgid "Regular expression" +msgstr "Düzenli ifade" + +#: documents/models.py:36 +msgid "Fuzzy word" +msgstr "Fuzzy Kelime" + +#: documents/models.py:37 +msgid "Automatic" +msgstr "Otomatik" + +#: documents/models.py:40 documents/models.py:314 paperless_mail/models.py:23 +#: paperless_mail/models.py:107 +msgid "name" +msgstr "ad" + +#: documents/models.py:42 +msgid "match" +msgstr "eÅŸleme" + +#: documents/models.py:45 +msgid "matching algorithm" +msgstr "eÅŸleÅŸtirme algoritması" + +#: documents/models.py:48 +msgid "is insensitive" +msgstr "duyarsızdır" + +#: documents/models.py:61 documents/models.py:104 +msgid "correspondent" +msgstr "muhabir" + +#: documents/models.py:62 +msgid "correspondents" +msgstr "muhabirler" + +#: documents/models.py:67 +msgid "color" +msgstr "renk" + +#: documents/models.py:70 +msgid "is inbox tag" +msgstr "gelen kutu etiketidir" + +#: documents/models.py:73 +msgid "Marks this tag as an inbox tag: All newly consumed documents will be tagged with inbox tags." +msgstr "Bu etiketi, gelen kutusu etiketi olarak iÅŸaretle: Tüm yeni olarak tüketilen dökümanlar gelen kutusu etiketi ile etiketlendirileceklerdir." + +#: documents/models.py:79 +msgid "tag" +msgstr "etiket" + +#: documents/models.py:80 documents/models.py:130 +msgid "tags" +msgstr "etiketler" + +#: documents/models.py:85 documents/models.py:115 +msgid "document type" +msgstr "belge türü" + +#: documents/models.py:86 +msgid "document types" +msgstr "belge türleri" + +#: documents/models.py:94 +msgid "Unencrypted" +msgstr "Åžifresiz" + +#: documents/models.py:95 +msgid "Encrypted with GNU Privacy Guard" +msgstr "GNU Gizlilik Koruması ile ÅŸifrelendirilmiÅŸtir" + +#: documents/models.py:107 +msgid "title" +msgstr "baÅŸlık" + +#: documents/models.py:119 +msgid "content" +msgstr "içerik" + +#: documents/models.py:122 +msgid "The raw, text-only data of the document. This field is primarily used for searching." +msgstr "Belgenin ham, yalnızca metin verileri. Bu alan öncelikle arama için kullanılır." + +#: documents/models.py:127 +msgid "mime type" +msgstr "mime türü" + +#: documents/models.py:134 +msgid "checksum" +msgstr "saÄŸlama toplamı" + +#: documents/models.py:138 +msgid "The checksum of the original document." +msgstr "Orjinal belgenin saÄŸlama toplamı." + +#: documents/models.py:142 +msgid "archive checksum" +msgstr "arÅŸiv saÄŸlama toplamı" + +#: documents/models.py:147 +msgid "The checksum of the archived document." +msgstr "ArÅŸivlenen belgenin saÄŸlama toplamı." + +#: documents/models.py:150 documents/models.py:295 +msgid "created" +msgstr "oluÅŸturuldu" + +#: documents/models.py:153 +msgid "modified" +msgstr "deÄŸiÅŸtirilmiÅŸ" + +#: documents/models.py:157 +msgid "storage type" +msgstr "depolama türü" + +#: documents/models.py:165 +msgid "added" +msgstr "eklendi" + +#: documents/models.py:169 +msgid "filename" +msgstr "dosya adı" + +#: documents/models.py:175 +msgid "Current filename in storage" +msgstr "Depolamadaki geçerli dosya adı" + +#: documents/models.py:179 +msgid "archive filename" +msgstr "arÅŸiv dosya adı" + +#: documents/models.py:185 +msgid "Current archive filename in storage" +msgstr "Depolamadaki geçerli arÅŸiv dosya adı" + +#: documents/models.py:189 +msgid "archive serial number" +msgstr "arÅŸiv seri numarası" + +#: documents/models.py:195 +msgid "The position of this document in your physical document archive." +msgstr "Bu belgenin fiziksel belge arÅŸivinizdeki posizyonu." + +#: documents/models.py:201 +msgid "document" +msgstr "belge" + +#: documents/models.py:202 +msgid "documents" +msgstr "belgeler" + +#: documents/models.py:280 +msgid "debug" +msgstr "hata ayıklama" + +#: documents/models.py:281 +msgid "information" +msgstr "bilgi" + +#: documents/models.py:282 +msgid "warning" +msgstr "uyarı" + +#: documents/models.py:283 +msgid "error" +msgstr "hata" + +#: documents/models.py:284 +msgid "critical" +msgstr "kritik" + +#: documents/models.py:287 +msgid "group" +msgstr "grup" + +#: documents/models.py:289 +msgid "message" +msgstr "mesaj" + +#: documents/models.py:292 +msgid "level" +msgstr "seviye" + +#: documents/models.py:299 +msgid "log" +msgstr "günlük" + +#: documents/models.py:300 +msgid "logs" +msgstr "günlükler" + +#: documents/models.py:310 documents/models.py:360 +msgid "saved view" +msgstr "kaydedilen görünüm" + +#: documents/models.py:311 +msgid "saved views" +msgstr "kaydedilen görünümler" + +#: documents/models.py:313 +msgid "user" +msgstr "kullanıcı" + +#: documents/models.py:317 +msgid "show on dashboard" +msgstr "kontrol paneli'nde göster" + +#: documents/models.py:320 +msgid "show in sidebar" +msgstr "kenar çubuÄŸunda göster" + +#: documents/models.py:324 +msgid "sort field" +msgstr "alanı sıralama" + +#: documents/models.py:326 +msgid "sort reverse" +msgstr "tersine sırala" + +#: documents/models.py:331 +msgid "title contains" +msgstr "baÅŸlık içerir" + +#: documents/models.py:332 +msgid "content contains" +msgstr "içerik içerir" + +#: documents/models.py:333 +msgid "ASN is" +msgstr "ASN ise" + +#: documents/models.py:334 +msgid "correspondent is" +msgstr "muhabir ise" + +#: documents/models.py:335 +msgid "document type is" +msgstr "belge türü ise" + +#: documents/models.py:336 +msgid "is in inbox" +msgstr "gelen kutusunun içerisindedir" + +#: documents/models.py:337 +msgid "has tag" +msgstr "etiketine sahip" + +#: documents/models.py:338 +msgid "has any tag" +msgstr "herhangi bir etiketine sahip" + +#: documents/models.py:339 +msgid "created before" +msgstr "bu tarihten önce oluÅŸturuldu" + +#: documents/models.py:340 +msgid "created after" +msgstr "bu tarihten sonra oluÅŸturuldu" + +#: documents/models.py:341 +msgid "created year is" +msgstr "oluÅŸturma yili ise" + +#: documents/models.py:342 +msgid "created month is" +msgstr "oluÅŸturma ayı ise" + +#: documents/models.py:343 +msgid "created day is" +msgstr "oluÅŸturma günü ise" + +#: documents/models.py:344 +msgid "added before" +msgstr "bu tarihten önce eklendi" + +#: documents/models.py:345 +msgid "added after" +msgstr "bu tarihten sonra eklendi" + +#: documents/models.py:346 +msgid "modified before" +msgstr "bu tarihten önce deÄŸiÅŸtirldi" + +#: documents/models.py:347 +msgid "modified after" +msgstr "bu tarihten sonra deÄŸiÅŸtirldi" + +#: documents/models.py:348 +msgid "does not have tag" +msgstr "etikete sahip deÄŸil" + +#: documents/models.py:349 +msgid "does not have ASN" +msgstr "ASN'e sahip deÄŸil" + +#: documents/models.py:350 +msgid "title or content contains" +msgstr "baÅŸlik veya içerik içerir" + +#: documents/models.py:351 +msgid "fulltext query" +msgstr "tam metin sorgulama" + +#: documents/models.py:352 +msgid "more like this" +msgstr "buna benzer daha" + +#: documents/models.py:353 +msgid "has tags in" +msgstr "içerisinde etiketine sahip" + +#: documents/models.py:363 +msgid "rule type" +msgstr "kural türü" + +#: documents/models.py:365 +msgid "value" +msgstr "deÄŸer" + +#: documents/models.py:368 +msgid "filter rule" +msgstr "filtreleme kuralı" + +#: documents/models.py:369 +msgid "filter rules" +msgstr "filtreleme kuralları" + +#: documents/serialisers.py:64 +#, python-format +msgid "Invalid regular expression: %(error)s" +msgstr "Hatalı Düzenli Ä°fade: %(error)s" + +#: documents/serialisers.py:185 +msgid "Invalid color." +msgstr "Geçersiz renk." + +#: documents/serialisers.py:459 +#, python-format +msgid "File type %(type)s not supported" +msgstr "Dosya türü %(type)s desteklenmiyor" + +#: documents/templates/index.html:22 +msgid "Paperless-ngx is loading..." +msgstr "Paperless-ngx yükleniyor..." + +#: documents/templates/registration/logged_out.html:14 +msgid "Paperless-ngx signed out" +msgstr "Paperless-ngx oturumunu kapatı" + +#: documents/templates/registration/logged_out.html:59 +msgid "You have been successfully logged out. Bye!" +msgstr "BaÅŸarılı bir ÅŸekilde çıkış yaptınız. Bye!" + +#: documents/templates/registration/logged_out.html:60 +msgid "Sign in again" +msgstr "Tekrar giriÅŸ yapın" + +#: documents/templates/registration/login.html:15 +msgid "Paperless-ngx sign in" +msgstr "Paperless-ngx oturumunu açin" + +#: documents/templates/registration/login.html:61 +msgid "Please sign in." +msgstr "Lütfen oturum açın." + +#: documents/templates/registration/login.html:64 +msgid "Your username and password didn't match. Please try again." +msgstr "Kullanıcı adınız ve parolanız uymuyor. Lütfen tekrar deneyiniz." + +#: documents/templates/registration/login.html:67 +msgid "Username" +msgstr "Kullanıcı Adı" + +#: documents/templates/registration/login.html:68 +msgid "Password" +msgstr "Parola" + +#: documents/templates/registration/login.html:73 +msgid "Sign in" +msgstr "Oturum aç" + +#: paperless/settings.py:299 +msgid "English (US)" +msgstr "Ä°ngilizce (BirleÅŸik Devletler)" + +#: paperless/settings.py:300 +msgid "Czech" +msgstr "Çekçe" + +#: paperless/settings.py:301 +msgid "Danish" +msgstr "Danca" + +#: paperless/settings.py:302 +msgid "German" +msgstr "Almanca" + +#: paperless/settings.py:303 +msgid "English (GB)" +msgstr "Ä°ngilizce (GB)" + +#: paperless/settings.py:304 +msgid "Spanish" +msgstr "Ä°spanyolca" + +#: paperless/settings.py:305 +msgid "French" +msgstr "Fransızca" + +#: paperless/settings.py:306 +msgid "Italian" +msgstr "Ä°talyanca" + +#: paperless/settings.py:307 +msgid "Luxembourgish" +msgstr "Lüksemburgca" + +#: paperless/settings.py:308 +msgid "Dutch" +msgstr "Hollandaca" + +#: paperless/settings.py:309 +msgid "Polish" +msgstr "Polonyaca" + +#: paperless/settings.py:310 +msgid "Portuguese (Brazil)" +msgstr "Portekizce (Brezilya)" + +#: paperless/settings.py:311 +msgid "Portuguese" +msgstr "Portekizce" + +#: paperless/settings.py:312 +msgid "Romanian" +msgstr "Romence" + +#: paperless/settings.py:313 +msgid "Russian" +msgstr "Rusça" + +#: paperless/settings.py:314 +msgid "Swedish" +msgstr "Ä°sveççe" + +#: paperless/urls.py:139 +msgid "Paperless-ngx administration" +msgstr "Paperless-ngx yönetimi" + +#: paperless_mail/admin.py:29 +msgid "Authentication" +msgstr "Kimlik DoÄŸrulaması" + +#: paperless_mail/admin.py:30 +msgid "Advanced settings" +msgstr "GeliÅŸmiÅŸ ayarlar" + +#: paperless_mail/admin.py:47 +msgid "Filter" +msgstr "Filtre" + +#: paperless_mail/admin.py:50 +msgid "Paperless will only process mails that match ALL of the filters given below." +msgstr "Paperless yalnızca aÅŸağıda verilen TÃœM filtrelerle eÅŸleÅŸen e-postalari iÅŸler." + +#: paperless_mail/admin.py:64 +msgid "Actions" +msgstr "Eylemler" + +#: paperless_mail/admin.py:67 +msgid "The action applied to the mail. This action is only performed when documents were consumed from the mail. Mails without attachments will remain entirely untouched." +msgstr "Eylem e-postaya uygulandı. Bu eylem yalnızca belgeler e-postadan tüketildiÄŸinde gerçekleÅŸtirilir. Eki olmayan e-postalarına tamamen dokunulmayacaktır." + +#: paperless_mail/admin.py:75 +msgid "Metadata" +msgstr "Metaveri" + +#: paperless_mail/admin.py:78 +msgid "Assign metadata to documents consumed from this rule automatically. If you do not assign tags, types or correspondents here, paperless will still process all matching rules that you have defined." +msgstr "Bu kuraldan tüketilen belgelere otomatik olarak meta veriler atayın. Burada etiketler, türler veya muhabirler atamazsanız, paperless yinede tanımladığınız tüm eÅŸleÅŸen kuralları iÅŸlemeye devam eder." + +#: paperless_mail/apps.py:9 +msgid "Paperless mail" +msgstr "Paperless e-posta" + +#: paperless_mail/models.py:10 +msgid "mail account" +msgstr "e-posta hesabı" + +#: paperless_mail/models.py:11 +msgid "mail accounts" +msgstr "e-posta hesapları" + +#: paperless_mail/models.py:18 +msgid "No encryption" +msgstr "Åžifreleme yok" + +#: paperless_mail/models.py:19 +msgid "Use SSL" +msgstr "SSL kullan" + +#: paperless_mail/models.py:20 +msgid "Use STARTTLS" +msgstr "STARTTLS kullan" + +#: paperless_mail/models.py:25 +msgid "IMAP server" +msgstr "IMAP sunucusu" + +#: paperless_mail/models.py:28 +msgid "IMAP port" +msgstr "IMAP portu" + +#: paperless_mail/models.py:32 +msgid "This is usually 143 for unencrypted and STARTTLS connections, and 993 for SSL connections." +msgstr "Åžifresiz ve STARTTLS baÄŸlantılar için bu genellikle 143 dür ve SSL baÄŸlantılar için 993 dür." + +#: paperless_mail/models.py:38 +msgid "IMAP security" +msgstr "IMAP güvenliÄŸi" + +#: paperless_mail/models.py:41 +msgid "username" +msgstr "kullanıcı adı" + +#: paperless_mail/models.py:43 +msgid "password" +msgstr "ÅŸifre" + +#: paperless_mail/models.py:46 +msgid "character set" +msgstr "karakter seti" + +#: paperless_mail/models.py:50 +msgid "The character set to use when communicating with the mail server, such as 'UTF-8' or 'US-ASCII'." +msgstr "E-posta sunucusu ile iletiÅŸim kurulduÄŸunda kullanılan 'UTF-8' veya 'US-ASCII' olan Karakter seti." + +#: paperless_mail/models.py:61 +msgid "mail rule" +msgstr "e-posta kuralı" + +#: paperless_mail/models.py:62 +msgid "mail rules" +msgstr "e-posta kuralları" + +#: paperless_mail/models.py:68 +msgid "Only process attachments." +msgstr "Sadece ekleri iÅŸle." + +#: paperless_mail/models.py:71 +msgid "Process all files, including 'inline' attachments." +msgstr "Tüm dosyaları iÅŸle, 'satır içi' ekletiler dahil." + +#: paperless_mail/models.py:81 +msgid "Mark as read, don't process read mails" +msgstr "OkunmuÅŸ olarak iÅŸaretle, okunmuÅŸ e-postaları iÅŸleme" + +#: paperless_mail/models.py:82 +msgid "Flag the mail, don't process flagged mails" +msgstr "E-Postayi etiketlendir, etiketlendirilmiÅŸ e-postaları iÅŸleme" + +#: paperless_mail/models.py:83 +msgid "Move to specified folder" +msgstr "Belirtilen klasöre taşı" + +#: paperless_mail/models.py:84 +msgid "Delete" +msgstr "Sil" + +#: paperless_mail/models.py:91 +msgid "Use subject as title" +msgstr "Konuyu baÅŸlık olarak kullan" + +#: paperless_mail/models.py:92 +msgid "Use attachment filename as title" +msgstr "Eklenti dosyanın ismini baÅŸlık olarak kullan" + +#: paperless_mail/models.py:101 +msgid "Do not assign a correspondent" +msgstr "Muhabir atanma" + +#: paperless_mail/models.py:102 +msgid "Use mail address" +msgstr "E-posta adresi kullan" + +#: paperless_mail/models.py:103 +msgid "Use name (or mail address if not available)" +msgstr "Ä°sim kullan (veya yoksa e-posta adresini)" + +#: paperless_mail/models.py:104 +msgid "Use correspondent selected below" +msgstr "AÅŸağıdaki seçili olan muhabiri kullan" + +#: paperless_mail/models.py:109 +msgid "order" +msgstr "sıra" + +#: paperless_mail/models.py:115 +msgid "account" +msgstr "hesap" + +#: paperless_mail/models.py:119 +msgid "folder" +msgstr "klasör" + +#: paperless_mail/models.py:122 +msgid "Subfolders must be separated by dots." +msgstr "Alt klasörler noktalar ile ayrıştırılmalıdır." + +#: paperless_mail/models.py:126 +msgid "filter from" +msgstr "den filtrele" + +#: paperless_mail/models.py:129 +msgid "filter subject" +msgstr "konuyu filtrele" + +#: paperless_mail/models.py:132 +msgid "filter body" +msgstr "içerik filtrele" + +#: paperless_mail/models.py:136 +msgid "filter attachment filename" +msgstr "eklenti ismini filtrele" + +#: paperless_mail/models.py:141 +msgid "Only consume documents which entirely match this filename if specified. Wildcards such as *.pdf or *invoice* are allowed. Case insensitive." +msgstr "Yalnızca belirtilmiÅŸse bu dosya ismiyla tamamen eÅŸleÅŸen belgeleri tüket. *.pdf veya *fatura* gibi joker karakterlere izin verilir. Büyük küçük yazılımına duyarsız." + +#: paperless_mail/models.py:148 +msgid "maximum age" +msgstr "yaÅŸ sınırı" + +#: paperless_mail/models.py:148 +msgid "Specified in days." +msgstr "Gün olarak belirtilmiÅŸ." + +#: paperless_mail/models.py:152 +msgid "attachment type" +msgstr "eklenti türü" + +#: paperless_mail/models.py:156 +msgid "Inline attachments include embedded images, so it's best to combine this option with a filename filter." +msgstr "Satır içi ekler katıştırılmış görüntüler içerir, bu nedenle bu seçeneÄŸi bir dosya adı filtresiyle birleÅŸtirmek en iyisidir." + +#: paperless_mail/models.py:162 +msgid "action" +msgstr "eylem" + +#: paperless_mail/models.py:168 +msgid "action parameter" +msgstr "eylem parametreleri" + +#: paperless_mail/models.py:173 +msgid "Additional parameter for the action selected above, i.e., the target folder of the move to folder action. Subfolders must be separated by dots." +msgstr "Yukarıda seçilen eylem için ek parametre, örneÄŸin klasöre taşı eyleminin hedef klasörü gibi. Alt klasörler noktalarla ayrıştırılmalıdır." + +#: paperless_mail/models.py:181 +msgid "assign title from" +msgstr "baÅŸlik atan" + +#: paperless_mail/models.py:189 +msgid "assign this tag" +msgstr "bu etiketi atan" + +#: paperless_mail/models.py:197 +msgid "assign this document type" +msgstr "bu dosya türünü atan" + +#: paperless_mail/models.py:201 +msgid "assign correspondent from" +msgstr "muhabiri atan" + +#: paperless_mail/models.py:211 +msgid "assign this correspondent" +msgstr "bu muhabiri atan" + diff --git a/src/locale/zh_CN/LC_MESSAGES/django.po b/src/locale/zh_CN/LC_MESSAGES/django.po index 5cefa0846..92bc9fa3c 100644 --- a/src/locale/zh_CN/LC_MESSAGES/django.po +++ b/src/locale/zh_CN/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: paperless-ngx\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-05-16 09:38+0000\n" -"PO-Revision-Date: 2022-02-17 04:18\n" +"POT-Creation-Date: 2022-03-02 11:20-0800\n" +"PO-Revision-Date: 2022-03-29 08:58\n" "Last-Translator: \n" "Language-Team: Chinese Simplified\n" "Language: zh_CN\n" @@ -19,680 +19,696 @@ msgstr "" #: documents/apps.py:10 msgid "Documents" -msgstr "" +msgstr "文档" #: documents/models.py:32 msgid "Any word" -msgstr "" +msgstr "ä»»æ„å•è¯" #: documents/models.py:33 msgid "All words" -msgstr "" +msgstr "所有å•è¯" #: documents/models.py:34 msgid "Exact match" -msgstr "" +msgstr "精确匹é…" #: documents/models.py:35 msgid "Regular expression" -msgstr "" +msgstr "正则表达å¼" #: documents/models.py:36 msgid "Fuzzy word" -msgstr "" +msgstr "模糊å•è¯" #: documents/models.py:37 msgid "Automatic" -msgstr "" +msgstr "自动" -#: documents/models.py:41 documents/models.py:350 paperless_mail/models.py:25 -#: paperless_mail/models.py:117 +#: documents/models.py:40 documents/models.py:314 paperless_mail/models.py:23 +#: paperless_mail/models.py:107 msgid "name" -msgstr "" +msgstr "å称" + +#: documents/models.py:42 +msgid "match" +msgstr "匹é…" #: documents/models.py:45 -msgid "match" -msgstr "" - -#: documents/models.py:49 msgid "matching algorithm" -msgstr "" +msgstr "匹é…算法" -#: documents/models.py:55 +#: documents/models.py:48 msgid "is insensitive" -msgstr "" +msgstr "忽略大å°å†™" -#: documents/models.py:74 documents/models.py:120 +#: documents/models.py:61 documents/models.py:104 msgid "correspondent" -msgstr "" +msgstr "è”系人" -#: documents/models.py:75 +#: documents/models.py:62 msgid "correspondents" -msgstr "" +msgstr "è”系人" -#: documents/models.py:81 +#: documents/models.py:67 msgid "color" -msgstr "" +msgstr "颜色" -#: documents/models.py:87 +#: documents/models.py:70 msgid "is inbox tag" -msgstr "" +msgstr "收件箱标签" -#: documents/models.py:89 +#: documents/models.py:73 msgid "Marks this tag as an inbox tag: All newly consumed documents will be tagged with inbox tags." -msgstr "" +msgstr "将此标签标记为收件箱标签:所有新处ç†çš„文档将被标记为收件箱标签。" + +#: documents/models.py:79 +msgid "tag" +msgstr "标签" + +#: documents/models.py:80 documents/models.py:130 +msgid "tags" +msgstr "标签" + +#: documents/models.py:85 documents/models.py:115 +msgid "document type" +msgstr "文档类型" + +#: documents/models.py:86 +msgid "document types" +msgstr "文档类型" #: documents/models.py:94 -msgid "tag" -msgstr "" - -#: documents/models.py:95 documents/models.py:151 -msgid "tags" -msgstr "" - -#: documents/models.py:101 documents/models.py:133 -msgid "document type" -msgstr "" - -#: documents/models.py:102 -msgid "document types" -msgstr "" - -#: documents/models.py:110 msgid "Unencrypted" -msgstr "" +msgstr "未加密" -#: documents/models.py:111 +#: documents/models.py:95 msgid "Encrypted with GNU Privacy Guard" -msgstr "" +msgstr "使用 GNU éšç§é˜²æŠ¤ï¼ˆGPG)加密" -#: documents/models.py:124 +#: documents/models.py:107 msgid "title" -msgstr "" +msgstr "标题" -#: documents/models.py:137 +#: documents/models.py:119 msgid "content" -msgstr "" +msgstr "内容" -#: documents/models.py:139 +#: documents/models.py:122 msgid "The raw, text-only data of the document. This field is primarily used for searching." -msgstr "" +msgstr "文档的原始ã€çº¯æ–‡æœ¬çš„æ•°æ®ã€‚这个字段主è¦ç”¨äºŽæœç´¢ã€‚" -#: documents/models.py:144 +#: documents/models.py:127 msgid "mime type" -msgstr "" +msgstr "mime 类型" -#: documents/models.py:155 +#: documents/models.py:134 msgid "checksum" -msgstr "" +msgstr "校验和" -#: documents/models.py:159 +#: documents/models.py:138 msgid "The checksum of the original document." -msgstr "" +msgstr "原始文档的校验和。" -#: documents/models.py:163 +#: documents/models.py:142 msgid "archive checksum" -msgstr "" +msgstr "存档校验和" -#: documents/models.py:168 +#: documents/models.py:147 msgid "The checksum of the archived document." -msgstr "" +msgstr "已归档文档的校验和。" -#: documents/models.py:172 documents/models.py:328 +#: documents/models.py:150 documents/models.py:295 msgid "created" -msgstr "" +msgstr "已创建" -#: documents/models.py:176 +#: documents/models.py:153 msgid "modified" -msgstr "" +msgstr "已修改" -#: documents/models.py:180 +#: documents/models.py:157 msgid "storage type" -msgstr "" +msgstr "存储类型" -#: documents/models.py:188 +#: documents/models.py:165 msgid "added" -msgstr "" +msgstr "已添加" -#: documents/models.py:192 +#: documents/models.py:169 msgid "filename" -msgstr "" +msgstr "文件å" -#: documents/models.py:198 +#: documents/models.py:175 msgid "Current filename in storage" -msgstr "" +msgstr "当å‰å­˜å‚¨ä¸­çš„文件å" + +#: documents/models.py:179 +msgid "archive filename" +msgstr "归档文件å" + +#: documents/models.py:185 +msgid "Current archive filename in storage" +msgstr "当å‰å­˜å‚¨ä¸­çš„归档文件å" + +#: documents/models.py:189 +msgid "archive serial number" +msgstr "å½’æ¡£åºåˆ—å·" + +#: documents/models.py:195 +msgid "The position of this document in your physical document archive." +msgstr "此文档在您的物ç†æ–‡æ¡£å½’档中的ä½ç½®ã€‚" + +#: documents/models.py:201 +msgid "document" +msgstr "文档" #: documents/models.py:202 -msgid "archive filename" -msgstr "" - -#: documents/models.py:208 -msgid "Current archive filename in storage" -msgstr "" - -#: documents/models.py:212 -msgid "archive serial number" -msgstr "" - -#: documents/models.py:217 -msgid "The position of this document in your physical document archive." -msgstr "" - -#: documents/models.py:223 -msgid "document" -msgstr "" - -#: documents/models.py:224 msgid "documents" -msgstr "" +msgstr "文档" + +#: documents/models.py:280 +msgid "debug" +msgstr "调试" + +#: documents/models.py:281 +msgid "information" +msgstr "ä¿¡æ¯" + +#: documents/models.py:282 +msgid "warning" +msgstr "警告" + +#: documents/models.py:283 +msgid "error" +msgstr "错误" + +#: documents/models.py:284 +msgid "critical" +msgstr "严é‡" + +#: documents/models.py:287 +msgid "group" +msgstr "用户组" + +#: documents/models.py:289 +msgid "message" +msgstr "消æ¯" + +#: documents/models.py:292 +msgid "level" +msgstr "等级" + +#: documents/models.py:299 +msgid "log" +msgstr "日志" + +#: documents/models.py:300 +msgid "logs" +msgstr "日志" + +#: documents/models.py:310 documents/models.py:360 +msgid "saved view" +msgstr "ä¿å­˜çš„视图" #: documents/models.py:311 -msgid "debug" -msgstr "" - -#: documents/models.py:312 -msgid "information" -msgstr "" +msgid "saved views" +msgstr "ä¿å­˜çš„视图" #: documents/models.py:313 -msgid "warning" -msgstr "" +msgid "user" +msgstr "用户" -#: documents/models.py:314 -msgid "error" -msgstr "" +#: documents/models.py:317 +msgid "show on dashboard" +msgstr "在仪表盘显示" -#: documents/models.py:315 -msgid "critical" -msgstr "" +#: documents/models.py:320 +msgid "show in sidebar" +msgstr "在侧边æ æ˜¾ç¤º" -#: documents/models.py:319 -msgid "group" -msgstr "" +#: documents/models.py:324 +msgid "sort field" +msgstr "排åºå­—段" -#: documents/models.py:322 -msgid "message" -msgstr "" +#: documents/models.py:326 +msgid "sort reverse" +msgstr "åå‘排åº" -#: documents/models.py:325 -msgid "level" -msgstr "" +#: documents/models.py:331 +msgid "title contains" +msgstr "标题包å«" #: documents/models.py:332 -msgid "log" -msgstr "" +msgid "content contains" +msgstr "内容包å«" #: documents/models.py:333 -msgid "logs" -msgstr "" +msgid "ASN is" +msgstr "ASN 为" -#: documents/models.py:344 documents/models.py:401 -msgid "saved view" -msgstr "" +#: documents/models.py:334 +msgid "correspondent is" +msgstr "è”系人是" + +#: documents/models.py:335 +msgid "document type is" +msgstr "文档类型是" + +#: documents/models.py:336 +msgid "is in inbox" +msgstr "在收件箱中" + +#: documents/models.py:337 +msgid "has tag" +msgstr "有标签" + +#: documents/models.py:338 +msgid "has any tag" +msgstr "有任æ„标签" + +#: documents/models.py:339 +msgid "created before" +msgstr "在此时间之å‰åˆ›å»º" + +#: documents/models.py:340 +msgid "created after" +msgstr "在此时间之åŽåˆ›å»º" + +#: documents/models.py:341 +msgid "created year is" +msgstr "创建年份是" + +#: documents/models.py:342 +msgid "created month is" +msgstr "创建月份是" + +#: documents/models.py:343 +msgid "created day is" +msgstr "创建日期是" + +#: documents/models.py:344 +msgid "added before" +msgstr "添加早于" #: documents/models.py:345 -msgid "saved views" -msgstr "" +msgid "added after" +msgstr "添加晚于" + +#: documents/models.py:346 +msgid "modified before" +msgstr "修改早于" + +#: documents/models.py:347 +msgid "modified after" +msgstr "修改晚于" #: documents/models.py:348 -msgid "user" -msgstr "" - -#: documents/models.py:354 -msgid "show on dashboard" -msgstr "" - -#: documents/models.py:357 -msgid "show in sidebar" -msgstr "" - -#: documents/models.py:361 -msgid "sort field" -msgstr "" - -#: documents/models.py:367 -msgid "sort reverse" -msgstr "" - -#: documents/models.py:373 -msgid "title contains" -msgstr "" - -#: documents/models.py:374 -msgid "content contains" -msgstr "" - -#: documents/models.py:375 -msgid "ASN is" -msgstr "" - -#: documents/models.py:376 -msgid "correspondent is" -msgstr "" - -#: documents/models.py:377 -msgid "document type is" -msgstr "" - -#: documents/models.py:378 -msgid "is in inbox" -msgstr "" - -#: documents/models.py:379 -msgid "has tag" -msgstr "" - -#: documents/models.py:380 -msgid "has any tag" -msgstr "" - -#: documents/models.py:381 -msgid "created before" -msgstr "" - -#: documents/models.py:382 -msgid "created after" -msgstr "" - -#: documents/models.py:383 -msgid "created year is" -msgstr "" - -#: documents/models.py:384 -msgid "created month is" -msgstr "" - -#: documents/models.py:385 -msgid "created day is" -msgstr "" - -#: documents/models.py:386 -msgid "added before" -msgstr "" - -#: documents/models.py:387 -msgid "added after" -msgstr "" - -#: documents/models.py:388 -msgid "modified before" -msgstr "" - -#: documents/models.py:389 -msgid "modified after" -msgstr "" - -#: documents/models.py:390 msgid "does not have tag" -msgstr "" +msgstr "没有标签" -#: documents/models.py:391 +#: documents/models.py:349 msgid "does not have ASN" -msgstr "" +msgstr "没有 ASN" -#: documents/models.py:392 +#: documents/models.py:350 msgid "title or content contains" -msgstr "" +msgstr "标题或内容包å«" -#: documents/models.py:393 +#: documents/models.py:351 msgid "fulltext query" -msgstr "" +msgstr "全文检索" -#: documents/models.py:394 +#: documents/models.py:352 msgid "more like this" -msgstr "" +msgstr "更多类似内容" -#: documents/models.py:405 +#: documents/models.py:353 +msgid "has tags in" +msgstr "有标签包å«äºŽ" + +#: documents/models.py:363 msgid "rule type" -msgstr "" +msgstr "规则类型" -#: documents/models.py:409 +#: documents/models.py:365 msgid "value" -msgstr "" +msgstr "值" -#: documents/models.py:415 +#: documents/models.py:368 msgid "filter rule" -msgstr "" +msgstr "过滤规则" -#: documents/models.py:416 +#: documents/models.py:369 msgid "filter rules" -msgstr "" +msgstr "过滤规则" -#: documents/serialisers.py:53 +#: documents/serialisers.py:64 #, python-format msgid "Invalid regular expression: %(error)s" -msgstr "" +msgstr "无效的正则表达å¼ï¼š%(error)s" -#: documents/serialisers.py:177 +#: documents/serialisers.py:185 msgid "Invalid color." -msgstr "" +msgstr "无效的颜色" -#: documents/serialisers.py:451 +#: documents/serialisers.py:459 #, python-format msgid "File type %(type)s not supported" -msgstr "" +msgstr "ä¸æ”¯æŒæ–‡ä»¶ç±»åž‹ %(type)s" #: documents/templates/index.html:22 -msgid "Paperless-ng is loading..." -msgstr "" +msgid "Paperless-ngx is loading..." +msgstr "Paperless-ngx 正在加载..." #: documents/templates/registration/logged_out.html:14 -msgid "Paperless-ng signed out" -msgstr "" +msgid "Paperless-ngx signed out" +msgstr "Paperless-ngx 已退出" -#: documents/templates/registration/logged_out.html:45 +#: documents/templates/registration/logged_out.html:59 msgid "You have been successfully logged out. Bye!" -msgstr "" +msgstr "您已æˆåŠŸé€€å‡ºã€‚å†è§ï¼" -#: documents/templates/registration/logged_out.html:46 +#: documents/templates/registration/logged_out.html:60 msgid "Sign in again" -msgstr "" +msgstr "é‡æ–°ç™»å½•" #: documents/templates/registration/login.html:15 -msgid "Paperless-ng sign in" -msgstr "" +msgid "Paperless-ngx sign in" +msgstr "Paperless-ngx 登录" -#: documents/templates/registration/login.html:47 +#: documents/templates/registration/login.html:61 msgid "Please sign in." -msgstr "" +msgstr "请登录。" -#: documents/templates/registration/login.html:50 +#: documents/templates/registration/login.html:64 msgid "Your username and password didn't match. Please try again." -msgstr "" +msgstr "您的用户å和密ç ä¸åŒ¹é…。请é‡è¯•ã€‚" -#: documents/templates/registration/login.html:53 +#: documents/templates/registration/login.html:67 msgid "Username" -msgstr "" +msgstr "用户å" -#: documents/templates/registration/login.html:54 +#: documents/templates/registration/login.html:68 msgid "Password" -msgstr "" +msgstr "密ç " -#: documents/templates/registration/login.html:59 +#: documents/templates/registration/login.html:73 msgid "Sign in" -msgstr "" +msgstr "登录" + +#: paperless/settings.py:299 +msgid "English (US)" +msgstr "英语(美国)" + +#: paperless/settings.py:300 +msgid "Czech" +msgstr "æ·å…‹è¯­" + +#: paperless/settings.py:301 +msgid "Danish" +msgstr "丹麦语" + +#: paperless/settings.py:302 +msgid "German" +msgstr "德语" #: paperless/settings.py:303 -msgid "English (US)" -msgstr "" +msgid "English (GB)" +msgstr "英语(英国)" #: paperless/settings.py:304 -msgid "English (GB)" -msgstr "" +msgid "Spanish" +msgstr "西ç­ç‰™è¯­" #: paperless/settings.py:305 -msgid "German" -msgstr "" +msgid "French" +msgstr "法语" #: paperless/settings.py:306 -msgid "Dutch" -msgstr "" +msgid "Italian" +msgstr "æ„大利语" #: paperless/settings.py:307 -msgid "French" -msgstr "" +msgid "Luxembourgish" +msgstr "å¢æ£®å ¡è¯­" #: paperless/settings.py:308 -msgid "Portuguese (Brazil)" -msgstr "" +msgid "Dutch" +msgstr "è·å…°è¯­" #: paperless/settings.py:309 -msgid "Portuguese" -msgstr "" +msgid "Polish" +msgstr "波兰语" #: paperless/settings.py:310 -msgid "Italian" -msgstr "" +msgid "Portuguese (Brazil)" +msgstr "è‘¡è„牙语 (巴西)" #: paperless/settings.py:311 -msgid "Romanian" -msgstr "" +msgid "Portuguese" +msgstr "è‘¡è„牙语" #: paperless/settings.py:312 -msgid "Russian" -msgstr "" +msgid "Romanian" +msgstr "罗马尼亚语" #: paperless/settings.py:313 -msgid "Spanish" -msgstr "" +msgid "Russian" +msgstr "俄语" #: paperless/settings.py:314 -msgid "Polish" -msgstr "" - -#: paperless/settings.py:315 msgid "Swedish" -msgstr "" +msgstr "瑞典语" -#: paperless/urls.py:120 -msgid "Paperless-ng administration" -msgstr "" +#: paperless/urls.py:139 +msgid "Paperless-ngx administration" +msgstr "Paperless-ngx 管ç†" -#: paperless_mail/admin.py:15 +#: paperless_mail/admin.py:29 msgid "Authentication" -msgstr "" +msgstr "身份验è¯" -#: paperless_mail/admin.py:18 +#: paperless_mail/admin.py:30 msgid "Advanced settings" -msgstr "" +msgstr "高级设置" -#: paperless_mail/admin.py:37 +#: paperless_mail/admin.py:47 msgid "Filter" -msgstr "" +msgstr "过滤器" -#: paperless_mail/admin.py:39 +#: paperless_mail/admin.py:50 msgid "Paperless will only process mails that match ALL of the filters given below." -msgstr "" +msgstr "Paperless-ngx åªä¼šå¤„ç†ç¬¦åˆä»¥ä¸‹æ‰€æœ‰è¿‡æ»¤è§„则的邮件。" -#: paperless_mail/admin.py:49 +#: paperless_mail/admin.py:64 msgid "Actions" -msgstr "" +msgstr "æ“作" -#: paperless_mail/admin.py:51 +#: paperless_mail/admin.py:67 msgid "The action applied to the mail. This action is only performed when documents were consumed from the mail. Mails without attachments will remain entirely untouched." -msgstr "" +msgstr "应用于邮件的æ“作。此æ“作仅在从邮件中处ç†æ–‡æ¡£æ—¶æ‰§è¡Œã€‚没有附件的邮件完全ä¸ä¼šè§¦åŠã€‚" -#: paperless_mail/admin.py:58 +#: paperless_mail/admin.py:75 msgid "Metadata" -msgstr "" +msgstr "元数æ®" -#: paperless_mail/admin.py:60 +#: paperless_mail/admin.py:78 msgid "Assign metadata to documents consumed from this rule automatically. If you do not assign tags, types or correspondents here, paperless will still process all matching rules that you have defined." -msgstr "" +msgstr "将元数æ®è‡ªåŠ¨æŒ‡å®šåˆ°è¢«æ­¤è§„则所处ç†çš„文档。 如果您ä¸åœ¨è¿™é‡ŒæŒ‡å®šæ ‡ç­¾ã€ç±»åž‹æˆ–è”系人,Paperless-ngx ä»å°†å¤„ç†æ‚¨å·²å®šä¹‰çš„所有匹é…规则。" #: paperless_mail/apps.py:9 msgid "Paperless mail" -msgstr "" +msgstr "Paperless-ngx 邮件" + +#: paperless_mail/models.py:10 +msgid "mail account" +msgstr "邮件账å·" #: paperless_mail/models.py:11 -msgid "mail account" -msgstr "" - -#: paperless_mail/models.py:12 msgid "mail accounts" -msgstr "" +msgstr "邮件账户" + +#: paperless_mail/models.py:18 +msgid "No encryption" +msgstr "无加密" #: paperless_mail/models.py:19 -msgid "No encryption" -msgstr "" +msgid "Use SSL" +msgstr "使用 SSL" #: paperless_mail/models.py:20 -msgid "Use SSL" -msgstr "" - -#: paperless_mail/models.py:21 msgid "Use STARTTLS" -msgstr "" +msgstr "使用 STARTTLS" -#: paperless_mail/models.py:29 +#: paperless_mail/models.py:25 msgid "IMAP server" -msgstr "" +msgstr "IMAP æœåŠ¡å™¨" -#: paperless_mail/models.py:33 +#: paperless_mail/models.py:28 msgid "IMAP port" -msgstr "" +msgstr "IMAP 端å£" -#: paperless_mail/models.py:36 +#: paperless_mail/models.py:32 msgid "This is usually 143 for unencrypted and STARTTLS connections, and 993 for SSL connections." -msgstr "" +msgstr "对于未加密的连接和STARTTLS连接,通常为143端å£ï¼ŒSSL连接为993端å£ã€‚" -#: paperless_mail/models.py:40 +#: paperless_mail/models.py:38 msgid "IMAP security" -msgstr "" +msgstr "IMAP 安全" + +#: paperless_mail/models.py:41 +msgid "username" +msgstr "用户å" + +#: paperless_mail/models.py:43 +msgid "password" +msgstr "密ç " #: paperless_mail/models.py:46 -msgid "username" -msgstr "" +msgid "character set" +msgstr "字符集" #: paperless_mail/models.py:50 -msgid "password" -msgstr "" - -#: paperless_mail/models.py:54 -msgid "character set" -msgstr "" - -#: paperless_mail/models.py:57 msgid "The character set to use when communicating with the mail server, such as 'UTF-8' or 'US-ASCII'." -msgstr "" +msgstr "与邮件æœåŠ¡å™¨é€šä¿¡æ—¶ä½¿ç”¨çš„字符集,例如“UTF-8â€æˆ–“US-ASCIIâ€ã€‚" + +#: paperless_mail/models.py:61 +msgid "mail rule" +msgstr "邮件规则" + +#: paperless_mail/models.py:62 +msgid "mail rules" +msgstr "邮件规则" #: paperless_mail/models.py:68 -msgid "mail rule" -msgstr "" - -#: paperless_mail/models.py:69 -msgid "mail rules" -msgstr "" - -#: paperless_mail/models.py:75 msgid "Only process attachments." -msgstr "" +msgstr "åªå¤„ç†é™„件。" -#: paperless_mail/models.py:76 +#: paperless_mail/models.py:71 msgid "Process all files, including 'inline' attachments." -msgstr "" +msgstr "处ç†æ‰€æœ‰æ–‡ä»¶ï¼ŒåŒ…括“内嵌â€é™„件。" -#: paperless_mail/models.py:86 +#: paperless_mail/models.py:81 msgid "Mark as read, don't process read mails" -msgstr "" +msgstr "标记为已读,ä¸å¤„ç†å·²è¯»é‚®ä»¶" -#: paperless_mail/models.py:87 +#: paperless_mail/models.py:82 msgid "Flag the mail, don't process flagged mails" -msgstr "" +msgstr "标记邮件,ä¸å¤„ç†å·²æ ‡è®°çš„邮件" -#: paperless_mail/models.py:88 +#: paperless_mail/models.py:83 msgid "Move to specified folder" -msgstr "" +msgstr "移动到指定文件夹" -#: paperless_mail/models.py:89 +#: paperless_mail/models.py:84 msgid "Delete" -msgstr "" +msgstr "删除" -#: paperless_mail/models.py:96 +#: paperless_mail/models.py:91 msgid "Use subject as title" -msgstr "" +msgstr "使用主题作为标题" -#: paperless_mail/models.py:97 +#: paperless_mail/models.py:92 msgid "Use attachment filename as title" -msgstr "" +msgstr "使用附件å作为标题" -#: paperless_mail/models.py:107 +#: paperless_mail/models.py:101 msgid "Do not assign a correspondent" -msgstr "" +msgstr "ä¸åˆ†é…è”系人" + +#: paperless_mail/models.py:102 +msgid "Use mail address" +msgstr "使用邮件地å€" + +#: paperless_mail/models.py:103 +msgid "Use name (or mail address if not available)" +msgstr "使用å称 (如果ä¸å¯ç”¨åˆ™ä½¿ç”¨é‚®ç®±åœ°å€)" + +#: paperless_mail/models.py:104 +msgid "Use correspondent selected below" +msgstr "使用下é¢é€‰æ‹©çš„è”系人" #: paperless_mail/models.py:109 -msgid "Use mail address" -msgstr "" - -#: paperless_mail/models.py:111 -msgid "Use name (or mail address if not available)" -msgstr "" - -#: paperless_mail/models.py:113 -msgid "Use correspondent selected below" -msgstr "" - -#: paperless_mail/models.py:121 msgid "order" -msgstr "" +msgstr "排åº" -#: paperless_mail/models.py:128 +#: paperless_mail/models.py:115 msgid "account" -msgstr "" +msgstr "账户" + +#: paperless_mail/models.py:119 +msgid "folder" +msgstr "文件夹" + +#: paperless_mail/models.py:122 +msgid "Subfolders must be separated by dots." +msgstr "å­æ–‡ä»¶å¤¹å¿…须用“.â€åˆ†éš”。" + +#: paperless_mail/models.py:126 +msgid "filter from" +msgstr "过滤æ¥è‡ª" + +#: paperless_mail/models.py:129 +msgid "filter subject" +msgstr "过滤主题" #: paperless_mail/models.py:132 -msgid "folder" -msgstr "" +msgid "filter body" +msgstr "过滤内容" -#: paperless_mail/models.py:134 -msgid "Subfolders must be separated by dots." -msgstr "" - -#: paperless_mail/models.py:138 -msgid "filter from" -msgstr "" +#: paperless_mail/models.py:136 +msgid "filter attachment filename" +msgstr "过滤附件文件å" #: paperless_mail/models.py:141 -msgid "filter subject" -msgstr "" - -#: paperless_mail/models.py:144 -msgid "filter body" -msgstr "" +msgid "Only consume documents which entirely match this filename if specified. Wildcards such as *.pdf or *invoice* are allowed. Case insensitive." +msgstr "如果指定了文件å,åªå¤„ç†å®Œå…¨åŒ¹é…此文件å的文档。å…许使用通é…符,如 *.pdf 或 *å‘票*。ä¸åŒºåˆ†å¤§å°å†™ã€‚" #: paperless_mail/models.py:148 -msgid "filter attachment filename" -msgstr "" +msgid "maximum age" +msgstr "存活期" -#: paperless_mail/models.py:150 -msgid "Only consume documents which entirely match this filename if specified. Wildcards such as *.pdf or *invoice* are allowed. Case insensitive." -msgstr "" +#: paperless_mail/models.py:148 +msgid "Specified in days." +msgstr "指定日期。" + +#: paperless_mail/models.py:152 +msgid "attachment type" +msgstr "附件类型" #: paperless_mail/models.py:156 -msgid "maximum age" -msgstr "" - -#: paperless_mail/models.py:158 -msgid "Specified in days." -msgstr "" - -#: paperless_mail/models.py:161 -msgid "attachment type" -msgstr "" - -#: paperless_mail/models.py:164 msgid "Inline attachments include embedded images, so it's best to combine this option with a filename filter." -msgstr "" +msgstr "内嵌附件包å«åµŒå…¥å›¾åƒï¼Œæ‰€ä»¥æœ€å¥½å°†æ­¤é€‰é¡¹ä¸Žæ–‡ä»¶å过滤器结åˆèµ·æ¥ã€‚" -#: paperless_mail/models.py:169 +#: paperless_mail/models.py:162 msgid "action" -msgstr "" +msgstr "æ“作" -#: paperless_mail/models.py:175 +#: paperless_mail/models.py:168 msgid "action parameter" -msgstr "" +msgstr "æ“作å‚æ•°" -#: paperless_mail/models.py:177 +#: paperless_mail/models.py:173 msgid "Additional parameter for the action selected above, i.e., the target folder of the move to folder action. Subfolders must be separated by dots." -msgstr "" +msgstr "上é¢é€‰æ‹©çš„æ“作的附加å‚数,å³ç§»åŠ¨åˆ°æ–‡ä»¶å¤¹æ“作的目标文件夹。å­æ–‡ä»¶å¤¹å¿…须用“.â€æ¥åˆ†éš”。" -#: paperless_mail/models.py:184 +#: paperless_mail/models.py:181 msgid "assign title from" -msgstr "" +msgstr "分é…标题æ¥è‡ª" -#: paperless_mail/models.py:194 +#: paperless_mail/models.py:189 msgid "assign this tag" -msgstr "" +msgstr "分é…此标签" -#: paperless_mail/models.py:202 +#: paperless_mail/models.py:197 msgid "assign this document type" -msgstr "" +msgstr "分é…此文档类型" -#: paperless_mail/models.py:206 +#: paperless_mail/models.py:201 msgid "assign correspondent from" -msgstr "" +msgstr "分é…è”系人æ¥è‡ª" -#: paperless_mail/models.py:216 +#: paperless_mail/models.py:211 msgid "assign this correspondent" -msgstr "" +msgstr "分é…æ­¤è”系人" diff --git a/src/paperless/__init__.py b/src/paperless/__init__.py index 0789cc963..8cdd600b3 100644 --- a/src/paperless/__init__.py +++ b/src/paperless/__init__.py @@ -1 +1,4 @@ -from .checks import paths_check, binaries_check +from .checks import binaries_check +from .checks import paths_check + +__all__ = ["binaries_check", "paths_check"] diff --git a/src/paperless/asgi.py b/src/paperless/asgi.py index a3bc386ce..633c75ce0 100644 --- a/src/paperless/asgi.py +++ b/src/paperless/asgi.py @@ -9,14 +9,14 @@ from django.core.asgi import get_asgi_application os.environ.setdefault("DJANGO_SETTINGS_MODULE", "paperless.settings") django_asgi_app = get_asgi_application() -from channels.auth import AuthMiddlewareStack # NOQA: E402 -from channels.routing import ProtocolTypeRouter, URLRouter # NOQA: E402 +from channels.auth import AuthMiddlewareStack # noqa: E402 +from channels.routing import ProtocolTypeRouter, URLRouter # noqa: E402 -from paperless.urls import websocket_urlpatterns # NOQA: E402 +from paperless.urls import websocket_urlpatterns # noqa: E402 application = ProtocolTypeRouter( { "http": get_asgi_application(), "websocket": AuthMiddlewareStack(URLRouter(websocket_urlpatterns)), - } + }, ) diff --git a/src/paperless/auth.py b/src/paperless/auth.py index 7af4f3590..86f428518 100644 --- a/src/paperless/auth.py +++ b/src/paperless/auth.py @@ -1,9 +1,9 @@ from django.conf import settings from django.contrib import auth +from django.contrib.auth.middleware import RemoteUserMiddleware from django.contrib.auth.models import User from django.utils.deprecation import MiddlewareMixin from rest_framework import authentication -from django.contrib.auth.middleware import RemoteUserMiddleware class AutoLoginMiddleware(MiddlewareMixin): @@ -25,7 +25,7 @@ class AngularApiAuthenticationOverride(authentication.BaseAuthentication): settings.DEBUG and "Referer" in request.headers and request.headers["Referer"].startswith("http://localhost:4200/") - ): # NOQA: E501 + ): user = User.objects.filter(is_staff=True).first() print("Auto-Login with user {}".format(user)) return (user, None) diff --git a/src/paperless/checks.py b/src/paperless/checks.py index 1adc8b149..ee9b95e09 100644 --- a/src/paperless/checks.py +++ b/src/paperless/checks.py @@ -3,7 +3,9 @@ import shutil import stat from django.conf import settings -from django.core.checks import Error, Warning, register +from django.core.checks import Error +from django.core.checks import register +from django.core.checks import Warning exists_message = "{} is set but doesn't exist." exists_hint = "Create a directory at {}" @@ -19,11 +21,12 @@ def path_check(var, directory): if directory: if not os.path.isdir(directory): messages.append( - Error(exists_message.format(var), exists_hint.format(directory)) + Error(exists_message.format(var), exists_hint.format(directory)), ) else: test_file = os.path.join( - directory, f"__paperless_write_test_{os.getpid()}__" + directory, + f"__paperless_write_test_{os.getpid()}__", ) try: with open(test_file, "w"): @@ -34,9 +37,9 @@ def path_check(var, directory): writeable_message.format(var), writeable_hint.format( f"\n{stat.filemode(os.stat(directory).st_mode)} " - f"{directory}\n" + f"{directory}\n", ), - ) + ), ) finally: if os.path.isfile(test_file): @@ -88,8 +91,8 @@ def debug_mode_check(app_configs, **kwargs): "security issue, since it puts security overides in place which " "are meant to be only used during development. This " "also means that paperless will tell anyone various " - "debugging information when something goes wrong." - ) + "debugging information when something goes wrong.", + ), ] else: return [] diff --git a/src/paperless/consumers.py b/src/paperless/consumers.py index 8b8e8c6dc..7013a8e79 100644 --- a/src/paperless/consumers.py +++ b/src/paperless/consumers.py @@ -1,7 +1,8 @@ import json from asgiref.sync import async_to_sync -from channels.exceptions import DenyConnection, AcceptConnection +from channels.exceptions import AcceptConnection +from channels.exceptions import DenyConnection from channels.generic.websocket import WebsocketConsumer @@ -14,13 +15,15 @@ class StatusConsumer(WebsocketConsumer): raise DenyConnection() else: async_to_sync(self.channel_layer.group_add)( - "status_updates", self.channel_name + "status_updates", + self.channel_name, ) raise AcceptConnection() def disconnect(self, close_code): async_to_sync(self.channel_layer.group_discard)( - "status_updates", self.channel_name + "status_updates", + self.channel_name, ) def status_update(self, event): diff --git a/src/paperless/db.py b/src/paperless/db.py index 5f476b5e7..51184750d 100644 --- a/src/paperless/db.py +++ b/src/paperless/db.py @@ -1,5 +1,4 @@ import gnupg - from django.conf import settings diff --git a/src/paperless/middleware.py b/src/paperless/middleware.py index bb634adf8..f82ba2435 100644 --- a/src/paperless/middleware.py +++ b/src/paperless/middleware.py @@ -1,5 +1,4 @@ from django.conf import settings - from paperless import version diff --git a/src/paperless/settings.py b/src/paperless/settings.py index e3fb5d155..e720a6946 100644 --- a/src/paperless/settings.py +++ b/src/paperless/settings.py @@ -3,11 +3,12 @@ import math import multiprocessing import os import re +from typing import Final +from urllib.parse import urlparse from concurrent_log_handler.queue import setup_logging_queues -from dotenv import load_dotenv - from django.utils.translation import gettext_lazy as _ +from dotenv import load_dotenv # Tap paperless.conf if it's available if os.path.exists("../paperless.conf"): @@ -30,7 +31,7 @@ elif os.path.exists("/usr/local/etc/paperless.conf"): os.environ["OMP_THREAD_LIMIT"] = "1" -def __get_boolean(key, default="NO"): +def __get_boolean(key: str, default: str = "NO") -> bool: """ Return a boolean value based on whatever the user has supplied in the environment based on whether the value "looks like" it's True or not. @@ -38,6 +39,13 @@ def __get_boolean(key, default="NO"): return bool(os.getenv(key, default).lower() in ("yes", "y", "1", "t", "true")) +def __get_int(key: str, default: int) -> int: + """ + Return an integer value based on the environment variable or a default + """ + return int(os.getenv(key, default)) + + # NEVER RUN WITH DEBUG IN PRODUCTION. DEBUG = __get_boolean("PAPERLESS_DEBUG", "NO") @@ -68,7 +76,8 @@ MODEL_FILE = os.path.join(DATA_DIR, "classification_model.pickle") LOGGING_DIR = os.getenv("PAPERLESS_LOGGING_DIR", os.path.join(DATA_DIR, "log")) CONSUMPTION_DIR = os.getenv( - "PAPERLESS_CONSUMPTION_DIR", os.path.join(BASE_DIR, "..", "consume") + "PAPERLESS_CONSUMPTION_DIR", + os.path.join(BASE_DIR, "..", "consume"), ) # This will be created if it doesn't exist @@ -119,7 +128,7 @@ REST_FRAMEWORK = { if DEBUG: REST_FRAMEWORK["DEFAULT_AUTHENTICATION_CLASSES"].append( - "paperless.auth.AngularApiAuthenticationOverride" + "paperless.auth.AngularApiAuthenticationOverride", ) MIDDLEWARE = [ @@ -191,7 +200,8 @@ if AUTO_LOGIN_USERNAME: ENABLE_HTTP_REMOTE_USER = __get_boolean("PAPERLESS_ENABLE_HTTP_REMOTE_USER") HTTP_REMOTE_USER_HEADER_NAME = os.getenv( - "PAPERLESS_HTTP_REMOTE_USER_HEADER_NAME", "HTTP_REMOTE_USER" + "PAPERLESS_HTTP_REMOTE_USER_HEADER_NAME", + "HTTP_REMOTE_USER", ) if ENABLE_HTTP_REMOTE_USER: @@ -201,7 +211,7 @@ if ENABLE_HTTP_REMOTE_USER: "django.contrib.auth.backends.ModelBackend", ] REST_FRAMEWORK["DEFAULT_AUTHENTICATION_CLASSES"].append( - "rest_framework.authentication.RemoteUserAuthentication" + "rest_framework.authentication.RemoteUserAuthentication", ) # X-Frame options for embedded PDF display: @@ -210,28 +220,48 @@ if DEBUG: else: X_FRAME_OPTIONS = "SAMEORIGIN" -# We allow CORS from localhost:8080 + +# The next 3 settings can also be set using just PAPERLESS_URL +_csrf_origins = os.getenv("PAPERLESS_CSRF_TRUSTED_ORIGINS") +if _csrf_origins: + CSRF_TRUSTED_ORIGINS = _csrf_origins.split(",") +else: + CSRF_TRUSTED_ORIGINS = [] + +# We allow CORS from localhost:8000 CORS_ALLOWED_ORIGINS = tuple( - os.getenv("PAPERLESS_CORS_ALLOWED_HOSTS", "http://localhost:8000").split(",") + os.getenv("PAPERLESS_CORS_ALLOWED_HOSTS", "http://localhost:8000").split(","), ) if DEBUG: # Allow access from the angular development server during debugging CORS_ALLOWED_ORIGINS += ("http://localhost:4200",) -# The secret key has a default that should be fine so long as you're hosting -# Paperless on a closed network. However, if you're putting this anywhere -# public, you should change the key to something unique and verbose. -SECRET_KEY = os.getenv( - "PAPERLESS_SECRET_KEY", "e11fl1oa-*ytql8p)(06fbj4ukrlo+n7k&q5+$1md7i+mge=ee" -) - _allowed_hosts = os.getenv("PAPERLESS_ALLOWED_HOSTS") if _allowed_hosts: ALLOWED_HOSTS = _allowed_hosts.split(",") else: ALLOWED_HOSTS = ["*"] +_paperless_url = os.getenv("PAPERLESS_URL") +if _paperless_url: + _paperless_uri = urlparse(_paperless_url) + CSRF_TRUSTED_ORIGINS.append(_paperless_url) + CORS_ALLOWED_ORIGINS += (_paperless_url,) + if _allowed_hosts: + ALLOWED_HOSTS.append(_paperless_uri.hostname) + else: + # always allow localhost. Necessary e.g. for healthcheck in docker. + ALLOWED_HOSTS = [_paperless_uri.hostname] + ["localhost"] + +# The secret key has a default that should be fine so long as you're hosting +# Paperless on a closed network. However, if you're putting this anywhere +# public, you should change the key to something unique and verbose. +SECRET_KEY = os.getenv( + "PAPERLESS_SECRET_KEY", + "e11fl1oa-*ytql8p)(06fbj4ukrlo+n7k&q5+$1md7i+mge=ee", +) + AUTH_PASSWORD_VALIDATORS = [ { "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", @@ -268,7 +298,7 @@ DATABASES = { "default": { "ENGINE": "django.db.backends.sqlite3", "NAME": os.path.join(DATA_DIR, "db.sqlite3"), - } + }, } if os.getenv("PAPERLESS_DBHOST"): @@ -297,6 +327,7 @@ LANGUAGE_CODE = "en-us" LANGUAGES = [ ("en-us", _("English (US)")), # needs to be first to act as fallback language + ("be-by", _("Belarusian")), ("cs-cz", _("Czech")), ("da-dk", _("Danish")), ("de-de", _("German")), @@ -311,7 +342,11 @@ LANGUAGES = [ ("pt-pt", _("Portuguese")), ("ro-ro", _("Romanian")), ("ru-ru", _("Russian")), + ("sl-si", _("Slovenian")), + ("sr-cs", _("Serbian")), ("sv-se", _("Swedish")), + ("tr-tr", _("Turkish")), + ("zh-cn", _("Chinese Simplified")), ] LOCALE_PATHS = [os.path.join(BASE_DIR, "locale")] @@ -389,7 +424,7 @@ LOGGING = { # in total. -def default_task_workers(): +def default_task_workers() -> int: # always leave one core open available_cores = max(multiprocessing.cpu_count(), 1) try: @@ -400,20 +435,29 @@ def default_task_workers(): return 1 -TASK_WORKERS = int(os.getenv("PAPERLESS_TASK_WORKERS", default_task_workers())) +TASK_WORKERS = __get_int("PAPERLESS_TASK_WORKERS", default_task_workers()) + +PAPERLESS_WORKER_TIMEOUT: Final[int] = __get_int("PAPERLESS_WORKER_TIMEOUT", 1800) + +# Per django-q docs, timeout must be smaller than retry +# We default retry to 10s more than the timeout +PAPERLESS_WORKER_RETRY: Final[int] = __get_int( + "PAPERLESS_WORKER_RETRY", + PAPERLESS_WORKER_TIMEOUT + 10, +) Q_CLUSTER = { "name": "paperless", "catch_up": False, "recycle": 1, - "retry": 1800, - "timeout": int(os.getenv("PAPERLESS_WORKER_TIMEOUT", 1800)), + "retry": PAPERLESS_WORKER_RETRY, + "timeout": PAPERLESS_WORKER_TIMEOUT, "workers": TASK_WORKERS, "redis": os.getenv("PAPERLESS_REDIS", "redis://localhost:6379"), } -def default_threads_per_worker(task_workers): +def default_threads_per_worker(task_workers) -> int: # always leave one core open available_cores = max(multiprocessing.cpu_count(), 1) try: @@ -423,7 +467,8 @@ def default_threads_per_worker(task_workers): THREADS_PER_WORKER = os.getenv( - "PAPERLESS_THREADS_PER_WORKER", default_threads_per_worker(TASK_WORKERS) + "PAPERLESS_THREADS_PER_WORKER", + default_threads_per_worker(TASK_WORKERS), ) ############################################################################### @@ -435,7 +480,7 @@ CONSUMER_POLLING = int(os.getenv("PAPERLESS_CONSUMER_POLLING", 0)) CONSUMER_POLLING_DELAY = int(os.getenv("PAPERLESS_CONSUMER_POLLING_DELAY", 5)) CONSUMER_POLLING_RETRY_COUNT = int( - os.getenv("PAPERLESS_CONSUMER_POLLING_RETRY_COUNT", 5) + os.getenv("PAPERLESS_CONSUMER_POLLING_RETRY_COUNT", 5), ) CONSUMER_DELETE_DUPLICATES = __get_boolean("PAPERLESS_CONSUMER_DELETE_DUPLICATES") @@ -447,13 +492,19 @@ CONSUMER_IGNORE_PATTERNS = list( json.loads( os.getenv( "PAPERLESS_CONSUMER_IGNORE_PATTERNS", - '[".DS_STORE/*", "._*", ".stfolder/*"]', - ) - ) + '[".DS_STORE/*", "._*", ".stfolder/*", ".stversions/*", ".localized/*", "desktop.ini"]', + ), + ), ) CONSUMER_SUBDIRS_AS_TAGS = __get_boolean("PAPERLESS_CONSUMER_SUBDIRS_AS_TAGS") +CONSUMER_ENABLE_BARCODES = __get_boolean( + "PAPERLESS_CONSUMER_ENABLE_BARCODES", +) + +CONSUMER_BARCODE_STRING = os.getenv("PAPERLESS_CONSUMER_BARCODE_STRING", "PATCHT") + OPTIMIZE_THUMBNAILS = __get_boolean("PAPERLESS_OPTIMIZE_THUMBNAILS", "true") OCR_PAGES = int(os.getenv("PAPERLESS_OCR_PAGES", 0)) @@ -479,7 +530,12 @@ OCR_DESKEW = __get_boolean("PAPERLESS_OCR_DESKEW", "true") OCR_ROTATE_PAGES = __get_boolean("PAPERLESS_OCR_ROTATE_PAGES", "true") OCR_ROTATE_PAGES_THRESHOLD = float( - os.getenv("PAPERLESS_OCR_ROTATE_PAGES_THRESHOLD", 12.0) + os.getenv("PAPERLESS_OCR_ROTATE_PAGES_THRESHOLD", 12.0), +) + +OCR_MAX_IMAGE_PIXELS = os.environ.get( + "PAPERLESS_OCR_MAX_IMAGE_PIXELS", + 256000000, ) OCR_USER_ARGS = os.getenv("PAPERLESS_OCR_USER_ARGS", "{}") @@ -536,7 +592,8 @@ THUMBNAIL_FONT_NAME = os.getenv( PAPERLESS_TIKA_ENABLED = __get_boolean("PAPERLESS_TIKA_ENABLED", "NO") PAPERLESS_TIKA_ENDPOINT = os.getenv("PAPERLESS_TIKA_ENDPOINT", "http://localhost:9998") PAPERLESS_TIKA_GOTENBERG_ENDPOINT = os.getenv( - "PAPERLESS_TIKA_GOTENBERG_ENDPOINT", "http://localhost:3000" + "PAPERLESS_TIKA_GOTENBERG_ENDPOINT", + "http://localhost:3000", ) if PAPERLESS_TIKA_ENABLED: @@ -552,3 +609,7 @@ if os.getenv("PAPERLESS_IGNORE_DATES", ""): d = dateparser.parse(s) if d: IGNORE_DATES.add(d.date()) + +ENABLE_UPDATE_CHECK = os.getenv("PAPERLESS_ENABLE_UPDATE_CHECK", "default") +if ENABLE_UPDATE_CHECK != "default": + ENABLE_UPDATE_CHECK = __get_boolean("PAPERLESS_ENABLE_UPDATE_CHECK") diff --git a/src/paperless/tests/test_checks.py b/src/paperless/tests/test_checks.py index b0301be0e..df0cb0afd 100644 --- a/src/paperless/tests/test_checks.py +++ b/src/paperless/tests/test_checks.py @@ -1,10 +1,11 @@ import os import shutil -from django.test import TestCase, override_settings - +from django.test import override_settings +from django.test import TestCase from documents.tests.utils import DirectoriesMixin -from paperless import binaries_check, paths_check +from paperless import binaries_check +from paperless import paths_check from paperless.checks import debug_mode_check @@ -20,7 +21,9 @@ class TestChecks(DirectoriesMixin, TestCase): self.assertEqual(paths_check(None), []) @override_settings( - MEDIA_ROOT="uuh", DATA_DIR="whatever", CONSUMPTION_DIR="idontcare" + MEDIA_ROOT="uuh", + DATA_DIR="whatever", + CONSUMPTION_DIR="idontcare", ) def test_paths_check_dont_exist(self): msgs = paths_check(None) diff --git a/src/paperless/tests/test_websockets.py b/src/paperless/tests/test_websockets.py index c8cc269fe..069bb644a 100644 --- a/src/paperless/tests/test_websockets.py +++ b/src/paperless/tests/test_websockets.py @@ -2,8 +2,8 @@ from unittest import mock from channels.layers import get_channel_layer from channels.testing import WebsocketCommunicator -from django.test import TestCase, override_settings - +from django.test import override_settings +from django.test import TestCase from paperless.asgi import application @@ -46,7 +46,8 @@ class TestWebSockets(TestCase): channel_layer = get_channel_layer() await channel_layer.group_send( - "status_updates", {"type": "status_update", "data": message} + "status_updates", + {"type": "status_update", "data": message}, ) response = await communicator.receive_json_from() diff --git a/src/paperless/urls.py b/src/paperless/urls.py index 510e624d1..833788cce 100644 --- a/src/paperless/urls.py +++ b/src/paperless/urls.py @@ -1,34 +1,31 @@ +from django.conf import settings from django.conf.urls import include from django.contrib import admin from django.contrib.auth.decorators import login_required -from django.urls import path, re_path +from django.urls import path +from django.urls import re_path +from django.utils.translation import gettext_lazy as _ from django.views.decorators.csrf import csrf_exempt from django.views.generic import RedirectView +from documents.views import BulkDownloadView +from documents.views import BulkEditView +from documents.views import CorrespondentViewSet +from documents.views import DocumentTypeViewSet +from documents.views import IndexView +from documents.views import LogViewSet +from documents.views import PostDocumentView +from documents.views import RemoteVersionView +from documents.views import SavedViewViewSet +from documents.views import SearchAutoCompleteView +from documents.views import SelectionDataView +from documents.views import StatisticsView +from documents.views import TagViewSet +from documents.views import UnifiedSearchViewSet +from paperless.consumers import StatusConsumer +from paperless.views import FaviconView from rest_framework.authtoken import views from rest_framework.routers import DefaultRouter -from django.utils.translation import gettext_lazy as _ - -from django.conf import settings - -from paperless.consumers import StatusConsumer -from documents.views import ( - CorrespondentViewSet, - UnifiedSearchViewSet, - LogViewSet, - TagViewSet, - DocumentTypeViewSet, - IndexView, - SearchAutoCompleteView, - StatisticsView, - PostDocumentView, - SavedViewViewSet, - BulkEditView, - SelectionDataView, - BulkDownloadView, -) -from paperless.views import FaviconView - api_router = DefaultRouter() api_router.register(r"correspondents", CorrespondentViewSet) api_router.register(r"document_types", DocumentTypeViewSet) @@ -62,7 +59,9 @@ urlpatterns = [ name="post_document", ), re_path( - r"^documents/bulk_edit/", BulkEditView.as_view(), name="bulk_edit" + r"^documents/bulk_edit/", + BulkEditView.as_view(), + name="bulk_edit", ), re_path( r"^documents/selection_data/", @@ -74,9 +73,14 @@ urlpatterns = [ BulkDownloadView.as_view(), name="bulk_download", ), + re_path( + r"^remote_version/", + RemoteVersionView.as_view(), + name="remoteversion", + ), path("token/", views.obtain_auth_token), ] - + api_router.urls + + api_router.urls, ), ), re_path(r"^favicon.ico$", FaviconView.as_view(), name="favicon"), @@ -88,35 +92,37 @@ urlpatterns = [ re_path( r"^doc/(?P<pk>\d+)$", RedirectView.as_view( - url=settings.BASE_URL + "api/documents/%(pk)s/download/" + url=settings.BASE_URL + "api/documents/%(pk)s/download/", ), ), re_path( r"^thumb/(?P<pk>\d+)$", RedirectView.as_view( - url=settings.BASE_URL + "api/documents/%(pk)s/thumb/" + url=settings.BASE_URL + "api/documents/%(pk)s/thumb/", ), ), re_path( r"^preview/(?P<pk>\d+)$", RedirectView.as_view( - url=settings.BASE_URL + "api/documents/%(pk)s/preview/" + url=settings.BASE_URL + "api/documents/%(pk)s/preview/", ), ), - ] + ], ), ), re_path( r"^push$", csrf_exempt( - RedirectView.as_view(url=settings.BASE_URL + "api/documents/post_document/") + RedirectView.as_view( + url=settings.BASE_URL + "api/documents/post_document/", + ), ), ), # Frontend assets TODO: this is pretty bad, but it works. path( "assets/<path:path>", RedirectView.as_view( - url=settings.STATIC_URL + "frontend/en-US/assets/%(path)s" + url=settings.STATIC_URL + "frontend/en-US/assets/%(path)s", ), ), # TODO: with localization, this is even worse! :/ diff --git a/src/paperless/views.py b/src/paperless/views.py index a6a37a679..9f3d017a6 100644 --- a/src/paperless/views.py +++ b/src/paperless/views.py @@ -14,7 +14,11 @@ class StandardPagination(PageNumberPagination): class FaviconView(View): def get(self, request, *args, **kwargs): favicon = os.path.join( - os.path.dirname(__file__), "static", "paperless", "img", "favicon.ico" + os.path.dirname(__file__), + "static", + "paperless", + "img", + "favicon.ico", ) with open(favicon, "rb") as f: return HttpResponse(f, content_type="image/x-icon") diff --git a/src/paperless/workers.py b/src/paperless/workers.py index 4f2f0802a..0f4a66149 100644 --- a/src/paperless/workers.py +++ b/src/paperless/workers.py @@ -1,6 +1,7 @@ import os -from uvicorn.workers import UvicornWorker + from django.conf import settings +from uvicorn.workers import UvicornWorker os.environ.setdefault("DJANGO_SETTINGS_MODULE", "paperless.settings") diff --git a/src/paperless/wsgi.py b/src/paperless/wsgi.py index 6aab72299..82e0744f7 100644 --- a/src/paperless/wsgi.py +++ b/src/paperless/wsgi.py @@ -6,7 +6,6 @@ It exposes the WSGI callable as a module-level variable named ``application``. For more information on this file, see https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/ """ - import os from django.core.wsgi import get_wsgi_application diff --git a/src/paperless_mail/admin.py b/src/paperless_mail/admin.py index 3c9ae0f56..3b488b153 100644 --- a/src/paperless_mail/admin.py +++ b/src/paperless_mail/admin.py @@ -1,8 +1,8 @@ -from django.contrib import admin from django import forms -from paperless_mail.models import MailAccount, MailRule - +from django.contrib import admin from django.utils.translation import gettext_lazy as _ +from paperless_mail.models import MailAccount +from paperless_mail.models import MailRule class MailAccountAdminForm(forms.ModelForm): @@ -48,7 +48,7 @@ class MailRuleAdmin(admin.ModelAdmin): { "description": _( "Paperless will only process mails that match ALL of the " - "filters given below." + "filters given below.", ), "fields": ( "filter_from", @@ -66,7 +66,7 @@ class MailRuleAdmin(admin.ModelAdmin): "description": _( "The action applied to the mail. This action is only " "performed when documents were consumed from the mail. " - "Mails without attachments will remain entirely untouched." + "Mails without attachments will remain entirely untouched.", ), "fields": ("action", "action_parameter"), }, @@ -78,11 +78,11 @@ class MailRuleAdmin(admin.ModelAdmin): "Assign metadata to documents consumed from this rule " "automatically. If you do not assign tags, types or " "correspondents here, paperless will still process all " - "matching rules that you have defined." + "matching rules that you have defined.", ), "fields": ( "assign_title_from", - "assign_tag", + "assign_tags", "assign_document_type", "assign_correspondent_from", "assign_correspondent", diff --git a/src/paperless_mail/apps.py b/src/paperless_mail/apps.py index f55240852..1c5d656e0 100644 --- a/src/paperless_mail/apps.py +++ b/src/paperless_mail/apps.py @@ -1,5 +1,4 @@ from django.apps import AppConfig - from django.utils.translation import gettext_lazy as _ diff --git a/src/paperless_mail/mail.py b/src/paperless_mail/mail.py index 0e9294927..b332233dc 100644 --- a/src/paperless_mail/mail.py +++ b/src/paperless_mail/mail.py @@ -1,6 +1,7 @@ import os import tempfile -from datetime import timedelta, date +from datetime import date +from datetime import timedelta from fnmatch import fnmatch import magic @@ -8,18 +9,18 @@ import pathvalidate from django.conf import settings from django.db import DatabaseError from django_q.tasks import async_task -from imap_tools import ( - MailBox, - MailBoxUnencrypted, - AND, - MailMessageFlags, - MailboxFolderSelectError, -) - from documents.loggers import LoggingMixin from documents.models import Correspondent from documents.parsers import is_mime_type_supported -from paperless_mail.models import MailAccount, MailRule +from imap_tools import AND +from imap_tools import MailBox +from imap_tools import MailboxFolderSelectError +from imap_tools import MailBoxUnencrypted +from imap_tools import MailMessage +from imap_tools import MailMessageFlags +from imap_tools.mailbox import MailBoxTls +from paperless_mail.models import MailAccount +from paperless_mail.models import MailRule class MailError(Exception): @@ -61,13 +62,13 @@ class FlagMailAction(BaseMailAction): def get_rule_action(rule): - if rule.action == MailRule.ACTION_FLAG: + if rule.action == MailRule.MailAction.FLAG: return FlagMailAction() - elif rule.action == MailRule.ACTION_DELETE: + elif rule.action == MailRule.MailAction.DELETE: return DeleteMailAction() - elif rule.action == MailRule.ACTION_MOVE: + elif rule.action == MailRule.MailAction.MOVE: return MoveMailAction() - elif rule.action == MailRule.ACTION_MARK_READ: + elif rule.action == MailRule.MailAction.MARK_READ: return MarkReadMailAction() else: raise NotImplementedError("Unknown action.") # pragma: nocover @@ -89,11 +90,11 @@ def make_criterias(rule): def get_mailbox(server, port, security): - if security == MailAccount.IMAP_SECURITY_NONE: + if security == MailAccount.ImapSecurity.NONE: mailbox = MailBoxUnencrypted(server, port) - elif security == MailAccount.IMAP_SECURITY_STARTTLS: - mailbox = MailBox(server, port, starttls=True) - elif security == MailAccount.IMAP_SECURITY_SSL: + elif security == MailAccount.ImapSecurity.STARTTLS: + mailbox = MailBoxTls(server, port) + elif security == MailAccount.ImapSecurity.SSL: mailbox = MailBox(server, port) else: raise NotImplementedError("Unknown IMAP security") # pragma: nocover @@ -112,43 +113,40 @@ class MailAccountHandler(LoggingMixin): return None def get_title(self, message, att, rule): - if rule.assign_title_from == MailRule.TITLE_FROM_SUBJECT: + if rule.assign_title_from == MailRule.TitleSource.FROM_SUBJECT: return message.subject - elif rule.assign_title_from == MailRule.TITLE_FROM_FILENAME: + elif rule.assign_title_from == MailRule.TitleSource.FROM_FILENAME: return os.path.splitext(os.path.basename(att.filename))[0] else: raise NotImplementedError( - "Unknown title selector." - ) # pragma: nocover # NOQA: E501 + "Unknown title selector.", + ) # pragma: nocover - def get_correspondent(self, message, rule): + def get_correspondent(self, message: MailMessage, rule): c_from = rule.assign_correspondent_from - if c_from == MailRule.CORRESPONDENT_FROM_NOTHING: + if c_from == MailRule.CorrespondentSource.FROM_NOTHING: return None - elif c_from == MailRule.CORRESPONDENT_FROM_EMAIL: + elif c_from == MailRule.CorrespondentSource.FROM_EMAIL: return self._correspondent_from_name(message.from_) - elif c_from == MailRule.CORRESPONDENT_FROM_NAME: - if ( - message.from_values - and "name" in message.from_values - and message.from_values["name"] - ): # NOQA: E501 - return self._correspondent_from_name(message.from_values["name"]) + elif c_from == MailRule.CorrespondentSource.FROM_NAME: + from_values = message.from_values + if from_values is not None and len(from_values.name) > 0: + return self._correspondent_from_name(from_values.name) else: return self._correspondent_from_name(message.from_) - elif c_from == MailRule.CORRESPONDENT_FROM_CUSTOM: + elif c_from == MailRule.CorrespondentSource.FROM_CUSTOM: return rule.assign_correspondent else: raise NotImplementedError( - "Unknwown correspondent selector" - ) # pragma: nocover # NOQA: E501 + "Unknwown correspondent selector", + ) # pragma: nocover def handle_mail_account(self, account): @@ -159,7 +157,9 @@ class MailAccountHandler(LoggingMixin): total_processed_files = 0 with get_mailbox( - account.imap_server, account.imap_port, account.imap_security + account.imap_server, + account.imap_port, + account.imap_security, ) as M: try: @@ -193,7 +193,7 @@ class MailAccountHandler(LoggingMixin): except MailboxFolderSelectError: raise MailError( f"Rule {rule}: Folder {rule.folder} " - f"does not exist in account {rule.account}" + f"does not exist in account {rule.account}", ) criterias = make_criterias(rule) @@ -242,17 +242,19 @@ class MailAccountHandler(LoggingMixin): try: get_rule_action(rule).post_consume( - M, post_consume_messages, rule.action_parameter + M, + post_consume_messages, + rule.action_parameter, ) except Exception as e: raise MailError( - f"Rule {rule}: Error while processing post-consume actions: " f"{e}" + f"Rule {rule}: Error while processing post-consume actions: " f"{e}", ) return total_processed_files - def handle_message(self, message, rule): + def handle_message(self, message, rule) -> int: if not message.attachments: return 0 @@ -264,7 +266,7 @@ class MailAccountHandler(LoggingMixin): ) correspondent = self.get_correspondent(message, rule) - tag = rule.assign_tag + tag_ids = [tag.id for tag in rule.assign_tags.all()] doc_type = rule.assign_document_type processed_attachments = 0 @@ -273,8 +275,9 @@ class MailAccountHandler(LoggingMixin): if ( not att.content_disposition == "attachment" - and rule.attachment_type == MailRule.ATTACHMENT_TYPE_ATTACHMENTS_ONLY - ): # NOQA: E501 + and rule.attachment_type + == MailRule.AttachmentProcessing.ATTACHMENTS_ONLY + ): self.log( "debug", f"Rule {rule}: " @@ -284,7 +287,12 @@ class MailAccountHandler(LoggingMixin): continue if rule.filter_attachment_filename: - if not fnmatch(att.filename, rule.filter_attachment_filename): + # Force the filename and pattern to the lowercase + # as this is system dependent otherwise + if not fnmatch( + att.filename.lower(), + rule.filter_attachment_filename.lower(), + ): continue title = self.get_title(message, att, rule) @@ -297,7 +305,8 @@ class MailAccountHandler(LoggingMixin): os.makedirs(settings.SCRATCH_DIR, exist_ok=True) _, temp_filename = tempfile.mkstemp( - prefix="paperless-mail-", dir=settings.SCRATCH_DIR + prefix="paperless-mail-", + dir=settings.SCRATCH_DIR, ) with open(temp_filename, "wb") as f: f.write(att.payload) @@ -313,16 +322,14 @@ class MailAccountHandler(LoggingMixin): "documents.tasks.consume_file", path=temp_filename, override_filename=pathvalidate.sanitize_filename( - att.filename - ), # NOQA: E501 + att.filename, + ), override_title=title, override_correspondent_id=correspondent.id if correspondent - else None, # NOQA: E501 - override_document_type_id=doc_type.id - if doc_type - else None, # NOQA: E501 - override_tag_ids=[tag.id] if tag else None, + else None, + override_document_type_id=doc_type.id if doc_type else None, + override_tag_ids=tag_ids, task_name=att.filename[:100], ) diff --git a/src/paperless_mail/management/commands/mail_fetcher.py b/src/paperless_mail/management/commands/mail_fetcher.py index 642633660..e2bc8262c 100644 --- a/src/paperless_mail/management/commands/mail_fetcher.py +++ b/src/paperless_mail/management/commands/mail_fetcher.py @@ -1,5 +1,4 @@ from django.core.management.base import BaseCommand - from paperless_mail import tasks @@ -7,7 +6,8 @@ class Command(BaseCommand): help = """ """.replace( - " ", "" + " ", + "", ) def handle(self, *args, **options): diff --git a/src/paperless_mail/migrations/0009_alter_mailrule_action_alter_mailrule_folder.py b/src/paperless_mail/migrations/0009_alter_mailrule_action_alter_mailrule_folder.py new file mode 100644 index 000000000..7eff52691 --- /dev/null +++ b/src/paperless_mail/migrations/0009_alter_mailrule_action_alter_mailrule_folder.py @@ -0,0 +1,37 @@ +# Generated by Django 4.0.3 on 2022-03-28 17:40 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("paperless_mail", "0008_auto_20210516_0940"), + ] + + operations = [ + migrations.AlterField( + model_name="mailrule", + name="action", + field=models.PositiveIntegerField( + choices=[ + (1, "Mark as read, don't process read mails"), + (2, "Flag the mail, don't process flagged mails"), + (3, "Move to specified folder"), + (4, "Delete"), + ], + default=3, + verbose_name="action", + ), + ), + migrations.AlterField( + model_name="mailrule", + name="folder", + field=models.CharField( + default="INBOX", + help_text="Subfolders must be separated by a delimiter, often a dot ('.') or slash ('/'), but it varies by mail server.", + max_length=256, + verbose_name="folder", + ), + ), + ] diff --git a/src/paperless_mail/migrations/0009_mailrule_assign_tags.py b/src/paperless_mail/migrations/0009_mailrule_assign_tags.py new file mode 100644 index 000000000..fe2447e62 --- /dev/null +++ b/src/paperless_mail/migrations/0009_mailrule_assign_tags.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.12 on 2022-03-11 15:00 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("paperless_mail", "0008_auto_20210516_0940"), + ] + + operations = [ + migrations.AddField( + model_name="mailrule", + name="assign_tags", + field=models.ManyToManyField( + blank=True, + related_name="mail_rules_multi", + to="documents.Tag", + verbose_name="assign this tag", + ), + ), + ] diff --git a/src/paperless_mail/migrations/0010_auto_20220311_1602.py b/src/paperless_mail/migrations/0010_auto_20220311_1602.py new file mode 100644 index 000000000..77a00d3c8 --- /dev/null +++ b/src/paperless_mail/migrations/0010_auto_20220311_1602.py @@ -0,0 +1,40 @@ +# Generated by Django 3.2.12 on 2022-03-11 15:02 + +from django.db import migrations + + +def migrate_tag_to_tags(apps, schema_editor): + # Manual data migration, see + # https://docs.djangoproject.com/en/3.2/topics/migrations/#data-migrations + # + # Copy the assign_tag property to the new assign_tags set if it exists. + MailRule = apps.get_model("paperless_mail", "MailRule") + for mail_rule in MailRule.objects.all(): + if mail_rule.assign_tag: + mail_rule.assign_tags.add(mail_rule.assign_tag) + mail_rule.save() + + +def migrate_tags_to_tag(apps, schema_editor): + # Manual data migration, see + # https://docs.djangoproject.com/en/3.2/topics/migrations/#data-migrations + # + # Copy the unique value in the assign_tags set to the old assign_tag property. + # Do nothing if the tag is not unique. + MailRule = apps.get_model("paperless_mail", "MailRule") + for mail_rule in MailRule.objects.all(): + tags = mail_rule.assign_tags.all() + if len(tags) == 1: + mail_rule.assign_tag = tags[0] + mail_rule.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ("paperless_mail", "0009_mailrule_assign_tags"), + ] + + operations = [ + migrations.RunPython(migrate_tag_to_tags, migrate_tags_to_tag), + ] diff --git a/src/paperless_mail/migrations/0011_remove_mailrule_assign_tag.py b/src/paperless_mail/migrations/0011_remove_mailrule_assign_tag.py new file mode 100644 index 000000000..ce3c24932 --- /dev/null +++ b/src/paperless_mail/migrations/0011_remove_mailrule_assign_tag.py @@ -0,0 +1,17 @@ +# Generated by Django 3.2.12 on 2022-03-11 15:18 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("paperless_mail", "0010_auto_20220311_1602"), + ] + + operations = [ + migrations.RemoveField( + model_name="mailrule", + name="assign_tag", + ), + ] diff --git a/src/paperless_mail/migrations/0012_alter_mailrule_assign_tags.py b/src/paperless_mail/migrations/0012_alter_mailrule_assign_tags.py new file mode 100644 index 000000000..811c7d90a --- /dev/null +++ b/src/paperless_mail/migrations/0012_alter_mailrule_assign_tags.py @@ -0,0 +1,20 @@ +# Generated by Django 3.2.12 on 2022-03-11 16:21 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("paperless_mail", "0011_remove_mailrule_assign_tag"), + ] + + operations = [ + migrations.AlterField( + model_name="mailrule", + name="assign_tags", + field=models.ManyToManyField( + blank=True, to="documents.Tag", verbose_name="assign this tag" + ), + ), + ] diff --git a/src/paperless_mail/migrations/0013_merge_20220412_1051.py b/src/paperless_mail/migrations/0013_merge_20220412_1051.py new file mode 100644 index 000000000..2fdb17ff5 --- /dev/null +++ b/src/paperless_mail/migrations/0013_merge_20220412_1051.py @@ -0,0 +1,13 @@ +# Generated by Django 4.0.4 on 2022-04-12 08:51 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("paperless_mail", "0009_alter_mailrule_action_alter_mailrule_folder"), + ("paperless_mail", "0012_alter_mailrule_assign_tags"), + ] + + operations = [] diff --git a/src/paperless_mail/migrations/0014_alter_mailrule_action.py b/src/paperless_mail/migrations/0014_alter_mailrule_action.py new file mode 100644 index 000000000..6d3a369cd --- /dev/null +++ b/src/paperless_mail/migrations/0014_alter_mailrule_action.py @@ -0,0 +1,27 @@ +# Generated by Django 4.0.4 on 2022-04-18 22:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("paperless_mail", "0013_merge_20220412_1051"), + ] + + operations = [ + migrations.AlterField( + model_name="mailrule", + name="action", + field=models.PositiveIntegerField( + choices=[ + (1, "Delete"), + (2, "Move to specified folder"), + (3, "Mark as read, don't process read mails"), + (4, "Flag the mail, don't process flagged mails"), + ], + default=3, + verbose_name="action", + ), + ), + ] diff --git a/src/paperless_mail/models.py b/src/paperless_mail/models.py index 08048d352..4e90197b7 100644 --- a/src/paperless_mail/models.py +++ b/src/paperless_mail/models.py @@ -1,7 +1,5 @@ -from django.db import models - import documents.models as document_models - +from django.db import models from django.utils.translation import gettext_lazy as _ @@ -10,15 +8,10 @@ class MailAccount(models.Model): verbose_name = _("mail account") verbose_name_plural = _("mail accounts") - IMAP_SECURITY_NONE = 1 - IMAP_SECURITY_SSL = 2 - IMAP_SECURITY_STARTTLS = 3 - - IMAP_SECURITY_OPTIONS = ( - (IMAP_SECURITY_NONE, _("No encryption")), - (IMAP_SECURITY_SSL, _("Use SSL")), - (IMAP_SECURITY_STARTTLS, _("Use STARTTLS")), - ) + class ImapSecurity(models.IntegerChoices): + NONE = 1, _("No encryption") + SSL = 2, _("Use SSL") + STARTTLS = 3, _("Use STARTTLS") name = models.CharField(_("name"), max_length=256, unique=True) @@ -30,12 +23,14 @@ class MailAccount(models.Model): null=True, help_text=_( "This is usually 143 for unencrypted and STARTTLS " - "connections, and 993 for SSL connections." + "connections, and 993 for SSL connections.", ), ) imap_security = models.PositiveIntegerField( - _("IMAP security"), choices=IMAP_SECURITY_OPTIONS, default=IMAP_SECURITY_SSL + _("IMAP security"), + choices=ImapSecurity.choices, + default=ImapSecurity.SSL, ) username = models.CharField(_("username"), max_length=256) @@ -48,7 +43,7 @@ class MailAccount(models.Model): default="UTF-8", help_text=_( "The character set to use when communicating with the " - "mail server, such as 'UTF-8' or 'US-ASCII'." + "mail server, such as 'UTF-8' or 'US-ASCII'.", ), ) @@ -61,48 +56,25 @@ class MailRule(models.Model): verbose_name = _("mail rule") verbose_name_plural = _("mail rules") - ATTACHMENT_TYPE_ATTACHMENTS_ONLY = 1 - ATTACHMENT_TYPE_EVERYTHING = 2 + class AttachmentProcessing(models.IntegerChoices): + ATTACHMENTS_ONLY = 1, _("Only process attachments.") + EVERYTHING = 2, _("Process all files, including 'inline' " "attachments.") - ATTACHMENT_TYPES = ( - (ATTACHMENT_TYPE_ATTACHMENTS_ONLY, _("Only process attachments.")), - ( - ATTACHMENT_TYPE_EVERYTHING, - _("Process all files, including 'inline' " "attachments."), - ), - ) + class MailAction(models.IntegerChoices): + DELETE = 1, _("Delete") + MOVE = 2, _("Move to specified folder") + MARK_READ = 3, _("Mark as read, don't process read mails") + FLAG = 4, _("Flag the mail, don't process flagged mails") - ACTION_DELETE = 1 - ACTION_MOVE = 2 - ACTION_MARK_READ = 3 - ACTION_FLAG = 4 + class TitleSource(models.IntegerChoices): + FROM_SUBJECT = 1, _("Use subject as title") + FROM_FILENAME = 2, _("Use attachment filename as title") - ACTIONS = ( - (ACTION_MARK_READ, _("Mark as read, don't process read mails")), - (ACTION_FLAG, _("Flag the mail, don't process flagged mails")), - (ACTION_MOVE, _("Move to specified folder")), - (ACTION_DELETE, _("Delete")), - ) - - TITLE_FROM_SUBJECT = 1 - TITLE_FROM_FILENAME = 2 - - TITLE_SELECTOR = ( - (TITLE_FROM_SUBJECT, _("Use subject as title")), - (TITLE_FROM_FILENAME, _("Use attachment filename as title")), - ) - - CORRESPONDENT_FROM_NOTHING = 1 - CORRESPONDENT_FROM_EMAIL = 2 - CORRESPONDENT_FROM_NAME = 3 - CORRESPONDENT_FROM_CUSTOM = 4 - - CORRESPONDENT_SELECTOR = ( - (CORRESPONDENT_FROM_NOTHING, _("Do not assign a correspondent")), - (CORRESPONDENT_FROM_EMAIL, _("Use mail address")), - (CORRESPONDENT_FROM_NAME, _("Use name (or mail address if not available)")), - (CORRESPONDENT_FROM_CUSTOM, _("Use correspondent selected below")), - ) + class CorrespondentSource(models.IntegerChoices): + FROM_NOTHING = 1, _("Do not assign a correspondent") + FROM_EMAIL = 2, _("Use mail address") + FROM_NAME = 3, _("Use name (or mail address if not available)") + FROM_CUSTOM = 4, _("Use correspondent selected below") name = models.CharField(_("name"), max_length=256, unique=True) @@ -119,17 +91,29 @@ class MailRule(models.Model): _("folder"), default="INBOX", max_length=256, - help_text=_("Subfolders must be separated by dots."), + help_text=_( + "Subfolders must be separated by a delimiter, often a dot ('.') or" + " slash ('/'), but it varies by mail server.", + ), ) filter_from = models.CharField( - _("filter from"), max_length=256, null=True, blank=True + _("filter from"), + max_length=256, + null=True, + blank=True, ) filter_subject = models.CharField( - _("filter subject"), max_length=256, null=True, blank=True + _("filter subject"), + max_length=256, + null=True, + blank=True, ) filter_body = models.CharField( - _("filter body"), max_length=256, null=True, blank=True + _("filter body"), + max_length=256, + null=True, + blank=True, ) filter_attachment_filename = models.CharField( @@ -140,28 +124,30 @@ class MailRule(models.Model): help_text=_( "Only consume documents which entirely match this " "filename if specified. Wildcards such as *.pdf or " - "*invoice* are allowed. Case insensitive." + "*invoice* are allowed. Case insensitive.", ), ) maximum_age = models.PositiveIntegerField( - _("maximum age"), default=30, help_text=_("Specified in days.") + _("maximum age"), + default=30, + help_text=_("Specified in days."), ) attachment_type = models.PositiveIntegerField( _("attachment type"), - choices=ATTACHMENT_TYPES, - default=ATTACHMENT_TYPE_ATTACHMENTS_ONLY, + choices=AttachmentProcessing.choices, + default=AttachmentProcessing.ATTACHMENTS_ONLY, help_text=_( "Inline attachments include embedded images, so it's best " - "to combine this option with a filename filter." + "to combine this option with a filename filter.", ), ) action = models.PositiveIntegerField( _("action"), - choices=ACTIONS, - default=ACTION_MARK_READ, + choices=MailAction.choices, + default=MailAction.MARK_READ, ) action_parameter = models.CharField( @@ -173,19 +159,19 @@ class MailRule(models.Model): "Additional parameter for the action selected above, " "i.e., " "the target folder of the move to folder action. " - "Subfolders must be separated by dots." + "Subfolders must be separated by dots.", ), ) assign_title_from = models.PositiveIntegerField( - _("assign title from"), choices=TITLE_SELECTOR, default=TITLE_FROM_SUBJECT + _("assign title from"), + choices=TitleSource.choices, + default=TitleSource.FROM_SUBJECT, ) - assign_tag = models.ForeignKey( + assign_tags = models.ManyToManyField( document_models.Tag, - null=True, blank=True, - on_delete=models.SET_NULL, verbose_name=_("assign this tag"), ) @@ -199,8 +185,8 @@ class MailRule(models.Model): assign_correspondent_from = models.PositiveIntegerField( _("assign correspondent from"), - choices=CORRESPONDENT_SELECTOR, - default=CORRESPONDENT_FROM_NOTHING, + choices=CorrespondentSource.choices, + default=CorrespondentSource.FROM_NOTHING, ) assign_correspondent = models.ForeignKey( diff --git a/src/paperless_mail/tasks.py b/src/paperless_mail/tasks.py index bbb163ff1..faa0300e8 100644 --- a/src/paperless_mail/tasks.py +++ b/src/paperless_mail/tasks.py @@ -1,6 +1,7 @@ import logging -from paperless_mail.mail import MailAccountHandler, MailError +from paperless_mail.mail import MailAccountHandler +from paperless_mail.mail import MailError from paperless_mail.models import MailAccount diff --git a/src/paperless_mail/tests/test_mail.py b/src/paperless_mail/tests/test_mail.py index 10aa431db..cd56d0aac 100644 --- a/src/paperless_mail/tests/test_mail.py +++ b/src/paperless_mail/tests/test_mail.py @@ -1,23 +1,40 @@ +import dataclasses +import email.contentmanager import os +import random import uuid from collections import namedtuple from typing import ContextManager +from typing import List +from typing import Union from unittest import mock from django.core.management import call_command from django.db import DatabaseError from django.test import TestCase -from imap_tools import MailMessageFlags, MailboxFolderSelectError - from documents.models import Correspondent from documents.tests.utils import DirectoriesMixin +from imap_tools import EmailAddress +from imap_tools import MailboxFolderSelectError +from imap_tools import MailMessage +from imap_tools import MailMessageFlags from paperless_mail import tasks -from paperless_mail.mail import MailError, MailAccountHandler -from paperless_mail.models import MailRule, MailAccount +from paperless_mail.mail import MailAccountHandler +from paperless_mail.mail import MailError +from paperless_mail.models import MailAccount +from paperless_mail.models import MailRule + + +@dataclasses.dataclass +class _AttachmentDef(object): + filename: str = "a_file.pdf" + maintype: str = "application/pdf" + subtype: str = "pdf" + disposition: str = "attachment" + content: bytes = b"a PDF document" class BogusFolderManager: - current_folder = "INBOX" def set(self, new_folder): @@ -34,8 +51,8 @@ class BogusMailBox(ContextManager): pass def __init__(self): - self.messages = [] - self.messages_spam = [] + self.messages: List[MailMessage] = [] + self.messages_spam: List[MailMessage] = [] def login(self, username, password): if not (username == "admin" and password == "secret"): @@ -57,7 +74,7 @@ class BogusMailBox(ContextManager): if "BODY" in criteria: body = criteria[criteria.index("BODY") + 1].strip('"') - msg = filter(lambda m: body in m.body, msg) + msg = filter(lambda m: body in m.text, msg) if "FROM" in criteria: from_ = criteria[criteria.index("FROM") + 1].strip('"') @@ -82,50 +99,74 @@ class BogusMailBox(ContextManager): def move(self, uid_list, folder): if folder == "spam": - self.messages_spam.append( - filter(lambda m: m.uid in uid_list, self.messages) + self.messages_spam += list( + filter(lambda m: m.uid in uid_list, self.messages), ) self.messages = list(filter(lambda m: m.uid not in uid_list, self.messages)) else: raise Exception() +_used_uids = set() + + def create_message( - num_attachments=1, - body="", - subject="the suject", - from_="noone@mail.com", - seen=False, - flagged=False, -): - message = namedtuple("MailMessage", []) + attachments: Union[int, List[_AttachmentDef]] = 1, + body: str = "", + subject: str = "the suject", + from_: str = "noone@mail.com", + seen: bool = False, + flagged: bool = False, +) -> MailMessage: + email_msg = email.message.EmailMessage() + # TODO: This does NOT set the UID + email_msg["Message-ID"] = str(uuid.uuid4()) + email_msg["Subject"] = subject + email_msg["From"] = from_ + email_msg.set_content(body) - message.uid = uuid.uuid4() - message.subject = subject - message.attachments = [] - message.from_ = from_ - message.body = body - for i in range(num_attachments): - message.attachments.append(create_attachment(filename=f"file_{i}.pdf")) + # Either add some default number of attachments + # or the provided attachments + if isinstance(attachments, int): + for i in range(attachments): + attachment = _AttachmentDef(filename=f"file_{i}.pdf") + email_msg.add_attachment( + attachment.content, + maintype=attachment.maintype, + subtype=attachment.subtype, + disposition=attachment.disposition, + filename=attachment.filename, + ) + else: + for attachment in attachments: + email_msg.add_attachment( + attachment.content, + maintype=attachment.maintype, + subtype=attachment.subtype, + disposition=attachment.disposition, + filename=attachment.filename, + ) - message.seen = seen - message.flagged = flagged + # Convert the EmailMessage to an imap_tools MailMessage + imap_msg = MailMessage.from_bytes(email_msg.as_bytes()) - return message + # TODO: Unsure how to add a uid to the actual EmailMessage. This hacks it in, + # based on how imap_tools uses regex to extract it. + # This should be a large enough pool + uid = random.randint(1, 10000) + while uid in _used_uids: + uid = random.randint(1, 10000) + _used_uids.add(uid) + imap_msg._raw_uid_data = f"UID {uid}".encode() -def create_attachment( - filename="the_file.pdf", content_disposition="attachment", payload=b"a PDF document" -): - attachment = namedtuple("Attachment", []) - attachment.filename = filename - attachment.content_disposition = content_disposition - attachment.payload = payload - return attachment + imap_msg.seen = seen + imap_msg.flagged = flagged + + return imap_msg def fake_magic_from_buffer(buffer, mime=False): - if mime: if "PDF" in str(buffer): return "application/pdf" @@ -163,7 +204,7 @@ class TestMail(DirectoriesMixin, TestCase): body="cables", seen=True, flagged=False, - ) + ), ) self.bogus_mailbox.messages.append( create_message( @@ -171,24 +212,32 @@ class TestMail(DirectoriesMixin, TestCase): body="from my favorite electronic store", seen=False, flagged=True, - ) + ), ) self.bogus_mailbox.messages.append( create_message( subject="Claim your $10M price now!", from_="amazon@amazon-some-indian-site.org", seen=False, - ) + ), ) def test_get_correspondent(self): message = namedtuple("MailMessage", []) message.from_ = "someone@somewhere.com" - message.from_values = {"name": "Someone!", "email": "someone@somewhere.com"} + message.from_values = EmailAddress( + "Someone!", + "someone@somewhere.com", + "Someone! <someone@somewhere.com>", + ) message2 = namedtuple("MailMessage", []) message2.from_ = "me@localhost.com" - message2.from_values = {"name": "", "email": "fake@localhost.com"} + message2.from_values = EmailAddress( + "", + "fake@localhost.com", + "", + ) me_localhost = Correspondent.objects.create(name=message2.from_) someone_else = Correspondent.objects.create(name="someone else") @@ -196,12 +245,14 @@ class TestMail(DirectoriesMixin, TestCase): handler = MailAccountHandler() rule = MailRule( - name="a", assign_correspondent_from=MailRule.CORRESPONDENT_FROM_NOTHING + name="a", + assign_correspondent_from=MailRule.CorrespondentSource.FROM_NOTHING, ) self.assertIsNone(handler.get_correspondent(message, rule)) rule = MailRule( - name="b", assign_correspondent_from=MailRule.CORRESPONDENT_FROM_EMAIL + name="b", + assign_correspondent_from=MailRule.CorrespondentSource.FROM_EMAIL, ) c = handler.get_correspondent(message, rule) self.assertIsNotNone(c) @@ -212,7 +263,8 @@ class TestMail(DirectoriesMixin, TestCase): self.assertEqual(c.id, me_localhost.id) rule = MailRule( - name="c", assign_correspondent_from=MailRule.CORRESPONDENT_FROM_NAME + name="c", + assign_correspondent_from=MailRule.CorrespondentSource.FROM_NAME, ) c = handler.get_correspondent(message, rule) self.assertIsNotNone(c) @@ -223,7 +275,7 @@ class TestMail(DirectoriesMixin, TestCase): rule = MailRule( name="d", - assign_correspondent_from=MailRule.CORRESPONDENT_FROM_CUSTOM, + assign_correspondent_from=MailRule.CorrespondentSource.FROM_CUSTOM, assign_correspondent=someone_else, ) c = handler.get_correspondent(message, rule) @@ -237,18 +289,31 @@ class TestMail(DirectoriesMixin, TestCase): handler = MailAccountHandler() - rule = MailRule(name="a", assign_title_from=MailRule.TITLE_FROM_FILENAME) + rule = MailRule( + name="a", + assign_title_from=MailRule.TitleSource.FROM_FILENAME, + ) self.assertEqual(handler.get_title(message, att, rule), "this_is_the_file") - rule = MailRule(name="b", assign_title_from=MailRule.TITLE_FROM_SUBJECT) + rule = MailRule( + name="b", + assign_title_from=MailRule.TitleSource.FROM_SUBJECT, + ) self.assertEqual(handler.get_title(message, att, rule), "the message title") def test_handle_message(self): message = create_message( - subject="the message title", from_="Myself", num_attachments=2 + subject="the message title", + from_="Myself", + attachments=2, ) account = MailAccount() - rule = MailRule(assign_title_from=MailRule.TITLE_FROM_FILENAME, account=account) + account.save() + rule = MailRule( + assign_title_from=MailRule.TitleSource.FROM_FILENAME, + account=account, + ) + rule.save() result = self.mail_account_handler.handle_message(message, rule) @@ -281,17 +346,23 @@ class TestMail(DirectoriesMixin, TestCase): self.assertEqual(result, 0) def test_handle_unknown_mime_type(self): - message = create_message() - message.attachments = [ - create_attachment(filename="f1.pdf"), - create_attachment( - filename="f2.json", - payload=b"{'much': 'payload.', 'so': 'json', 'wow': true}", - ), - ] + message = create_message( + attachments=[ + _AttachmentDef(filename="f1.pdf"), + _AttachmentDef( + filename="f2.json", + content=b"{'much': 'payload.', 'so': 'json', 'wow': true}", + ), + ], + ) account = MailAccount() - rule = MailRule(assign_title_from=MailRule.TITLE_FROM_FILENAME, account=account) + account.save() + rule = MailRule( + assign_title_from=MailRule.TitleSource.FROM_FILENAME, + account=account, + ) + rule.save() result = self.mail_account_handler.handle_message(message, rule) @@ -303,14 +374,23 @@ class TestMail(DirectoriesMixin, TestCase): self.assertEqual(kwargs["override_filename"], "f1.pdf") def test_handle_disposition(self): - message = create_message() - message.attachments = [ - create_attachment(filename="f1.pdf", content_disposition="inline"), - create_attachment(filename="f2.pdf", content_disposition="attachment"), - ] + message = create_message( + attachments=[ + _AttachmentDef( + filename="f1.pdf", + disposition="inline", + ), + _AttachmentDef(filename="f2.pdf"), + ], + ) account = MailAccount() - rule = MailRule(assign_title_from=MailRule.TITLE_FROM_FILENAME, account=account) + account.save() + rule = MailRule( + assign_title_from=MailRule.TitleSource.FROM_FILENAME, + account=account, + ) + rule.save() result = self.mail_account_handler.handle_message(message, rule) @@ -321,18 +401,24 @@ class TestMail(DirectoriesMixin, TestCase): self.assertEqual(kwargs["override_filename"], "f2.pdf") def test_handle_inline_files(self): - message = create_message() - message.attachments = [ - create_attachment(filename="f1.pdf", content_disposition="inline"), - create_attachment(filename="f2.pdf", content_disposition="attachment"), - ] + message = create_message( + attachments=[ + _AttachmentDef( + filename="f1.pdf", + disposition="inline", + ), + _AttachmentDef(filename="f2.pdf"), + ], + ) account = MailAccount() + account.save() rule = MailRule( - assign_title_from=MailRule.TITLE_FROM_FILENAME, + assign_title_from=MailRule.TitleSource.FROM_FILENAME, account=account, - attachment_type=MailRule.ATTACHMENT_TYPE_EVERYTHING, + attachment_type=MailRule.AttachmentProcessing.EVERYTHING, ) + rule.save() result = self.mail_account_handler.handle_message(message, rule) @@ -340,47 +426,59 @@ class TestMail(DirectoriesMixin, TestCase): self.assertEqual(self.async_task.call_count, 2) def test_filename_filter(self): - message = create_message() - message.attachments = [ - create_attachment(filename="f1.pdf"), - create_attachment(filename="f2.pdf"), - create_attachment(filename="f3.pdf"), - create_attachment(filename="f2.png"), - ] + message = create_message( + attachments=[ + _AttachmentDef(filename="f1.pdf"), + _AttachmentDef(filename="f2.pdf"), + _AttachmentDef(filename="f3.pdf"), + _AttachmentDef(filename="f2.png"), + _AttachmentDef(filename="file.PDf"), + _AttachmentDef(filename="f1.Pdf"), + ], + ) tests = [ - ("*.pdf", ["f1.pdf", "f2.pdf", "f3.pdf"]), - ("f1.pdf", ["f1.pdf"]), + ("*.pdf", ["f1.pdf", "f1.Pdf", "f2.pdf", "f3.pdf", "file.PDf"]), + ("f1.pdf", ["f1.pdf", "f1.Pdf"]), ("f1", []), - ("*", ["f1.pdf", "f2.pdf", "f3.pdf", "f2.png"]), + ("*", ["f1.pdf", "f2.pdf", "f3.pdf", "f2.png", "f1.Pdf", "file.PDf"]), ("*.png", ["f2.png"]), ] for (pattern, matches) in tests: + matches.sort() self.async_task.reset_mock() - account = MailAccount() + account = MailAccount(name=str(uuid.uuid4())) + account.save() rule = MailRule( - assign_title_from=MailRule.TITLE_FROM_FILENAME, + name=str(uuid.uuid4()), + assign_title_from=MailRule.TitleSource.FROM_FILENAME, account=account, filter_attachment_filename=pattern, ) + rule.save() result = self.mail_account_handler.handle_message(message, rule) - self.assertEqual(result, len(matches)) - filenames = [ - a[1]["override_filename"] for a in self.async_task.call_args_list - ] - self.assertCountEqual(filenames, matches) + self.assertEqual(result, len(matches), f"Error with pattern: {pattern}") + filenames = sorted( + [a[1]["override_filename"] for a in self.async_task.call_args_list], + ) + self.assertListEqual(filenames, matches) def test_handle_mail_account_mark_read(self): account = MailAccount.objects.create( - name="test", imap_server="", username="admin", password="secret" + name="test", + imap_server="", + username="admin", + password="secret", ) - rule = MailRule.objects.create( - name="testrule", account=account, action=MailRule.ACTION_MARK_READ + _ = MailRule.objects.create( + name="testrule", + account=account, + action=MailRule.MailAction.MARK_READ, ) self.assertEqual(len(self.bogus_mailbox.messages), 3) @@ -394,13 +492,16 @@ class TestMail(DirectoriesMixin, TestCase): def test_handle_mail_account_delete(self): account = MailAccount.objects.create( - name="test", imap_server="", username="admin", password="secret" + name="test", + imap_server="", + username="admin", + password="secret", ) - rule = MailRule.objects.create( + _ = MailRule.objects.create( name="testrule", account=account, - action=MailRule.ACTION_DELETE, + action=MailRule.MailAction.DELETE, filter_subject="Invoice", ) @@ -412,13 +513,16 @@ class TestMail(DirectoriesMixin, TestCase): def test_handle_mail_account_flag(self): account = MailAccount.objects.create( - name="test", imap_server="", username="admin", password="secret" + name="test", + imap_server="", + username="admin", + password="secret", ) - rule = MailRule.objects.create( + _ = MailRule.objects.create( name="testrule", account=account, - action=MailRule.ACTION_FLAG, + action=MailRule.MailAction.FLAG, filter_subject="Invoice", ) @@ -432,13 +536,16 @@ class TestMail(DirectoriesMixin, TestCase): def test_handle_mail_account_move(self): account = MailAccount.objects.create( - name="test", imap_server="", username="admin", password="secret" + name="test", + imap_server="", + username="admin", + password="secret", ) - rule = MailRule.objects.create( + _ = MailRule.objects.create( name="testrule", account=account, - action=MailRule.ACTION_MOVE, + action=MailRule.MailAction.MOVE, action_parameter="spam", filter_subject="Claim", ) @@ -446,35 +553,45 @@ class TestMail(DirectoriesMixin, TestCase): self.assertEqual(self.async_task.call_count, 0) self.assertEqual(len(self.bogus_mailbox.messages), 3) self.assertEqual(len(self.bogus_mailbox.messages_spam), 0) + self.mail_account_handler.handle_mail_account(account) + self.assertEqual(self.async_task.call_count, 1) self.assertEqual(len(self.bogus_mailbox.messages), 2) self.assertEqual(len(self.bogus_mailbox.messages_spam), 1) def test_error_login(self): account = MailAccount.objects.create( - name="test", imap_server="", username="admin", password="wrong" + name="test", + imap_server="", + username="admin", + password="wrong", ) - try: + with self.assertRaises(MailError) as context: self.mail_account_handler.handle_mail_account(account) - except MailError as e: - self.assertTrue(str(e).startswith("Error while authenticating account")) - else: - self.fail("Should raise exception") + self.assertTrue( + str(context).startswith("Error while authenticating account"), + ) def test_error_skip_account(self): - account_faulty = MailAccount.objects.create( - name="test", imap_server="", username="admin", password="wroasdng" + _ = MailAccount.objects.create( + name="test", + imap_server="", + username="admin", + password="wroasdng", ) account = MailAccount.objects.create( - name="test2", imap_server="", username="admin", password="secret" + name="test2", + imap_server="", + username="admin", + password="secret", ) - rule = MailRule.objects.create( + _ = MailRule.objects.create( name="testrule", account=account, - action=MailRule.ACTION_MOVE, + action=MailRule.MailAction.MOVE, action_parameter="spam", filter_subject="Claim", ) @@ -487,21 +604,24 @@ class TestMail(DirectoriesMixin, TestCase): def test_error_skip_rule(self): account = MailAccount.objects.create( - name="test2", imap_server="", username="admin", password="secret" + name="test2", + imap_server="", + username="admin", + password="secret", ) - rule = MailRule.objects.create( + _ = MailRule.objects.create( name="testrule", account=account, - action=MailRule.ACTION_MOVE, + action=MailRule.MailAction.MOVE, action_parameter="spam", filter_subject="Claim", order=1, folder="uuuhhhh", ) - rule2 = MailRule.objects.create( + _ = MailRule.objects.create( name="testrule2", account=account, - action=MailRule.ACTION_MOVE, + action=MailRule.MailAction.MOVE, action_parameter="spam", filter_subject="Claim", order=2, @@ -523,12 +643,15 @@ class TestMail(DirectoriesMixin, TestCase): m.side_effect = get_correspondent_fake account = MailAccount.objects.create( - name="test2", imap_server="", username="admin", password="secret" + name="test2", + imap_server="", + username="admin", + password="secret", ) - rule = MailRule.objects.create( + _ = MailRule.objects.create( name="testrule", account=account, - action=MailRule.ACTION_MOVE, + action=MailRule.MailAction.MOVE, action_parameter="spam", ) @@ -544,15 +667,18 @@ class TestMail(DirectoriesMixin, TestCase): def test_error_create_correspondent(self): account = MailAccount.objects.create( - name="test2", imap_server="", username="admin", password="secret" + name="test2", + imap_server="", + username="admin", + password="secret", ) - rule = MailRule.objects.create( + _ = MailRule.objects.create( name="testrule", filter_from="amazon@amazon.de", account=account, - action=MailRule.ACTION_MOVE, + action=MailRule.MailAction.MOVE, action_parameter="spam", - assign_correspondent_from=MailRule.CORRESPONDENT_FROM_EMAIL, + assign_correspondent_from=MailRule.CorrespondentSource.FROM_EMAIL, ) self.mail_account_handler.handle_mail_account(account) @@ -579,12 +705,15 @@ class TestMail(DirectoriesMixin, TestCase): def test_filters(self): account = MailAccount.objects.create( - name="test3", imap_server="", username="admin", password="secret" + name="test3", + imap_server="", + username="admin", + password="secret", ) rule = MailRule.objects.create( name="testrule3", account=account, - action=MailRule.ACTION_DELETE, + action=MailRule.MailAction.DELETE, filter_subject="Claim", ) @@ -629,10 +758,9 @@ class TestMail(DirectoriesMixin, TestCase): class TestManagementCommand(TestCase): @mock.patch( - "paperless_mail.management.commands.mail_fetcher.tasks.process_mail_accounts" + "paperless_mail.management.commands.mail_fetcher.tasks.process_mail_accounts", ) def test_mail_fetcher(self, m): - call_command("mail_fetcher") m.assert_called_once() @@ -644,10 +772,16 @@ class TestTasks(TestCase): m.side_effect = lambda account: 6 MailAccount.objects.create( - name="A", imap_server="A", username="A", password="A" + name="A", + imap_server="A", + username="A", + password="A", ) MailAccount.objects.create( - name="B", imap_server="A", username="A", password="A" + name="B", + imap_server="A", + username="A", + password="A", ) result = tasks.process_mail_accounts() @@ -661,9 +795,11 @@ class TestTasks(TestCase): @mock.patch("paperless_mail.tasks.MailAccountHandler.handle_mail_account") def test_single_accounts(self, m): - MailAccount.objects.create( - name="A", imap_server="A", username="A", password="A" + name="A", + imap_server="A", + username="A", + password="A", ) tasks.process_mail_account("A") diff --git a/src/paperless_tesseract/__init__.py b/src/paperless_tesseract/__init__.py index 5c9f358c3..1e857428c 100644 --- a/src/paperless_tesseract/__init__.py +++ b/src/paperless_tesseract/__init__.py @@ -1,2 +1,5 @@ # this is here so that django finds the checks. -from .checks import * +from .checks import check_default_language_available +from .checks import get_tesseract_langs + +__all__ = ["get_tesseract_langs", "check_default_language_available"] diff --git a/src/paperless_tesseract/apps.py b/src/paperless_tesseract/apps.py index 67b90f006..02045758b 100644 --- a/src/paperless_tesseract/apps.py +++ b/src/paperless_tesseract/apps.py @@ -1,5 +1,4 @@ from django.apps import AppConfig - from paperless_tesseract.signals import tesseract_consumer_declaration diff --git a/src/paperless_tesseract/checks.py b/src/paperless_tesseract/checks.py index e627aa0ac..99780cad4 100644 --- a/src/paperless_tesseract/checks.py +++ b/src/paperless_tesseract/checks.py @@ -1,7 +1,9 @@ import subprocess from django.conf import settings -from django.core.checks import Error, Warning, register +from django.core.checks import Error +from django.core.checks import register +from django.core.checks import Warning def get_tesseract_langs(): @@ -19,8 +21,8 @@ def check_default_language_available(app_configs, **kwargs): return [ Warning( "No OCR language has been specified with PAPERLESS_OCR_LANGUAGE. " - "This means that tesseract will fallback to english." - ) + "This means that tesseract will fallback to english.", + ), ] specified_langs = settings.OCR_LANGUAGE.split("+") @@ -31,8 +33,8 @@ def check_default_language_available(app_configs, **kwargs): Error( f"The selected ocr language {lang} is " f"not installed. Paperless cannot OCR your documents " - f"without it. Please fix PAPERLESS_OCR_LANGUAGE." - ) + f"without it. Please fix PAPERLESS_OCR_LANGUAGE.", + ), ] return [] diff --git a/src/paperless_tesseract/parsers.py b/src/paperless_tesseract/parsers.py index c27b598c8..4b1049566 100644 --- a/src/paperless_tesseract/parsers.py +++ b/src/paperless_tesseract/parsers.py @@ -2,10 +2,13 @@ import json import os import re -from PIL import Image from django.conf import settings +from documents.parsers import DocumentParser +from documents.parsers import make_thumbnail_from_pdf +from documents.parsers import ParseError +from PIL import Image -from documents.parsers import DocumentParser, ParseError, make_thumbnail_from_pdf +Image.MAX_IMAGE_PIXELS = settings.OCR_MAX_IMAGE_PIXELS class NoTextFoundException(Exception): @@ -42,7 +45,7 @@ class RasterisedDocumentParser(DocumentParser): "prefix": meta.REVERSE_NS[m.group(1)], "key": m.group(2), "value": value, - } + }, ) except Exception as e: self.log( @@ -53,7 +56,9 @@ class RasterisedDocumentParser(DocumentParser): def get_thumbnail(self, document_path, mime_type, file_name=None): return make_thumbnail_from_pdf( - self.archive_path or document_path, self.tempdir, self.logging_group + self.archive_path or document_path, + self.tempdir, + self.logging_group, ) def is_image(self, mime_type): @@ -110,7 +115,6 @@ class RasterisedDocumentParser(DocumentParser): return None from pdfminer.high_level import extract_text as pdfminer_extract_text - from pdfminer.pdftypes import PDFException try: stripped = post_process_text(pdfminer_extract_text(pdf_file)) @@ -121,7 +125,7 @@ class RasterisedDocumentParser(DocumentParser): # TODO catch all for various issues with PDFminer.six. # If PDFminer fails, fall back to OCR. self.log( - "warn", + "warning", "Error while getting text from PDF document with " "pdfminer.six", exc_info=True, ) @@ -129,7 +133,12 @@ class RasterisedDocumentParser(DocumentParser): return None def construct_ocrmypdf_parameters( - self, input_file, mime_type, output_file, sidecar_file, safe_fallback=False + self, + input_file, + mime_type, + output_file, + sidecar_file, + safe_fallback=False, ): ocrmypdf_args = { "input_file": input_file, @@ -167,7 +176,7 @@ class RasterisedDocumentParser(DocumentParser): ocrmypdf_args["rotate_pages"] = True ocrmypdf_args[ "rotate_pages_threshold" - ] = settings.OCR_ROTATE_PAGES_THRESHOLD # NOQA: E501 + ] = settings.OCR_ROTATE_PAGES_THRESHOLD if settings.OCR_PAGES > 0: ocrmypdf_args["pages"] = f"1-{settings.OCR_PAGES}" @@ -202,7 +211,7 @@ class RasterisedDocumentParser(DocumentParser): raise ParseError( f"Cannot produce archive PDF for image {input_file}, " f"no DPI information is present in this image and " - f"OCR_IMAGE_DPI is not set." + f"OCR_IMAGE_DPI is not set.", ) if settings.OCR_USER_ARGS and not safe_fallback: @@ -241,7 +250,10 @@ class RasterisedDocumentParser(DocumentParser): sidecar_file = os.path.join(self.tempdir, "sidecar.txt") args = self.construct_ocrmypdf_parameters( - document_path, mime_type, archive_path, sidecar_file + document_path, + mime_type, + archive_path, + sidecar_file, ) try: @@ -289,7 +301,8 @@ class RasterisedDocumentParser(DocumentParser): # is bigger and blurry due to --force-ocr. self.text = self.extract_text( - sidecar_file_fallback, archive_path_fallback + sidecar_file_fallback, + archive_path_fallback, ) except Exception as e: diff --git a/src/paperless_tesseract/tests/test_checks.py b/src/paperless_tesseract/tests/test_checks.py index 31d60f4ee..cfac11d3c 100644 --- a/src/paperless_tesseract/tests/test_checks.py +++ b/src/paperless_tesseract/tests/test_checks.py @@ -1,8 +1,8 @@ from unittest import mock from django.core.checks import ERROR -from django.test import TestCase, override_settings - +from django.test import override_settings +from django.test import TestCase from paperless_tesseract import check_default_language_available @@ -16,8 +16,8 @@ class TestChecks(TestCase): self.assertEqual(len(msgs), 1) self.assertTrue( msgs[0].msg.startswith( - "No OCR language has been specified with PAPERLESS_OCR_LANGUAGE" - ) + "No OCR language has been specified with PAPERLESS_OCR_LANGUAGE", + ), ) @override_settings(OCR_LANGUAGE="ita") diff --git a/src/paperless_tesseract/tests/test_parser.py b/src/paperless_tesseract/tests/test_parser.py index 9b59c324d..97ec26ca9 100644 --- a/src/paperless_tesseract/tests/test_parser.py +++ b/src/paperless_tesseract/tests/test_parser.py @@ -3,11 +3,13 @@ import uuid from typing import ContextManager from unittest import mock -from django.test import TestCase, override_settings - -from documents.parsers import ParseError, run_convert +from django.test import override_settings +from django.test import TestCase +from documents.parsers import ParseError +from documents.parsers import run_convert from documents.tests.utils import DirectoriesMixin -from paperless_tesseract.parsers import RasterisedDocumentParser, post_process_text +from paperless_tesseract.parsers import post_process_text +from paperless_tesseract.parsers import RasterisedDocumentParser image_to_string_calls = [] @@ -56,7 +58,9 @@ class TestParser(DirectoriesMixin, TestCase): result, actual_result, "strip_exceess_whitespace({}) != '{}', but '{}'".format( - source, result, actual_result + source, + result, + actual_result, ), ) @@ -65,7 +69,8 @@ class TestParser(DirectoriesMixin, TestCase): def test_get_text_from_pdf(self): parser = RasterisedDocumentParser(uuid.uuid4()) text = parser.extract_text( - None, os.path.join(self.SAMPLE_FILES, "simple-digital.pdf") + None, + os.path.join(self.SAMPLE_FILES, "simple-digital.pdf"), ) self.assertContainsStrings(text.strip(), ["This is a test document."]) @@ -73,7 +78,8 @@ class TestParser(DirectoriesMixin, TestCase): def test_thumbnail(self): parser = RasterisedDocumentParser(uuid.uuid4()) thumb = parser.get_thumbnail( - os.path.join(self.SAMPLE_FILES, "simple-digital.pdf"), "application/pdf" + os.path.join(self.SAMPLE_FILES, "simple-digital.pdf"), + "application/pdf", ) self.assertTrue(os.path.isfile(thumb)) @@ -89,14 +95,16 @@ class TestParser(DirectoriesMixin, TestCase): parser = RasterisedDocumentParser(uuid.uuid4()) thumb = parser.get_thumbnail( - os.path.join(self.SAMPLE_FILES, "simple-digital.pdf"), "application/pdf" + os.path.join(self.SAMPLE_FILES, "simple-digital.pdf"), + "application/pdf", ) self.assertTrue(os.path.isfile(thumb)) def test_thumbnail_encrypted(self): parser = RasterisedDocumentParser(uuid.uuid4()) thumb = parser.get_thumbnail( - os.path.join(self.SAMPLE_FILES, "encrypted.pdf"), "application/pdf" + os.path.join(self.SAMPLE_FILES, "encrypted.pdf"), + "application/pdf", ) self.assertTrue(os.path.isfile(thumb)) @@ -113,7 +121,8 @@ class TestParser(DirectoriesMixin, TestCase): parser = RasterisedDocumentParser(None) parser.parse( - os.path.join(self.SAMPLE_FILES, "simple-digital.pdf"), "application/pdf" + os.path.join(self.SAMPLE_FILES, "simple-digital.pdf"), + "application/pdf", ) self.assertTrue(os.path.isfile(parser.archive_path)) @@ -124,7 +133,8 @@ class TestParser(DirectoriesMixin, TestCase): parser = RasterisedDocumentParser(None) parser.parse( - os.path.join(self.SAMPLE_FILES, "with-form.pdf"), "application/pdf" + os.path.join(self.SAMPLE_FILES, "with-form.pdf"), + "application/pdf", ) self.assertTrue(os.path.isfile(parser.archive_path)) @@ -139,7 +149,8 @@ class TestParser(DirectoriesMixin, TestCase): parser = RasterisedDocumentParser(None) parser.parse( - os.path.join(self.SAMPLE_FILES, "with-form.pdf"), "application/pdf" + os.path.join(self.SAMPLE_FILES, "with-form.pdf"), + "application/pdf", ) self.assertIsNone(parser.archive_path) @@ -168,7 +179,8 @@ class TestParser(DirectoriesMixin, TestCase): parser = RasterisedDocumentParser(None) parser.parse( - os.path.join(self.SAMPLE_FILES, "encrypted.pdf"), "application/pdf" + os.path.join(self.SAMPLE_FILES, "encrypted.pdf"), + "application/pdf", ) self.assertIsNone(parser.archive_path) @@ -178,7 +190,8 @@ class TestParser(DirectoriesMixin, TestCase): def test_with_form_error_notext(self): parser = RasterisedDocumentParser(None) parser.parse( - os.path.join(self.SAMPLE_FILES, "with-form.pdf"), "application/pdf" + os.path.join(self.SAMPLE_FILES, "with-form.pdf"), + "application/pdf", ) self.assertContainsStrings( @@ -191,7 +204,8 @@ class TestParser(DirectoriesMixin, TestCase): parser = RasterisedDocumentParser(None) parser.parse( - os.path.join(self.SAMPLE_FILES, "with-form.pdf"), "application/pdf" + os.path.join(self.SAMPLE_FILES, "with-form.pdf"), + "application/pdf", ) self.assertContainsStrings( @@ -221,7 +235,7 @@ class TestParser(DirectoriesMixin, TestCase): parser = RasterisedDocumentParser(None) dpi = parser.calculate_a4_dpi( - os.path.join(self.SAMPLE_FILES, "simple-no-dpi.png") + os.path.join(self.SAMPLE_FILES, "simple-no-dpi.png"), ) self.assertEqual(dpi, 62) @@ -233,7 +247,8 @@ class TestParser(DirectoriesMixin, TestCase): def f(): parser.parse( - os.path.join(self.SAMPLE_FILES, "simple-no-dpi.png"), "image/png" + os.path.join(self.SAMPLE_FILES, "simple-no-dpi.png"), + "image/png", ) self.assertRaises(ParseError, f) @@ -247,68 +262,80 @@ class TestParser(DirectoriesMixin, TestCase): self.assertTrue(os.path.isfile(parser.archive_path)) self.assertContainsStrings( - parser.get_text().lower(), ["this is a test document."] + parser.get_text().lower(), + ["this is a test document."], ) def test_multi_page(self): parser = RasterisedDocumentParser(None) parser.parse( - os.path.join(self.SAMPLE_FILES, "multi-page-digital.pdf"), "application/pdf" + os.path.join(self.SAMPLE_FILES, "multi-page-digital.pdf"), + "application/pdf", ) self.assertTrue(os.path.isfile(parser.archive_path)) self.assertContainsStrings( - parser.get_text().lower(), ["page 1", "page 2", "page 3"] + parser.get_text().lower(), + ["page 1", "page 2", "page 3"], ) @override_settings(OCR_PAGES=2, OCR_MODE="skip") def test_multi_page_pages_skip(self): parser = RasterisedDocumentParser(None) parser.parse( - os.path.join(self.SAMPLE_FILES, "multi-page-digital.pdf"), "application/pdf" + os.path.join(self.SAMPLE_FILES, "multi-page-digital.pdf"), + "application/pdf", ) self.assertTrue(os.path.isfile(parser.archive_path)) self.assertContainsStrings( - parser.get_text().lower(), ["page 1", "page 2", "page 3"] + parser.get_text().lower(), + ["page 1", "page 2", "page 3"], ) @override_settings(OCR_PAGES=2, OCR_MODE="redo") def test_multi_page_pages_redo(self): parser = RasterisedDocumentParser(None) parser.parse( - os.path.join(self.SAMPLE_FILES, "multi-page-digital.pdf"), "application/pdf" + os.path.join(self.SAMPLE_FILES, "multi-page-digital.pdf"), + "application/pdf", ) self.assertTrue(os.path.isfile(parser.archive_path)) self.assertContainsStrings( - parser.get_text().lower(), ["page 1", "page 2", "page 3"] + parser.get_text().lower(), + ["page 1", "page 2", "page 3"], ) @override_settings(OCR_PAGES=2, OCR_MODE="force") def test_multi_page_pages_force(self): parser = RasterisedDocumentParser(None) parser.parse( - os.path.join(self.SAMPLE_FILES, "multi-page-digital.pdf"), "application/pdf" + os.path.join(self.SAMPLE_FILES, "multi-page-digital.pdf"), + "application/pdf", ) self.assertTrue(os.path.isfile(parser.archive_path)) self.assertContainsStrings( - parser.get_text().lower(), ["page 1", "page 2", "page 3"] + parser.get_text().lower(), + ["page 1", "page 2", "page 3"], ) @override_settings(OOCR_MODE="skip") def test_multi_page_analog_pages_skip(self): parser = RasterisedDocumentParser(None) parser.parse( - os.path.join(self.SAMPLE_FILES, "multi-page-images.pdf"), "application/pdf" + os.path.join(self.SAMPLE_FILES, "multi-page-images.pdf"), + "application/pdf", ) self.assertTrue(os.path.isfile(parser.archive_path)) self.assertContainsStrings( - parser.get_text().lower(), ["page 1", "page 2", "page 3"] + parser.get_text().lower(), + ["page 1", "page 2", "page 3"], ) @override_settings(OCR_PAGES=2, OCR_MODE="redo") def test_multi_page_analog_pages_redo(self): parser = RasterisedDocumentParser(None) parser.parse( - os.path.join(self.SAMPLE_FILES, "multi-page-images.pdf"), "application/pdf" + os.path.join(self.SAMPLE_FILES, "multi-page-images.pdf"), + "application/pdf", ) self.assertTrue(os.path.isfile(parser.archive_path)) self.assertContainsStrings(parser.get_text().lower(), ["page 1", "page 2"]) @@ -318,7 +345,8 @@ class TestParser(DirectoriesMixin, TestCase): def test_multi_page_analog_pages_force(self): parser = RasterisedDocumentParser(None) parser.parse( - os.path.join(self.SAMPLE_FILES, "multi-page-images.pdf"), "application/pdf" + os.path.join(self.SAMPLE_FILES, "multi-page-images.pdf"), + "application/pdf", ) self.assertTrue(os.path.isfile(parser.archive_path)) self.assertContainsStrings(parser.get_text().lower(), ["page 1"]) @@ -329,29 +357,34 @@ class TestParser(DirectoriesMixin, TestCase): def test_skip_noarchive_withtext(self): parser = RasterisedDocumentParser(None) parser.parse( - os.path.join(self.SAMPLE_FILES, "multi-page-digital.pdf"), "application/pdf" + os.path.join(self.SAMPLE_FILES, "multi-page-digital.pdf"), + "application/pdf", ) self.assertIsNone(parser.archive_path) self.assertContainsStrings( - parser.get_text().lower(), ["page 1", "page 2", "page 3"] + parser.get_text().lower(), + ["page 1", "page 2", "page 3"], ) @override_settings(OCR_MODE="skip_noarchive") def test_skip_noarchive_notext(self): parser = RasterisedDocumentParser(None) parser.parse( - os.path.join(self.SAMPLE_FILES, "multi-page-images.pdf"), "application/pdf" + os.path.join(self.SAMPLE_FILES, "multi-page-images.pdf"), + "application/pdf", ) self.assertTrue(os.path.isfile(parser.archive_path)) self.assertContainsStrings( - parser.get_text().lower(), ["page 1", "page 2", "page 3"] + parser.get_text().lower(), + ["page 1", "page 2", "page 3"], ) @override_settings(OCR_MODE="skip") def test_multi_page_mixed(self): parser = RasterisedDocumentParser(None) parser.parse( - os.path.join(self.SAMPLE_FILES, "multi-page-mixed.pdf"), "application/pdf" + os.path.join(self.SAMPLE_FILES, "multi-page-mixed.pdf"), + "application/pdf", ) self.assertTrue(os.path.isfile(parser.archive_path)) self.assertContainsStrings( @@ -368,11 +401,13 @@ class TestParser(DirectoriesMixin, TestCase): def test_multi_page_mixed_no_archive(self): parser = RasterisedDocumentParser(None) parser.parse( - os.path.join(self.SAMPLE_FILES, "multi-page-mixed.pdf"), "application/pdf" + os.path.join(self.SAMPLE_FILES, "multi-page-mixed.pdf"), + "application/pdf", ) self.assertIsNone(parser.archive_path) self.assertContainsStrings( - parser.get_text().lower(), ["page 4", "page 5", "page 6"] + parser.get_text().lower(), + ["page 4", "page 5", "page 6"], ) @override_settings(OCR_MODE="skip", OCR_ROTATE_PAGES=True) diff --git a/src/paperless_text/apps.py b/src/paperless_text/apps.py index 1acc361aa..61f5eb7ef 100644 --- a/src/paperless_text/apps.py +++ b/src/paperless_text/apps.py @@ -1,5 +1,4 @@ from django.apps import AppConfig - from paperless_text.signals import text_consumer_declaration diff --git a/src/paperless_text/parsers.py b/src/paperless_text/parsers.py index 86d4e8d43..2e002457e 100644 --- a/src/paperless_text/parsers.py +++ b/src/paperless_text/parsers.py @@ -1,9 +1,12 @@ import os -from PIL import ImageDraw, ImageFont, Image from django.conf import settings - from documents.parsers import DocumentParser +from PIL import Image +from PIL import ImageDraw +from PIL import ImageFont + +Image.MAX_IMAGE_PIXELS = settings.OCR_MAX_IMAGE_PIXELS class TextDocumentParser(DocumentParser): diff --git a/src/paperless_text/tests/test_parser.py b/src/paperless_text/tests/test_parser.py index f63c327cb..d952ceb9a 100644 --- a/src/paperless_text/tests/test_parser.py +++ b/src/paperless_text/tests/test_parser.py @@ -1,7 +1,6 @@ import os from django.test import TestCase - from documents.tests.utils import DirectoriesMixin from paperless_text.parsers import TextDocumentParser @@ -13,7 +12,8 @@ class TestTextParser(DirectoriesMixin, TestCase): # just make sure that it does not crash f = parser.get_thumbnail( - os.path.join(os.path.dirname(__file__), "samples", "test.txt"), "text/plain" + os.path.join(os.path.dirname(__file__), "samples", "test.txt"), + "text/plain", ) self.assertTrue(os.path.isfile(f)) @@ -22,7 +22,8 @@ class TestTextParser(DirectoriesMixin, TestCase): parser = TextDocumentParser(None) parser.parse( - os.path.join(os.path.dirname(__file__), "samples", "test.txt"), "text/plain" + os.path.join(os.path.dirname(__file__), "samples", "test.txt"), + "text/plain", ) self.assertEqual(parser.get_text(), "This is a test file.\n") diff --git a/src/paperless_tika/parsers.py b/src/paperless_tika/parsers.py index 5dff20098..22218dfe7 100644 --- a/src/paperless_tika/parsers.py +++ b/src/paperless_tika/parsers.py @@ -1,10 +1,11 @@ import os -import requests + import dateutil.parser - +import requests from django.conf import settings - -from documents.parsers import DocumentParser, ParseError, make_thumbnail_from_pdf +from documents.parsers import DocumentParser +from documents.parsers import make_thumbnail_from_pdf +from documents.parsers import ParseError from tika import parser @@ -20,7 +21,9 @@ class TikaDocumentParser(DocumentParser): self.archive_path = self.convert_to_pdf(document_path, file_name) return make_thumbnail_from_pdf( - self.archive_path, self.tempdir, self.logging_group + self.archive_path, + self.tempdir, + self.logging_group, ) def extract_metadata(self, document_path, mime_type): @@ -53,7 +56,7 @@ class TikaDocumentParser(DocumentParser): except Exception as err: raise ParseError( f"Could not parse {document_path} with tika server at " - f"{tika_server}: {err}" + f"{tika_server}: {err}", ) self.text = parsed["content"].strip() @@ -74,22 +77,23 @@ class TikaDocumentParser(DocumentParser): url = gotenberg_server + "/forms/libreoffice/convert" self.log("info", f"Converting {document_path} to PDF as {pdf_path}") - files = { - "files": ( - file_name or os.path.basename(document_path), - open(document_path, "rb"), - ) - } - headers = {} + with open(document_path, "rb") as document_handle: + files = { + "files": ( + file_name or os.path.basename(document_path), + document_handle, + ), + } + headers = {} - try: - response = requests.post(url, files=files, headers=headers) - response.raise_for_status() # ensure we notice bad responses - except Exception as err: - raise ParseError(f"Error while converting document to PDF: {err}") + try: + response = requests.post(url, files=files, headers=headers) + response.raise_for_status() # ensure we notice bad responses + except Exception as err: + raise ParseError(f"Error while converting document to PDF: {err}") - file = open(pdf_path, "wb") - file.write(response.content) - file.close() + with open(pdf_path, "wb") as file: + file.write(response.content) + file.close() return pdf_path diff --git a/src/paperless_tika/signals.py b/src/paperless_tika/signals.py index 6b1698f2d..39838f076 100644 --- a/src/paperless_tika/signals.py +++ b/src/paperless_tika/signals.py @@ -10,12 +10,12 @@ def tika_consumer_declaration(sender, **kwargs): "weight": 10, "mime_types": { "application/msword": ".doc", - "application/vnd.openxmlformats-officedocument.wordprocessingml.document": ".docx", # NOQA: E501 + "application/vnd.openxmlformats-officedocument.wordprocessingml.document": ".docx", # noqa: E501 "application/vnd.ms-excel": ".xls", - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": ".xlsx", # NOQA: E501 + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": ".xlsx", # noqa: E501 "application/vnd.ms-powerpoint": ".ppt", - "application/vnd.openxmlformats-officedocument.presentationml.presentation": ".pptx", # NOQA: E501 - "application/vnd.openxmlformats-officedocument.presentationml.slideshow": ".ppsx", # NOQA: E501 + "application/vnd.openxmlformats-officedocument.presentationml.presentation": ".pptx", # noqa: E501 + "application/vnd.openxmlformats-officedocument.presentationml.slideshow": ".ppsx", # noqa: E501 "application/vnd.oasis.opendocument.presentation": ".odp", "application/vnd.oasis.opendocument.spreadsheet": ".ods", "application/vnd.oasis.opendocument.text": ".odt", diff --git a/src/paperless_tika/tests/test_tika_parser.py b/src/paperless_tika/tests/test_tika_parser.py index 7eaaab25e..bf6b4e7c8 100644 --- a/src/paperless_tika/tests/test_tika_parser.py +++ b/src/paperless_tika/tests/test_tika_parser.py @@ -4,9 +4,8 @@ from pathlib import Path from unittest import mock from django.test import TestCase -from requests import Response - from paperless_tika.parsers import TikaDocumentParser +from requests import Response class TestTikaParser(TestCase): @@ -42,14 +41,15 @@ class TestTikaParser(TestCase): @mock.patch("paperless_tika.parsers.parser.from_file") def test_metadata(self, from_file): from_file.return_value = { - "metadata": {"Creation-Date": "2020-11-21", "Some-key": "value"} + "metadata": {"Creation-Date": "2020-11-21", "Some-key": "value"}, } file = os.path.join(self.parser.tempdir, "input.odt") Path(file).touch() metadata = self.parser.extract_metadata( - file, "application/vnd.oasis.opendocument.text" + file, + "application/vnd.oasis.opendocument.text", ) self.assertTrue("Creation-Date" in [m["key"] for m in metadata]) diff --git a/src/setup.cfg b/src/setup.cfg index 2a1a348bd..40ae9f1f1 100644 --- a/src/setup.cfg +++ b/src/setup.cfg @@ -1,13 +1,16 @@ -[pycodestyle] -exclude = migrations, paperless/settings.py, .tox, */tests/* +[flake8] +extend-exclude = */migrations/*, paperless/settings.py, */tests/* +# E203 - https://www.flake8rules.com/rules/E203.html +# W503 - https://www.flake8rules.com/rules/W503.html +ignore = E203,W503 +max-line-length = 88 [tool:pytest] DJANGO_SETTINGS_MODULE=paperless.settings -addopts = --pythonwarnings=all --cov --cov-report=html -n auto +addopts = --pythonwarnings=all --cov --cov-report=html --numprocesses auto --quiet env = PAPERLESS_DISABLE_DBHANDLER=true - [coverage:run] source = ./